summaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
authorKarol Lewandowski <k.lewandowsk@samsung.com>2024-01-23 12:58:00 +0100
committerKarol Lewandowski <k.lewandowsk@samsung.com>2024-01-23 12:58:00 +0100
commitcbab226a74fbaaa43220dee80e8435555c6506ce (patch)
tree1bbd14ec625ea85d0bcc32232d51c1f71e2604d2 /test
parent44a3c2255bc480c82f34db156553a595606d8a0b (diff)
downloaddevice-mapper-cbab226a74fbaaa43220dee80e8435555c6506ce.tar.gz
device-mapper-cbab226a74fbaaa43220dee80e8435555c6506ce.tar.bz2
device-mapper-cbab226a74fbaaa43220dee80e8435555c6506ce.zip
Diffstat (limited to 'test')
-rw-r--r--test/.gitignore4
-rw-r--r--test/Makefile.in388
-rw-r--r--test/api/Makefile.in60
-rw-r--r--test/api/dbustest.sh42
-rw-r--r--test/api/lvtest.c64
-rw-r--r--test/api/pe_start.c47
-rw-r--r--test/api/percent.c63
-rw-r--r--test/api/percent.sh29
-rw-r--r--test/api/test.c1107
-rw-r--r--test/api/thin_percent.c68
-rw-r--r--test/api/thin_percent.sh37
-rw-r--r--test/api/vgtest.c164
-rwxr-xr-xtest/dbus/lvm_error_inject.py348
-rwxr-xr-xtest/dbus/lvmdbustest.py2614
-rw-r--r--test/dbus/testlib.py331
-rwxr-xr-xtest/dbus/validatestate.py32
-rw-r--r--test/lib/aux.sh1987
-rw-r--r--test/lib/brick-shelltest.h1340
-rw-r--r--test/lib/check.sh366
-rw-r--r--test/lib/dmsecuretest.c86
-rw-r--r--test/lib/flavour-ndev-cluster-lvmpolld.sh2
-rw-r--r--test/lib/flavour-ndev-cluster.sh1
-rw-r--r--test/lib/flavour-ndev-devicesfile.sh2
-rw-r--r--test/lib/flavour-ndev-lvmpolld.sh2
-rw-r--r--test/lib/flavour-ndev-vanilla.sh1
-rw-r--r--test/lib/flavour-udev-cluster-lvmpolld.sh3
-rw-r--r--test/lib/flavour-udev-cluster.sh2
-rw-r--r--test/lib/flavour-udev-lvmlockd-dlm.sh6
-rw-r--r--test/lib/flavour-udev-lvmlockd-idm.sh5
-rw-r--r--test/lib/flavour-udev-lvmlockd-sanlock.sh5
-rw-r--r--test/lib/flavour-udev-lvmlockd-test.sh8
-rw-r--r--test/lib/flavour-udev-lvmpolld.sh3
-rw-r--r--test/lib/flavour-udev-vanilla.sh2
-rw-r--r--test/lib/get.sh96
-rw-r--r--test/lib/harness.c431
-rw-r--r--test/lib/idm_inject_failure.c55
-rw-r--r--test/lib/inittest.sh197
-rw-r--r--test/lib/lvm-wrapper.sh47
-rwxr-xr-xtest/lib/lvm_vdo_wrapper.sh364
-rw-r--r--test/lib/mke2fs.conf45
-rw-r--r--test/lib/not.c52
-rw-r--r--test/lib/runner.cpp46
-rw-r--r--test/lib/test-corosync-conf28
-rw-r--r--test/lib/test-dlm-conf4
-rw-r--r--test/lib/test-sanlock-conf2
-rw-r--r--test/lib/test.sh79
-rw-r--r--test/lib/utils.sh233
-rw-r--r--test/shell/000-basic.sh37
-rw-r--r--test/shell/aa-lvmlockd-dlm-prepare.sh23
-rw-r--r--test/shell/aa-lvmlockd-idm-prepare.sh22
-rw-r--r--test/shell/aa-lvmlockd-sanlock-prepare.sh46
-rw-r--r--test/shell/activate-minor.sh18
-rw-r--r--test/shell/activate-missing-segment.sh12
-rw-r--r--test/shell/activate-missing.sh24
-rw-r--r--test/shell/activate-partial.sh20
-rw-r--r--test/shell/activation-skip.sh38
-rw-r--r--test/shell/allow-mixed-block-sizes.sh71
-rw-r--r--test/shell/autoactivation-metadata.sh336
-rw-r--r--test/shell/backup-read-only.sh84
-rw-r--r--test/shell/cache-metadata2.sh100
-rw-r--r--test/shell/cache-no-discard.sh45
-rw-r--r--test/shell/cache-single-options.sh273
-rw-r--r--test/shell/cache-single-split.sh423
-rw-r--r--test/shell/cache-single-thin.sh46
-rw-r--r--test/shell/cache-single-types.sh88
-rw-r--r--test/shell/cache-single-usage.sh146
-rw-r--r--test/shell/cachevol-cachedevice.sh235
-rw-r--r--test/shell/caching-snapshot.sh162
-rw-r--r--test/shell/clvmd-restart.sh53
-rw-r--r--test/shell/component-cache.sh92
-rw-r--r--test/shell/component-mirror.sh70
-rw-r--r--test/shell/component-raid.sh50
-rw-r--r--test/shell/component-thin.sh43
-rw-r--r--test/shell/covercmd.sh127
-rw-r--r--test/shell/creation-time.sh40
-rw-r--r--test/shell/dev-aliases.sh53
-rw-r--r--test/shell/devicesfile-basic.sh687
-rw-r--r--test/shell/devicesfile-devname.sh628
-rw-r--r--test/shell/devicesfile-edit.sh257
-rw-r--r--test/shell/devicesfile-realdevs.sh612
-rw-r--r--test/shell/devicesfile-serial.sh890
-rw-r--r--test/shell/devicesfile-vpd-ids.sh436
-rw-r--r--test/shell/discards-thin.sh64
-rw-r--r--test/shell/dmeventd-restart.sh43
-rw-r--r--test/shell/dmsecuretest.sh77
-rw-r--r--test/shell/dmsetup-integrity-keys.sh58
-rw-r--r--test/shell/dmsetup-keyring.sh75
-rw-r--r--test/shell/dmstats-create.sh30
-rw-r--r--test/shell/dmstats-report.sh30
-rw-r--r--test/shell/dumpconfig.sh12
-rw-r--r--test/shell/duplicate-pvs-md0.sh308
-rw-r--r--test/shell/duplicate-pvs-md1.sh21
-rw-r--r--test/shell/duplicate-pvs-multipath.sh71
-rw-r--r--test/shell/duplicate-vgid.sh52
-rw-r--r--test/shell/duplicate-vgnames.sh624
-rw-r--r--test/shell/duplicate-vgrename.sh304
-rw-r--r--test/shell/error-usage.sh47
-rw-r--r--test/shell/exported.sh209
-rw-r--r--test/shell/fsadm-crypt-fsresize.sh625
-rw-r--r--test/shell/fsadm-crypt.sh614
-rw-r--r--test/shell/fsadm-renamed.sh138
-rw-r--r--test/shell/fsadm.sh122
-rw-r--r--test/shell/hints.sh480
-rw-r--r--test/shell/idm_fabric_failure.sh58
-rw-r--r--test/shell/idm_fabric_failure_half_brain.sh78
-rw-r--r--test/shell/idm_fabric_failure_timeout.sh74
-rw-r--r--test/shell/idm_ilm_failure.sh80
-rw-r--r--test/shell/inconsistent-metadata.sh99
-rw-r--r--test/shell/integrity-blocksize-2.sh98
-rw-r--r--test/shell/integrity-blocksize-3.sh252
-rw-r--r--test/shell/integrity-blocksize.sh298
-rw-r--r--test/shell/integrity-caching.sh527
-rw-r--r--test/shell/integrity-dmeventd.sh263
-rw-r--r--test/shell/integrity-large.sh177
-rw-r--r--test/shell/integrity-misc.sh216
-rw-r--r--test/shell/integrity-syncaction.sh159
-rw-r--r--test/shell/integrity.sh771
-rw-r--r--test/shell/large-physical-sector-size.sh43
-rw-r--r--test/shell/listings.sh195
-rw-r--r--test/shell/lock-blocking.sh38
-rw-r--r--test/shell/lock-parallel.sh50
-rw-r--r--test/shell/losetup-partscan.sh68
-rw-r--r--test/shell/lv-ancestry.sh230
-rw-r--r--test/shell/lvchange-cache-mode.sh90
-rw-r--r--test/shell/lvchange-cache-old.sh43
-rw-r--r--test/shell/lvchange-cache-syncaction-raid.sh44
-rw-r--r--test/shell/lvchange-cache.sh97
-rw-r--r--test/shell/lvchange-mirror.sh22
-rw-r--r--test/shell/lvchange-partial-raid10.sh34
-rw-r--r--test/shell/lvchange-partial.sh20
-rw-r--r--test/shell/lvchange-raid-transient-failures.sh70
-rw-r--r--test/shell/lvchange-raid.sh349
-rw-r--r--test/shell/lvchange-raid1-writemostly.sh44
-rw-r--r--test/shell/lvchange-raid10.sh (renamed from test/shell/lvmetad-pvscan-cache.sh)20
-rw-r--r--test/shell/lvchange-raid456.sh24
-rw-r--r--test/shell/lvchange-rebuild-raid.sh144
-rw-r--r--test/shell/lvchange-syncaction-raid.sh92
-rw-r--r--test/shell/lvchange-thin.sh204
-rw-r--r--test/shell/lvchange-vdo.sh170
-rw-r--r--test/shell/lvconvert-cache-abort.sh89
-rw-r--r--test/shell/lvconvert-cache-chunks.sh62
-rw-r--r--test/shell/lvconvert-cache-raid.sh115
-rw-r--r--test/shell/lvconvert-cache-smq.sh34
-rw-r--r--test/shell/lvconvert-cache-snapshot.sh63
-rw-r--r--test/shell/lvconvert-cache-thin.sh125
-rw-r--r--test/shell/lvconvert-cache-vdo.sh71
-rw-r--r--test/shell/lvconvert-cache.sh202
-rw-r--r--test/shell/lvconvert-m-raid1-degraded.sh47
-rw-r--r--test/shell/lvconvert-mirror-basic-0.sh8
-rw-r--r--test/shell/lvconvert-mirror-basic-1.sh8
-rw-r--r--test/shell/lvconvert-mirror-basic-2.sh8
-rw-r--r--test/shell/lvconvert-mirror-basic-3.sh8
-rw-r--r--test/shell/lvconvert-mirror-basic.sh57
-rw-r--r--test/shell/lvconvert-mirror-split.sh32
-rw-r--r--test/shell/lvconvert-mirror-updown.sh42
-rw-r--r--test/shell/lvconvert-mirror.sh323
-rw-r--r--test/shell/lvconvert-raid-allocation.sh81
-rw-r--r--test/shell/lvconvert-raid-regionsize.sh104
-rw-r--r--test/shell/lvconvert-raid-reshape-linear_to_raid6-single-type.sh102
-rw-r--r--test/shell/lvconvert-raid-reshape-linear_to_striped-single-type.sh78
-rw-r--r--test/shell/lvconvert-raid-reshape-linear_to_striped.sh72
-rw-r--r--test/shell/lvconvert-raid-reshape-load.sh75
-rw-r--r--test/shell/lvconvert-raid-reshape-striped_to_linear-single-type.sh86
-rw-r--r--test/shell/lvconvert-raid-reshape-striped_to_linear.sh115
-rw-r--r--test/shell/lvconvert-raid-reshape-stripes-load-fail.sh84
-rw-r--r--test/shell/lvconvert-raid-reshape-stripes-load-reload.sh103
-rw-r--r--test/shell/lvconvert-raid-reshape-stripes-load.sh80
-rw-r--r--test/shell/lvconvert-raid-reshape.sh242
-rw-r--r--test/shell/lvconvert-raid-restripe-linear.sh74
-rw-r--r--test/shell/lvconvert-raid-status-validation.sh172
-rw-r--r--test/shell/lvconvert-raid-takeover-alloc-failure.sh104
-rw-r--r--test/shell/lvconvert-raid-takeover-linear_to_raid4.sh60
-rw-r--r--test/shell/lvconvert-raid-takeover-raid4_to_linear.sh71
-rw-r--r--test/shell/lvconvert-raid-takeover-thin.sh73
-rw-r--r--test/shell/lvconvert-raid-takeover.sh372
-rw-r--r--test/shell/lvconvert-raid.sh263
-rw-r--r--test/shell/lvconvert-raid0-striped.sh25
-rw-r--r--test/shell/lvconvert-raid0_to_raid10.sh30
-rw-r--r--test/shell/lvconvert-raid1-split-trackchanges.sh41
-rw-r--r--test/shell/lvconvert-raid10.sh31
-rw-r--r--test/shell/lvconvert-raid456.sh72
-rw-r--r--test/shell/lvconvert-raid5_to_raid10.sh64
-rw-r--r--test/shell/lvconvert-repair-cache.sh156
-rw-r--r--test/shell/lvconvert-repair-dmeventd.sh17
-rw-r--r--test/shell/lvconvert-repair-mirror.sh78
-rw-r--r--test/shell/lvconvert-repair-policy.sh64
-rw-r--r--test/shell/lvconvert-repair-raid-dmeventd.sh40
-rw-r--r--test/shell/lvconvert-repair-raid.sh176
-rw-r--r--test/shell/lvconvert-repair-replace.sh111
-rw-r--r--test/shell/lvconvert-repair-snapshot.sh19
-rw-r--r--test/shell/lvconvert-repair-thin-raid.sh69
-rw-r--r--test/shell/lvconvert-repair-thin.sh105
-rw-r--r--test/shell/lvconvert-repair-transient-dmeventd.sh26
-rw-r--r--test/shell/lvconvert-repair-transient.sh27
-rw-r--r--test/shell/lvconvert-repair.sh88
-rw-r--r--test/shell/lvconvert-snapshot-cache.sh78
-rw-r--r--test/shell/lvconvert-snapshot-mirror.sh60
-rw-r--r--test/shell/lvconvert-snapshot-raid.sh62
-rw-r--r--test/shell/lvconvert-snapshot-thin.sh80
-rw-r--r--test/shell/lvconvert-snapshot.sh73
-rw-r--r--test/shell/lvconvert-striped-raid0.sh25
-rw-r--r--test/shell/lvconvert-thin-external-cache.sh110
-rw-r--r--test/shell/lvconvert-thin-external.sh180
-rw-r--r--test/shell/lvconvert-thin-from-thick.sh93
-rw-r--r--test/shell/lvconvert-thin-raid.sh61
-rw-r--r--test/shell/lvconvert-thin.sh150
-rw-r--r--test/shell/lvconvert-twostep.sh20
-rw-r--r--test/shell/lvconvert-vdo-raid.sh70
-rw-r--r--test/shell/lvconvert-vdo.sh78
-rw-r--r--test/shell/lvcreate-cache-fail.sh42
-rw-r--r--test/shell/lvcreate-cache-no-tools.sh119
-rw-r--r--test/shell/lvcreate-cache-raid.sh36
-rw-r--r--test/shell/lvcreate-cache-snapshot.sh63
-rw-r--r--test/shell/lvcreate-cache.sh308
-rw-r--r--test/shell/lvcreate-external-dmeventd.sh47
-rw-r--r--test/shell/lvcreate-large-raid.sh106
-rw-r--r--test/shell/lvcreate-large-raid10.sh47
-rw-r--r--test/shell/lvcreate-large.sh31
-rw-r--r--test/shell/lvcreate-mirror.sh44
-rw-r--r--test/shell/lvcreate-missing.sh (renamed from test/shell/lvmetad-restart.sh)25
-rw-r--r--test/shell/lvcreate-operation.sh38
-rw-r--r--test/shell/lvcreate-pvtags.sh31
-rw-r--r--test/shell/lvcreate-raid-nosync.sh101
-rw-r--r--test/shell/lvcreate-raid-volume_list.sh42
-rw-r--r--test/shell/lvcreate-raid.sh177
-rw-r--r--test/shell/lvcreate-raid1-read-error.sh33
-rw-r--r--test/shell/lvcreate-raid10.sh79
-rw-r--r--test/shell/lvcreate-repair.sh19
-rw-r--r--test/shell/lvcreate-signature-wiping.sh125
-rw-r--r--test/shell/lvcreate-small-snap.sh36
-rw-r--r--test/shell/lvcreate-striped-mirror.sh62
-rw-r--r--test/shell/lvcreate-thin-big.sh90
-rw-r--r--test/shell/lvcreate-thin-cache.sh48
-rw-r--r--test/shell/lvcreate-thin-external-size.sh94
-rw-r--r--test/shell/lvcreate-thin-external.sh109
-rw-r--r--test/shell/lvcreate-thin-limits.sh61
-rw-r--r--test/shell/lvcreate-thin-power2.sh21
-rw-r--r--test/shell/lvcreate-thin-snap.sh79
-rw-r--r--test/shell/lvcreate-thin.sh193
-rw-r--r--test/shell/lvcreate-usage.sh227
-rw-r--r--test/shell/lvcreate-vdo-cache.sh58
-rw-r--r--test/shell/lvcreate-vdo.sh91
-rw-r--r--test/shell/lvdisplay-raid.sh80
-rw-r--r--test/shell/lvextend-caches-on-thindata.sh178
-rw-r--r--test/shell/lvextend-caches.sh154
-rw-r--r--test/shell/lvextend-percent-extents.sh45
-rw-r--r--test/shell/lvextend-raid.sh89
-rw-r--r--test/shell/lvextend-snapshot-dmeventd.sh27
-rw-r--r--test/shell/lvextend-snapshot-policy.sh20
-rw-r--r--test/shell/lvextend-thin-adddel.sh78
-rw-r--r--test/shell/lvextend-thin-cache.sh43
-rw-r--r--test/shell/lvextend-thin-data-dmeventd.sh68
-rw-r--r--test/shell/lvextend-thin-full.sh68
-rw-r--r--test/shell/lvextend-thin-metadata-dmeventd.sh207
-rw-r--r--test/shell/lvextend-thin-raid.sh63
-rw-r--r--test/shell/lvextend-thin.sh43
-rw-r--r--test/shell/lvextend-vdo-dmeventd.sh68
-rw-r--r--test/shell/lvextend-vdo.sh54
-rw-r--r--test/shell/lvm-conf-error.sh62
-rw-r--r--test/shell/lvm-init.sh10
-rw-r--r--test/shell/lvm-on-md.sh317
-rw-r--r--test/shell/lvmcache-exercise.sh52
-rw-r--r--test/shell/lvmetad-disabled.sh26
-rw-r--r--test/shell/lvmetad-dump.sh38
-rw-r--r--test/shell/lvmetad-pvs.sh19
-rw-r--r--test/shell/lvmetad-test.sh34
-rw-r--r--test/shell/lvmetad-warning.sh27
-rw-r--r--test/shell/lvmlockd-hello-world.sh27
-rw-r--r--test/shell/lvmlockd-lv-types.sh192
-rw-r--r--test/shell/lvmlockd_failure.sh38
-rw-r--r--test/shell/lvremove-thindata-caches.sh71
-rw-r--r--test/shell/lvrename-cache-thin.sh52
-rw-r--r--test/shell/lvrename-vdo.sh88
-rw-r--r--test/shell/lvresize-fs-crypt.sh163
-rw-r--r--test/shell/lvresize-fs.sh627
-rw-r--r--test/shell/lvresize-full.sh78
-rw-r--r--test/shell/lvresize-mirror.sh56
-rw-r--r--test/shell/lvresize-raid.sh87
-rw-r--r--test/shell/lvresize-raid10.sh29
-rw-r--r--test/shell/lvresize-rounding.sh50
-rw-r--r--test/shell/lvresize-thin-external-origin.sh60
-rw-r--r--test/shell/lvresize-thin-metadata.sh49
-rw-r--r--test/shell/lvresize-usage.sh49
-rw-r--r--test/shell/lvresize-vdo.sh50
-rw-r--r--test/shell/lvresize-xfs.sh306
-rw-r--r--test/shell/lvs-cache.sh93
-rw-r--r--test/shell/mda-rollback.sh33
-rw-r--r--test/shell/mdata-strings.sh27
-rw-r--r--test/shell/metadata-bad-mdaheader.sh78
-rw-r--r--test/shell/metadata-bad-text.sh320
-rw-r--r--test/shell/metadata-balance.sh127
-rw-r--r--test/shell/metadata-dirs.sh43
-rw-r--r--test/shell/metadata-full.sh131
-rw-r--r--test/shell/metadata-old.sh221
-rw-r--r--test/shell/metadata-zero-space.sh88
-rw-r--r--test/shell/metadata.sh56
-rw-r--r--test/shell/mirror-names.sh73
-rw-r--r--test/shell/mirror-vgreduce-removemissing.sh222
-rw-r--r--test/shell/missing-pv-unused.sh79
-rw-r--r--test/shell/missing-pv.sh187
-rw-r--r--test/shell/multi_hosts_lv_ex_timeout_hosta.sh87
-rw-r--r--test/shell/multi_hosts_lv_ex_timeout_hostb.sh56
-rw-r--r--test/shell/multi_hosts_lv_hosta.sh78
-rw-r--r--test/shell/multi_hosts_lv_hostb.sh61
-rw-r--r--test/shell/multi_hosts_lv_sh_timeout_hosta.sh87
-rw-r--r--test/shell/multi_hosts_lv_sh_timeout_hostb.sh56
-rw-r--r--test/shell/multi_hosts_vg_hosta.sh45
-rw-r--r--test/shell/multi_hosts_vg_hostb.sh52
-rw-r--r--test/shell/multipath-config.sh171
-rw-r--r--test/shell/name-mangling.sh92
-rw-r--r--test/shell/nomda-missing.sh29
-rw-r--r--test/shell/nomda-restoremissing.sh48
-rw-r--r--test/shell/open-file-limit.sh48
-rw-r--r--test/shell/orphan-ondisk.sh (renamed from test/api/vgtest.sh)17
-rw-r--r--test/shell/outdated-pv.sh64
-rw-r--r--test/shell/pe-align.sh142
-rw-r--r--test/shell/pool-labels.sh21
-rw-r--r--test/shell/process-each-duplicate-pvs.sh528
-rw-r--r--test/shell/process-each-lv.sh659
-rw-r--r--test/shell/process-each-pv-nomda-all.sh63
-rw-r--r--test/shell/process-each-pv-nomda.sh30
-rw-r--r--test/shell/process-each-pv.sh1063
-rw-r--r--test/shell/process-each-pvresize.sh563
-rw-r--r--test/shell/process-each-vg.sh269
-rw-r--r--test/shell/process-each-vgreduce.sh331
-rw-r--r--test/shell/profiles-cache.sh153
-rw-r--r--test/shell/profiles-thin.sh97
-rw-r--r--test/shell/profiles-vdo.sh54
-rw-r--r--test/shell/profiles.sh134
-rw-r--r--test/shell/pv-check-dev-size.sh46
-rw-r--r--test/shell/pv-corruption.sh56
-rw-r--r--test/shell/pv-duplicate-uuid.sh49
-rw-r--r--test/shell/pv-duplicate.sh25
-rw-r--r--test/shell/pv-ext-flags.sh157
-rw-r--r--test/shell/pv-ext-update.sh185
-rw-r--r--test/shell/pv-min-size.sh10
-rw-r--r--test/shell/pv-range-overflow.sh13
-rw-r--r--test/shell/pvchange-usage.sh94
-rw-r--r--test/shell/pvck-dump.sh204
-rw-r--r--test/shell/pvck-repair.sh421
-rw-r--r--test/shell/pvcreate-bootloaderarea.sh58
-rw-r--r--test/shell/pvcreate-ff.sh (renamed from test/shell/lvmetad-lvm1.sh)25
-rw-r--r--test/shell/pvcreate-md-fake-hdr.sh102
-rw-r--r--test/shell/pvcreate-metadata0.sh16
-rw-r--r--test/shell/pvcreate-operation-md.sh169
-rw-r--r--test/shell/pvcreate-operation.sh99
-rw-r--r--test/shell/pvcreate-restore.sh45
-rw-r--r--test/shell/pvcreate-usage.sh84
-rw-r--r--test/shell/pvmove-abort-all.sh85
-rw-r--r--test/shell/pvmove-abort.sh73
-rw-r--r--test/shell/pvmove-all-segtypes.sh111
-rw-r--r--test/shell/pvmove-background.sh36
-rw-r--r--test/shell/pvmove-basic.sh402
-rw-r--r--test/shell/pvmove-cache-segtypes.sh177
-rw-r--r--test/shell/pvmove-lvs.sh35
-rw-r--r--test/shell/pvmove-raid-segtypes.sh96
-rw-r--r--test/shell/pvmove-restart.sh103
-rw-r--r--test/shell/pvmove-resume-1.sh244
-rw-r--r--test/shell/pvmove-resume-2.sh197
-rw-r--r--test/shell/pvmove-resume-multiseg.sh222
-rw-r--r--test/shell/pvmove-thin-segtypes.sh77
-rw-r--r--test/shell/pvremove-thin.sh35
-rw-r--r--test/shell/pvremove-usage.sh32
-rw-r--r--test/shell/pvremove-warnings.sh26
-rw-r--r--test/shell/pvresize-mdas.sh38
-rw-r--r--test/shell/pvscan-autoactivate.sh240
-rw-r--r--test/shell/pvscan-autoactivation-polling.sh74
-rw-r--r--test/shell/pvscan-cache.sh80
-rw-r--r--test/shell/pvscan-nomda-bg.sh43
-rw-r--r--test/shell/read-ahead.sh22
-rw-r--r--test/shell/relative-sign-options.sh80
-rw-r--r--test/shell/report-fields.sh91
-rw-r--r--test/shell/report-format.sh77
-rw-r--r--test/shell/report-hidden.sh33
-rw-r--r--test/shell/scan-lvs.sh46
-rw-r--r--test/shell/select-report.sh223
-rw-r--r--test/shell/select-tools-thin.sh43
-rw-r--r--test/shell/select-tools.sh280
-rw-r--r--test/shell/snapshot-autoumount-dmeventd.sh44
-rw-r--r--test/shell/snapshot-cluster.sh28
-rw-r--r--test/shell/snapshot-maxsize.sh35
-rw-r--r--test/shell/snapshot-merge-stack.sh89
-rw-r--r--test/shell/snapshot-merge-thin.sh78
-rw-r--r--test/shell/snapshot-merge.sh74
-rw-r--r--test/shell/snapshot-raid.sh423
-rw-r--r--test/shell/snapshot-reactivate.sh60
-rw-r--r--test/shell/snapshot-remove-dmsetup.sh93
-rw-r--r--test/shell/snapshot-rename.sh28
-rw-r--r--test/shell/snapshot-usage-exa.sh47
-rw-r--r--test/shell/snapshot-usage.sh205
-rw-r--r--test/shell/snapshots-of-mirrors.sh26
-rw-r--r--test/shell/stray-device-node.sh36
-rw-r--r--test/shell/stress_multi_threads_1.sh113
-rw-r--r--test/shell/stress_multi_threads_2.sh95
-rw-r--r--test/shell/stress_single_thread.sh61
-rw-r--r--test/shell/system_id.sh709
-rw-r--r--test/shell/tags.sh31
-rw-r--r--test/shell/test-partition.sh14
-rw-r--r--test/shell/thin-16g.sh88
-rw-r--r--test/shell/thin-autoumount-dmeventd.sh114
-rw-r--r--test/shell/thin-defaults.sh41
-rw-r--r--test/shell/thin-dmeventd-warns.sh83
-rw-r--r--test/shell/thin-errors.sh79
-rw-r--r--test/shell/thin-flags.sh140
-rw-r--r--test/shell/thin-foreign-dmeventd.sh108
-rw-r--r--test/shell/thin-foreign-repair.sh80
-rw-r--r--test/shell/thin-large.sh55
-rw-r--r--test/shell/thin-many-dmeventd.sh69
-rw-r--r--test/shell/thin-merge.sh142
-rw-r--r--test/shell/thin-overprovisioning.sh79
-rw-r--r--test/shell/thin-resize-match.sh84
-rw-r--r--test/shell/thin-restore.sh40
-rw-r--r--test/shell/thin-vglock.sh65
-rw-r--r--test/shell/thin-volume-list.sh60
-rw-r--r--test/shell/thin-zero-meta.sh68
-rw-r--r--test/shell/topology-support.sh89
-rw-r--r--test/shell/udev-pvscan-vgchange.sh457
-rw-r--r--test/shell/unknown-segment.sh33
-rw-r--r--test/shell/unlost-pv.sh67
-rw-r--r--test/shell/vdo-autoumount-dmeventd.sh127
-rw-r--r--test/shell/vdo-convert.sh230
-rw-r--r--test/shell/vg-check-devs-used.sh39
-rw-r--r--test/shell/vg-name-from-env.sh108
-rw-r--r--test/shell/vg-raid-takeover-1.sh202
-rw-r--r--test/shell/vg-raid-takeover-2.sh65
-rw-r--r--test/shell/vg-raid-takeover-3.sh52
-rw-r--r--test/shell/vg-raid-takeover-4.sh37
-rw-r--r--test/shell/vgcfgbackup-lvm1.sh38
-rw-r--r--test/shell/vgcfgbackup-usage.sh71
-rw-r--r--test/shell/vgchange-many.sh57
-rw-r--r--test/shell/vgchange-maxlv.sh21
-rw-r--r--test/shell/vgchange-partial.sh15
-rw-r--r--test/shell/vgchange-pvs-online.sh232
-rw-r--r--test/shell/vgchange-sysinit.sh27
-rw-r--r--test/shell/vgchange-usage.sh75
-rw-r--r--test/shell/vgck.sh34
-rw-r--r--test/shell/vgcreate-many-pvs.sh64
-rw-r--r--test/shell/vgcreate-usage.sh115
-rw-r--r--test/shell/vgextend-restoremissing.sh44
-rw-r--r--test/shell/vgextend-usage.sh42
-rw-r--r--test/shell/vgimportclone.sh134
-rw-r--r--test/shell/vgimportdevices.sh309
-rw-r--r--test/shell/vgmerge-operation.sh75
-rw-r--r--test/shell/vgmerge-usage.sh13
-rw-r--r--test/shell/vgreduce-removemissing-snapshot.sh15
-rw-r--r--test/shell/vgreduce-usage.sh41
-rw-r--r--test/shell/vgremove-corrupt-vg.sh (renamed from test/api/lvtest.sh)22
-rw-r--r--test/shell/vgrename-usage.sh25
-rw-r--r--test/shell/vgsplit-cache.sh135
-rw-r--r--test/shell/vgsplit-operation.sh132
-rw-r--r--test/shell/vgsplit-raid.sh61
-rw-r--r--test/shell/vgsplit-stacked.sh24
-rw-r--r--test/shell/vgsplit-thin.sh67
-rw-r--r--test/shell/vgsplit-usage.sh51
-rw-r--r--test/shell/vgsplit-vdo.sh56
-rw-r--r--test/shell/writecache-cache-blocksize-2.sh242
-rw-r--r--test/shell/writecache-cache-blocksize.sh251
-rw-r--r--test/shell/writecache-large.sh181
-rw-r--r--test/shell/writecache-misc.sh116
-rw-r--r--test/shell/writecache-split.sh265
-rw-r--r--test/shell/writecache.sh272
-rw-r--r--test/shell/zero-usage.sh46
-rw-r--r--test/shell/zz-lvmlockd-dlm-remove.sh30
-rw-r--r--test/shell/zz-lvmlockd-idm-remove.sh29
-rw-r--r--test/shell/zz-lvmlockd-sanlock-remove.sh45
-rw-r--r--test/unit/Makefile65
-rw-r--r--test/unit/Makefile.in33
-rw-r--r--test/unit/bcache_t.c1036
-rw-r--r--test/unit/bcache_utils_t.c474
-rw-r--r--test/unit/bitset_t.c99
-rw-r--r--test/unit/config_t.c154
-rw-r--r--test/unit/dmlist_t.c49
-rw-r--r--test/unit/dmstatus_t.c84
-rw-r--r--test/unit/framework.c66
-rw-r--r--test/unit/framework.h51
-rw-r--r--test/unit/io_engine_t.c229
-rw-r--r--test/unit/matcher_t.c122
-rw-r--r--test/unit/percent_t.c102
-rw-r--r--test/unit/radix_tree_t.c852
-rw-r--r--test/unit/rt_case1.c1669
-rw-r--r--test/unit/run.c335
-rw-r--r--test/unit/string_t.c72
-rw-r--r--test/unit/unit-test.sh (renamed from test/api/pe_start.sh)14
-rw-r--r--test/unit/units.h55
-rw-r--r--test/unit/vdo_t.c325
485 files changed, 60619 insertions, 5122 deletions
diff --git a/test/.gitignore b/test/.gitignore
new file mode 100644
index 0000000..5b377c7
--- /dev/null
+++ b/test/.gitignore
@@ -0,0 +1,4 @@
+.bin-dir-stamp
+bin
+init.sh
+results/
diff --git a/test/Makefile.in b/test/Makefile.in
index 5bbd1d6..20e97eb 100644
--- a/test/Makefile.in
+++ b/test/Makefile.in
@@ -1,4 +1,4 @@
-# Copyright (C) 2007-2012 Red Hat, Inc. All rights reserved.
+# Copyright (C) 2007-2015 Red Hat, Inc. All rights reserved.
#
# This file is part of LVM2.
#
@@ -8,7 +8,7 @@
#
# 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
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
#TEST_OPTS=--verbose --debug
SHELL_PATH ?= $(SHELL)
@@ -19,121 +19,351 @@ 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@
+datarootdir = @datarootdir@
-SUBDIRS = api unit
-SOURCES = lib/not.c lib/harness.c
+LVM_TEST_RESULTS ?= results
+
+# FIXME: resolve testing of: unit
+SOURCES := lib/not.c lib/harness.c lib/dmsecuretest.c
+CXXSOURCES := lib/runner.cpp
+CXXFLAGS += $(EXTRA_EXEC_CFLAGS)
+
+CLEAN_DIRS += dbus/__pycache__ $(LVM_TEST_RESULTS)
+ifneq (.,$(firstword $(srcdir)))
+CLEAN_TARGETS += $(RUN_BASE) $(addprefix lib/,$(LIB_LVMLOCKD_CONF) $(LIB_MKE2FS_CONF))
+endif
+CLEAN_TARGETS += $(shell find -H lib -type l) \
+ $(CXXSOURCES:%.cpp=%.o) $(CXXSOURCES:%.cpp=%.d) $(CXXSOURCES:%.cpp=%.gcno) $(CXXSOURCES:%.cpp=%.gcda)
+
+CLEAN_TARGETS += .lib-dir-stamp .tests-stamp $(LIB) $(addprefix lib/,\
+ clvmd harness dmeventd dmsetup dmstats lvmpolld \
+ $(LVM_PROFILES) $(LVM_SCRIPTS) \
+ paths-installed paths-installed-t paths-common paths-common-t)
include $(top_builddir)/make.tmpl
T ?= .
S ?= @ # never match anything by default
VERBOSE ?= 0
-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)
+comma = ,
+RUN := $(shell find -L $(srcdir) -regextype posix-egrep \( -path \*/shell/\*.sh -or -path \*/api/\*.sh -or -path \*/unit/\*.sh \) -and -regex "$(srcdir)/.*($(subst $(comma),|,$(T))).*" -and -not -regex "$(srcdir)/.*($(subst $(comma),|,$(S))).*" | $(SORT))
RUN_BASE = $(subst $(srcdir)/,,$(RUN))
+ifeq ("@BUILD_DMEVENTD@", "yes")
+DMEVENTD_TOOLS :=\
+ daemons/dmeventd/dmeventd
+endif
+
+ifeq ("@BUILD_LVMPOLLD@", "yes")
+LVMPOLLD_RUN_BASE = $(RUN_BASE)
+LVMPOLLD_NDEV_FLAVOUR = ,ndev-lvmpolld
+LVMPOLLD_UDEV_FLAVOUR = ,udev-lvmpolld
+LVMPOLLD_TOOLS :=\
+ daemons/lvmpolld/lvmpolld
+endif
+
+ifeq ("@BUILD_LVMLOCKD@", "yes")
+LVMLOCKD_RUN_BASE = $(RUN_BASE)
+LVMLOCKD_UDEV_FLAVOUR = ,udev-lvmlockd-test
+LVMLOCKD_TOOLS :=\
+ daemons/lvmlockd/lvmlockd\
+ daemons/lvmlockd/lvmlockctl
+endif
+
# Shell quote;
-SHELL_PATH_SQ = $(subst ','\'',$(SHELL_PATH))
+SHELL_PATH_SQ := $(subst ','\'',$(SHELL_PATH))
ifeq ("@UDEV_SYNC@", "yes")
-dm_udev_synchronisation = 1
+dm_udev_synchronization = 1
endif
-all: check
+all: .tests-stamp
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 " check_system Run all tests using udev."
+ @echo " check_local Run tests."
+ @echo " check_lvmpolld Run tests with lvmpolld daemon."
+ @echo " check_devicesfile Run tests using a devices file."
+ @echo " check_all_lvmpolld Run all tests with lvmpolld daemon."
+ @echo " check_lvmlockd_sanlock Run tests with lvmlockd and sanlock."
+ @echo " check_lvmlockd_dlm Run tests with lvmlockd and dlm."
+ @echo " check_lvmlockd_idm Run tests with lvmlockd and idm."
+ @echo " check_lvmlockd_test Run tests with lvmlockd --test."
+ @echo " run-unit-test Run only unit tests (root not needed)."
@echo " clean Clean dir."
@echo " help Display callable targets."
@echo -e "\nSupported variables:"
+ @echo " LVM_TEST_AUX_TRACE Set for verbose messages for aux scripts []."
+ @echo " LVM_TEST_BACKING_DEVICE Set device used for testing (see also LVM_TEST_DIR)."
+ @echo " LVM_TEST_MULTI_HOST Set multiple hosts used for testing."
+ @echo " LVM_TEST_CAN_CLOBBER_DMESG Allow to clobber dmesg buffer without /dev/kmsg. (1)"
@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_PREFER_BRD Prefer using brd (ramdisk) over loop for testing [1]."
+ @echo " LVM_TEST_DIR Where to create test files [$(LVM_TEST_DIR)]."
@echo " LVM_TEST_LOCKING Normal (1), Cluster (3)."
- @echo " LVM_TEST_LVMETAD Start lvmetad (1)."
+ @echo " LVM_TEST_LVMPOLLD Start lvmpolld"
@echo " LVM_TEST_NODEBUG Do not debug lvm commands."
@echo " LVM_TEST_PARALLEL May skip agresive wipe of LVMTEST resources."
+ @echo " LVM_TEST_RESULTS Where to create result files [results]."
+ @echo " LVM_TEST_THIN_CHECK_CMD Command for thin_check [$(LVM_TEST_THIN_CHECK_CMD)]."
+ @echo " LVM_TEST_THIN_DUMP_CMD Command for thin_dump [$(LVM_TEST_THIN_DUMP_CMD)]."
+ @echo " LVM_TEST_THIN_REPAIR_CMD Command for thin_repair [$(LVM_TEST_THIN_REPAIR_CMD)]."
+ @echo " LVM_TEST_THIN_RESTORE_CMD Command for thin_restore [$(LVM_TEST_THIN_RESTORE_CMD)]."
+ @echo " LVM_TEST_CACHE_CHECK_CMD Command for cache_check [$(LVM_TEST_CACHE_CHECK_CMD)]."
+ @echo " LVM_TEST_CACHE_DUMP_CMD Command for cache_dump [$(LVM_TEST_CACHE_DUMP_CMD)]."
+ @echo " LVM_TEST_CACHE_REPAIR_CMD Command for cache_repair [$(LVM_TEST_CACHE_REPAIR_CMD)]."
+ @echo " LVM_TEST_CACHE_RESTORE_CMD Command for cache_restore [$(LVM_TEST_CACHE_RESTORE_CMD)]."
+ @echo " LVM_TEST_UNLIMITED Set to get unlimited test log (>32MB)"
+ @echo " LVM_TEST_DEVICE_LIST File path listing real devs that tests can use."
+ @echo " LVM_VALGRIND Enable valgrind testing, execs $$"VALGRIND.
+ @echo " LVM_VALGRIND_DMEVENTD Enable valgrind testing of dmeventd (1)."
+ @echo " LVM_VALGRIND_LVMPOLLD Enable valgrind testing of lvmpolld (1)."
+ @echo " LVM_STRACE Enable strace logging."
+ @echo " LVM_DEBUG_LEVEL Sets debuging level for valgrind/strace (use > 0)."
+ @echo " LVM_DEBUG_LVMDBUS Run lvmdbus with --debug option."
@echo " LVM_VERIFY_UDEV Default verify state for lvm.conf."
- @echo " S Skip given test (regex)."
- @echo " T Run given test (regex)."
+ @echo " LVM_LOG_FILE_MAX_LINES Maximum number of logged lines for lvm2 command [1000000]."
+ @echo " S Skip given test(s) (regex)."
+ @echo " T Run given test(s) (regex)."
@echo " VERBOSE Verbose output (1), timing (2)."
-check: check_local check_cluster check_lvmetad
+check: .tests-stamp
+ VERBOSE=$(VERBOSE) ./lib/runner \
+ --testdir . --outdir $(LVM_TEST_RESULTS) \
+ --flavours ndev-vanilla$(LVMPOLLD_NDEV_FLAVOUR) --only $(T) --skip $(S)
-check_cluster: .tests-stamp
- @echo Testing with locking_type 3
- VERBOSE=$(VERBOSE) LVM_TEST_LOCKING=3 ./lib/harness $(RUN_BASE)
+check_system: .tests-stamp
+ VERBOSE=$(VERBOSE) ./lib/runner \
+ --testdir . --outdir $(LVM_TEST_RESULTS) \
+ --flavours udev-vanilla$(LVMPOLLD_UDEV_FLAVOUR)$(LVMLOCKD_UDEV_FLAVOUR) --only $(T) --skip $(S)
check_local: .tests-stamp
- @echo Testing with locking_type 1
- VERBOSE=$(VERBOSE) LVM_TEST_LOCKING=1 ./lib/harness $(RUN_BASE)
+ VERBOSE=$(VERBOSE) ./lib/runner \
+ --testdir . --outdir $(LVM_TEST_RESULTS) \
+ --flavours ndev-vanilla --only $(T) --skip $(S)
+
+ifeq ("@BUILD_LVMPOLLD@", "yes")
+check_lvmpolld: .tests-stamp
+ VERBOSE=$(VERBOSE) ./lib/runner \
+ --testdir . --outdir $(LVM_TEST_RESULTS) \
+ --flavours ndev-lvmpolld --only $(T) --skip $(S)
+
+check_all_lvmpolld: .tests-stamp
+ VERBOSE=$(VERBOSE) ./lib/runner \
+ --testdir . --outdir $(LVM_TEST_RESULTS) \
+ --flavours ndev-lvmpolld --only $(T) --skip $(S)
+endif
+
+check_devicesfile: .tests-stamp
+ VERBOSE=$(VERBOSE) ./lib/runner \
+ --testdir . --outdir $(LVM_TEST_RESULTS) \
+ --flavours ndev-devicesfile --only $(T) --skip $(S)
+
+ifeq ("@BUILD_LVMLOCKD@", "yes")
+check_lvmlockd_sanlock: .tests-stamp
+ VERBOSE=$(VERBOSE) ./lib/runner \
+ --testdir . --outdir $(LVM_TEST_RESULTS) \
+ --flavours udev-lvmlockd-sanlock --only shell/aa-lvmlockd-sanlock-prepare.sh,$(T),shell/zz-lvmlockd-sanlock-remove.sh --skip $(S)
+
+check_lvmlockd_dlm: .tests-stamp
+ VERBOSE=$(VERBOSE) ./lib/runner \
+ --testdir . --outdir $(LVM_TEST_RESULTS) \
+ --flavours udev-lvmlockd-dlm --only shell/aa-lvmlockd-dlm-prepare.sh,$(T),shell/zz-lvmlockd-dlm-remove.sh --skip $(S)
+
+check_lvmlockd_idm: .tests-stamp lib/idm_inject_failure
+ $(INSTALL_PROGRAM) lib/idm_inject_failure $(EXECDIR)
+ VERBOSE=$(VERBOSE) ./lib/runner \
+ --testdir . --outdir $(LVM_TEST_RESULTS) \
+ --flavours udev-lvmlockd-idm --only shell/aa-lvmlockd-idm-prepare.sh,$(T),shell/zz-lvmlockd-idm-remove.sh --skip $(S)
+
+check_lvmlockd_test: .tests-stamp
+ VERBOSE=$(VERBOSE) ./lib/runner \
+ --testdir . --outdir $(LVM_TEST_RESULTS) \
+ --flavours udev-lvmlockd-test --only $(T) --skip $(S)
+endif
+
+run-unit-test unit-test unit/unit-test:
+ @echo " [MAKE] $(@F)"
+ $(Q) $(MAKE) -C $(top_builddir) $(@F)
+
+DATADIR := $(datadir)/lvm2-testsuite
+EXECDIR := $(libexecdir)/lvm2-testsuite
+
+LIB_FLAVOURS :=\
+ flavour-ndev-lvmpolld\
+ flavour-ndev-vanilla\
+ flavour-ndev-devicesfile\
+ flavour-udev-lvmpolld\
+ flavour-udev-lvmlockd-sanlock\
+ flavour-udev-lvmlockd-dlm\
+ flavour-udev-lvmlockd-idm\
+ flavour-udev-lvmlockd-test\
+ flavour-udev-vanilla
-check_lvmetad: .tests-stamp
- @echo Testing with lvmetad on
- VERBOSE=$(VERBOSE) LVM_TEST_LVMETAD=1 ./lib/harness $(RUN_BASE)
+LIB_LVMLOCKD_CONF :=\
+ test-corosync-conf \
+ test-dlm-conf \
+ test-sanlock-conf
-lib/should: lib/not
- ln -sf not lib/should
+LIB_MKE2FS_CONF := mke2fs.conf
+
+LVM_TOOLS := \
+ $(LVMPOLLD_TOOLS)\
+ $(LVMLOCKD_TOOLS)\
+ $(DMEVENTD_TOOLS)\
+ libdm/dm-tools/dmsetup
+
+LVM_PROFILES := $(addsuffix .profile,\
+ cache-mq\
+ cache-smq\
+ lvmdbusd\
+ thin-performance)
+
+LIB_LINK_NOT := invalid fail should
+LIB_LOCAL := paths runner
+LIB_NOT := not
+LIB_SHARED := check aux inittest utils get lvm-wrapper lvm_vdo_wrapper
+LIB_CONF := $(LIB_LVMLOCKD_CONF) $(LIB_MKE2FS_CONF)
+LIB_DATA := $(LIB_FLAVOURS) dm-version-expected version-expected
+LIB_EXEC := $(LIB_NOT) dmsecuretest securetest
+LVM_SCRIPTS := fsadm lvm_import_vdo
+
+install: .tests-stamp lib/paths-installed
+ $(SHOW) " [INSTALL] tests"
+ $(Q) $(INSTALL_DIR) $(DATADIR)/{shell,api,unit,lib,dbus} $(EXECDIR)
+ $(Q) $(INSTALL_DATA) shell/*.sh $(DATADIR)/shell
+ $(Q) $(INSTALL_DATA) api/*.sh $(DATADIR)/api
+ $(Q) $(INSTALL_DATA) unit/*.sh $(DATADIR)/unit
+ $(Q)- $(INSTALL_PROGRAM) unit/unit-test $(DATADIR)/unit
+ $(Q)- $(INSTALL_PROGRAM) dbus/*.py $(DATADIR)/dbus/
+ $(Q) $(INSTALL_DATA) lib/paths-installed $(DATADIR)/lib/paths
+ $(Q) cd lib &&\
+ $(INSTALL_DATA) $(LIB_DATA) $(LIB_CONF) $(DATADIR)/lib
+ $(Q) cd lib &&\
+ $(INSTALL_SCRIPT) $(LIB_SHARED) $(DATADIR)/lib
+ $(Q) cd lib &&\
+ $(INSTALL_PROGRAM) -D $(LIB_EXEC) $(EXECDIR)
+ $(Q) cd $(abs_top_srcdir)/conf &&\
+ $(INSTALL_DATA) $(LVM_PROFILES) $(DATADIR)/lib
+ $(Q) cd $(DATADIR)/lib &&\
+ $(foreach FILE, $(CMDS), $(LN_S) -f lvm-wrapper $(FILE) $(newline))
+ $(Q) cd $(EXECDIR) &&\
+ $(foreach FILE, $(LIB_LINK_NOT), $(LN_S) -f $(LIB_NOT) $(FILE) $(newline))
+ $(Q) $(INSTALL_PROGRAM) -D lib/runner $(bindir)/lvm2-testsuite
+
+lib/should lib/invalid lib/fail: lib/not
+ $(SHOW) " [LN] $@"
+ $(Q) $(LN_S) -f $(<F) $@
+
+lib/runner: lib/runner.o .lib-dir-stamp
+ $(SHOW) " [LD] $@"
+ $(Q) $(CXX) $(CXXFLAGS) $(LDFLAGS) $(EXTRA_EXEC_LDFLAGS) $(ELDFLAGS) -o $@ $<
+
+lib/securetest: lib/dmsecuretest.o .lib-dir-stamp
+ $(SHOW) " [LD] $@"
+ $(Q) $(CC) $(CFLAGS) $(LDFLAGS) $(EXTRA_EXEC_LDFLAGS) $(ELDFLAGS) -o $@ $< -L$(interfacebuilddir) -ldevmapper $(LIBS)
+
+lib/not: lib/not.o
+lib/runner.o: $(wildcard $(srcdir)/lib/*.h)
+
+CFLAGS_lib/runner.o += $(EXTRA_EXEC_CFLAGS)
+CFLAGS_lib/dmsecuretest.o += $(EXTRA_EXEC_CFLAGS)
+LDFLAGS_lib/dmsecuretest += $(EXTRA_EXEC_LDFLAGS) $(INTERNAL_LIBS) $(LIBS)
+LDFLAGS_lib/idm_inject_failure += $(INTERNAL_LIBS) $(LIBS) -lseagate_ilm
lib/%: lib/%.o .lib-dir-stamp
- $(CC) $(LDFLAGS) -o $@ $<
+ $(SHOW) " [LD] $@"
+ $(Q) $(CC) $(CFLAGS) $(LDFLAGS) $(ELDFLAGS) -o $@ $< $(LDFLAGS_$@)
lib/%: $(srcdir)/lib/%.sh .lib-dir-stamp
- cp $< $@
- chmod +x $@
-
-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_srcdir)' >> $@-t
- echo 'abs_srcdir=$(abs_srcdir)' >> $@-t
- echo 'abs_builddir=$(abs_builddir)' >> $@-t
- echo 'export DM_UDEV_SYNCHRONISATION=$(dm_udev_synchronisation)' >> $@-t
- echo 'export THIN=@THIN@' >> $@-t
- echo 'export LVMETAD_PIDFILE=@LVMETAD_PIDFILE@' >> $@-t
- mv $@-t $@
-
-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)
-
-.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 $@
-
-.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:
- 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
+ $(SHOW) " [CP] $@"
+ $(Q) cp $< $@
+ $(Q) $(CHMOD) +x $@
+
+lib/%: $(top_srcdir)/scripts/%.sh .lib-dir-stamp
+ $(SHOW) " [CP] $@"
+ $(Q) cp $< $@
+ $(Q) $(CHMOD) +x $@
+
+lib/flavour-%: $(srcdir)/lib/flavour-%.sh .lib-dir-stamp
+ $(SHOW) " [FLAVOUR] $<"
+ $(Q) cp $< $@
+
+lib/paths-common: $(srcdir)/Makefile.in Makefile .lib-dir-stamp
+ $(SHOW) " [PATHS] $@"
+ $(Q) echo 'DM_UDEV_SYNCHRONIZATION=$(dm_udev_synchronization)' >> $@-t
+ $(Q) echo 'LVMPOLLD_PIDFILE="@LVMPOLLD_PIDFILE@"' >> $@-t
+ $(Q) echo 'DMEVENTD_PIDFILE="@DMEVENTD_PIDFILE@"' >> $@-t
+ $(Q) echo 'LVM_TEST_THIN_CHECK_CMD=$${LVM_TEST_THIN_CHECK_CMD-@THIN_CHECK_CMD@}' >> $@-t
+ $(Q) echo 'LVM_TEST_THIN_DUMP_CMD=$${LVM_TEST_THIN_DUMP_CMD-@THIN_DUMP_CMD@}' >> $@-t
+ $(Q) echo 'LVM_TEST_THIN_REPAIR_CMD=$${LVM_TEST_THIN_REPAIR_CMD-@THIN_REPAIR_CMD@}' >> $@-t
+ $(Q) echo 'LVM_TEST_THIN_RESTORE_CMD=$${LVM_TEST_THIN_RESTORE_CMD-@THIN_RESTORE_CMD@}' >> $@-t
+ $(Q) echo 'LVM_TEST_CACHE_CHECK_CMD=$${LVM_TEST_CACHE_CHECK_CMD-@CACHE_CHECK_CMD@}' >> $@-t
+ $(Q) echo 'LVM_TEST_CACHE_DUMP_CMD=$${LVM_TEST_CACHE_DUMP_CMD-@CACHE_DUMP_CMD@}' >> $@-t
+ $(Q) echo 'LVM_TEST_CACHE_REPAIR_CMD=$${LVM_TEST_CACHE_REPAIR_CMD-@CACHE_REPAIR_CMD@}' >> $@-t
+ $(Q) echo 'LVM_TEST_CACHE_RESTORE_CMD=$${LVM_TEST_CACHE_RESTORE_CMD-@CACHE_RESTORE_CMD@}' >> $@-t
+ $(Q) echo 'export DM_UDEV_SYNCHRONIZATION THIN RAID CACHE\' >> $@-t
+ $(Q) echo ' LVM_TEST_THIN_CHECK_CMD LVM_TEST_THIN_DUMP_CMD LVM_TEST_THIN_REPAIR_CMD LVM_TEST_THIN_RESTORE_CMD\' >> $@-t
+ $(Q) echo ' LVM_TEST_CACHE_CHECK_CMD LVM_TEST_CACHE_DUMP_CMD LVM_TEST_CACHE_REPAIR_CMD LVM_TEST_CACHE_RESTORE_CMD' >> $@-t
+ $(Q) mv $@-t $@
+
+lib/paths-installed: lib/paths-common
+ $(SHOW) " [PATHS] $@"
+ $(Q) $(RM) $@-t
+ $(Q) cat lib/paths-common > $@-t
+ $(Q) echo 'installed_testsuite=1' >> $@-t
+ $(Q) echo 'export PATH=@libexecdir@/lvm2-testsuite:@datadir@/lvm2-testsuite/lib:@datadir@/lvm2-testsuite/api:$$PATH' >> $@-t
+ $(Q) mv $@-t $@
+
+lib/paths: lib/paths-common
+ $(SHOW) " [PATHS] $@"
+ $(Q) $(RM) $@-t
+ $(Q) cat lib/paths-common > $@-t
+ $(Q) echo 'top_srcdir="$(top_srcdir)"' >> $@-t
+ $(Q) echo 'abs_top_builddir="$(abs_top_builddir)"' >> $@-t
+ $(Q) echo 'abs_top_srcdir="$(abs_top_srcdir)"' >> $@-t
+ $(Q) echo 'abs_srcdir="$(abs_srcdir)"' >> $@-t
+ $(Q) echo 'abs_builddir="$(abs_builddir)"' >> $@-t
+ $(Q) mv $@-t $@
+
+lib/version-expected: $(top_srcdir)/VERSION .lib-dir-stamp
+ $(Q) cut -f 1 -d ' ' <$< >$@
+
+lib/dm-version-expected: $(top_srcdir)/VERSION_DM .lib-dir-stamp
+ $(Q) cut -f 1 -d ' ' <$< >$@
+
+CMDS := lvm $(shell cat $(abs_top_builddir)/tools/.commands 2>/dev/null)
+LIB := $(addprefix lib/, $(LVM_SCRIPTS) $(LIB_SHARED) $(LIB_LOCAL) $(LIB_EXEC) $(LIB_LINK_NOT) $(LIB_DATA))
+
+.tests-stamp: .lib-dir-stamp $(LIB) $(SUBDIRS)
+ $(SHOW) " [TESTS-STAMP]"
+ifneq (.,$(firstword $(srcdir)))
+ $(SHOW) " Linking tests to builddir."
+ $(Q) $(LN_S) -f $(srcdir)/shell
+endif
+ $(Q) $(MKDIR_P) -m a=rwx $(LVM_TEST_RESULTS)
+ $(Q) touch $@
+
+.lib-dir-stamp: unit/unit-test
+ $(SHOW) " [LIB-DIR-STAMP]"
+ $(Q) $(MKDIR_P) api lib unit
+ $(Q) $(RM) lib/clvmd
+ $(Q) $(LN_S) -f dmsetup lib/dmstats
+ $(Q) $(foreach FILE, $(CMDS), $(LN_S) -f lvm-wrapper lib/$(FILE) $(newline))
+ $(Q) $(foreach FILE, $(LVM_TOOLS), $(LN_S) -f $(abs_top_builddir)/$(FILE) lib/ $(newline))
+ $(Q) $(LN_S) -f $(addprefix $(abs_top_srcdir)/conf/, $(LVM_PROFILES)) lib/
+ifneq (.,$(firstword $(srcdir)))
+ $(Q) $(LN_S) -f $(addprefix $(abs_top_srcdir)/test/lib/,\
+ $(LIB_LVMLOCKD_CONF) $(LIB_MKE2FS_CONF)) lib/
+endif
+ $(Q) touch $@
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
diff --git a/test/api/Makefile.in b/test/api/Makefile.in
deleted file mode 100644
index 7ad6743..0000000
--- a/test/api/Makefile.in
+++ /dev/null
@@ -1,60 +0,0 @@
-#
-# Copyright (C) 2009-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@
-
-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
-
-endif
-
-include $(top_builddir)/make.tmpl
-
-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
-endif
-
-LVMLIBS += $(LIBS)
-
-%.t: %.o $(DEPLIBS)
- $(CC) -o $@ $(<) $(LDFLAGS) $(LVMLIBS)
-
-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/dbustest.sh b/test/api/dbustest.sh
new file mode 100644
index 0000000..d69c0e8
--- /dev/null
+++ b/test/api/dbustest.sh
@@ -0,0 +1,42 @@
+#!/bin/sh
+# Copyright (C) 2016 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+SKIP_WITH_LVMPOLLD=1
+SKIP_WITH_LVMLOCKD=1
+SKIP_WITH_CLVMD=1
+
+. lib/inittest
+
+# Unsupported with valgrid testing
+test "${LVM_VALGRIND:-0}" -eq 0 || skip "Unsupported with valgrind"
+
+# NOTE: Some tests, namely anything with vdo, and
+# api/dbus_test_lv_interface_cache_lv.sh, require larger PVs
+aux prepare_pvs 6 6400
+
+# Required by test_nesting:
+aux extend_filter_LVMTEST
+
+# We need the lvmdbusd.profile for the daemon to utilize JSON
+# output
+aux prepare_profiles "lvmdbusd"
+
+# Keep generating test file within test dir
+export TMPDIR=$PWD
+aux prepare_lvmdbusd
+
+# Example for testing individual test:
+#"$TESTOLDPWD/dbus/lvmdbustest.py" -v TestDbusService.test_lv_interface_cache_lv
+#"$TESTOLDPWD/dbus/lvmdbustest.py" -v TestDbusService.test_pv_symlinks
+
+"$TESTOLDPWD/dbus/lvmdbustest.py" -v
diff --git a/test/api/lvtest.c b/test/api/lvtest.c
deleted file mode 100644
index c0fee65..0000000
--- a/test/api/lvtest.c
+++ /dev/null
@@ -1,64 +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 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/pe_start.c b/test/api/pe_start.c
deleted file mode 100644
index 129f8a2..0000000
--- a/test/api/pe_start.c
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * 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/percent.c b/test/api/percent.c
deleted file mode 100644
index c5fa434..0000000
--- a/test/api/percent.c
+++ /dev/null
@@ -1,63 +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 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;
- lv_t lv;
- struct lvm_property_value v;
- struct lvm_property_value d;
-
- handle = lvm_init(NULL);
- assert(handle);
-
- vg = lvm_vg_open(handle, argv[1], "r", 0);
- assert(vg);
-
- lv = lvm_lv_from_name(vg, "snap");
- assert(lv);
-
- v = lvm_lv_get_property(lv, "snap_percent");
- assert(v.is_valid);
- assert(v.value.integer == PERCENT_0);
-
- lv = lvm_lv_from_name(vg, "mirr");
- assert(lv);
-
- v = lvm_lv_get_property(lv, "copy_percent");
- assert(v.is_valid);
- assert(v.value.integer == PERCENT_100);
-
- lv = lvm_lv_from_name(vg, "snap2");
- assert(lv);
-
- v = lvm_lv_get_property(lv, "snap_percent");
- 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);
-
- lvm_quit(handle);
- return 0;
-}
diff --git a/test/api/percent.sh b/test/api/percent.sh
deleted file mode 100644
index 07b8bc6..0000000
--- a/test/api/percent.sh
+++ /dev/null
@@ -1,29 +0,0 @@
-#!/bin/sh
-# 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
-
-. lib/test
-
-kernel_at_least 2 6 33 || skip
-
-aux prepare_devs 2
-
-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
-lvcreate -m 1 -n mirr $vg -l 1 --mirrorlog core
-lvs $vg
-aux apitest percent $vg
-
-vgremove -ff $vg
diff --git a/test/api/test.c b/test/api/test.c
deleted file mode 100644
index b27aed1..0000000
--- a/test/api/test.c
+++ /dev/null
@@ -1,1107 +0,0 @@
-/*
- * 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 <stdio.h>
-#include <string.h>
-#include <stdlib.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)
-{
- char *b = str, *e;
- *argc = 0;
-
- while (*b) {
- while (*b && isspace(*b))
- b++;
-
- if ((!*b) || ((*argc == 0)&&(*b == '#')))
- break;
-
- e = b;
- while (*e && !isspace(*e))
- e++;
-
- argv[(*argc)++] = b;
- if (!*e)
- break;
- *e++ = '\0';
- b = e;
- if (*argc == max)
- break;
- }
-
- return *argc;
-}
-
-static void _show_help(void)
-{
- printf("'lv_activate vgname lvname: "
- "Activate an LV\n");
- printf("'lv_deactivate vgname lvname: "
- "Deactivate an LV\n");
- printf("'vg_remove_lv vgname lvname': "
- "Remove a LV\n");
- printf("'vg_create_lv_linear vgname lvname size_in_bytes': "
- "Create a linear LV\n");
- printf("'scan_vgs': "
- "Scan the system for LVM metadata\n");
- printf("'list_vg_names': "
- "List the names of the VGs that exist in the system\n");
- printf("'list_vg_ids': "
- "List the uuids of the VGs that exist in the system\n");
- printf("'vg_list_pvs vgname': "
- "List the PVs that exist in VG vgname\n");
- printf("'pv_list_pvsegs pvname': "
- "List the PV segments that exist in PV pvname\n");
- printf("'vg_list_lvs vgname': "
- "List the LVs that exist in VG vgname\n");
- printf("'lv_list_lvsegs vgname lvname': "
- "List the LV segments that exist in LV vgname/lvname\n");
- printf("'vgs_open': "
- "List the VGs that are currently open\n");
- printf("'vgs': "
- "List all VGs known to the system\n");
- printf("'vg_extend vgname device: "
- "Issue a lvm_vg_extend() API call on VG 'vgname'\n");
- printf("'vg_reduce vgname device: "
- "Issue a lvm_vg_reduce() API call on VG 'vgname'\n");
- printf("'vg_open vgname ['r' | 'w']': "
- "Issue a lvm_vg_open() API call on VG 'vgname'\n");
- printf("'vg_close vgname': "
- "Issue a lvm_vg_close() API call on VG 'vgname'\n");
- printf("'vg_create vgname: "
- "Issue a lvm_vg_create() to create VG 'vgname'\n");
- printf("'vg_remove vgname: "
- "Issue a lvm_vg_remove() to remove VG 'vgname'\n");
- printf("'config_reload': "
- "Issue a lvm_config_reload() API to reload LVM config\n");
- printf("'config_override' device: "
- "Issue a lvm_config_override() with accept device filter\n");
- printf("'vg_get_tags vgname': "
- "List the tags of a VG\n");
- printf("'lv_get_property vgname lvname property_name': "
- "Display the value of LV property\n");
- printf("'vg_get_property vgname property_name': "
- "Display the value of VG property\n");
- printf("'pv_get_property pvname property_name': "
- "Display the value of PV property\n");
- printf("'vg_set_property vgname property_name': "
- "Set the value of VG property\n");
- printf("'lv_get_tags vgname lvname': "
- "List the tags of a LV\n");
- printf("'vg_{add|remove}_tag vgname tag': "
- "Add/remove a tag from a VG\n");
- printf("'lv_{add|remove}_tag vgname lvname tag': "
- "Add/remove a tag from a LV\n");
- printf("'vgname_from_devname device': "
- "Lookup a vgname from a device name\n");
- printf("'vgname_from_pvid pvid': "
- "Lookup a vgname from a pvid\n");
- printf("'lv_from_uuid vgname lvuuid': "
- "Lookup an LV from an LV uuid\n");
- printf("'lv_from_name vgname lvname': "
- "Lookup an LV from an LV name\n");
- printf("'pv_from_uuid vgname pvuuid': "
- "Lookup an LV from an LV uuid\n");
- printf("'pv_from_name vgname pvname': "
- "Lookup an LV from an LV name\n");
- printf("'quit': exit the program\n");
-}
-
-static struct dm_hash_table *_vgid_hash = NULL;
-static struct dm_hash_table *_vgname_hash = NULL;
-static struct dm_hash_table *_pvname_hash = NULL;
-static struct dm_hash_table *_lvname_hash = NULL;
-
-static void _hash_destroy_single(struct dm_hash_table **htable)
-{
- if (htable && *htable) {
- dm_hash_destroy(*htable);
- *htable = NULL;
- }
-}
-
-static void _hash_destroy(void)
-{
- _hash_destroy_single(&_vgname_hash);
- _hash_destroy_single(&_vgid_hash);
- _hash_destroy_single(&_pvname_hash);
- _hash_destroy_single(&_lvname_hash);
-}
-
-static int _hash_create(void)
-{
- if (!(_vgname_hash = dm_hash_create(128)))
- return 0;
- if (!(_pvname_hash = dm_hash_create(128))) {
- _hash_destroy_single(&_vgname_hash);
- return 0;
- }
- if (!(_lvname_hash = dm_hash_create(128))) {
- _hash_destroy_single(&_vgname_hash);
- _hash_destroy_single(&_pvname_hash);
- return 0;
- }
- if (!(_vgid_hash = dm_hash_create(128))) {
- _hash_destroy_single(&_vgname_hash);
- _hash_destroy_single(&_pvname_hash);
- _hash_destroy_single(&_lvname_hash);
- return 0;
- }
- return 1;
-}
-
-/* FIXME: this should be per vg */
-static lv_t _lookup_lv_by_name(const char *name)
-{
- lv_t lv;
-
- if (!name) {
- printf ("Invalid LV name\n");
- return NULL;
- }
- if (!(lv = dm_hash_lookup(_lvname_hash, name))) {
- printf ("Can't find %s in LVs - run vg_create_lv first\n",
- name);
- return NULL;
- }
- return lv;
-}
-
-static vg_t _lookup_vg_by_name(char **argv, int argc)
-{
- vg_t vg;
-
- if (argc < 2) {
- printf ("Please enter vg_name\n");
- return NULL;
- }
- if (!(vg = dm_hash_lookup(_vgid_hash, argv[1])) &&
- !(vg = dm_hash_lookup(_vgname_hash, argv[1]))) {
- printf ("Can't find %s in open VGs - run vg_open first\n",
- argv[1]);
- return NULL;
- }
- return vg;
-}
-
-static pv_t _lookup_pv_by_name(const char *name)
-{
- pv_t pv;
-
- if (!(pv = dm_hash_lookup(_pvname_hash, name))) {
- printf ("Can't find %s in open PVs - run vg_open first\n",
- name);
- return NULL;
- }
- return pv;
-}
-
-static void _add_lvs_to_lvname_hash(struct dm_list *lvs)
-{
- struct lvm_lv_list *lvl;
- dm_list_iterate_items(lvl, lvs) {
- /* Concatenate VG name with LV name */
- dm_hash_insert(_lvname_hash, lvm_lv_get_name(lvl->lv), lvl->lv);
- }
-}
-
-static void _add_pvs_to_pvname_hash(struct dm_list *pvs)
-{
- struct lvm_pv_list *pvl;
- dm_list_iterate_items(pvl, pvs) {
- dm_hash_insert(_pvname_hash, lvm_pv_get_name(pvl->pv), pvl->pv);
- }
-}
-
-static void _remove_device_from_pvname_hash(struct dm_list *pvs, const char *name)
-{
- struct lvm_pv_list *pvl;
- dm_list_iterate_items(pvl, pvs) {
- if (!strncmp(lvm_pv_get_name(pvl->pv), name, strlen(name)))
- dm_hash_remove(_pvname_hash, name);
- }
-}
-static void _add_device_to_pvname_hash(struct dm_list *pvs, const char *name)
-{
- struct lvm_pv_list *pvl;
- dm_list_iterate_items(pvl, pvs) {
- if (!strncmp(lvm_pv_get_name(pvl->pv), name, strlen(name)))
- dm_hash_insert(_pvname_hash, name, pvl->pv);
- }
-}
-
-static void _vg_reduce(char **argv, int argc, lvm_t libh)
-{
- vg_t vg;
- struct dm_list *pvs;
-
- if (argc < 2) {
- printf ("Please enter vg_name\n");
- return;
- }
- if (!(vg = dm_hash_lookup(_vgid_hash, argv[1])) &&
- !(vg = dm_hash_lookup(_vgname_hash, argv[1]))) {
- printf ("VG not open\n");
- return;
- }
- if (lvm_vg_reduce(vg, argv[2])) {
- printf("Error reducing %s by %s\n", argv[1], argv[2]);
- return;
- }
-
- printf("Success reducing vg %s by %s\n", argv[1], argv[2]);
-
- /*
- * Add the device into the hashes for lookups
- */
- pvs = lvm_vg_list_pvs(vg);
- if (pvs && !dm_list_empty(pvs))
- _remove_device_from_pvname_hash(pvs, argv[2]);
-}
-
-/* Print "Error" or "Success" depending on lvm status */
-static int _lvm_status_to_pass_fail(int rc)
-{
- if (rc)
- printf("Error ");
- else
- printf("Success ");
- return rc;
-}
-static void _config_override(char **argv, int argc, lvm_t libh)
-{
- int rc;
- char tmp[64];
-
- if (argc < 2) {
- printf ("Please enter device\n");
- return;
- }
- snprintf(tmp, 63, "devices{filter=[\"a|%s|\", \"r|.*|\"]}", argv[1]);
- rc = lvm_config_override(libh, tmp);
- _lvm_status_to_pass_fail(rc);
- printf("overriding LVM configuration\n");
-}
-
-static void _config_reload(char **argv, int argc, lvm_t libh)
-{
- int rc;
- rc = lvm_config_reload(libh);
- _lvm_status_to_pass_fail(rc);
- printf("reloading LVM configuration\n");
-}
-
-static void _vg_extend(char **argv, int argc, lvm_t libh)
-{
- vg_t vg;
- struct dm_list *pvs;
-
- if (argc < 2) {
- printf ("Please enter vg_name\n");
- return;
- }
- if (!(vg = dm_hash_lookup(_vgid_hash, argv[1])) &&
- !(vg = dm_hash_lookup(_vgname_hash, argv[1]))) {
- printf ("VG not open\n");
- return;
- }
- if (lvm_vg_extend(vg, argv[2])) {
- printf("Error extending %s with %s\n", argv[1], argv[2]);
- return;
- }
-
- printf("Success extending vg %s with %s\n", argv[1], argv[2]);
-
- /*
- * Add the device into the hashes for lookups
- */
- pvs = lvm_vg_list_pvs(vg);
- if (pvs && !dm_list_empty(pvs))
- _add_device_to_pvname_hash(pvs, argv[2]);
-}
-
-static void _vg_open(char **argv, int argc, lvm_t libh)
-{
- vg_t vg;
- struct dm_list *lvs;
- struct dm_list *pvs;
-
- if (argc < 2) {
- printf ("Please enter vg_name\n");
- return;
- }
- if ((vg = dm_hash_lookup(_vgid_hash, argv[1])) ||
- (vg = dm_hash_lookup(_vgname_hash, argv[1]))) {
- printf ("VG already open\n");
- return;
- }
- if (argc < 3)
- vg = lvm_vg_open(libh, argv[1], "r", 0);
- else
- vg = lvm_vg_open(libh, argv[1], argv[2], 0);
- if (!vg || !lvm_vg_get_name(vg)) {
- printf("Error opening %s\n", argv[1]);
- return;
- }
-
- printf("Success opening vg %s\n", argv[1]);
- dm_hash_insert(_vgname_hash, lvm_vg_get_name(vg), vg);
- dm_hash_insert(_vgid_hash, lvm_vg_get_uuid(vg), vg);
-
- /*
- * Add the LVs and PVs into the hashes for lookups
- */
- lvs = lvm_vg_list_lvs(vg);
- if (lvs && !dm_list_empty(lvs))
- _add_lvs_to_lvname_hash(lvs);
- pvs = lvm_vg_list_pvs(vg);
- if (pvs && !dm_list_empty(pvs))
- _add_pvs_to_pvname_hash(pvs);
-}
-/* Lookup the vg and remove it from the vgname and vgid hashes */
-static vg_t _lookup_and_remove_vg(const char *vgname)
-{
- vg_t vg=NULL;
-
- if ((vg = dm_hash_lookup(_vgname_hash, vgname))) {
- dm_hash_remove(_vgid_hash, lvm_vg_get_uuid(vg));
- dm_hash_remove(_vgname_hash, lvm_vg_get_name(vg));
- }
- if (!vg && (vg = dm_hash_lookup(_vgid_hash, vgname))) {
- dm_hash_remove(_vgid_hash, lvm_vg_get_uuid(vg));
- dm_hash_remove(_vgname_hash, lvm_vg_get_name(vg));
- }
- return vg;
-}
-
-static void _vg_write(char **argv, int argc)
-{
- vg_t vg;
- int rc = 0;
-
- if (argc < 2) {
- printf ("Please enter vg_name\n");
- return;
- }
- vg = _lookup_vg_by_name(argv, argc);
- if (!vg) {
- printf("Can't find vg_name %s\n", argv[1]);
- return;
- }
- rc = lvm_vg_write(vg);
- _lvm_status_to_pass_fail(rc);
- printf("writing VG %s\n", lvm_vg_get_name(vg));
-}
-
-static void _vg_create(char **argv, int argc, lvm_t libh)
-{
- vg_t vg;
-
- if (argc < 2) {
- printf ("Please enter vg_name\n");
- return;
- }
- vg = lvm_vg_create(libh, argv[1]);
- if (!vg || !lvm_vg_get_name(vg)) {
- printf("Error creating %s\n", argv[1]);
- return;
- }
-
- printf("Success creating vg %s\n", argv[1]);
- dm_hash_insert(_vgname_hash, lvm_vg_get_name(vg), vg);
- dm_hash_insert(_vgid_hash, lvm_vg_get_uuid(vg), vg);
-}
-
-static void _vg_remove(char **argv, int argc)
-{
- vg_t vg;
- int rc = 0;
-
- if (argc < 2) {
- printf ("Please enter vg_name\n");
- return;
- }
- vg = _lookup_vg_by_name(argv, argc);
- if (!vg) {
- printf("Can't find vg_name %s\n", argv[1]);
- return;
- }
- rc = lvm_vg_remove(vg);
- _lvm_status_to_pass_fail(rc);
- printf("removing VG\n");
-}
-
-static void _vg_close(char **argv, int argc)
-{
- vg_t vg;
- int rc = 0;
-
- if (argc < 2) {
- printf ("Please enter vg_name\n");
- return;
- }
- vg = _lookup_and_remove_vg(argv[1]);
- if (!vg) {
- printf("Can't find vg_name %s\n", argv[1]);
- return;
- }
- rc = lvm_vg_close(vg);
- _lvm_status_to_pass_fail(rc);
- printf("closing VG\n");
-}
-
-static void _show_one_vg(vg_t vg)
-{
- printf("%s (%s): sz=%"PRIu64", free=%"PRIu64", #pv=%"PRIu64
- ", seq#=%"PRIu64"\n",
- lvm_vg_get_name(vg), lvm_vg_get_uuid(vg),
- lvm_vg_get_size(vg), lvm_vg_get_free_size(vg),
- lvm_vg_get_pv_count(vg), lvm_vg_get_seqno(vg));
-}
-
-static void _print_pv(pv_t pv)
-{
- if (!pv)
- return;
- printf("%s (%s): size=%"PRIu64", free=%"PRIu64
- ", dev_size=%"PRIu64", mda_count=%"PRIu64"\n",
- lvm_pv_get_name(pv), lvm_pv_get_uuid(pv),
- lvm_pv_get_size(pv), lvm_pv_get_free(pv),
- lvm_pv_get_dev_size(pv),
- lvm_pv_get_mda_count(pv));
-}
-
-static void _print_lv(vg_t vg, lv_t lv)
-{
- if (!lv)
- return;
- printf("%s/%s (%s): size=%"PRIu64", %sACTIVE / %sSUSPENDED\n",
- lvm_vg_get_name(vg),
- lvm_lv_get_name(lv), lvm_lv_get_uuid(lv),
- lvm_lv_get_size(lv),
- lvm_lv_is_active(lv) ? "" : "IN",
- lvm_lv_is_suspended(lv) ? "" : "NOT ");
-}
-
-static void _list_open_vgs(void)
-{
- dm_hash_iter(_vgid_hash, (dm_hash_iterate_fn) _show_one_vg);
-}
-
-static void _pvs_in_vg(char **argv, int argc)
-{
- struct dm_list *pvs;
- struct lvm_pv_list *pvl;
- vg_t vg;
-
- if (!(vg = _lookup_vg_by_name(argv, argc)))
- return;
- pvs = lvm_vg_list_pvs(vg);
- if (!pvs || dm_list_empty(pvs)) {
- printf("No PVs in VG %s\n", lvm_vg_get_name(vg));
- return;
- }
- printf("PVs in VG %s:\n", lvm_vg_get_name(vg));
- dm_list_iterate_items(pvl, pvs) {
- _print_pv(pvl->pv);
- }
-}
-
-static void _print_property_value(const char *name,
- struct lvm_property_value v)
-{
- if (!v.is_valid)
- printf("%s = INVALID\n", name);
- else if (v.is_string)
- printf("%s = %s\n", name, v.value.string);
- else
- printf("%s = %"PRIu64"\n", name, v.value.integer);
-}
-
-static void _pvsegs_in_pv(char **argv, int argc)
-{
- struct dm_list *pvsegs;
- struct lvm_pvseg_list *pvl;
- pv_t pv;
-
- if (!(pv = _lookup_pv_by_name(argv[1])))
- return;
- pvsegs = lvm_pv_list_pvsegs(pv);
- if (!pvsegs || dm_list_empty(pvsegs)) {
- printf("No PV segments in pv %s\n", argv[1]);
- return;
- }
- printf("PV segments in pv %s:\n", argv[1]);
- dm_list_iterate_items(pvl, pvsegs) {
- struct lvm_property_value v;
- v = lvm_pvseg_get_property(pvl->pvseg, "pvseg_start");
- _print_property_value("pvseg_start", v);
- v = lvm_pvseg_get_property(pvl->pvseg, "pvseg_size");
- _print_property_value("pvseg_size", v);
- }
-}
-
-static void _scan_vgs(lvm_t libh)
-{
- lvm_scan(libh);
-}
-
-static void _list_vg_names(lvm_t libh)
-{
- struct dm_list *list;
- struct lvm_str_list *strl;
-
- list = lvm_list_vg_names(libh);
- printf("VG names:\n");
- dm_list_iterate_items(strl, list) {
- printf("%s\n", strl->str);
- }
-}
-
-static void _list_vg_ids(lvm_t libh)
-{
- struct dm_list *list;
- struct lvm_str_list *strl;
-
- list = lvm_list_vg_uuids(libh);
- printf("VG uuids:\n");
- dm_list_iterate_items(strl, list) {
- printf("%s\n", strl->str);
- }
-}
-
-static void _display_tags(struct dm_list *list)
-{
- struct lvm_str_list *strl;
- if (dm_list_empty(list)) {
- printf("No tags exist\n");
- return;
- } else if (!list) {
- printf("Error obtaining tags\n");
- return;
- }
- dm_list_iterate_items(strl, list) {
- printf("%s\n", strl->str);
- }
-}
-
-static void _vg_get_tags(char **argv, int argc)
-{
- vg_t vg;
-
- if (!(vg = _lookup_vg_by_name(argv, argc)))
- return;
- printf("VG tags:\n");
- _display_tags(lvm_vg_get_tags(vg));
-}
-
-static void _vg_tag(char **argv, int argc, int add)
-{
- vg_t vg;
-
- if (argc < 3) {
- printf("Please enter vgname, tag\n");
- return;
- }
- if (!(vg = _lookup_vg_by_name(argv, argc)))
- return;
- if (add && lvm_vg_add_tag(vg, argv[2]))
- printf("Error ");
- else if (!add && lvm_vg_remove_tag(vg, argv[2])){
- printf("Error ");
- } else {
- printf("Success ");
- }
- printf("%s tag %s to VG %s\n",
- add ? "adding":"removing", argv[2], argv[1]);
-}
-
-static void _pv_get_property(char **argv, int argc)
-{
- pv_t pv;
- struct lvm_property_value v;
-
- if (argc < 3) {
- printf("Please enter pvname, field_id\n");
- return;
- }
- if (!(pv = _lookup_pv_by_name(argv[1])))
- return;
- v = lvm_pv_get_property(pv, argv[2]);
- _print_property_value(argv[2], v);
-}
-
-static void _vg_get_property(char **argv, int argc)
-{
- vg_t vg;
- struct lvm_property_value v;
-
- if (argc < 3) {
- printf("Please enter vgname, field_id\n");
- return;
- }
- if (!(vg = _lookup_vg_by_name(argv, argc)))
- return;
- v = lvm_vg_get_property(vg, argv[2]);
- _print_property_value(argv[2], v);
-}
-
-static void _lv_get_property(char **argv, int argc)
-{
- lv_t lv;
- struct lvm_property_value v;
-
- if (argc < 4) {
- printf("Please enter vgname, lvname, field_id\n");
- return;
- }
- if (!(lv = _lookup_lv_by_name(argv[2])))
- return;
- v = lvm_lv_get_property(lv, argv[3]);
- _print_property_value(argv[3], v);
-}
-
-static void _vg_set_property(char **argv, int argc)
-{
- vg_t vg;
- struct lvm_property_value value;
- int rc;
-
- if (argc < 4) {
- printf("Please enter vgname, field_id, value\n");
- return;
- }
- if (!(vg = _lookup_vg_by_name(argv, argc)))
- return;
- value = lvm_vg_get_property(vg, argv[2]);
- if (!value.is_valid) {
- printf("Error obtaining property value\n");
- return;
- }
- if (value.is_string)
- value.value.string = argv[3];
- else
- value.value.integer = atoi(argv[3]);
- rc = lvm_vg_set_property(vg, argv[2], &value);
- if (rc)
- printf("Error ");
- else
- printf("Success ");
- printf("setting value of property %s in VG %s\n",
- argv[2], argv[1]);
-}
-
-static void _lv_get_tags(char **argv, int argc)
-{
- lv_t lv;
-
- if (argc < 3) {
- printf("Please enter vgname, lvname\n");
- return;
- }
- if (!(lv = _lookup_lv_by_name(argv[2])))
- return;
- printf("LV tags:\n");
- _display_tags(lvm_lv_get_tags(lv));
-}
-
-static void _lv_tag(char **argv, int argc, int add)
-{
- lv_t lv;
-
- if (argc < 3) {
- printf("Please enter vgname, lvname\n");
- return;
- }
- if (!(lv = _lookup_lv_by_name(argv[2])))
- return;
- if (add && lvm_lv_add_tag(lv, argv[3]))
- printf("Error ");
- else if (!add && lvm_lv_remove_tag(lv, argv[3])){
- printf("Error ");
- } else {
- printf("Success ");
- }
- printf("%s tag %s to LV %s\n",
- add ? "adding":"removing", argv[3], argv[2]);
-}
-
-static void _lv_from_uuid(char **argv, int argc)
-{
- vg_t vg;
-
- if (argc < 3) {
- printf("Please enter vgname, lv_uuid\n");
- return;
- }
- if (!(vg = _lookup_vg_by_name(argv, argc)))
- return;
- _print_lv(vg, lvm_lv_from_uuid(vg, argv[2]));
-}
-
-static void _lv_from_name(char **argv, int argc)
-{
- vg_t vg;
-
- if (argc < 3) {
- printf("Please enter vgname, lv_uuid\n");
- return;
- }
- if (!(vg = _lookup_vg_by_name(argv, argc)))
- return;
- _print_lv(vg, lvm_lv_from_name(vg, argv[2]));
-}
-
-static void _pv_from_uuid(char **argv, int argc)
-{
- vg_t vg;
-
- if (argc < 3) {
- printf("Please enter vgname, pv_uuid\n");
- return;
- }
- if (!(vg = _lookup_vg_by_name(argv, argc)))
- return;
- _print_pv(lvm_pv_from_uuid(vg, argv[2]));
-}
-
-static void _pv_from_name(char **argv, int argc)
-{
- vg_t vg;
-
- if (argc < 3) {
- printf("Please enter vgname, pv_uuid\n");
- return;
- }
- if (!(vg = _lookup_vg_by_name(argv, argc)))
- return;
- _print_pv(lvm_pv_from_name(vg, argv[2]));
-}
-
-static void _vgname_from_pvid(char **argv, int argc, lvm_t libh)
-{
- const char *vgname;
-
- if (argc < 1) {
- printf("Please enter pvid\n");
- return;
- }
- if (!(vgname = lvm_vgname_from_pvid(libh, argv[1]))) {
- printf("Error ");
- } else {
- printf("Success ");
- }
- printf("looking up vgname=%s from PVID=%s\n",
- vgname, argv[1]);
-}
-static void _vgname_from_devname(char **argv, int argc, lvm_t libh)
-{
- const char *vgname;
-
- if (argc < 1) {
- printf("Please enter device\n");
- return;
- }
- if (!(vgname = lvm_vgname_from_device(libh, argv[1]))) {
- printf("Error ");
- } else {
- printf("Success ");
- }
- printf("looking up vgname=%s from device name=%s\n",
- vgname, argv[1]);
-}
-static void _lvs_in_vg(char **argv, int argc)
-{
- struct dm_list *lvs;
- struct lvm_lv_list *lvl;
- vg_t vg;
-
- if (!(vg = _lookup_vg_by_name(argv, argc)))
- return;
- lvs = lvm_vg_list_lvs(vg);
- if (!lvs || dm_list_empty(lvs)) {
- printf("No LVs in VG %s\n", lvm_vg_get_name(vg));
- return;
- }
- printf("LVs in VG %s:\n", lvm_vg_get_name(vg));
- dm_list_iterate_items(lvl, lvs) {
- _print_lv(vg, lvl->lv);
- }
-}
-
-static void _lvsegs_in_lv(char **argv, int argc)
-{
- struct dm_list *lvsegs;
- struct lvm_lvseg_list *lvl;
- lv_t lv;
-
- if (!(lv = _lookup_lv_by_name(argv[2])))
- return;
- lvsegs = lvm_lv_list_lvsegs(lv);
- if (!lvsegs || dm_list_empty(lvsegs)) {
- printf("No LV segments in lv %s\n", lvm_lv_get_name(lv));
- return;
- }
- printf("LV segments in lv %s:\n", lvm_lv_get_name(lv));
- dm_list_iterate_items(lvl, lvsegs) {
- struct lvm_property_value v;
- v = lvm_lvseg_get_property(lvl->lvseg, "segtype");
- _print_property_value("segtype", v);
- v = lvm_lvseg_get_property(lvl->lvseg, "seg_start_pe");
- _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);
- }
-}
-
-static void _lv_deactivate(char **argv, int argc)
-{
- lv_t lv;
- int rc=0;
-
- if (argc < 3) {
- printf("Please enter vgname, lvname\n");
- return;
- }
- if (!(lv = _lookup_lv_by_name(argv[2])))
- return;
- rc = lvm_lv_deactivate(lv);
- _lvm_status_to_pass_fail(rc);
- printf("De-activating LV %s in VG %s\n",
- argv[2], argv[1]);
-}
-static void _lv_activate(char **argv, int argc)
-{
- lv_t lv;
- int rc=0;
-
- if (argc < 3) {
- printf("Please enter vgname, lvname\n");
- return;
- }
- if (!(lv = _lookup_lv_by_name(argv[2])))
- return;
- rc = lvm_lv_activate(lv);
- _lvm_status_to_pass_fail(rc);
- printf("activating LV %s in VG %s\n",
- argv[2], argv[1]);
-}
-
-static void _vg_remove_lv(char **argv, int argc)
-{
- lv_t lv;
-
- if (argc < 3) {
- printf("Please enter vgname, lvname\n");
- return;
- }
- if (!(lv = _lookup_lv_by_name(argv[2])))
- return;
- if (lvm_vg_remove_lv(lv))
- printf("Error ");
- else {
- printf("Success ");
- dm_hash_remove(_lvname_hash, argv[2]);
- }
- printf("removing LV %s in VG %s\n",
- argv[2], argv[1]);
-}
-
-static void _vg_create_lv_linear(char **argv, int argc)
-{
- vg_t vg;
- lv_t lv;
-
- if (argc < 4) {
- printf("Please enter vgname, lvname, and size\n");
- return;
- }
- if (!(vg = _lookup_vg_by_name(argv, argc)))
- return;
- lv = lvm_vg_create_lv_linear(vg, argv[2], atol(argv[3]));
- if (!lv)
- printf("Error ");
- else {
- printf("Success ");
- dm_hash_insert(_lvname_hash, argv[2], lv);
- }
- printf("creating LV %s in VG %s\n",
- argv[2], argv[1]);
-}
-
-static int lvmapi_test_shell(lvm_t libh)
-{
- int argc;
- char *input = NULL, *args[MAX_ARGS], **argv;
-
- _hash_create();
- argc=0;
- while (1) {
- free(input);
- input = readline("liblvm> ");
-
- /* EOF */
- if (!input) {
- printf("\n");
- break;
- }
-
- /* empty line */
- if (!*input)
- continue;
-
- argv = args;
-
- if (lvm_split(input, &argc, argv, MAX_ARGS) == MAX_ARGS) {
- printf("Too many arguments, sorry.");
- continue;
- }
-
- if (!strcmp(argv[0], "lvm")) {
- argv++;
- argc--;
- }
-
- if (!argc)
- continue;
-
- if (!strcmp(argv[0], "quit") || !strcmp(argv[0], "exit")) {
- printf("Exiting.\n");
- break;
- } else if (!strcmp(argv[0], "?") || !strcmp(argv[0], "help")) {
- _show_help();
- } else if (!strcmp(argv[0], "config_reload")) {
- _config_reload(argv, argc, libh);
- } else if (!strcmp(argv[0], "config_override")) {
- _config_override(argv, argc, libh);
- } else if (!strcmp(argv[0], "vg_extend")) {
- _vg_extend(argv, argc, libh);
- } else if (!strcmp(argv[0], "vg_reduce")) {
- _vg_reduce(argv, argc, libh);
- } else if (!strcmp(argv[0], "vg_write")) {
- _vg_write(argv, argc);
- } else if (!strcmp(argv[0], "vg_open")) {
- _vg_open(argv, argc, libh);
- } else if (!strcmp(argv[0], "vg_close")) {
- _vg_close(argv, argc);
- } else if (!strcmp(argv[0], "vg_create")) {
- _vg_create(argv, argc, libh);
- } else if (!strcmp(argv[0], "vg_remove")) {
- _vg_remove(argv, argc);
- } else if (!strcmp(argv[0], "lv_activate")) {
- _lv_activate(argv, argc);
- } else if (!strcmp(argv[0], "lv_deactivate")) {
- _lv_deactivate(argv, argc);
- } else if (!strcmp(argv[0], "vg_remove_lv")) {
- _vg_remove_lv(argv, argc);
- } else if (!strcmp(argv[0], "vgs_open")) {
- _list_open_vgs();
- } else if (!strcmp(argv[0], "vg_list_pvs")) {
- _pvs_in_vg(argv, argc);
- } else if (!strcmp(argv[0], "pv_list_pvsegs")) {
- _pvsegs_in_pv(argv, argc);
- } else if (!strcmp(argv[0], "vg_list_lvs")) {
- _lvs_in_vg(argv, argc);
- } else if (!strcmp(argv[0], "lv_list_lvsegs")) {
- _lvsegs_in_lv(argv, argc);
- } else if (!strcmp(argv[0], "list_vg_names")) {
- _list_vg_names(libh);
- } else if (!strcmp(argv[0], "list_vg_ids")) {
- _list_vg_ids(libh);
- } else if (!strcmp(argv[0], "scan_vgs")) {
- _scan_vgs(libh);
- } else if (!strcmp(argv[0], "vg_create_lv_linear")) {
- _vg_create_lv_linear(argv, argc);
- } else if (!strcmp(argv[0], "vg_add_tag")) {
- _vg_tag(argv, argc, 1);
- } else if (!strcmp(argv[0], "vg_remove_tag")) {
- _vg_tag(argv, argc, 0);
- } else if (!strcmp(argv[0], "vg_get_tags")) {
- _vg_get_tags(argv, argc);
- } else if (!strcmp(argv[0], "lv_get_property")) {
- _lv_get_property(argv, argc);
- } else if (!strcmp(argv[0], "vg_get_property")) {
- _vg_get_property(argv, argc);
- } else if (!strcmp(argv[0], "pv_get_property")) {
- _pv_get_property(argv, argc);
- } else if (!strcmp(argv[0], "vg_set_property")) {
- _vg_set_property(argv, argc);
- } else if (!strcmp(argv[0], "lv_add_tag")) {
- _lv_tag(argv, argc, 1);
- } else if (!strcmp(argv[0], "lv_remove_tag")) {
- _lv_tag(argv, argc, 0);
- } else if (!strcmp(argv[0], "lv_get_tags")) {
- _lv_get_tags(argv, argc);
- } else if (!strcmp(argv[0], "vgname_from_devname")) {
- _vgname_from_devname(argv, argc, libh);
- } else if (!strcmp(argv[0], "vgname_from_pvid")) {
- _vgname_from_pvid(argv, argc, libh);
- } else if (!strcmp(argv[0], "lv_from_uuid")) {
- _lv_from_uuid(argv, argc);
- } else if (!strcmp(argv[0], "lv_from_name")) {
- _lv_from_name(argv, argc);
- } else if (!strcmp(argv[0], "pv_from_uuid")) {
- _pv_from_uuid(argv, argc);
- } else if (!strcmp(argv[0], "pv_from_name")) {
- _pv_from_name(argv, argc);
- } else {
- printf ("Unrecognized command %s\n", argv[0]);
- }
- }
-
- dm_hash_iter(_vgname_hash, (dm_hash_iterate_fn) lvm_vg_close);
- _hash_destroy();
- 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[])
-{
- lvm_t libh;
-
- libh = lvm_init(NULL);
- if (!libh) {
- printf("Unable to open lvm library instance\n");
- return 1;
- }
-
- printf("Library version: %s\n", lvm_library_get_version());
- lvmapi_test_shell(libh);
-
- lvm_quit(libh);
- return 0;
-}
-
diff --git a/test/api/thin_percent.c b/test/api/thin_percent.c
deleted file mode 100644
index 2c8b19b..0000000
--- a/test/api/thin_percent.c
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * 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
deleted file mode 100644
index 9287cf3..0000000
--- a/test/api/thin_percent.sh
+++ /dev/null
@@ -1,37 +0,0 @@
-#!/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
diff --git a/test/api/vgtest.c b/test/api/vgtest.c
deleted file mode 100644
index cb35da3..0000000
--- a/test/api/vgtest.c
+++ /dev/null
@@ -1,164 +0,0 @@
-/*
- * Copyright (C) 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
- */
-/*
- * Unit test case for vgcreate and related APIs.
- * # gcc -g vgcreate.c -I../../liblvm -I../../include -L../../liblvm \
- * -L../../libdm -ldevmapper -llvm2app
- * # export LD_LIBRARY_PATH=`pwd`/../../libdm:`pwd`/../../liblvm
- */
-#include <stdio.h>
-#include <unistd.h>
-#include <inttypes.h>
-
-#include "lvm2app.h"
-
-lvm_t handle;
-vg_t vg;
-const char *vg_name;
-#define MAX_DEVICES 16
-const char *device[MAX_DEVICES];
-uint64_t size = 1024;
-
-#define vg_create(vg_name) \
- printf("Creating VG %s\n", vg_name); \
- vg = lvm_vg_create(handle, vg_name); \
- if (!vg) { \
- fprintf(stderr, "Error creating volume group %s\n", vg_name); \
- goto bad; \
- }
-#define vg_extend(vg, dev) \
- printf("Extending VG %s by %s\n", vg_name, dev); \
- status = lvm_vg_extend(vg, dev); \
- if (status) { \
- fprintf(stderr, "Error extending volume group %s " \
- "with device %s\n", vg_name, dev); \
- goto bad; \
- }
-#define vg_commit(vg) \
- printf("Committing VG %s to disk\n", vg_name); \
- status = lvm_vg_write(vg); \
- if (status) { \
- fprintf(stderr, "Commit of volume group '%s' failed\n", \
- lvm_vg_get_name(vg)); \
- goto bad; \
- }
-#define vg_open(vg_name, mode) \
- printf("Opening VG %s %s\n", vg_name, mode); \
- vg = lvm_vg_open(handle, vg_name, mode, 0); \
- if (!vg) { \
- fprintf(stderr, "Error opening volume group %s\n", vg_name); \
- goto bad; \
- }
-#define vg_close(vg) \
- printf("Closing VG %s\n", vg_name); \
- if (lvm_vg_close(vg)) { \
- fprintf(stderr, "Error closing volume group %s\n", vg_name); \
- goto bad; \
- }
-#define vg_reduce(vg, dev) \
- printf("Reducing VG %s by %s\n", vg_name, dev); \
- status = lvm_vg_reduce(vg, dev); \
- if (status) { \
- fprintf(stderr, "Error reducing volume group %s " \
- "by device %s\n", vg_name, dev); \
- goto bad; \
- }
-#define vg_remove(vg) \
- printf("Removing VG %s from system\n", vg_name); \
- status = lvm_vg_remove(vg); \
- if (status) { \
- fprintf(stderr, "Revmoval of volume group '%s' failed\n", \
- vg_name); \
- goto bad; \
- }
-
-static int init_vgtest(int argc, char *argv[])
-{
- int i;
-
- if (argc < 4) {
- fprintf(stderr, "Usage: %s <vgname> <pv1> <pv2> [... <pvN> ]",
- argv[0]);
- return -1;
- }
- vg_name = argv[1];
- for(i=2; i<MAX_DEVICES && i < argc; i++) {
- device[i-2] = argv[i];
- }
- return 0;
-}
-
-int main(int argc, char *argv[])
-{
- int status;
-
- if (init_vgtest(argc, argv) < 0)
- goto bad;
-
- /* FIXME: make the below messages verbose-only and print PASS/FAIL*/
- printf("Opening LVM\n");
- handle = lvm_init(NULL);
- if (!handle) {
- fprintf(stderr, "Unable to lvm_init\n");
- goto bad;
- }
-
- printf("Library version: %s\n", lvm_library_get_version());
- vg_create(vg_name);
- vg_extend(vg, device[0]);
-
- printf("Setting VG %s extent_size to %"PRIu64"\n", vg_name, size);
- status = lvm_vg_set_extent_size(vg, size);
- if (status) {
- fprintf(stderr, "Can not set physical extent "
- "size '%"PRIu64"' for '%s'\n",
- size, vg_name);
- goto bad;
- }
-
- vg_commit(vg);
- vg_close(vg);
-
- vg_open(vg_name, "r");
- vg_close(vg);
-
- vg_open(vg_name, "w");
- vg_extend(vg, device[1]);
- vg_reduce(vg, device[0]);
- vg_commit(vg);
- vg_close(vg);
-
- vg_open(vg_name, "w");
- vg_extend(vg, device[0]);
- vg_commit(vg);
- vg_close(vg);
-
- vg_open(vg_name, "w");
- vg_remove(vg);
- vg_commit(vg);
- vg_close(vg);
-
- lvm_quit(handle);
- printf("liblvm vgcreate unit test PASS\n");
- _exit(0);
-bad:
- printf("liblvm vgcreate unit test FAIL\n");
- 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);
- _exit(-1);
-}
diff --git a/test/dbus/lvm_error_inject.py b/test/dbus/lvm_error_inject.py
new file mode 100755
index 0000000..098f870
--- /dev/null
+++ b/test/dbus/lvm_error_inject.py
@@ -0,0 +1,348 @@
+#!/usr/bin/python3
+
+# Simulate errors by doing the following for both lvm and lvm shell:
+# Randomly return
+# - Bad exit code
+# - Exit code 5 (exported VG)
+# - Truncated JSON
+# - Missing key in JSON
+#
+# This is done by sitting between lvm dbusd and lvm. If running via systemd, add the following to the service file
+# Environment="LVM_BINARY=/path/to/this file/lvm2/test/dbus/lvm_error_inject.py"
+# systemctl daemon-reload
+# systemctl restart lvm2-lvmdbusd
+import copy
+import json
+import multiprocessing
+import os
+import pty
+import random
+import select
+import signal
+import string
+import subprocess
+import sys
+import tempfile
+import traceback
+from collections import deque
+from fcntl import fcntl, F_GETFL, F_SETFL
+from subprocess import Popen
+
+
+CS = string.ascii_letters + "\n\t " + string.digits
+
+run = multiprocessing.Value('i', 1)
+
+SH = None
+
+
+def rs(length, character_set=CS):
+ return ''.join(random.choice(character_set) for _ in range(length))
+
+
+RS = rs(512)
+
+d_out = open(os.path.join(tempfile.gettempdir(), "mitm_lvm.txt"), "a")
+
+
+def debug(msg):
+ m = str(msg)
+ d_out.write(m)
+ if m[-1] != "\n":
+ d_out.write("\n")
+ d_out.flush()
+
+
+# Make stream non-blocking
+def make_non_block(stream):
+ flags = fcntl(stream, F_GETFL)
+ fcntl(stream, F_SETFL, flags | os.O_NONBLOCK)
+
+
+def read_decoded(stream):
+ tmp = stream.read()
+ if tmp:
+ return tmp.decode("utf-8")
+ return ''
+
+
+def write_some(q, stream, remaining=False, binary=False):
+ if len(q) > 0:
+ if remaining:
+ to_send = len(q)
+ else:
+ to_send = random.randint(1, len(q))
+
+ for _ in range(0, to_send):
+ c = q.popleft()
+ if binary:
+ stream.write(bytes(c, "utf-8"))
+ else:
+ stream.write(c)
+ stream.flush()
+
+
+def del_random_key(src_dict):
+ keys = list(src_dict.keys())
+ pick = random.randint(0, len(keys) - 1)
+ debug("%s will be deleted" % keys[pick])
+ del src_dict[keys[pick]]
+
+
+def inject_key_error(output_json):
+ debug("Deleting a key")
+ for r in output_json['report']:
+ if 'lv' in r:
+ for i in r['lv']:
+ debug("deleting a lv key")
+ del_random_key(i)
+ return
+ if 'vg' in r:
+ for i in r["vg"]:
+ debug("deleting a vg key")
+ del_random_key(i)
+ return
+ elif 'pv' in r:
+ for i in r["pv"]:
+ debug("deleting a pv key")
+ del_random_key(i)
+ return
+
+
+def inject_exit_error(output_json, val):
+ if 'log' in output_json and len(output_json['log']) > 0:
+ debug("Returning bad exit code")
+ # Change the exit code to failure
+ output_json['log'][-1:][0]['log_ret_code'] = "%d" % val
+ else:
+ # We are in fork & exec mode, just exit.
+ if val == 0:
+ sys.exit(1)
+ sys.exit(val)
+
+
+def inject_error(output_str, output_json=None):
+ try:
+ if random.randint(0, 9) == 1:
+ error_case = random.randint(0, 3)
+ if error_case == 0:
+ debug("Truncating JSON")
+ # Create bad JSON by truncating it
+ str_rep = output_str[:-len(output_str) // 2]
+ rc = str_rep
+ else:
+ if output_json is None:
+ output_json = json.loads(output_str)
+ if error_case == 1:
+ inject_key_error(output_json)
+ elif error_case == 2:
+ debug("Returning bad exit code")
+ inject_exit_error(output_json, 0)
+ else:
+ debug("Returning exit code 5")
+ inject_exit_error(output_json, 5)
+
+ rc = json.dumps(output_json) + "\n"
+ else:
+ rc = output_str
+ except Exception as e:
+ debug("Exception %s occurred: JSON = \n%s\n" % (str(e), output_str))
+ sys.exit(100)
+
+ return rc
+
+
+def run_one(cmd):
+ debug("run_one(%s)" % str(cmd))
+ result = subprocess.run(cmd, capture_output=True, text=True)
+
+ if "fullreport" in cmd:
+ sys.stdout.write(inject_error(result.stdout))
+ else:
+ sys.stdout.write(result.stdout)
+ sys.stdout.flush()
+ sys.stderr.write(result.stderr)
+ sys.stderr.flush()
+ return result.returncode
+
+
+class LvmShellHandler:
+
+ def __init__(self, cmd):
+ debug(os.environ)
+
+ self.d_stdout = deque()
+ self.d_stderr = deque()
+ self.d_report = deque()
+
+ tmp_dir = tempfile.mkdtemp(prefix="pipeinmiddle_")
+ self.tmp_file = "%s/middle_man_report" % tmp_dir
+
+ # Let's create a fifo for the report output
+ os.mkfifo(self.tmp_file, 0o600)
+
+ self.child_report_fd = os.open(self.tmp_file, os.O_NONBLOCK)
+ self.child_report_stream = os.fdopen(self.child_report_fd, 'rb', 0)
+ passed_report_fd = os.open(self.tmp_file, os.O_WRONLY)
+
+ debug("passed_report_fd = %d" % passed_report_fd)
+
+ # The report FD from who executed us.
+ self.daemon_report_fd = int(os.environ["LVM_REPORT_FD"])
+ self.daemon_report_stream = os.fdopen(self.daemon_report_fd, "wb", 0)
+
+ env = copy.deepcopy(os.environ)
+ env["LVM_REPORT_FD"] = "%s" % str(passed_report_fd)
+ env["LC_ALL"] = "C"
+ env["LVM_COMMAND_PROFILE"] = "lvmdbusd"
+
+ self.parent_stdin_fd, child_stdin_fd = pty.openpty()
+ self.parent_stdout_fd, child_stdout_fd = pty.openpty()
+ self.parent_stderr_fd, child_stderr_fd = pty.openpty()
+ self.parent_stdin = os.fdopen(self.parent_stdin_fd, "w")
+ self.parent_stdout = os.fdopen(self.parent_stdout_fd, "r")
+ self.parent_stderr = os.fdopen(self.parent_stderr_fd, "r")
+
+ debug("exec'ing %s" % cmd)
+ self.process = Popen(cmd,
+ stdin=child_stdin_fd,
+ stdout=child_stdout_fd,
+ stderr=child_stderr_fd,
+ close_fds=True,
+ env=env,
+ pass_fds=[passed_report_fd, ],
+ shell=False)
+
+ os.close(passed_report_fd)
+ os.close(child_stdin_fd)
+ os.close(child_stdout_fd)
+ os.close(child_stderr_fd)
+
+ make_non_block(self.parent_stdout_fd)
+ make_non_block(self.parent_stderr_fd)
+ make_non_block(sys.stdin)
+
+ self.report_text_in_progress = ""
+ self.last_request = ""
+
+ os.unlink(self.tmp_file)
+ os.rmdir(tmp_dir)
+
+ def _complete_response(self):
+ try:
+ _complete_json = json.loads(self.report_text_in_progress)
+ return _complete_json
+ except ValueError:
+ return None
+
+ def _write_all(self):
+ write_some(self.d_stderr, sys.stderr, remaining=True)
+ write_some(self.d_report, self.daemon_report_stream, remaining=True, binary=True)
+ write_some(self.d_stdout, sys.stdout, remaining=True)
+
+ def _handle_report(self):
+ # Read from child report stream, write to parent report stream
+ report_text = read_decoded(self.child_report_stream)
+ self.report_text_in_progress += report_text
+ report_json = self._complete_response()
+
+ # Always wait until we have a full response before we do anything with the output
+ if report_json is not None:
+ # Only add data to d_report after we have the entire JSON and have injected
+ # an error into it if we so wish, usually only for 'fullreport'
+ if "fullreport" in self.last_request:
+ self.d_report.extend(inject_error(self.report_text_in_progress, report_json))
+ else:
+ debug("Not the cmd we are looking for ...")
+ self.d_report.extend(self.report_text_in_progress)
+
+ self.report_text_in_progress = ""
+
+ def _handle_command(self):
+ global run
+ stdin_text = sys.stdin.readline()
+ self.last_request = stdin_text
+
+ debug("stdin: %s..." % stdin_text[:min(10, len(stdin_text) - 1)])
+
+ if "exit\n" in stdin_text:
+ debug("asking to exit ...")
+ run.value = 0
+
+ self.parent_stdin.writelines(stdin_text)
+ self.parent_stdin.flush()
+
+ @staticmethod
+ def _empty_stream_to_queue(stream, queue):
+ read_text = stream.readlines()
+ for line in read_text:
+ queue.extend(line)
+
+ def run(self):
+ global run
+ select_tmo = 0.2
+ while run.value == 1:
+ try:
+ rd_fd = [sys.stdin.fileno(), self.parent_stdout_fd, self.parent_stderr_fd, self.child_report_fd]
+ ready = select.select(rd_fd, [], [], select_tmo)
+
+ if len(ready[0]) == 0:
+ write_some(self.d_stderr, sys.stderr)
+ write_some(self.d_report, self.daemon_report_stream, binary=True)
+
+ for r in ready[0]:
+ if r == self.parent_stdout_fd:
+ LvmShellHandler._empty_stream_to_queue(self.parent_stdout, self.d_stdout)
+ elif r == self.parent_stderr_fd:
+ LvmShellHandler._empty_stream_to_queue(self.parent_stderr, self.d_stderr)
+ elif r == self.child_report_fd:
+ self._handle_report()
+ elif r == sys.stdin.fileno():
+ # Read from parent stdin write to child stdin, this is a command getting issued.
+ self._handle_command()
+ else:
+ debug("FD %d not handled!" % r)
+ sys.exit(10)
+
+ # We have handled all the FDs that were ready, write some output
+ if len(self.d_stdout) > 0:
+ self._write_all()
+ else:
+ write_some(self.d_stderr, sys.stderr)
+ write_some(self.d_report, self.daemon_report_stream, binary=True)
+
+ # Check to see if child process has terminated, None when running
+ if self.process.poll() is not None:
+ self._write_all()
+ debug("child process %s exited %d" % (cmd, self.process.returncode))
+ break
+ except IOError as ioe:
+ debug("run_cmd:" + str(ioe))
+
+ if self.process.poll() is not None:
+ debug("exiting %d " % self.process.returncode)
+ else:
+ debug("lvm process still running, be we are exiting ...")
+ return self.process.returncode
+
+
+if __name__ == "__main__":
+ try:
+ args = sys.argv[1:]
+
+ exe = os.getenv("LVM_MAN_IN_MIDDLE", "/usr/sbin/lvm")
+ cmdline = [exe, ]
+ if args:
+ cmdline.extend(args)
+ ec = run_one(cmdline)
+ else:
+ if "LVM_REPORT_FD" in os.environ:
+ SH = LvmShellHandler(cmdline)
+ ec = SH.run()
+ else:
+ debug('running as lvm shell requires: LVM_REPORT_FD to be set')
+ ec = 1
+ sys.exit(ec)
+ except Exception:
+ traceback.print_exc(file=d_out)
+ sys.exit(1)
diff --git a/test/dbus/lvmdbustest.py b/test/dbus/lvmdbustest.py
new file mode 100755
index 0000000..475f328
--- /dev/null
+++ b/test/dbus/lvmdbustest.py
@@ -0,0 +1,2614 @@
+#!/usr/bin/python3
+
+# Copyright (C) 2015-2016 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, see <http://www.gnu.org/licenses/>.
+import os
+import signal
+# noinspection PyUnresolvedReferences
+import subprocess
+import unittest
+import tempfile
+from glob import glob
+from subprocess import Popen, PIPE
+
+import dbus
+import pyudev
+# noinspection PyUnresolvedReferences
+from dbus.mainloop.glib import DBusGMainLoop
+
+import testlib
+from testlib import *
+
+g_tmo = 0
+
+g_lvm_shell = False
+
+# Approx. min size
+VDO_MIN_SIZE = mib(8192)
+
+VG_TEST_SUFFIX = "_vg_LvMdBuS_TEST"
+
+EXE_NAME = "/lvmdbusd"
+
+# Prefix on created objects to enable easier clean-up
+g_prefix = os.getenv('PREFIX', '')
+
+# Check dev dir prefix for test suite (LVM_TEST_DEVDIR
+dm_dev_dir = os.getenv('DM_DEV_DIR', '/dev')
+
+# Use the session bus instead of the system bus
+use_session = os.getenv('LVM_DBUSD_USE_SESSION', False)
+
+# Only use the devices listed in the ENV variable
+pv_device_list = os.getenv('LVM_DBUSD_PV_DEVICE_LIST', None)
+
+# Default is to test all modes
+# 0 == Only test fork & exec mode
+# 1 == Only test lvm shell mode
+# 2 == Test both fork & exec & lvm shell mode (default)
+# Other == Test just lvm shell mode
+test_shell = os.getenv('LVM_DBUSD_TEST_MODE', 2)
+
+# LVM binary to use
+LVM_EXECUTABLE = os.getenv('LVM_BINARY', '/usr/sbin/lvm')
+
+# Empty options dictionary (EOD)
+EOD = dbus.Dictionary({}, signature=dbus.Signature('sv'))
+# Base interfaces on LV objects
+LV_BASE_INT = (LV_COMMON_INT, LV_INT)
+
+if use_session:
+ bus = dbus.SessionBus(mainloop=DBusGMainLoop())
+else:
+ bus = dbus.SystemBus(mainloop=DBusGMainLoop())
+
+# If we have multiple clients we will globally disable introspection
+# validation to limit the massive amount of introspection calls we make as
+# that method prevents things from executing concurrently
+if pv_device_list:
+ testlib.validate_introspection = False
+
+
+def vg_n(prefix=None):
+ name = rs(8, VG_TEST_SUFFIX)
+ if prefix:
+ name = prefix + name
+ return g_prefix + name
+
+
+def lv_n(suffix=None):
+ if not suffix:
+ s = '_lv'
+ else:
+ s = suffix
+ return rs(8, s)
+
+
+def _is_testsuite_pv(pv_name):
+ return g_prefix != "" and pv_name[-1].isdigit() and \
+ pv_name[:-1].endswith(g_prefix + "pv")
+
+
+def is_nested_pv(pv_name):
+ return pv_name.count('/') == 3 and not _is_testsuite_pv(pv_name)
+
+
+def _root_pv_name(res, pv_name):
+ if not is_nested_pv(pv_name):
+ return pv_name
+ vg_name = pv_name.split('/')[2]
+ for v in res[VG_INT]:
+ if v.Vg.Name == vg_name:
+ for pv in res[PV_INT]:
+ if pv.object_path in v.Vg.Pvs:
+ return _root_pv_name(res, pv.Pv.Name)
+ return None
+
+
+def _prune_lvs(res, interface, vg_object_path):
+ lvs = [lv for lv in res[interface] if lv.LvCommon.Vg == vg_object_path]
+ res[interface] = lvs
+
+
+def _prune(res, pv_filter):
+ if pv_filter:
+ pv_lookup = {}
+
+ pv_list = []
+ for p in res[PV_INT]:
+ if _root_pv_name(res, p.Pv.Name) in pv_filter:
+ pv_list.append(p)
+ pv_lookup[p.object_path] = p
+
+ res[PV_INT] = pv_list
+
+ vg_list = []
+ for v in res[VG_INT]:
+ if v.Vg.Pvs[0] in pv_lookup:
+ vg_list.append(v)
+
+ for interface in \
+ [LV_INT, THINPOOL_INT, LV_COMMON_INT,
+ CACHE_POOL_INT, CACHE_LV_INT, VDOPOOL_INT]:
+ _prune_lvs(res, interface, v.object_path)
+
+ res[VG_INT] = vg_list
+
+ return res
+
+
+def get_objects():
+ rc = {
+ MANAGER_INT: [], PV_INT: [], VG_INT: [], LV_INT: [],
+ THINPOOL_INT: [], JOB_INT: [], SNAPSHOT_INT: [], LV_COMMON_INT: [],
+ CACHE_POOL_INT: [], CACHE_LV_INT: [], VG_VDO_INT: [], VDOPOOL_INT: []}
+
+ object_manager_object = bus.get_object(
+ BUS_NAME, "/com/redhat/lvmdbus1", introspect=False)
+
+ manager_interface = dbus.Interface(
+ object_manager_object, "org.freedesktop.DBus.ObjectManager")
+
+ objects = manager_interface.GetManagedObjects()
+
+ for object_path, v in objects.items():
+ proxy = ClientProxy(bus, object_path, v)
+ for interface in v.keys():
+ rc[interface].append(proxy)
+
+ # At this point we have a full population of everything, we now need to
+ # prune the objects if we are filtering PVs with a sub selection.
+ return _prune(rc, pv_device_list), bus
+
+
+def set_exec_mode(lvmshell):
+ lvm_manager = dbus.Interface(bus.get_object(
+ BUS_NAME, "/com/redhat/lvmdbus1/Manager", introspect=False),
+ "com.redhat.lvmdbus1.Manager")
+ return lvm_manager.UseLvmShell(lvmshell)
+
+
+def set_execution(lvmshell, test_result):
+ global g_lvm_shell
+ if lvmshell:
+ m = 'lvm shell (non-fork)'
+ else:
+ m = "forking & exec'ing"
+
+ rc = set_exec_mode(lvmshell)
+
+ if rc:
+ g_lvm_shell = lvmshell
+ std_err_print('Successfully changed execution mode to "%s"' % m)
+ else:
+ std_err_print('ERROR: Failed to change execution mode to "%s"' % m)
+ test_result.register_fail()
+ return rc
+
+
+def call_lvm(command):
+ """
+ Call lvm executable and return a tuple of exitcode, stdout, stderr
+ :param command: Command to execute
+ :type command: list
+ :returns (exitcode, stdout, stderr)
+ :rtype (int, str, str)
+ """
+
+ # Prepend the full lvm executable so that we can run different versions
+ # in different locations on the same box
+ command.insert(0, LVM_EXECUTABLE)
+
+ process = Popen(
+ command, stdout=PIPE, stderr=PIPE, close_fds=True, env=os.environ)
+ out = process.communicate()
+
+ stdout_text = bytes(out[0]).decode("utf-8")
+ stderr_text = bytes(out[1]).decode("utf-8")
+ return process.returncode, stdout_text, stderr_text
+
+
+def supports_vdo():
+ cmd = ['segtypes']
+ modprobe = Popen(["modprobe", "kvdo"], stdout=PIPE, stderr=PIPE, close_fds=True, env=os.environ)
+ modprobe.communicate()
+ if modprobe.returncode != 0:
+ return False
+ rc, out, err = call_lvm(cmd)
+ if rc != 0 or "vdo" not in out:
+ return False
+ return True
+
+
+def process_exists(name):
+ # Walk the process table looking for executable 'name'
+ for p in [pid for pid in os.listdir('/proc') if pid.isdigit()]:
+ try:
+ cmdline_args = read_file_split_nuls("/proc/%s/cmdline" % p)
+ except OSError:
+ continue
+ for arg in cmdline_args:
+ if name in arg:
+ return int(p)
+ return None
+
+
+def read_file_split_nuls(fn):
+ with open(fn, "rb") as fh:
+ return [p.decode("utf-8") for p in fh.read().split(b'\x00') if len(p) > 0]
+
+
+def read_file_build_hash(fn):
+ rc = dict()
+ lines = read_file_split_nuls(fn)
+ for line in lines:
+ if line.count("=") == 1:
+ k, v = line.split("=")
+ rc[k] = v
+ return rc
+
+
+def remove_lvm_debug():
+ # If we are running the lvmdbusd daemon and collecting lvm debug data, check and
+ # clean-up after the tests.
+ tmpdir = tempfile.gettempdir()
+ fp = os.path.join(tmpdir, "lvmdbusd.lvm.debug.*.log")
+ for f in glob(fp):
+ os.unlink(f)
+
+
+class DaemonInfo(object):
+ def __init__(self, pid):
+ # The daemon is running, we have a pid, lets see how it's being run.
+ # When running under systemd, fd 0 -> /dev/null, fd 1&2 -> socket
+ # when ran manually it may have output re-directed to a file etc.
+ # we need the following
+ # command line arguments
+ # cwd
+ # where the output is going (in case it's directed to a file)
+ # Which lvm binary is being used (check LVM_BINARY env. variable)
+ # PYTHONPATH
+ base = "/proc/%d" % pid
+ self.cwd = os.readlink("%s/cwd" % base)
+ self.cmdline = read_file_split_nuls("%s/cmdline" % (base))[1:]
+ self.env = read_file_build_hash("%s/environ" % base)
+ self.stdin = os.readlink("%s/fd/0" % base)
+ self.stdout = os.readlink("%s/fd/1" % base)
+ self.stderr = os.readlink("%s/fd/2" % base)
+
+ if self.cwd == "/" and self.stdin == "/dev/null":
+ self.systemd = True
+ else:
+ self.systemd = False
+
+ self.process = None
+
+ @classmethod
+ def get(cls):
+ pid = process_exists(EXE_NAME)
+ if pid:
+ return cls(pid)
+ return None
+
+ def start(self, expect_fail=False):
+ if self.systemd:
+ subprocess.run(["/usr/bin/systemctl", "start", "lvm2-lvmdbusd"], check=True)
+ else:
+ stdin_stream = None
+ stdout_stream = None
+ stderr_stream = None
+ try:
+ stdout_stream = open(self.stdout, "ab")
+ stdin_stream = open(self.stdin, "rb")
+ stderr_stream = open(self.stderr, "ab")
+
+ self.process = Popen(self.cmdline, cwd=self.cwd, stdin=stdin_stream,
+ stdout=stdout_stream, stderr=stderr_stream, env=self.env)
+
+ if expect_fail:
+ # Let's wait a bit to see if this process dies as expected and return the exit code
+ try:
+ self.process.wait(10)
+ return self.process.returncode
+ except subprocess.TimeoutExpired as e:
+ # Process did not fail as expected, lets kill it
+ os.kill(self.process.pid, signal.SIGKILL)
+ self.process.wait(20)
+ raise e
+ else:
+ # This is a hack to set the returncode. When the Popen object goes out of scope during the unit test
+ # the __del__ method gets called. As we leave the daemon running the process.returncode
+ # hasn't been set, so it incorrectly raises an exception that the process is still running
+ # which in our case is correct and expected.
+ self.process.returncode = 0
+ finally:
+ # Close these in the parent
+ if stdin_stream:
+ stdin_stream.close()
+ if stderr_stream:
+ stderr_stream.close()
+ if stdout_stream:
+ stdout_stream.close()
+
+ # Make sure daemon is responding to dbus events before returning
+ DaemonInfo._ensure_daemon("Daemon is not responding on dbus within 20 seconds of starting!")
+
+ # During local testing it usually takes ~0.25 seconds for daemon to be ready
+ return None
+
+ @staticmethod
+ def _ensure_no_daemon():
+ start = time.time()
+ pid = process_exists(EXE_NAME)
+ while pid is not None and (time.time() - start) <= 20:
+ time.sleep(0.3)
+ pid = process_exists(EXE_NAME)
+
+ if pid:
+ raise Exception(
+ "lsmd daemon did not exit within 20 seconds, pid = %s" % pid)
+
+ @staticmethod
+ def _ensure_daemon(msg):
+ start = time.time()
+ running = False
+ while True and (time.time() - start) < 20:
+ try:
+ get_objects()
+ running = True
+ break
+ except dbus.exceptions.DBusException:
+ time.sleep(0.2)
+ pass
+ if not running:
+ raise RuntimeError(msg)
+
+ def term_signal(self, sig_number):
+ # Used for signals that we expect with terminate the daemon, eg. SIGINT, SIGKILL
+ if self.process:
+ os.kill(self.process.pid, sig_number)
+ # Note: The following should work, but doesn't!
+ # self.process.send_signal(sig_number)
+ try:
+ self.process.wait(10)
+ except subprocess.TimeoutExpired:
+ std_err_print("Daemon hasn't exited within 10 seconds")
+ if self.process.poll() is None:
+ std_err_print("Daemon still running...")
+ else:
+ self.process = None
+ else:
+ pid = process_exists(EXE_NAME)
+ os.kill(pid, sig_number)
+
+ # Make sure there is no daemon present before we return for things to be "good"
+ DaemonInfo._ensure_no_daemon()
+
+ def non_term_signal(self, sig_number):
+ if sig_number not in [signal.SIGUSR1, signal.SIGUSR2]:
+ raise ValueError("Incorrect signal number! %d" % sig_number)
+ if self.process:
+ os.kill(self.process.pid, sig_number)
+ else:
+ pid = process_exists(EXE_NAME)
+ os.kill(pid, sig_number)
+
+
+# noinspection PyUnresolvedReferences
+class TestDbusService(unittest.TestCase):
+ def setUp(self):
+ self.pvs = []
+
+ # Because of the sensitive nature of running LVM tests we will only
+ # run if we have PVs and nothing else, so that we can be confident that
+ # we are not mucking with someone's data on their system
+ self.objs, self.bus = get_objects()
+ if len(self.objs[PV_INT]) == 0:
+ std_err_print('No PVs present exiting!')
+ sys.exit(1)
+
+ for p in self.objs[PV_INT]:
+ self.pvs.append(p.Pv.Name)
+
+ if len(self.objs[MANAGER_INT]) != 1:
+ std_err_print('Expecting a manager object!')
+ sys.exit(1)
+
+ if len(self.objs[VG_INT]) != 0:
+ std_err_print('Expecting no VGs to exist!')
+ sys.exit(1)
+
+ self.addCleanup(self.clean_up)
+
+ self.vdo = supports_vdo()
+ remove_lvm_debug()
+
+ def _recurse_vg_delete(self, vg_proxy, pv_proxy, nested_pv_hash):
+ vg_name = str(vg_proxy.Vg.Name)
+
+ if not vg_name.endswith(VG_TEST_SUFFIX):
+ std_err_print("Refusing to remove VG: %s" % vg_name)
+ return
+
+ for pv_device_name, t in nested_pv_hash.items():
+ if vg_name in pv_device_name:
+ self._recurse_vg_delete(t[0], t[1], nested_pv_hash)
+ break
+
+ vg_proxy.update()
+
+ self.handle_return(vg_proxy.Vg.Remove(dbus.Int32(g_tmo), EOD))
+ if is_nested_pv(pv_proxy.Pv.Name):
+ rc = self._pv_remove(pv_proxy)
+ self.assertTrue(rc == '/', "We expected a '/', but got %s when removing a PV" % str(rc))
+
+ def clean_up(self):
+ self.objs, self.bus = get_objects()
+
+ # The self.objs[PV_INT] list only contains those which we should be
+ # mucking with, lets remove any embedded/nested PVs first, then proceed
+ # to walk the base PVs and remove the VGs
+ nested_pvs = {}
+ non_nested = []
+
+ for p in self.objs[PV_INT]:
+ if is_nested_pv(p.Pv.Name):
+ if p.Pv.Vg != '/':
+ v = ClientProxy(self.bus, p.Pv.Vg, interfaces=(VG_INT,))
+ nested_pvs[p.Pv.Name] = (v, p)
+ else:
+ # Nested PV with no VG, so just simply remove it!
+ self._pv_remove(p)
+ else:
+ non_nested.append(p)
+
+ for p in non_nested:
+ # When we remove a VG for a PV it could ripple across multiple
+ # PVs, so update each PV while removing each VG, to ensure
+ # the properties are current and correct.
+ p.update()
+ if p.Pv.Vg != '/':
+ v = ClientProxy(self.bus, p.Pv.Vg, interfaces=(VG_INT,))
+ self._recurse_vg_delete(v, p, nested_pvs)
+
+ # Check to make sure the PVs we had to start exist, else re-create
+ # them
+ self.objs, self.bus = get_objects()
+ if len(self.pvs) != len(self.objs[PV_INT]):
+ for p in self.pvs:
+ found = False
+ for pc in self.objs[PV_INT]:
+ if pc.Pv.Name == p:
+ found = True
+ break
+
+ if not found:
+ # print('Re-creating PV=', p)
+ self._pv_create(p)
+
+ remove_lvm_debug()
+
+ def _check_consistency(self):
+ # Only do consistency checks if we aren't running the unit tests
+ # concurrently
+ if pv_device_list is None:
+ self.assertEqual(self._refresh(), 0)
+
+ def handle_return(self, rc):
+ if isinstance(rc, (tuple, list)):
+ # We have a tuple returned
+ if rc[0] != '/':
+ return rc[0]
+ else:
+ return self._wait_for_job(rc[1])
+ else:
+ if rc == '/':
+ return rc
+ else:
+ return self._wait_for_job(rc)
+
+ def _pv_create(self, device):
+
+ pv_path = self.handle_return(
+ self.objs[MANAGER_INT][0].Manager.PvCreate(
+ dbus.String(device), dbus.Int32(g_tmo), EOD)
+ )
+
+ self._validate_lookup(device, pv_path)
+
+ self.assertTrue(pv_path is not None and len(pv_path) > 0,
+ "When creating a PV we expected the returned path to be valid")
+ return pv_path
+
+ def _manager(self):
+ return self.objs[MANAGER_INT][0]
+
+ def _refresh(self):
+ return self._manager().Manager.Refresh()
+
+ def test_refresh(self):
+ self._check_consistency()
+
+ def test_version(self):
+ rc = self.objs[MANAGER_INT][0].Manager.Version
+ self.assertTrue(rc is not None and len(rc) > 0, "Manager.Version is invalid")
+ self._check_consistency()
+
+ def _vg_create(self, pv_paths=None, vg_prefix=None, options=None):
+
+ if not pv_paths:
+ pv_paths = self._all_pv_object_paths()
+
+ if options is None:
+ options = EOD
+
+ vg_name = vg_n(prefix=vg_prefix)
+
+ vg_path = self.handle_return(
+ self.objs[MANAGER_INT][0].Manager.VgCreate(
+ dbus.String(vg_name),
+ dbus.Array(pv_paths, signature=dbus.Signature('o')),
+ dbus.Int32(g_tmo),
+ options))
+
+ self._validate_lookup(vg_name, vg_path)
+ self.assertTrue(vg_path is not None and len(vg_path) > 0, "During VG creation, returned path is empty")
+
+ intf = [VG_INT, ]
+ if self.vdo:
+ intf.append(VG_VDO_INT)
+
+ return ClientProxy(self.bus, vg_path, interfaces=intf)
+
+ def test_vg_create(self):
+ self._vg_create()
+ self._check_consistency()
+
+ def test_vg_delete(self):
+ vg = self._vg_create().Vg
+
+ self.handle_return(
+ vg.Remove(dbus.Int32(g_tmo), EOD))
+ self._check_consistency()
+
+ def _pv_remove(self, pv):
+ rc = self.handle_return(
+ pv.Pv.Remove(dbus.Int32(g_tmo), EOD))
+ return rc
+
+ def test_pv_remove_add(self):
+ target = self.objs[PV_INT][0]
+
+ # Remove the PV
+ rc = self._pv_remove(target)
+ self.assertTrue(rc == '/')
+ self._check_consistency()
+
+ # Add it back
+ rc = self._pv_create(target.Pv.Name)[0]
+ self.assertTrue(rc == '/')
+ self._check_consistency()
+
+ def _create_raid5_thin_pool(self, vg=None):
+
+ meta_name = "meta_r5"
+ data_name = "data_r5"
+
+ if not vg:
+ vg = self._vg_create(self._all_pv_object_paths()).Vg
+
+ lv_meta_path = self.handle_return(
+ vg.LvCreateRaid(
+ dbus.String(meta_name),
+ dbus.String("raid5"),
+ dbus.UInt64(mib(4)),
+ dbus.UInt32(0),
+ dbus.UInt32(0),
+ dbus.Int32(g_tmo),
+ EOD)
+ )
+ self._validate_lookup("%s/%s" % (vg.Name, meta_name), lv_meta_path)
+
+ lv_data_path = self.handle_return(
+ vg.LvCreateRaid(
+ dbus.String(data_name),
+ dbus.String("raid5"),
+ dbus.UInt64(mib(16)),
+ dbus.UInt32(0),
+ dbus.UInt32(0),
+ dbus.Int32(g_tmo),
+ EOD)
+ )
+
+ self._validate_lookup("%s/%s" % (vg.Name, data_name), lv_data_path)
+
+ thin_pool_path = self.handle_return(
+ vg.CreateThinPool(
+ dbus.ObjectPath(lv_meta_path),
+ dbus.ObjectPath(lv_data_path),
+ dbus.Int32(g_tmo), EOD)
+ )
+
+ # Get thin pool client proxy
+ intf = (LV_COMMON_INT, LV_INT, THINPOOL_INT)
+ thin_pool = ClientProxy(self.bus, thin_pool_path, interfaces=intf)
+
+ return vg, thin_pool
+
+ def test_meta_lv_data_lv_props(self):
+ # Ensure that metadata lv and data lv for thin pools and cache pools
+ # point to a valid LV
+ (vg, thin_pool) = self._create_raid5_thin_pool()
+
+ # Check properties on thin pool
+ self.assertTrue(thin_pool.ThinPool.DataLv != '/')
+ self.assertTrue(thin_pool.ThinPool.MetaDataLv != '/')
+
+ (vg, cache_pool) = self._create_cache_pool(vg)
+
+ self.assertTrue(cache_pool.CachePool.DataLv != '/')
+ self.assertTrue(cache_pool.CachePool.MetaDataLv != '/')
+
+ # Cache the thin pool
+ cached_thin_pool_path = self.handle_return(
+ cache_pool.CachePool.CacheLv(
+ dbus.ObjectPath(thin_pool.object_path),
+ dbus.Int32(g_tmo), EOD)
+ )
+
+ # Get object proxy for cached thin pool
+ intf = (LV_COMMON_INT, LV_INT, THINPOOL_INT)
+ cached_thin_pool_object = ClientProxy(
+ self.bus, cached_thin_pool_path, interfaces=intf)
+
+ # Check properties on cache pool
+ self.assertTrue(cached_thin_pool_object.ThinPool.DataLv != '/')
+ self.assertTrue(cached_thin_pool_object.ThinPool.MetaDataLv != '/')
+
+ def _lookup(self, lvm_id):
+ return self.objs[MANAGER_INT][0].\
+ Manager.LookUpByLvmId(dbus.String(lvm_id))
+
+ def _validate_lookup(self, lvm_name, object_path):
+ t = self._lookup(lvm_name)
+ self.assertTrue(
+ object_path == t, "%s != %s for %s" % (object_path, t, lvm_name))
+
+ def test_lookup_by_lvm_id(self):
+ # For the moment lets just lookup what we know about which is PVs
+ # When we start testing VGs and LVs we will test lookups for those
+ # during those unit tests
+ for p in self.objs[PV_INT]:
+ rc = self._lookup(p.Pv.Name)
+ self.assertTrue(rc is not None and rc != '/')
+
+ # Search for something which doesn't exist
+ rc = self._lookup('/dev/null')
+ self.assertTrue(rc == '/')
+
+ def test_vg_extend(self):
+ # Create a VG
+ self.assertTrue(len(self.objs[PV_INT]) >= 2)
+
+ if len(self.objs[PV_INT]) >= 2:
+ pv_initial = self.objs[PV_INT][0]
+ pv_next = self.objs[PV_INT][1]
+
+ vg = self._vg_create([pv_initial.object_path]).Vg
+
+ path = self.handle_return(
+ vg.Extend(
+ dbus.Array([pv_next.object_path], signature="o"),
+ dbus.Int32(g_tmo), EOD)
+ )
+ self.assertTrue(path == '/')
+ self._check_consistency()
+
+ # noinspection PyUnresolvedReferences
+ def test_vg_reduce(self):
+ self.assertTrue(len(self.objs[PV_INT]) >= 2)
+
+ if len(self.objs[PV_INT]) >= 2:
+ vg = self._vg_create(
+ [self.objs[PV_INT][0].object_path,
+ self.objs[PV_INT][1].object_path]).Vg
+
+ path = self.handle_return(
+ vg.Reduce(
+ dbus.Boolean(False), dbus.Array([vg.Pvs[0]], signature='o'),
+ dbus.Int32(g_tmo), EOD)
+ )
+ self.assertTrue(path == '/')
+ self._check_consistency()
+
+ def _verify_lv_paths(self, vg, new_name):
+ """
+ # Go through each LV and make sure it has the correct path back to the
+ # VG
+ :return:
+ """
+ lv_paths = vg.Lvs
+
+ for l in lv_paths:
+ lv_proxy = ClientProxy(
+ self.bus, l, interfaces=(LV_COMMON_INT,)).LvCommon
+ self.assertTrue(
+ lv_proxy.Vg == vg.object_path, "%s != %s" %
+ (lv_proxy.Vg, vg.object_path))
+ full_name = "%s/%s" % (new_name, lv_proxy.Name)
+ lv_path = self._lookup(full_name)
+ self.assertTrue(
+ lv_path == lv_proxy.object_path, "%s != %s" %
+ (lv_path, lv_proxy.object_path))
+
+ # noinspection PyUnresolvedReferences
+ def test_vg_rename(self):
+ vg = self._vg_create().Vg
+
+ # Do a vg lookup
+ path = self._lookup(vg.Name)
+
+ vg_name_start = vg.Name
+
+ prev_path = path
+ self.assertTrue(path != '/', "%s" % (path))
+
+ # Create some LVs in the VG
+ for i in range(0, 5):
+ lv_t = self._create_lv(size=mib(4), vg=vg)
+ full_name = "%s/%s" % (vg_name_start, lv_t.LvCommon.Name)
+ lv_path = self._lookup(full_name)
+ self.assertTrue(lv_path == lv_t.object_path)
+
+ new_name = 'renamed_' + vg.Name
+
+ path = self.handle_return(
+ vg.Rename(dbus.String(new_name), dbus.Int32(g_tmo), EOD))
+ self.assertTrue(path == '/')
+ self._check_consistency()
+
+ # Do a vg lookup
+ path = self._lookup(new_name)
+ self.assertTrue(path != '/', "%s" % (path))
+ self.assertTrue(prev_path == path, "%s != %s" % (prev_path, path))
+
+ # Go through each LV and make sure it has the correct path back to the
+ # VG
+ vg.update()
+
+ self.assertTrue(len(vg.Lvs) == 5)
+ self._verify_lv_paths(vg, new_name)
+
+ def _verify_hidden_lookups(self, lv_common_object, vgname):
+ hidden_lv_paths = lv_common_object.HiddenLvs
+
+ for h in hidden_lv_paths:
+ h_lv = ClientProxy(
+ self.bus, h, interfaces=(LV_COMMON_INT,)).LvCommon
+
+ if len(h_lv.HiddenLvs) > 0:
+ self._verify_hidden_lookups(h_lv, vgname)
+
+ full_name = "%s/%s" % (vgname, h_lv.Name)
+ # print("Hidden check %s" % (full_name))
+ lookup_path = self._lookup(full_name)
+ self.assertTrue(lookup_path != '/')
+ self.assertTrue(lookup_path == h_lv.object_path)
+
+ # Lets's strip off the '[ ]' and make sure we can find
+ full_name = "%s/%s" % (vgname, h_lv.Name[1:-1])
+ # print("Hidden check %s" % (full_name))
+
+ lookup_path = self._lookup(full_name)
+ self.assertTrue(lookup_path != '/')
+ self.assertTrue(lookup_path == h_lv.object_path)
+
+ def test_vg_rename_with_thin_pool(self):
+
+ (vg, thin_pool) = self._create_raid5_thin_pool()
+
+ vg_name_start = vg.Name
+
+ # noinspection PyTypeChecker
+ self._verify_hidden_lookups(thin_pool.LvCommon, vg_name_start)
+
+ for i in range(0, 5):
+ lv_name = lv_n()
+
+ thin_lv_path = self.handle_return(
+ thin_pool.ThinPool.LvCreate(
+ dbus.String(lv_name),
+ dbus.UInt64(mib(16)),
+ dbus.Int32(g_tmo),
+ EOD))
+
+ self._validate_lookup(
+ "%s/%s" % (vg_name_start, lv_name), thin_lv_path)
+
+ self.assertTrue(thin_lv_path != '/')
+
+ full_name = "%s/%s" % (vg_name_start, lv_name)
+
+ lookup_lv_path = self._lookup(full_name)
+ self.assertTrue(
+ thin_lv_path == lookup_lv_path,
+ "%s != %s" % (thin_lv_path, lookup_lv_path))
+
+ # Rename the VG
+ new_name = 'renamed_' + vg.Name
+ path = self.handle_return(
+ vg.Rename(dbus.String(new_name), dbus.Int32(g_tmo), EOD))
+
+ self.assertTrue(path == '/')
+ self._check_consistency()
+
+ vg.update()
+ thin_pool.update()
+ self._verify_lv_paths(vg, new_name)
+ # noinspection PyTypeChecker
+ self._verify_hidden_lookups(thin_pool.LvCommon, new_name)
+
+ def _test_lv_create(self, method, params, vg, proxy_interfaces=None):
+ lv = None
+
+ path = self.handle_return(method(*params))
+ self.assertTrue(vg)
+
+ if path:
+ lv = ClientProxy(self.bus, path, interfaces=proxy_interfaces)
+
+ # We are quick enough now that we can get VolumeType changes from
+ # 'I' to 'i' between the time it takes to create a RAID and it returns
+ # and when we refresh state here. Not sure how we can handle this as
+ # we cannot just sit and poll all the time for changes...
+ # self._check_consistency()
+ return lv
+
+ def test_lv_create(self):
+ lv_name = lv_n()
+ vg = self._vg_create().Vg
+ lv = self._test_lv_create(
+ vg.LvCreate,
+ (dbus.String(lv_name), dbus.UInt64(mib(4)),
+ dbus.Array([], signature='(ott)'), dbus.Int32(g_tmo),
+ EOD), vg, LV_BASE_INT)
+ self._validate_lookup("%s/%s" % (vg.Name, lv_name), lv.object_path)
+
+ def test_prop_get(self):
+ lv_name = lv_n()
+ vg = self._vg_create().Vg
+ lv = self._test_lv_create(
+ vg.LvCreate,
+ (dbus.String(lv_name), dbus.UInt64(mib(4)),
+ dbus.Array([], signature='(ott)'), dbus.Int32(g_tmo),
+ EOD), vg, LV_BASE_INT)
+ ri = RemoteInterface(lv.dbus_object, interface=LV_COMMON_INT, introspect=False)
+
+ ri.update()
+ for prop_name in ri.get_property_names():
+ self.assertEqual(ri.get_property_value(prop_name), getattr(ri, prop_name))
+
+ def test_lv_create_job(self):
+ lv_name = lv_n()
+ vg = self._vg_create().Vg
+ (object_path, job_path) = vg.LvCreate(
+ dbus.String(lv_name), dbus.UInt64(mib(4)),
+ dbus.Array([], signature='(ott)'), dbus.Int32(0),
+ EOD)
+
+ self.assertTrue(object_path == '/')
+ self.assertTrue(job_path != '/')
+ object_path = self._wait_for_job(job_path)
+
+ self._validate_lookup("%s/%s" % (vg.Name, lv_name), object_path)
+ self.assertTrue(object_path != '/')
+
+ def test_lv_create_linear(self):
+
+ lv_name = lv_n()
+ vg = self._vg_create().Vg
+ lv = self._test_lv_create(
+ vg.LvCreateLinear,
+ (dbus.String(lv_name), dbus.UInt64(mib(4)), dbus.Boolean(False),
+ dbus.Int32(g_tmo), EOD), vg, LV_BASE_INT)
+ self._validate_lookup("%s/%s" % (vg.Name, lv_name), lv.object_path)
+
+ def _all_pv_object_paths(self):
+ return [pp.object_path for pp in self.objs[PV_INT]]
+
+ def test_lv_create_striped(self):
+ lv_name = lv_n()
+ vg = self._vg_create(self._all_pv_object_paths()).Vg
+ lv = self._test_lv_create(
+ vg.LvCreateStriped,
+ (dbus.String(lv_name), dbus.UInt64(mib(4)),
+ dbus.UInt32(2), dbus.UInt32(8), dbus.Boolean(False),
+ dbus.Int32(g_tmo), EOD), vg, LV_BASE_INT)
+ self._validate_lookup("%s/%s" % (vg.Name, lv_name), lv.object_path)
+
+ def test_lv_create_mirror(self):
+ lv_name = lv_n()
+ vg = self._vg_create(self._all_pv_object_paths()).Vg
+ lv = self._test_lv_create(
+ vg.LvCreateMirror,
+ (dbus.String(lv_name), dbus.UInt64(mib(4)), dbus.UInt32(2),
+ dbus.Int32(g_tmo), EOD), vg, LV_BASE_INT)
+ self._validate_lookup("%s/%s" % (vg.Name, lv_name), lv.object_path)
+
+ def test_lv_create_raid(self):
+ lv_name = lv_n()
+ vg = self._vg_create(self._all_pv_object_paths()).Vg
+ lv = self._test_lv_create(
+ vg.LvCreateRaid,
+ (dbus.String(lv_name), dbus.String('raid5'), dbus.UInt64(mib(16)),
+ dbus.UInt32(2), dbus.UInt32(8), dbus.Int32(g_tmo), EOD),
+ vg, LV_BASE_INT)
+ self._validate_lookup("%s/%s" % (vg.Name, lv_name), lv.object_path)
+
+ def _create_lv(self, thinpool=False, size=None, vg=None, suffix=None):
+
+ lv_name = lv_n(suffix=suffix)
+ interfaces = list(LV_BASE_INT)
+
+ if thinpool:
+ interfaces.append(THINPOOL_INT)
+
+ if not vg:
+ vg = self._vg_create(self._all_pv_object_paths()).Vg
+
+ if size is None:
+ size = mib(8)
+
+ lv = self._test_lv_create(
+ vg.LvCreateLinear,
+ (dbus.String(lv_name), dbus.UInt64(size),
+ dbus.Boolean(thinpool), dbus.Int32(g_tmo), EOD),
+ vg, interfaces)
+
+ self._validate_lookup("%s/%s" % (vg.Name, lv_name), lv.object_path)
+ return lv
+
+ def _create_thin_pool_lv(self):
+ return self._create_lv(True)
+
+ def test_lv_create_rounding(self):
+ self._create_lv(size=(mib(2) + 13))
+
+ def test_lv_create_thin_pool(self):
+ self._create_thin_pool_lv()
+
+ def _rename_lv_test(self, lv):
+ path = self._lookup(lv.LvCommon.Name)
+ prev_path = path
+
+ new_name = 'renamed_' + lv.LvCommon.Name
+
+ self.handle_return(
+ lv.Lv.Rename(dbus.String(new_name), dbus.Int32(g_tmo), EOD))
+
+ path = self._lookup(new_name)
+
+ self._check_consistency()
+ self.assertTrue(prev_path == path, "%s != %s" % (prev_path, path))
+
+ lv.update()
+ self.assertTrue(
+ lv.LvCommon.Name == new_name,
+ "%s != %s" % (lv.LvCommon.Name, new_name))
+
+ def test_lv_rename(self):
+ # Rename a regular LV
+ lv = self._create_lv()
+ self._rename_lv_test(lv)
+
+ def test_lv_thinpool_rename(self):
+ # Rename a thin pool
+ tp = self._create_lv(True)
+ self.assertTrue(
+ THINPOOL_LV_PATH in tp.object_path,
+ "%s" % (tp.object_path))
+
+ new_name = 'renamed_' + tp.LvCommon.Name
+ self.handle_return(tp.Lv.Rename(
+ dbus.String(new_name), dbus.Int32(g_tmo), EOD))
+ tp.update()
+ self._check_consistency()
+ self.assertEqual(new_name, tp.LvCommon.Name)
+
+ def _create_thin_lv(self):
+ vg = self._vg_create().Vg
+ tp = self._create_lv(thinpool=True, vg=vg)
+
+ lv_name = lv_n('_thin_lv')
+
+ thin_path = self.handle_return(
+ tp.ThinPool.LvCreate(
+ dbus.String(lv_name),
+ dbus.UInt64(mib(10)),
+ dbus.Int32(g_tmo),
+ EOD)
+ )
+ self._validate_lookup("%s/%s" % (vg.Name, lv_name), thin_path)
+
+ lv = ClientProxy(
+ self.bus, thin_path, interfaces=(LV_COMMON_INT, LV_INT))
+ return vg, thin_path, lv
+
+ # noinspection PyUnresolvedReferences
+ def test_lv_on_thin_pool_rename(self):
+ # Rename a LV on a thin Pool
+ vg, thin_path, lv = self._create_thin_lv()
+ re_named = 'rename_test' + lv.LvCommon.Name
+ rc = self.handle_return(
+ lv.Lv.Rename(
+ dbus.String(re_named),
+ dbus.Int32(g_tmo),
+ EOD)
+ )
+
+ self._validate_lookup("%s/%s" % (vg.Name, re_named), thin_path)
+ self.assertTrue(rc == '/')
+ self._check_consistency()
+
+ def _lv_remove(self, lv):
+ rc = self.handle_return(
+ lv.Lv.Remove(
+ dbus.Int32(g_tmo),
+ EOD))
+ self.assertTrue(rc == '/')
+ self._check_consistency()
+
+ def test_lv_remove(self):
+ lv = self._create_lv()
+ self._lv_remove(lv)
+
+ def _take_lv_snapshot(self, lv_p):
+ ss_name = 'ss_' + lv_p.LvCommon.Name
+
+ ss_obj_path = self.handle_return(lv_p.Lv.Snapshot(
+ dbus.String(ss_name),
+ dbus.UInt64(0),
+ dbus.Int32(g_tmo),
+ EOD))
+
+ self.assertTrue(ss_obj_path != '/')
+ return ClientProxy(
+ self.bus, ss_obj_path, interfaces=(LV_COMMON_INT, LV_INT))
+
+ def test_lv_snapshot(self):
+ lv_p = self._create_lv()
+ self._take_lv_snapshot(lv_p)
+
+ # noinspection PyUnresolvedReferences,PyUnusedLocal
+ def _wait_for_job(self, j_path):
+ rc = None
+ j = ClientProxy(self.bus, j_path, interfaces=(JOB_INT, )).Job
+
+ while True:
+ j.update()
+ if j.Complete:
+ (ec, error_msg) = j.GetError
+ self.assertTrue(ec == 0, "%d :%s" % (ec, error_msg))
+
+ if ec == 0:
+ self.assertTrue(j.Percent == 100, "P= %f" % j.Percent)
+
+ rc = j.Result
+ j.Remove()
+
+ break
+
+ if j.Wait(1):
+ self.assertTrue(j.Wait(0))
+ j.update()
+ self.assertTrue(j.Complete)
+
+ return rc
+
+ def test_lv_create_pv_specific(self):
+ vg = self._vg_create().Vg
+ lv_name = lv_n()
+ pv = vg.Pvs
+ pvp = ClientProxy(self.bus, pv[0], interfaces=(PV_INT,))
+
+ lv = self._test_lv_create(
+ vg.LvCreate, (
+ dbus.String(lv_name),
+ dbus.UInt64(mib(4)),
+ dbus.Array(
+ [[pvp.object_path, 0, (pvp.Pv.PeCount - 1)]],
+ signature='(ott)'),
+ dbus.Int32(g_tmo), EOD), vg, LV_BASE_INT)
+ self._validate_lookup("%s/%s" % (vg.Name, lv_name), lv.object_path)
+
+ def _test_lv_resize(self, lv):
+ # Can't resize cache or thin pool volumes or vdo pool lv
+ if lv.LvCommon.Attr[0] == 'C' or lv.LvCommon.Attr[0] == 't' or \
+ lv.LvCommon.Attr[0] == 'd':
+ return
+
+ vg = ClientProxy(self.bus, lv.LvCommon.Vg, interfaces=(VG_INT,)).Vg
+
+ start_size = lv.LvCommon.SizeBytes
+
+ # Vdo are fairly big and need large re-size amounts.
+ if start_size > mib(4) * 3:
+ delta = mib(4)
+ else:
+ delta = 16384
+
+ for size in [start_size + delta, start_size - delta]:
+
+ pv_in_use = [i[0] for i in lv.LvCommon.Devices]
+ # Select a PV in the VG that isn't in use
+ pv_empty = [p for p in vg.Pvs if p not in pv_in_use]
+
+ prev = lv.LvCommon.SizeBytes
+
+ if len(pv_empty):
+ p = ClientProxy(self.bus, pv_empty[0], interfaces=(PV_INT,))
+
+ rc = self.handle_return(
+ lv.Lv.Resize(
+ dbus.UInt64(size),
+ dbus.Array(
+ [[p.object_path, 0, p.Pv.PeCount - 1]], '(oii)'),
+ dbus.Int32(g_tmo), EOD))
+ else:
+ rc = self.handle_return(
+ lv.Lv.Resize(
+ dbus.UInt64(size),
+ dbus.Array([], '(oii)'),
+ dbus.Int32(g_tmo), EOD))
+
+ self.assertEqual(rc, '/')
+ self._check_consistency()
+
+ lv.update()
+
+ if prev < size:
+ self.assertTrue(lv.LvCommon.SizeBytes > prev)
+ else:
+ # We are testing re-sizing to same size too...
+ self.assertTrue(lv.LvCommon.SizeBytes <= prev)
+
+ def test_lv_resize(self):
+
+ pv_paths = [
+ self.objs[PV_INT][0].object_path, self.objs[PV_INT][1].object_path]
+
+ vg = self._vg_create(pv_paths).Vg
+ lv = self._create_lv(vg=vg, size=mib(16))
+
+ self._test_lv_resize(lv)
+
+ def test_lv_resize_same(self):
+ vg = self._vg_create(self._all_pv_object_paths()).Vg
+ lv = self._create_lv(vg=vg)
+
+ with self.assertRaises(dbus.exceptions.DBusException):
+ lv.Lv.Resize(
+ dbus.UInt64(lv.LvCommon.SizeBytes),
+ dbus.Array([], '(oii)'),
+ dbus.Int32(-1), EOD)
+
+ def test_lv_move(self):
+ lv = self._create_lv()
+
+ pv_path_move = str(lv.LvCommon.Devices[0][0])
+
+ # Test moving a specific LV
+ rc = self.handle_return(
+ lv.Lv.Move(
+ dbus.ObjectPath(pv_path_move),
+ dbus.Struct((0, 0), signature='(tt)'),
+ dbus.Array([], '(ott)'), dbus.Int32(g_tmo),
+ EOD))
+ self.assertTrue(rc == '/')
+ self._check_consistency()
+
+ lv.update()
+ new_pv = str(lv.LvCommon.Devices[0][0])
+ self.assertTrue(
+ pv_path_move != new_pv, "%s == %s" % (pv_path_move, new_pv))
+
+ def _test_activate_deactivate(self, lv_p):
+ self.handle_return(lv_p.Lv.Deactivate(
+ dbus.UInt64(0), dbus.Int32(g_tmo), EOD))
+ lv_p.update()
+ self.assertFalse(lv_p.LvCommon.Active)
+ self._check_consistency()
+
+ self.handle_return(lv_p.Lv.Activate(
+ dbus.UInt64(0), dbus.Int32(g_tmo), EOD))
+
+ lv_p.update()
+ self.assertTrue(lv_p.LvCommon.Active)
+
+ # Vdo property "IndexState" when getting activated goes from
+ # "opening" -> "online" after we have returned from the activate call
+ # thus when we try to check the consistency we fail as the property
+ # is changing on it's own and not because the lvmdbusd failed to
+ # refresh it's own state. One solution is to not expose IndexState as
+ # a property.
+ # TODO Expose method to determine if Lv is partaking in VDO.
+ vg = ClientProxy(self.bus, lv_p.LvCommon.Vg, interfaces=(VG_INT,))
+ if "vdo" not in vg.Vg.Name:
+ self._check_consistency()
+
+ # Try control flags
+ for i in range(0, 6):
+
+ self.handle_return(lv_p.Lv.Activate(
+ dbus.UInt64(1 << i),
+ dbus.Int32(g_tmo),
+ EOD))
+
+ self.assertTrue(lv_p.LvCommon.Active)
+ self._check_consistency()
+
+ def test_lv_activate_deactivate(self):
+ lv_p = self._create_lv()
+ self._test_activate_deactivate(lv_p)
+
+ def test_move(self):
+ lv = self._create_lv()
+
+ # Test moving without being LV specific
+ vg = ClientProxy(self.bus, lv.LvCommon.Vg, interfaces=(VG_INT, )).Vg
+ pv_to_move = str(lv.LvCommon.Devices[0][0])
+
+ rc = self.handle_return(
+ vg.Move(
+ dbus.ObjectPath(pv_to_move),
+ dbus.Struct((0, 0), signature='tt'),
+ dbus.Array([], '(ott)'),
+ dbus.Int32(0),
+ EOD))
+ self.assertEqual(rc, '/')
+ self._check_consistency()
+
+ vg.update()
+ lv.update()
+
+ location = lv.LvCommon.Devices[0][0]
+
+ dst = None
+ for p in vg.Pvs:
+ if p != location:
+ dst = p
+
+ # Fetch the destination
+ pv = ClientProxy(self.bus, dst, interfaces=(PV_INT, )).Pv
+
+ # Test range, move it to the middle of the new destination
+ job = self.handle_return(
+ vg.Move(
+ dbus.ObjectPath(location),
+ dbus.Struct((0, 0), signature='tt'),
+ dbus.Array([(dst, pv.PeCount // 2, 0), ], '(ott)'),
+ dbus.Int32(g_tmo),
+ EOD))
+ self.assertEqual(job, '/')
+ self._check_consistency()
+
+ def test_job_handling(self):
+ pv_paths = self._all_pv_object_paths()
+ vg_name = vg_n()
+
+ # Test getting a job right away
+ vg_path, vg_job = self.objs[MANAGER_INT][0].Manager.VgCreate(
+ dbus.String(vg_name),
+ dbus.Array(pv_paths, 'o'),
+ dbus.Int32(0),
+ EOD)
+
+ self.assertTrue(vg_path == '/')
+ self.assertTrue(vg_job and len(vg_job) > 0)
+
+ vg_path = self._wait_for_job(vg_job)
+ self._validate_lookup(vg_name, vg_path)
+
+ def _create_num_lvs(self, num_lvs, no_wait=False):
+ vg_proxy = self._vg_create(self._all_pv_object_paths())
+ if no_wait:
+ tmo = 0
+ else:
+ tmo = g_tmo
+
+ for i in range(0, num_lvs):
+ lv_name = lv_n()
+ vg_proxy.update()
+ if vg_proxy.Vg.FreeCount > 0:
+ create_result = vg_proxy.Vg.LvCreateLinear(
+ dbus.String(lv_name),
+ dbus.UInt64(mib(4)),
+ dbus.Boolean(False),
+ dbus.Int32(tmo),
+ EOD)
+
+ if not no_wait:
+ lv_path = self.handle_return(create_result)
+ self.assertTrue(lv_path != '/')
+ self._validate_lookup("%s/%s" % (vg_proxy.Vg.Name, lv_name), lv_path)
+ else:
+ # We ran out of space, test(s) may fail
+ break
+ return vg_proxy
+
+ def _test_expired_timer(self, num_lvs):
+ rc = False
+
+ # In small configurations lvm is pretty snappy, so let's create a VG
+ # add a number of LVs and then remove the VG and all the contained
+ # LVs which appears to consistently run a little slow.
+
+ vg_proxy = self._create_num_lvs(num_lvs)
+
+ # Make sure that we are honoring the timeout
+ start = time.time()
+
+ remove_job = vg_proxy.Vg.Remove(dbus.Int32(1), EOD)
+
+ end = time.time()
+
+ tt_remove = float(end) - float(start)
+
+ self.assertTrue(tt_remove < 2.0, "remove time %s" % (str(tt_remove)))
+
+ # Depending on how long it took we could finish either way
+ if remove_job != '/':
+ # We got a job
+ result = self._wait_for_job(remove_job)
+ self.assertTrue(result == '/')
+ rc = True
+ else:
+ # It completed before timer popped
+ pass
+
+ return rc
+
+ # noinspection PyUnusedLocal
+ def test_job_handling_timer(self):
+
+ yes = False
+
+ for pp in self.objs[PV_INT]:
+ if '/dev/sd' not in pp.Pv.Name:
+ std_err_print("Skipping test_job_handling_timer on loopback")
+ return
+
+ # This may not pass
+ for i in [128, 256]:
+ yes = self._test_expired_timer(i)
+ if yes:
+ break
+ std_err_print('Attempt (%d) failed, trying again...' % (i))
+
+ self.assertTrue(yes)
+
+ def test_pv_tags(self):
+ pvs = []
+ vg = self._vg_create(self._all_pv_object_paths()).Vg
+
+ # Get the PVs
+ for p in vg.Pvs:
+ pvs.append(ClientProxy(self.bus, p, interfaces=(PV_INT, )).Pv)
+
+ for tags_value in [['hello'], ['foo', 'bar']]:
+
+ rc = self.handle_return(
+ vg.PvTagsAdd(
+ dbus.Array(vg.Pvs, 'o'),
+ dbus.Array(tags_value, 's'),
+ dbus.Int32(g_tmo),
+ EOD))
+ self.assertTrue(rc == '/')
+
+ for p in pvs:
+ p.update()
+ self.assertTrue(sorted(tags_value) == p.Tags)
+
+ rc = self.handle_return(
+ vg.PvTagsDel(
+ dbus.Array(vg.Pvs, 'o'),
+ dbus.Array(tags_value, 's'),
+ dbus.Int32(g_tmo),
+ EOD))
+ self.assertEqual(rc, '/')
+
+ for p in pvs:
+ p.update()
+ self.assertTrue([] == p.Tags)
+
+ def test_vg_tags(self):
+ vg = self._vg_create().Vg
+
+ t = ['Testing', 'tags']
+
+ self.handle_return(
+ vg.TagsAdd(
+ dbus.Array(t, 's'),
+ dbus.Int32(g_tmo),
+ EOD))
+
+ vg.update()
+ self.assertTrue(t == vg.Tags)
+
+ self.handle_return(
+ vg.TagsDel(
+ dbus.Array(t, 's'),
+ dbus.Int32(g_tmo),
+ EOD))
+ vg.update()
+ self.assertTrue([] == vg.Tags)
+
+ def _test_lv_tags(self, lv):
+ t = ['Testing', 'tags']
+
+ self.handle_return(
+ lv.Lv.TagsAdd(
+ dbus.Array(t, 's'), dbus.Int32(g_tmo), EOD))
+ self._check_consistency()
+ lv.update()
+ self.assertTrue(t == lv.LvCommon.Tags)
+
+ self.handle_return(
+ lv.Lv.TagsDel(
+ dbus.Array(t, 's'),
+ dbus.Int32(g_tmo),
+ EOD))
+ self._check_consistency()
+ lv.update()
+ self.assertTrue([] == lv.LvCommon.Tags)
+
+ def test_lv_tags(self):
+ vg = self._vg_create().Vg
+ lv = self._create_lv(vg=vg)
+ self._test_lv_tags(lv)
+
+ def test_vg_allocation_policy_set(self):
+ vg = self._vg_create().Vg
+
+ for p in ['anywhere', 'contiguous', 'cling', 'normal']:
+ rc = self.handle_return(
+ vg.AllocationPolicySet(
+ dbus.String(p), dbus.Int32(g_tmo), EOD))
+
+ self.assertEqual(rc, '/')
+ vg.update()
+
+ prop = getattr(vg, 'Alloc' + p.title())
+ self.assertTrue(prop)
+
+ def test_vg_max_pv(self):
+ vg = self._vg_create([self.objs[PV_INT][0].object_path]).Vg
+ for p in [0, 1, 10, 100, 100, 1024, 2 ** 32 - 1]:
+ rc = self.handle_return(
+ vg.MaxPvSet(
+ dbus.UInt64(p), dbus.Int32(g_tmo), EOD))
+ self.assertEqual(rc, '/')
+ vg.update()
+ self.assertTrue(
+ vg.MaxPv == p,
+ "Expected %s != Actual %s" % (str(p), str(vg.MaxPv)))
+
+ def test_vg_max_lv(self):
+ vg = self._vg_create().Vg
+ for p in [0, 1, 10, 100, 100, 1024, 2 ** 32 - 1]:
+ rc = self.handle_return(
+ vg.MaxLvSet(
+ dbus.UInt64(p), dbus.Int32(g_tmo), EOD))
+ self.assertEqual(rc, '/')
+ vg.update()
+ self.assertTrue(
+ vg.MaxLv == p,
+ "Expected %s != Actual %s" % (str(p), str(vg.MaxLv)))
+
+ def test_vg_uuid_gen(self):
+ vg = self._vg_create().Vg
+ prev_uuid = vg.Uuid
+ rc = self.handle_return(
+ vg.UuidGenerate(
+ dbus.Int32(g_tmo),
+ EOD))
+ self.assertEqual(rc, '/')
+ vg.update()
+ self.assertTrue(
+ vg.Uuid != prev_uuid,
+ "Expected %s != Actual %s" % (vg.Uuid, prev_uuid))
+
+ def test_vg_activate_deactivate(self):
+ vg = self._vg_create().Vg
+ self._create_lv(vg=vg)
+ vg.update()
+
+ rc = self.handle_return(
+ vg.Deactivate(
+ dbus.UInt64(0), dbus.Int32(g_tmo), EOD))
+ self.assertEqual(rc, '/')
+ self._check_consistency()
+
+ rc = self.handle_return(
+ vg.Activate(
+ dbus.UInt64(0), dbus.Int32(g_tmo), EOD))
+
+ self.assertEqual(rc, '/')
+ self._check_consistency()
+
+ # Try control flags
+ for i in range(0, 5):
+ self.handle_return(
+ vg.Activate(
+ dbus.UInt64(1 << i),
+ dbus.Int32(g_tmo),
+ EOD))
+
+ def test_pv_resize(self):
+
+ self.assertTrue(len(self.objs[PV_INT]) > 0)
+
+ if len(self.objs[PV_INT]) > 0:
+ pv = ClientProxy(
+ self.bus, self.objs[PV_INT][0].object_path,
+ interfaces=(PV_INT, )).Pv
+
+ original_size = pv.SizeBytes
+
+ new_size = original_size // 2
+
+ self.handle_return(
+ pv.ReSize(
+ dbus.UInt64(new_size),
+ dbus.Int32(g_tmo),
+ EOD))
+
+ self._check_consistency()
+ pv.update()
+
+ self.assertTrue(pv.SizeBytes != original_size)
+ self.handle_return(
+ pv.ReSize(
+ dbus.UInt64(0),
+ dbus.Int32(g_tmo),
+ EOD))
+ self._check_consistency()
+ pv.update()
+ self.assertTrue(pv.SizeBytes == original_size)
+
+ def test_pv_allocation(self):
+ vg = self._vg_create(self._all_pv_object_paths()).Vg
+
+ pv = ClientProxy(self.bus, vg.Pvs[0], interfaces=(PV_INT, )).Pv
+
+ self.handle_return(
+ pv.AllocationEnabled(
+ dbus.Boolean(False),
+ dbus.Int32(g_tmo),
+ EOD))
+
+ pv.update()
+ self.assertFalse(pv.Allocatable)
+
+ self.handle_return(
+ pv.AllocationEnabled(
+ dbus.Boolean(True),
+ dbus.Int32(g_tmo),
+ EOD))
+
+ self.handle_return(
+ pv.AllocationEnabled(
+ dbus.Boolean(True),
+ dbus.Int32(g_tmo),
+ EOD))
+ pv.update()
+ self.assertTrue(pv.Allocatable)
+
+ self._check_consistency()
+
+ @staticmethod
+ def _get_devices():
+ context = pyudev.Context()
+ bd = context.list_devices(subsystem='block')
+ # Handle block extended major too (259)
+ return [b for b in bd if b.properties.get('MAJOR') == '8' or
+ b.properties.get('MAJOR') == '259']
+
+ def _pv_scan(self, activate, cache, device_paths, major_minors):
+ mgr = self._manager().Manager
+ return self.handle_return(
+ mgr.PvScan(
+ dbus.Boolean(activate),
+ dbus.Boolean(cache),
+ dbus.Array(device_paths, 's'),
+ dbus.Array(major_minors, '(ii)'),
+ dbus.Int32(g_tmo),
+ EOD))
+
+ def test_pv_scan(self):
+
+ def major_minor(d):
+ return (int(d.properties.get('MAJOR')), int(d.properties.get('MINOR')))
+
+ devices = TestDbusService._get_devices()
+
+ self.assertEqual(self._pv_scan(False, True, [], []), '/')
+ self._check_consistency()
+ self.assertEqual(self._pv_scan(False, False, [], []), '/')
+ self._check_consistency()
+
+ block_path = [d.properties.get('DEVNAME') for d in devices]
+ self.assertEqual(self._pv_scan(False, True, block_path, []), '/')
+ self._check_consistency()
+
+ mm = [major_minor(d) for d in devices]
+
+ self.assertEqual(self._pv_scan(False, True, block_path, mm), '/')
+ self._check_consistency()
+
+ self.assertEqual(self._pv_scan(False, True, [], mm), '/')
+ self._check_consistency()
+
+ @staticmethod
+ def _write_some_data(device_path, size):
+ blocks = int(size // 512)
+ block = bytearray(512)
+ for i in range(0, 512):
+ block[i] = i % 255
+
+ with open(device_path, mode='wb') as lv:
+ for i in range(0, blocks):
+ lv.write(block)
+
+ def test_snapshot_merge(self):
+ # Create a non-thin LV and merge it
+ ss_size = mib(8)
+
+ lv_p = self._create_lv(size=mib(16))
+ ss_name = lv_p.LvCommon.Name + '_snap'
+
+ snapshot_path = self.handle_return(
+ lv_p.Lv.Snapshot(
+ dbus.String(ss_name),
+ dbus.UInt64(ss_size),
+ dbus.Int32(g_tmo),
+ EOD))
+
+ intf = (LV_COMMON_INT, LV_INT, SNAPSHOT_INT, )
+ ss = ClientProxy(self.bus, snapshot_path, interfaces=intf)
+
+ # Write some data to snapshot so merge takes some time
+ TestDbusService._write_some_data(ss.LvCommon.Path, ss_size // 2)
+
+ job_path = self.handle_return(
+ ss.Snapshot.Merge(
+ dbus.Int32(g_tmo),
+ EOD))
+ self.assertEqual(job_path, '/')
+
+ def test_snapshot_merge_thin(self):
+ # Create a thin LV, snapshot it and merge it
+ _vg, _thin_path, lv_p = self._create_thin_lv()
+
+ ss_name = lv_p.LvCommon.Name + '_snap'
+ snapshot_path = self.handle_return(
+ lv_p.Lv.Snapshot(
+ dbus.String(ss_name),
+ dbus.UInt64(0),
+ dbus.Int32(g_tmo),
+ EOD))
+
+ intf = (LV_INT, LV_COMMON_INT, SNAPSHOT_INT)
+ ss = ClientProxy(self.bus, snapshot_path, interfaces=intf)
+
+ job_path = self.handle_return(
+ ss.Snapshot.Merge(
+ dbus.Int32(g_tmo), EOD)
+ )
+ self.assertTrue(job_path == '/')
+
+ def _create_cache_pool(self, vg=None):
+
+ if not vg:
+ vg = self._vg_create().Vg
+
+ md = self._create_lv(size=(mib(8)), vg=vg)
+ data = self._create_lv(size=(mib(8)), vg=vg)
+
+ cache_pool_path = self.handle_return(
+ vg.CreateCachePool(
+ dbus.ObjectPath(md.object_path),
+ dbus.ObjectPath(data.object_path),
+ dbus.Int32(g_tmo),
+ EOD))
+
+ intf = (CACHE_POOL_INT, )
+ cp = ClientProxy(self.bus, cache_pool_path, interfaces=intf)
+
+ return vg, cp
+
+ def test_cache_pool_create(self):
+
+ vg, cache_pool = self._create_cache_pool()
+
+ self.assertTrue(
+ '/com/redhat/lvmdbus1/CachePool' in cache_pool.object_path)
+
+ def _create_cache_lv(self, return_all=False):
+ vg, cache_pool = self._create_cache_pool()
+
+ lv_to_cache = self._create_lv(size=mib(32), vg=vg)
+
+ c_lv_path = self.handle_return(
+ cache_pool.CachePool.CacheLv(
+ dbus.ObjectPath(lv_to_cache.object_path),
+ dbus.Int32(g_tmo),
+ EOD))
+
+ intf = (LV_COMMON_INT, LV_INT, CACHE_LV_INT)
+ cached_lv = ClientProxy(self.bus, c_lv_path, interfaces=intf)
+
+ if return_all:
+ return vg, cache_pool, cached_lv
+ return cached_lv
+
+ def test_cache_lv_create(self):
+
+ for destroy_cache in [True, False]:
+ vg, _, cached_lv = self._create_cache_lv(True)
+ uncached_lv_path = self.handle_return(
+ cached_lv.CachedLv.DetachCachePool(
+ dbus.Boolean(destroy_cache),
+ dbus.Int32(g_tmo),
+ EOD))
+
+ self.assertTrue(
+ '/com/redhat/lvmdbus1/Lv' in uncached_lv_path)
+
+ rc = self.handle_return(
+ vg.Remove(dbus.Int32(g_tmo), EOD))
+ self.assertTrue(rc == '/')
+
+ def test_cache_lv_rename(self):
+ """
+ Make sure that if we rename a cache lv that we correctly handle the
+ internal state update.
+ :return:
+ """
+ def verify_cache_lv_count():
+ cur_objs, _ = get_objects()
+ self.assertEqual(len(cur_objs[CACHE_LV_INT]), 2)
+ self._check_consistency()
+
+ cached_lv = self._create_cache_lv()
+
+ verify_cache_lv_count()
+ new_name = 'renamed_' + cached_lv.LvCommon.Name
+ self.handle_return(
+ cached_lv.Lv.Rename(dbus.String(new_name), dbus.Int32(g_tmo), EOD))
+ verify_cache_lv_count()
+
+ def test_writecache_lv(self):
+ vg = self._vg_create().Vg
+ data_lv = self._create_lv(size=mib(16), vg=vg)
+ cache_lv = self._create_lv(size=mib(16), vg=vg)
+
+ # both LVs need to be inactive
+ self.handle_return(data_lv.Lv.Deactivate(
+ dbus.UInt64(0), dbus.Int32(g_tmo), EOD))
+ data_lv.update()
+ self.handle_return(cache_lv.Lv.Deactivate(
+ dbus.UInt64(0), dbus.Int32(g_tmo), EOD))
+ cache_lv.update()
+
+ cached_lv_path = self.handle_return(
+ cache_lv.Lv.WriteCacheLv(
+ dbus.ObjectPath(data_lv.object_path),
+ dbus.Int32(g_tmo),
+ EOD))
+
+ intf = (LV_COMMON_INT, LV_INT, CACHE_LV_INT)
+ cached_lv = ClientProxy(self.bus, cached_lv_path, interfaces=intf)
+ self.assertEqual(cached_lv.LvCommon.SegType, ["writecache"])
+
+ uncached_lv_path = self.handle_return(
+ cached_lv.CachedLv.DetachCachePool(
+ dbus.Boolean(True),
+ dbus.Int32(g_tmo),
+ EOD))
+ self.assertTrue('/com/redhat/lvmdbus1/Lv' in uncached_lv_path)
+
+ def test_vg_change(self):
+ vg_proxy = self._vg_create()
+
+ result = self.handle_return(vg_proxy.Vg.Change(
+ dbus.Int32(g_tmo),
+ dbus.Dictionary({'-a': 'ay'}, 'sv')))
+ self.assertTrue(result == '/')
+
+ result = self.handle_return(
+ vg_proxy.Vg.Change(
+ dbus.Int32(g_tmo),
+ dbus.Dictionary({'-a': 'n'}, 'sv')))
+ self.assertTrue(result == '/')
+
+ @staticmethod
+ def _invalid_vg_lv_name_characters():
+ bad_vg_lv_set = set(string.printable) - \
+ set(string.ascii_letters + string.digits + '.-_+')
+ return ''.join(bad_vg_lv_set)
+
+ def test_invalid_names(self):
+ mgr = self.objs[MANAGER_INT][0].Manager
+
+ # Pv device path
+ with self.assertRaises(dbus.exceptions.DBusException):
+ self.handle_return(
+ mgr.PvCreate(
+ dbus.String("/dev/space in name"),
+ dbus.Int32(g_tmo),
+ EOD))
+
+ # VG Name testing...
+ # Go through all bad characters
+ pv_paths = [self.objs[PV_INT][0].object_path]
+ bad_chars = TestDbusService._invalid_vg_lv_name_characters()
+ for c in bad_chars:
+ with self.assertRaises(dbus.exceptions.DBusException):
+ self.handle_return(
+ mgr.VgCreate(
+ dbus.String("name%s" % (c)),
+ dbus.Array(pv_paths, 'o'),
+ dbus.Int32(g_tmo),
+ EOD))
+
+ # Bad names
+ for bad in [".", ".."]:
+ with self.assertRaises(dbus.exceptions.DBusException):
+ self.handle_return(
+ mgr.VgCreate(
+ dbus.String(bad),
+ dbus.Array(pv_paths, 'o'),
+ dbus.Int32(g_tmo),
+ EOD))
+
+ # Exceed name length
+ for i in [128, 1024, 4096]:
+ with self.assertRaises(dbus.exceptions.DBusException):
+ self.handle_return(
+ mgr.VgCreate(
+ dbus.String('T' * i),
+ dbus.Array(pv_paths, 'o'),
+ dbus.Int32(g_tmo),
+ EOD))
+
+ # Create a VG and try to create LVs with different bad names
+ vg_name = vg_n()
+ vg_path = self.handle_return(
+ mgr.VgCreate(
+ dbus.String(vg_name),
+ dbus.Array(pv_paths, 'o'),
+ dbus.Int32(g_tmo),
+ EOD))
+ self._validate_lookup(vg_name, vg_path)
+
+ vg_proxy = ClientProxy(self.bus, vg_path, interfaces=(VG_INT, ))
+
+ for c in bad_chars:
+ with self.assertRaises(dbus.exceptions.DBusException):
+ self.handle_return(
+ vg_proxy.Vg.LvCreateLinear(
+ dbus.String(lv_n() + c),
+ dbus.UInt64(mib(4)),
+ dbus.Boolean(False),
+ dbus.Int32(g_tmo),
+ EOD))
+
+ for reserved in (
+ "_cdata", "_cmeta", "_corig", "_mimage", "_mlog",
+ "_pmspare", "_rimage", "_rmeta", "_tdata", "_tmeta",
+ "_vorigin", "_vdata"):
+ with self.assertRaises(dbus.exceptions.DBusException):
+ self.handle_return(
+ vg_proxy.Vg.LvCreateLinear(
+ dbus.String(lv_n() + reserved),
+ dbus.UInt64(mib(4)),
+ dbus.Boolean(False),
+ dbus.Int32(g_tmo),
+ EOD))
+
+ for reserved in ("snapshot", "pvmove"):
+ with self.assertRaises(dbus.exceptions.DBusException):
+ self.handle_return(
+ vg_proxy.Vg.LvCreateLinear(
+ dbus.String(reserved + lv_n()),
+ dbus.UInt64(mib(4)),
+ dbus.Boolean(False),
+ dbus.Int32(g_tmo),
+ EOD))
+
+ _ALLOWABLE_TAG_CH = string.ascii_letters + string.digits + "._-+/=!:&#"
+
+ def _invalid_tag_characters(self):
+ bad_tag_ch_set = set(string.printable) - set(self._ALLOWABLE_TAG_CH)
+ return ''.join(bad_tag_ch_set)
+
+ def test_invalid_tags(self):
+ vg_proxy = self._vg_create()
+
+ for c in self._invalid_tag_characters():
+ with self.assertRaises(dbus.exceptions.DBusException):
+ self.handle_return(
+ vg_proxy.Vg.TagsAdd(
+ dbus.Array([c], 's'),
+ dbus.Int32(g_tmo),
+ EOD))
+
+ for c in self._invalid_tag_characters():
+ with self.assertRaises(dbus.exceptions.DBusException):
+ self.handle_return(
+ vg_proxy.Vg.TagsAdd(
+ dbus.Array(["a%sb" % (c)], 's'),
+ dbus.Int32(g_tmo),
+ EOD))
+
+ def _tag_add_common(self, vg_proxy, tag):
+ tmp = self.handle_return(
+ vg_proxy.Vg.TagsAdd(
+ dbus.Array([tag], 's'),
+ dbus.Int32(g_tmo),
+ EOD))
+ self.assertTrue(tmp == '/')
+ vg_proxy.update()
+
+ self.assertTrue(
+ tag in vg_proxy.Vg.Tags,
+ "%s not in %s" % (tag, str(vg_proxy.Vg.Tags)))
+
+ def test_tag_names(self):
+ vg_proxy = self._vg_create()
+
+ for i in range(1, 64):
+ tag = rs(i, "", self._ALLOWABLE_TAG_CH)
+ self._tag_add_common(vg_proxy, tag)
+
+ self.assertEqual(
+ i, len(vg_proxy.Vg.Tags),
+ "%d != %d" % (i, len(vg_proxy.Vg.Tags)))
+
+ def test_tag_regression(self):
+ vg_proxy = self._vg_create()
+ tag = '--h/K.6g0A4FOEatf3+k_nI/Yp&L_u2oy-=j649x:+dUcYWPEo6.IWT0c'
+ self._tag_add_common(vg_proxy, tag)
+
+ def _verify_existence(self, cmd, operation, resource_name):
+ ec, stdout, stderr = call_lvm(cmd)
+ if ec == 0:
+ path = self._lookup(resource_name)
+ self.assertTrue(path != '/')
+ else:
+ std_err_print(
+ "%s failed with stdout= %s, stderr= %s" %
+ (operation, stdout, stderr))
+ self.assertTrue(ec == 0, "%s exit code = %d" % (operation, ec))
+
+ def test_external_vg_create(self):
+ # We need to ensure that if a user creates something outside lvm
+ # dbus service that things are sequenced correctly so that if a dbus
+ # user calls into the service they will find the same information.
+ vg_name = vg_n()
+
+ # Get all the PV device paths
+ pv_device_paths = [p.Pv.Name for p in self.objs[PV_INT]]
+
+ cmd = ['vgcreate', vg_name]
+ cmd.extend(pv_device_paths)
+ self._verify_existence(cmd, cmd[0], vg_name)
+
+ def test_external_lv_create(self):
+ # Let's create a LV outside of service and see if we correctly handle
+ # its inclusion
+ vg = self._vg_create().Vg
+ lv_name = lv_n()
+ full_name = "%s/%s" % (vg.Name, lv_name)
+
+ cmd = ['lvcreate', '-L4M', '-n', lv_name, vg.Name]
+ self._verify_existence(cmd, cmd[0], full_name)
+
+ def test_external_pv_create(self):
+ # Let's create a PV outside of service and see if we correctly handle
+ # its inclusion
+ target = self.objs[PV_INT][0]
+
+ # Remove the PV
+ rc = self._pv_remove(target)
+ self.assertTrue(rc == '/')
+ self._check_consistency()
+
+ # Make sure the PV we removed no longer exists
+ self.assertTrue(self._lookup(target.Pv.Name) == '/')
+
+ # Add it back with external command line
+ cmd = ['pvcreate', target.Pv.Name]
+ self._verify_existence(cmd, cmd[0], target.Pv.Name)
+
+ def _create_nested(self, pv_object_path, vg_suffix):
+ vg = self._vg_create([pv_object_path], vg_suffix)
+ pv = ClientProxy(self.bus, pv_object_path, interfaces=(PV_INT,))
+
+ self.assertEqual(pv.Pv.Vg, vg.object_path)
+ self.assertIn(
+ pv_object_path, vg.Vg.Pvs, "Expecting PV object path in Vg.Pvs")
+
+ lv = self._create_lv(
+ vg=vg.Vg, size=vg.Vg.FreeBytes, suffix="_pv0")
+ device_path = '/dev/%s/%s' % (vg.Vg.Name, lv.LvCommon.Name)
+ dev_info = os.stat(device_path)
+ major = os.major(dev_info.st_rdev)
+ minor = os.minor(dev_info.st_rdev)
+ sysfs = "/sys/dev/block/%d:%d" % (major, minor)
+ self.assertTrue(os.path.exists(sysfs))
+ new_pv_object_path = self._pv_create(device_path)
+ vg.update()
+
+ self.assertEqual(lv.LvCommon.Vg, vg.object_path)
+ self.assertIn(
+ lv.object_path, vg.Vg.Lvs, "Expecting LV object path in Vg.Lvs")
+
+ new_pv_proxy = ClientProxy(
+ self.bus, new_pv_object_path, interfaces=(PV_INT, ))
+ self.assertEqual(new_pv_proxy.Pv.Name, device_path)
+
+ return new_pv_object_path
+
+ @staticmethod
+ def _scan_lvs_enabled():
+ cmd = ['lvmconfig', '--typeconfig', 'full', 'devices/scan_lvs']
+ config = Popen(cmd, stdout=PIPE, stderr=PIPE, close_fds=True, env=os.environ)
+ out = config.communicate()
+ if config.returncode != 0:
+ return False
+ if "scan_lvs=1" == out[0].decode("utf-8").strip():
+ return True
+ return False
+
+ def test_nesting(self):
+ # check to see if we handle an LV becoming a PV which has it's own
+ # LV
+ #
+ # NOTE: This needs an equivalent of aux extend_filter_LVMTEST
+ # when run from lvm2 testsuite. See dbustest.sh.
+ # Also, if developing locally with actual devices one can achieve this
+ # by editing lvm.conf with "devices/scan_lvs = 1" As testing
+ # typically utilizes loopback, this test is skipped in
+ # those environments.
+
+ if dm_dev_dir != '/dev':
+ raise unittest.SkipTest('test not running in real /dev')
+ if not TestDbusService._scan_lvs_enabled():
+ raise unittest.SkipTest('scan_lvs=0 in config, unit test requires scan_lvs=1')
+ pv_object_path = self.objs[PV_INT][0].object_path
+ if not self.objs[PV_INT][0].Pv.Name.startswith("/dev"):
+ raise unittest.SkipTest('test not running in /dev')
+
+ for i in range(0, 5):
+ pv_object_path = self._create_nested(pv_object_path, "nest_%d_" % i)
+
+ def test_pv_symlinks(self):
+ # Let's take one of our test PVs, pvremove it, find a symlink to it
+ # and re-create using the symlink to ensure we return an object
+ # path to it. Additionally, we will take the symlink and do a lookup
+ # (Manager.LookUpByLvmId) using it and the original device path to
+ # ensure that we can find the PV.
+ symlink = None
+
+ pv = self.objs[PV_INT][0]
+ pv_device_path = pv.Pv.Name
+
+ if dm_dev_dir != '/dev':
+ raise unittest.SkipTest('test not running in real /dev')
+
+ if not pv_device_path.startswith("/dev"):
+ raise unittest.SkipTest('test not running in /dev')
+
+ self._pv_remove(pv)
+
+ # Make sure we no longer find the pv
+ rc = self._lookup(pv_device_path)
+ self.assertEqual(rc, '/')
+
+ # Let's locate a symlink for it
+ devices = glob('/dev/disk/*/*')
+ rp_pv_device_path = os.path.realpath(pv_device_path)
+ for d in devices:
+ if rp_pv_device_path == os.path.realpath(d):
+ symlink = d
+ break
+
+ self.assertIsNotNone(symlink, "We expected to find at least 1 symlink!")
+
+ # Make sure symlink look up fails too
+ rc = self._lookup(symlink)
+ self.assertEqual(rc, '/')
+
+ ### pv_object_path = self._pv_create(symlink)
+ ### Test is limited by filter rules and must use /dev/mapper/LVMTEST path
+ pv_object_path = self._pv_create(pv_device_path)
+
+ self.assertNotEqual(pv_object_path, '/')
+
+ pv_proxy = ClientProxy(self.bus, pv_object_path, interfaces=(PV_INT, ))
+ self.assertEqual(pv_proxy.Pv.Name, pv_device_path)
+
+ # Lets check symlink lookup
+ self.assertEqual(pv_object_path, self._lookup(pv_device_path))
+
+ def _create_vdo_pool_and_lv(self, vg_prefix="vdo_"):
+ pool_name = lv_n("_vdo_pool")
+ lv_name = lv_n()
+
+ vg_proxy = self._vg_create(vg_prefix=vg_prefix)
+ vdo_pool_object_path = self.handle_return(
+ vg_proxy.VgVdo.CreateVdoPoolandLv(
+ pool_name, lv_name,
+ dbus.UInt64(VDO_MIN_SIZE),
+ dbus.UInt64(VDO_MIN_SIZE * 2),
+ dbus.Int32(g_tmo),
+ EOD))
+
+ self.assertNotEqual(vdo_pool_object_path, "/")
+ self.assertEqual(
+ vdo_pool_object_path,
+ self._lookup("%s/%s" % (vg_proxy.Vg.Name, pool_name)))
+
+ vdo_pool_path = self._lookup("%s/%s" % (vg_proxy.Vg.Name, pool_name))
+ self.assertNotEqual(vdo_pool_path, "/")
+ intf = [LV_COMMON_INT, LV_INT]
+ vdo_lv_obj_path = self._lookup("%s/%s" % (vg_proxy.Vg.Name, lv_name))
+ vdo_lv = ClientProxy(self.bus, vdo_lv_obj_path, interfaces=intf)
+ intf.append(VDOPOOL_INT)
+ vdo_pool_lv = ClientProxy(self.bus, vdo_pool_path, interfaces=intf)
+ return vg_proxy, vdo_pool_lv, vdo_lv
+
+ def _create_vdo_lv(self):
+ return self._create_vdo_pool_and_lv()[2]
+
+ def _vdo_pool_lv(self):
+ return self._create_vdo_pool_and_lv()[1]
+
+ def test_vdo_pool_create(self):
+ # Basic vdo sanity testing
+ if not self.vdo:
+ raise unittest.SkipTest('vdo not supported')
+
+ # Do this twice to ensure we are providing the correct flags to force
+ # the operation when it finds an existing vdo signature, which likely
+ # shouldn't exist.
+ for _ in range(0, 2):
+ vg, _, _ = self._create_vdo_pool_and_lv()
+ self.handle_return(vg.Vg.Remove(dbus.Int32(g_tmo), EOD))
+
+ def _create_vdo_pool(self):
+ pool_name = lv_n('_vdo_pool')
+ lv_name = lv_n('_vdo_data')
+ vg_proxy = self._vg_create(vg_prefix="vdo_conv_")
+ lv = self._test_lv_create(
+ vg_proxy.Vg.LvCreate,
+ (dbus.String(pool_name), dbus.UInt64(VDO_MIN_SIZE),
+ dbus.Array([], signature='(ott)'), dbus.Int32(g_tmo),
+ EOD), vg_proxy.Vg, LV_BASE_INT)
+ lv_obj_path = self._lookup("%s/%s" % (vg_proxy.Vg.Name, pool_name))
+ self.assertNotEqual(lv_obj_path, "/")
+
+ vdo_pool_path = self.handle_return(
+ vg_proxy.VgVdo.CreateVdoPool(
+ dbus.ObjectPath(lv.object_path), lv_name,
+ dbus.UInt64(VDO_MIN_SIZE),
+ dbus.Int32(g_tmo),
+ EOD))
+
+ self.assertNotEqual(vdo_pool_path, "/")
+ self.assertEqual(
+ vdo_pool_path,
+ self._lookup("%s/%s" % (vg_proxy.Vg.Name, pool_name)))
+ intf = [LV_COMMON_INT, LV_INT]
+ vdo_lv_obj_path = self._lookup("%s/%s" % (vg_proxy.Vg.Name, lv_name))
+ vdo_lv = ClientProxy(self.bus, vdo_lv_obj_path, interfaces=intf)
+ intf.append(VDOPOOL_INT)
+ vdo_pool_lv = ClientProxy(self.bus, vdo_pool_path, interfaces=intf)
+ return vg_proxy, vdo_pool_lv, vdo_lv
+
+ def test_vdo_pool_convert(self):
+ # Basic vdo sanity testing
+ if not self.vdo:
+ raise unittest.SkipTest('vdo not supported')
+
+ vg, _pool, _lv = self._create_vdo_pool()
+ self.handle_return(vg.Vg.Remove(dbus.Int32(g_tmo), EOD))
+
+ def test_vdo_pool_compression_deduplication(self):
+ if not self.vdo:
+ raise unittest.SkipTest('vdo not supported')
+
+ vg, pool, _lv = self._create_vdo_pool_and_lv(vg_prefix="vdo2_")
+
+ # compression and deduplication should be enabled by default
+ self.assertEqual(pool.VdoPool.Compression, "enabled")
+ self.assertEqual(pool.VdoPool.Deduplication, "enabled")
+
+ self.handle_return(
+ pool.VdoPool.DisableCompression(dbus.Int32(g_tmo), EOD))
+ self.handle_return(
+ pool.VdoPool.DisableDeduplication(dbus.Int32(g_tmo), EOD))
+ pool.update()
+ self.assertEqual(pool.VdoPool.Compression, "")
+ self.assertEqual(pool.VdoPool.Deduplication, "")
+
+ self.handle_return(
+ pool.VdoPool.EnableCompression(dbus.Int32(g_tmo), EOD))
+ self.handle_return(
+ pool.VdoPool.EnableDeduplication(dbus.Int32(g_tmo), EOD))
+ pool.update()
+ self.assertEqual(pool.VdoPool.Compression, "enabled")
+ self.assertEqual(pool.VdoPool.Deduplication, "enabled")
+
+ self.handle_return(vg.Vg.Remove(dbus.Int32(g_tmo), EOD))
+
+ def _test_lv_method_interface(self, lv):
+ self._rename_lv_test(lv)
+ self._test_activate_deactivate(lv)
+ self._test_lv_tags(lv)
+ self._test_lv_resize(lv)
+
+ def _test_lv_method_interface_sequence(
+ self, lv, test_ss=True, remove_lv=True):
+ self._test_lv_method_interface(lv)
+
+ # We can't take a snapshot of a pool lv (not yet).
+ if test_ss:
+ ss_lv = self._take_lv_snapshot(lv)
+ self._test_lv_method_interface(ss_lv)
+ self._lv_remove(ss_lv)
+
+ if remove_lv:
+ self._lv_remove(lv)
+
+ def test_lv_interface_plain_lv(self):
+ self._test_lv_method_interface_sequence(self._create_lv())
+
+ def test_lv_interface_vdo_lv(self):
+ if not self.vdo:
+ raise unittest.SkipTest('vdo not supported')
+ self._test_lv_method_interface_sequence(self._create_vdo_lv())
+
+ def test_lv_interface_cache_lv(self):
+ self._test_lv_method_interface_sequence(
+ self._create_cache_lv(), remove_lv=False)
+
+ def test_lv_interface_thin_pool_lv(self):
+ self._test_lv_method_interface_sequence(
+ self._create_thin_pool_lv(), test_ss=False)
+
+ def test_lv_interface_vdo_pool_lv(self):
+ if not self.vdo:
+ raise unittest.SkipTest('vdo not supported')
+ self._test_lv_method_interface_sequence(
+ self._vdo_pool_lv(), test_ss=False)
+
+ def _log_file_option(self):
+ fn = os.path.join(tempfile.gettempdir(), rs(8, "_lvm.log"))
+ try:
+ options = dbus.Dictionary({}, signature=dbus.Signature('sv'))
+ option_str = "log { level=7 file=%s syslog=0 }" % fn
+ options["config"] = dbus.String(option_str)
+ self._vg_create(None, None, options)
+ self.assertTrue(os.path.exists(fn),
+ "We passed the following options %s to lvm while creating a VG and the "
+ "log file we expected to exist (%s) was not found" % (option_str, fn))
+ finally:
+ if os.path.exists(fn):
+ os.unlink(fn)
+
+ def test_log_file_option(self):
+ self._log_file_option()
+
+ def test_external_event(self):
+ # Call into the service to register an external event, so that we can test sending the path
+ # where we don't send notifications on the command line in addition to the logging
+ lvm_manager = dbus.Interface(bus.get_object(
+ BUS_NAME, "/com/redhat/lvmdbus1/Manager", introspect=False),
+ "com.redhat.lvmdbus1.Manager")
+ rc = lvm_manager.ExternalEvent("unit_test")
+ self.assertTrue(rc == 0)
+ self._log_file_option()
+
+ def test_delete_non_complete_job(self):
+ # Let's create a vg with a number of lvs and then delete it all
+ # to hopefully create a long-running job.
+ vg_proxy = self._create_num_lvs(64)
+ job_path = vg_proxy.Vg.Remove(dbus.Int32(0), EOD)
+ self.assertNotEqual(job_path, "/")
+
+ # Try to delete the job expecting an exception
+ job_proxy = ClientProxy(self.bus, job_path, interfaces=(JOB_INT,)).Job
+ with self.assertRaises(dbus.exceptions.DBusException):
+ try:
+ job_proxy.Remove()
+ except dbus.exceptions.DBusException as e:
+ # Verify we got the expected text in exception
+ self.assertTrue('Job is not complete!' in str(e))
+ raise e
+
+ def test_z_sigint(self):
+ # Issue SIGINT while daemon is processing work to ensure we shut down.
+ if bool(int(os.getenv("LVM_DBUSD_TEST_SKIP_SIGNAL", "0"))):
+ raise unittest.SkipTest("Skipping as env. LVM_DBUSD_TEST_SKIP_SIGNAL is '1'")
+
+ di = DaemonInfo.get()
+ self.assertTrue(di is not None)
+ if di:
+ # Find out how long it takes to create a VG and a number of LVs
+ # we will then issue the creation of the LVs async., wait, then issue a signal
+ # and repeat stepping through the entire time range.
+ start = time.time()
+ vg_proxy = self._create_num_lvs(20)
+ end = time.time()
+
+ self.handle_return(vg_proxy.Vg.Remove(dbus.Int32(g_tmo), EOD))
+ total = end - start
+
+ for i in range(5):
+ sleep_amt = i * (total/5.0)
+ self._create_num_lvs(20, True)
+ time.sleep(sleep_amt)
+
+ exited = False
+ try:
+ di.term_signal(signal.SIGINT)
+ exited = True
+ except Exception:
+ std_err_print("Failed to exit on SIGINT, sending SIGKILL...")
+ di.term_signal(signal.SIGKILL)
+ finally:
+ di.start()
+ self.clean_up()
+
+ self.assertTrue(exited,
+ "Failed to exit after sending signal %f seconds after "
+ "queuing up work for signal %d" % (sleep_amt, signal.SIGINT))
+ set_exec_mode(g_lvm_shell)
+
+ def test_z_singleton_daemon(self):
+ # Ensure we can only have 1 daemon running at a time, daemon should exit with 114 if already running
+ di = DaemonInfo.get()
+ self.assertTrue(di is not None)
+ if di.systemd:
+ raise unittest.SkipTest('existing dameon running via systemd')
+ if di:
+ ec = di.start(True)
+ self.assertEqual(ec, 114)
+
+ def test_z_switching(self):
+ # Ensure we can switch from forking to shell repeatedly
+ try:
+ t_mode = True
+ for _ in range(50):
+ t_mode = not t_mode
+ set_exec_mode(t_mode)
+ finally:
+ set_exec_mode(g_lvm_shell)
+
+ @staticmethod
+ def _wipe_it(block_device):
+ cmd = ["/usr/sbin/wipefs", '-a', block_device]
+ config = Popen(cmd, stdout=PIPE, stderr=PIPE, close_fds=True, env=os.environ)
+ config.communicate()
+ if config.returncode != 0:
+ return False
+ return True
+
+ def _block_present_absent(self, block_device, present=False):
+ start = time.time()
+ keep_looping = True
+ max_wait = 10
+ while keep_looping and time.time() < start + max_wait:
+ if present:
+ if (self._lookup(block_device) != "/"):
+ keep_looping = False
+ else:
+ if (self._lookup(block_device) == "/"):
+ keep_looping = False
+
+ if keep_looping:
+ print("Daemon failed to update within %d seconds!" % max_wait)
+ else:
+ print("Note: Time for udev update = %f" % (time.time() - start))
+ if present:
+ rc = self._lookup(block_device)
+ self.assertNotEqual(rc, '/', "Daemon failed to update, missing udev change event?")
+ return True
+ else:
+ rc = self._lookup(block_device)
+ self.assertEqual(rc, '/', "Daemon failed to update, missing udev change event?")
+ return True
+
+ def test_wipefs(self):
+ # Ensure we update the status of the daemon if an external process clears a PV
+ pv = self.objs[PV_INT][0]
+ pv_device_path = pv.Pv.Name
+
+ wipe_result = TestDbusService._wipe_it(pv_device_path)
+ self.assertTrue(wipe_result)
+
+ if wipe_result:
+ # Need to wait a bit before the daemon will reflect the change
+ self._block_present_absent(pv_device_path, False)
+
+ # Put it back
+ pv_object_path = self._pv_create(pv_device_path)
+ self.assertNotEqual(pv_object_path, '/')
+
+ @staticmethod
+ def _write_signature(device, data=None):
+ fd = os.open(device, os.O_RDWR|os.O_EXCL|os.O_NONBLOCK)
+ existing = os.read(fd, 1024)
+ os.lseek(fd, 0, os.SEEK_SET)
+
+ if data is None:
+ data_copy = bytearray(existing)
+ # Clear lvm signature
+ data_copy[536:536+9] = bytearray(8)
+ os.write(fd, data_copy)
+ else:
+ os.write(fd, data)
+ os.sync()
+ os.close(fd)
+ return existing
+
+ def test_copy_signature(self):
+ # Ensure we update the state of the daemon if an external process copies
+ # a pv signature onto a block device
+ pv = self.objs[PV_INT][0]
+ pv_device_path = pv.Pv.Name
+
+ try:
+ existing = TestDbusService._write_signature(pv_device_path, None)
+ if self._block_present_absent(pv_device_path, False):
+ TestDbusService._write_signature(pv_device_path, existing)
+ self._block_present_absent(pv_device_path, True)
+ finally:
+ # Ensure we put the PV back for sure.
+ rc = self._lookup(pv_device_path)
+ if rc == "/":
+ self._pv_create(pv_device_path)
+
+ def test_stderr_collection(self):
+ lv_name = lv_n()
+ vg = self._vg_create().Vg
+ (object_path, job_path) = vg.LvCreate(
+ dbus.String(lv_name), dbus.UInt64(vg.SizeBytes * 2),
+ dbus.Array([], signature='(ott)'), dbus.Int32(0),
+ EOD)
+
+ self.assertTrue(object_path == '/')
+ self.assertTrue(job_path != '/')
+
+ j = ClientProxy(self.bus, job_path, interfaces=(JOB_INT,)).Job
+ while True:
+ j.update()
+ if j.Complete:
+ (ec, error_msg) = j.GetError
+ self.assertTrue("insufficient free space" in error_msg,
+ "We're expecting 'insufficient free space' in \n\"%s\"\n, stderr missing?" % error_msg)
+ break
+ else:
+ time.sleep(0.1)
+
+ @staticmethod
+ def _is_vg_devices_supported():
+ rc, stdout_txt, stderr_txt = call_lvm(["vgcreate", "--help"])
+ if rc == 0:
+ for line in stdout_txt.split("\n"):
+ if "--devices " in line:
+ return True
+ return False
+
+ @staticmethod
+ def _vg_create_specify_devices(name, device):
+ cmd = [LVM_EXECUTABLE, "vgcreate", "--devices", device, name, device]
+ outcome = Popen(cmd, stdout=PIPE, stderr=PIPE, close_fds=True, env=os.environ)
+ outcome.communicate()
+ if outcome.returncode == 0:
+ return True
+ else:
+ print("Failed to create vg %s, stdout= %s, stderr= %s" % (name, outcome.stdout, outcome.stderr))
+ return False
+
+ def test_duplicate_vg_name(self):
+ # LVM allows duplicate VG names, test handling renames for now
+ if not TestDbusService._is_vg_devices_supported():
+ raise unittest.SkipTest("lvm does not support vgcreate with --device syntax")
+
+ if len(self.objs[PV_INT]) < 2:
+ raise unittest.SkipTest("we need at least 2 PVs to run test")
+
+ vg_name = vg_n()
+ if TestDbusService._vg_create_specify_devices(vg_name, self.objs[PV_INT][0].Pv.Name) and \
+ TestDbusService._vg_create_specify_devices(vg_name, self.objs[PV_INT][1].Pv.Name):
+ objects, _ = get_objects()
+ self.assertEqual(len(objects[VG_INT]), 2)
+
+ if len(objects[VG_INT]) == 2:
+ for vg in objects[VG_INT]:
+ new_name = vg_n()
+ vg.Vg.Rename(dbus.String(new_name), dbus.Int32(g_tmo), EOD)
+ # Ensure we find the renamed VG
+ self.assertNotEqual("/", self._lookup(new_name), "Expecting to find VG='%s'" % new_name)
+ else:
+ self.assertFalse(True, "We failed to create 2 VGs with same name!")
+
+
+class AggregateResults(object):
+
+ def __init__(self):
+ self.no_errors = True
+
+ def register_result(self, result):
+ if not result.result.wasSuccessful():
+ self.no_errors = False
+
+ def register_fail(self):
+ self.no_errors = False
+
+ def exit_run(self):
+ if self.no_errors:
+ sys.exit(0)
+ sys.exit(1)
+
+
+if __name__ == '__main__':
+
+ r = AggregateResults()
+ mode = int(test_shell)
+
+ # To test with error injection, simply set the env. variable LVM_BINARY to the error inject script
+ # and the LVM_MAN_IN_MIDDLE variable to the lvm binary to test which defaults to "/usr/sbin/lvm"
+ # An example
+ # export LVM_BINARY=/home/tasleson/projects/lvm2/test/dbus/lvm_error_inject.py
+ # export LVM_MAN_IN_MIDDLE=/home/tasleson/projects/lvm2/tools/lvm
+
+ if mode == 0:
+ std_err_print('\n*** Testing only lvm fork & exec test mode ***\n')
+ elif mode == 1:
+ std_err_print('\n*** Testing only lvm shell mode ***\n')
+ elif mode == 2:
+ std_err_print('\n*** Testing fork & exec & lvm shell mode ***\n')
+ else:
+ std_err_print("Unsupported \"LVM_DBUSD_TEST_MODE\"=%d, [0-2] valid" % mode)
+ sys.exit(1)
+
+ for g_tmo in [0, 15]:
+ std_err_print('Testing TMO=%d\n' % g_tmo)
+ if mode == 0:
+ if set_execution(False, r):
+ r.register_result(unittest.main(exit=False))
+ elif mode == 1:
+ if set_execution(True, r):
+ r.register_result(unittest.main(exit=False))
+ else:
+ if set_execution(False, r):
+ r.register_result(unittest.main(exit=False))
+ # Test lvm shell
+ if set_execution(True, r):
+ r.register_result(unittest.main(exit=False))
+
+ if not r.no_errors:
+ break
+
+ r.exit_run()
diff --git a/test/dbus/testlib.py b/test/dbus/testlib.py
new file mode 100644
index 0000000..b793b67
--- /dev/null
+++ b/test/dbus/testlib.py
@@ -0,0 +1,331 @@
+#!/usr/bin/python3
+
+# Copyright (C) 2015-2016 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, see <http://www.gnu.org/licenses/>.
+import string
+import random
+import functools
+import xml.etree.ElementTree as Et
+from collections import OrderedDict
+import dbus
+import os
+import sys
+import time
+
+BUS_NAME = os.getenv('LVM_DBUS_NAME', 'com.redhat.lvmdbus1')
+BASE_INTERFACE = 'com.redhat.lvmdbus1'
+MANAGER_INT = BASE_INTERFACE + '.Manager'
+MANAGER_OBJ = '/' + BASE_INTERFACE.replace('.', '/') + '/Manager'
+PV_INT = BASE_INTERFACE + ".Pv"
+VG_INT = BASE_INTERFACE + ".Vg"
+VG_VDO_INT = BASE_INTERFACE + ".VgVdo"
+LV_INT = BASE_INTERFACE + ".Lv"
+THINPOOL_INT = BASE_INTERFACE + ".ThinPool"
+VDOPOOL_INT = BASE_INTERFACE + ".VdoPool"
+SNAPSHOT_INT = BASE_INTERFACE + ".Snapshot"
+LV_COMMON_INT = BASE_INTERFACE + ".LvCommon"
+JOB_INT = BASE_INTERFACE + ".Job"
+CACHE_POOL_INT = BASE_INTERFACE + ".CachePool"
+CACHE_LV_INT = BASE_INTERFACE + ".CachedLv"
+THINPOOL_LV_PATH = '/' + THINPOOL_INT.replace('.', '/')
+
+
+validate_introspection = True
+
+
+def rs(length, suffix, character_set=string.ascii_lowercase):
+ return ''.join(random.choice(character_set) for _ in range(length)) + suffix
+
+
+def mib(s):
+ return 1024 * 1024 * s
+
+
+def std_err_print(*args):
+ sys.stderr.write(' '.join(map(str, args)) + '\n')
+ sys.stderr.flush()
+
+
+class DbusIntrospection(object):
+ @staticmethod
+ def introspect(xml_representation):
+ interfaces = {}
+
+ root = Et.fromstring(xml_representation)
+
+ for c in root:
+ if c.tag == "interface":
+ in_f = c.attrib['name']
+ interfaces[in_f] = dict(methods=OrderedDict(), properties={})
+ for nested in c:
+ if nested.tag == "method":
+ mn = nested.attrib['name']
+ interfaces[in_f]['methods'][mn] = OrderedDict()
+
+ for arg in nested:
+ if arg.tag == 'arg':
+ arg_dir = arg.attrib['direction']
+ if arg_dir == 'in':
+ n = arg.attrib['name']
+ else:
+ n = 'RETURN_VALUE'
+
+ arg_type = arg.attrib['type']
+
+ if n:
+ v = dict(
+ name=mn,
+ a_dir=arg_dir,
+ a_type=arg_type
+ )
+ interfaces[in_f]['methods'][mn][n] = v
+
+ elif nested.tag == 'property':
+ pn = nested.attrib['name']
+ p_access = nested.attrib['access']
+ p_type = nested.attrib['type']
+
+ interfaces[in_f]['properties'][pn] = \
+ dict(p_access=p_access, p_type=p_type)
+ else:
+ pass
+
+ # print('Interfaces...')
+ # for k, v in list(interfaces.items()):
+ # print('Interface %s' % k)
+ # if v['methods']:
+ # for m, args in list(v['methods'].items()):
+ # print(' method: %s' % m)
+ # for a, aa in args.items():
+ # print(' method arg: %s type %s' %
+ # (a, aa['a_type']))
+ # if v['properties']:
+ # for p, d in list(v['properties'].items()):
+ # print(' Property: %s type= %s' % (p, d['p_type']))
+ # print('End interfaces')
+
+ return interfaces
+
+
+def btsr(value):
+ t = type(value)
+ if t == dbus.Boolean:
+ return 'b'
+ elif t == dbus.ObjectPath:
+ return 'o'
+ elif t == dbus.String:
+ return 's'
+ elif t == dbus.Byte:
+ return 'y'
+ elif t == dbus.Int16:
+ return 'n'
+ elif t == dbus.Int32:
+ return 'i'
+ elif t == dbus.Int64:
+ return 'x'
+ elif t == dbus.UInt16:
+ return 'q'
+ elif t == dbus.UInt32:
+ return 'u'
+ elif t == dbus.UInt64:
+ return 't'
+ elif t == dbus.Double:
+ return 'd'
+ elif t == dbus.Struct:
+ rc = '('
+ for vt in value:
+ rc += btsr(vt)
+ rc += ')'
+ return rc
+ elif t == dbus.Array:
+ rc = "a"
+ if hasattr(value, "signature"):
+ return rc + value.signature
+ for i in value:
+ rc += btsr(i)
+ break
+ return rc
+ else:
+ raise RuntimeError("Unhandled type %s" % str(t))
+
+
+def verify_type(value, dbus_str_rep):
+ actual_str_rep = btsr(value)
+
+ if dbus_str_rep != actual_str_rep:
+ raise RuntimeError(
+ "Incorrect type, expected= %s actual = %s object= %s" %
+ (dbus_str_rep, actual_str_rep, str(type(value))))
+
+
+class RemoteInterface(object):
+ def _set_props(self, props=None):
+ if not props:
+ for _ in range(0, 3):
+ try:
+ prop_interface = dbus.Interface(
+ self.dbus_object, 'org.freedesktop.DBus.Properties')
+ props = prop_interface.GetAll(self.interface)
+ break
+ except dbus.exceptions.DBusException as dbe:
+ if "GetAll" not in str(dbe):
+ raise dbe
+ if props:
+ for kl, vl in list(props.items()):
+ # Verify type is correct!
+ if self.introspect:
+ verify_type(
+ vl, self.introspect[self.interface]
+ ['properties'][kl]['p_type'])
+ self.p_name[kl] = True
+ setattr(self, kl, vl)
+
+ @property
+ def object_path(self):
+ return self.dbus_object.object_path
+
+ def __init__(
+ self, dbus_object, interface,
+ introspect, properties=None, timelimit=-1):
+ self.dbus_object = dbus_object
+ self.interface = interface
+ self.introspect = introspect
+ self.tmo = 0
+ self.p_name = {}
+
+ if timelimit >= 0:
+ self.tmo = float(timelimit)
+ self.tmo *= 1.10
+
+ self.dbus_interface = dbus.Interface(self.dbus_object, self.interface)
+ self._set_props(properties)
+
+ # noinspection PyTypeChecker
+ def __getattr__(self, item):
+ if hasattr(self.dbus_interface, item):
+ return functools.partial(self._wrapper, item)
+ else:
+ return functools.partial(self, item)
+
+ def _wrapper(self, _method_name, *args, **kwargs):
+
+ # Let's see how long a method takes to execute, in call cases we should
+ # return something when the time limit has been reached.
+ start = time.time()
+ result = getattr(self.dbus_interface, _method_name)(*args, **kwargs)
+ end = time.time()
+
+ diff = end - start
+
+ if self.tmo > 0.0:
+ if diff > self.tmo:
+ std_err_print(
+ "\n Time exceeded: %f > %f %s" %
+ (diff, self.tmo, _method_name))
+
+ if self.introspect:
+ if 'RETURN_VALUE' in self.introspect[
+ self.interface]['methods'][_method_name]:
+ r_type = self.introspect[
+ self.interface]['methods'][
+ _method_name]['RETURN_VALUE']['a_type']
+
+ verify_type(result, r_type)
+
+ return result
+
+ def update(self):
+ self._set_props()
+
+ def get_property_names(self):
+ return self.p_name.keys()
+
+ def get_property_value(self, name):
+ prop_interface = dbus.Interface(
+ self.dbus_object, 'org.freedesktop.DBus.Properties')
+ return prop_interface.Get(self.interface, name)
+
+
+class ClientProxy(object):
+
+ @staticmethod
+ def _intf_short_name(nm):
+ return nm.split('.')[-1:][0]
+
+ def get_introspect(self):
+ i = dbus.Interface(
+ self.dbus_object,
+ 'org.freedesktop.DBus.Introspectable')
+
+ return DbusIntrospection.introspect(i.Introspect())
+
+ def _common(self, interface, introspect, properties):
+ short_name = ClientProxy._intf_short_name(interface)
+ self.short_interface_names.append(short_name)
+ ro = RemoteInterface(
+ self.dbus_object, interface, introspect, properties,
+ timelimit=self.tmo)
+ setattr(self, short_name, ro)
+
+ def __init__(
+ self, bus, object_path, interface_prop_hash=None,
+ interfaces=None, timelimit=-1):
+ # Instance variables which may or may not get assigned during class
+ # construction dynamically. Assigned here so code inspection tools
+ # have knowledge of their existence.
+ self.Manager = None
+ self.Pv = None
+ self.Vg = None
+ self.Lv = None
+ self.VgVdo = None
+ self.ThinPool = None
+ self.VdoPool = None
+ self.SnapShot = None
+ self.LvCommon = None
+ self.Job = None
+ self.CachePool = None
+ self.CachedLv = None
+
+ self.object_path = object_path
+ self.short_interface_names = []
+ self.tmo = timelimit
+ self.dbus_object = bus.get_object(
+ BUS_NAME, self.object_path, introspect=False)
+
+ if interface_prop_hash:
+ assert interfaces is None
+ if interfaces:
+ assert interface_prop_hash is None
+
+ if interface_prop_hash and not validate_introspection:
+ # We have everything including the values of the properties
+ for i, props in interface_prop_hash.items():
+ self._common(i, None, props)
+ elif interfaces and not validate_introspection:
+ # We are retrieving the values of the properties
+ for i in interfaces:
+ self._common(i, None, None)
+ else:
+ # We need to query the interfaces and gather all the properties
+ # for each interface, as we have the introspection data we
+ # will also utilize it to verify what we get back verifies
+ introspect = self.get_introspect()
+
+ if interface_prop_hash:
+ introspect_interfaces = list(introspect.keys())
+ for object_manager_key in interface_prop_hash.keys():
+ assert object_manager_key in introspect_interfaces
+
+ for i in list(introspect.keys()):
+ self._common(i, introspect, None)
+
+ def update(self):
+ # Go through all interfaces and update them
+ for sn in self.short_interface_names:
+ getattr(self, sn).update()
diff --git a/test/dbus/validatestate.py b/test/dbus/validatestate.py
new file mode 100755
index 0000000..1af303f
--- /dev/null
+++ b/test/dbus/validatestate.py
@@ -0,0 +1,32 @@
+#!/usr/bin/python3
+
+# Copyright (C) 2015-2016 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, see <http://www.gnu.org/licenses/>.
+#
+# Simply connects to the dbus service and calls Refresh and ensures that the
+# value returned is zero
+
+import testlib
+import dbus
+from dbus.mainloop.glib import DBusGMainLoop
+import sys
+import os
+
+
+if __name__ == "__main__":
+
+ use_session = os.getenv('LVMD_BUSD_USE_SESSION', False)
+
+ if use_session:
+ bus = dbus.SessionBus(mainloop=DBusGMainLoop())
+ else:
+ bus = dbus.SystemBus(mainloop=DBusGMainLoop())
+
+ mgr_proxy = testlib.ClientProxy(bus, testlib.MANAGER_OBJ)
+ sys.exit(mgr_proxy.Manager.Refresh())
diff --git a/test/lib/aux.sh b/test/lib/aux.sh
index 7c0c189..3f66e92 100644
--- a/test/lib/aux.sh
+++ b/test/lib/aux.sh
@@ -1,5 +1,5 @@
-#!/bin/bash
-# Copyright (C) 2011-2012 Red Hat, Inc. All rights reserved.
+#!/usr/bin/env bash
+# Copyright (C) 2011-2017 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
@@ -7,188 +7,575 @@
#
# 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
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
. lib/utils
+test -n "$BASH" && set -euE -o pipefail
+
run_valgrind() {
# Execute script which may use $TESTNAME for creating individual
# log files for each execute command
- exec "${VALGRIND:-valg}" "$@"
+ exec "${VALGRIND:-valgrind}" "$@"
}
expect_failure() {
echo "TEST EXPECT FAILURE"
}
+check_daemon_in_builddir() {
+ # skip if we don't have our own deamon...
+ if test -z "${installed_testsuite+varset}"; then
+ (which "$1" 2>/dev/null | grep "$abs_builddir" >/dev/null ) || skip "$1 is not in executed path."
+ fi
+ rm -f debug.log strace.log
+}
+
+create_corosync_conf() {
+ local COROSYNC_CONF="/etc/corosync/corosync.conf"
+ local COROSYNC_NODE=$(hostname)
+
+ if test -a "$COROSYNC_CONF"; then
+ if ! grep "created by lvm test suite" "$COROSYNC_CONF"; then
+ rm "$COROSYNC_CONF"
+ else
+ mv "$COROSYNC_CONF" "$COROSYNC_CONF.prelvmtest"
+ fi
+ fi
+
+ sed -e "s/@LOCAL_NODE@/$COROSYNC_NODE/" lib/test-corosync-conf > "$COROSYNC_CONF"
+ echo "created new $COROSYNC_CONF"
+}
+
+create_dlm_conf() {
+ local DLM_CONF="/etc/dlm/dlm.conf"
+
+ if test -a "$DLM_CONF"; then
+ if ! grep "created by lvm test suite" "$DLM_CONF"; then
+ rm "$DLM_CONF"
+ else
+ mv "$DLM_CONF" "$DLM_CONF.prelvmtest"
+ fi
+ fi
+ mkdir -p "$(dirname "$DLM_CONF")"
+ cp lib/test-dlm-conf "$DLM_CONF"
+ echo "created new $DLM_CONF"
+}
+
+prepare_dlm() {
+ pgrep dlm_controld && skip "Cannot run while existing dlm_controld process exists."
+ pgrep corosync && skip "Cannot run while existing corosync process exists."
+
+ create_corosync_conf
+ create_dlm_conf
+
+ systemctl start corosync
+ sleep 1
+ if ! pgrep corosync; then
+ echo "Failed to start corosync."
+ exit 1
+ fi
+
+ systemctl start dlm
+ sleep 1
+ if ! pgrep dlm_controld; then
+ echo "Failed to start dlm."
+ exit 1
+ fi
+}
+
+create_sanlock_conf() {
+ local SANLOCK_CONF="/etc/sanlock/sanlock.conf"
+
+ if test -a "$SANLOCK_CONF"; then
+ if ! grep "created by lvm test suite" "$SANLOCK_CONF"; then
+ rm "$SANLOCK_CONF"
+ else
+ mv "$SANLOCK_CONF" "$SANLOCK_CONF.prelvmtest"
+ fi
+ fi
+
+ mkdir -p "$(dirname "$SANLOCK_CONF")"
+ cp lib/test-sanlock-conf "$SANLOCK_CONF"
+ echo "created new $SANLOCK_CONF"
+}
+
+prepare_sanlock() {
+ pgrep sanlock && skip "Cannot run while existing sanlock process exists"
+
+ create_sanlock_conf
+
+ systemctl start sanlock
+ if ! pgrep sanlock; then
+ echo "Failed to start sanlock"
+ exit 1
+ fi
+}
+
+prepare_idm() {
+ pgrep seagate_ilm && skip "Cannot run while existing seagate_ilm process exists"
+
+ seagate_ilm -D 0 -l 0 -L 7 -E 7 -S 7
+
+ if ! pgrep seagate_ilm; then
+ echo "Failed to start seagate_ilm"
+ exit 1
+ fi
+}
+
+prepare_lvmlockd() {
+ pgrep lvmlockd && skip "Cannot run while existing lvmlockd process exists"
+
+ if test -n "$LVM_TEST_LOCK_TYPE_SANLOCK"; then
+ # make check_lvmlockd_sanlock
+ echo "starting lvmlockd for sanlock"
+ lvmlockd -o 2
+
+ elif test -n "$LVM_TEST_LOCK_TYPE_DLM"; then
+ # make check_lvmlockd_dlm
+ echo "starting lvmlockd for dlm"
+ lvmlockd
+
+ elif test -n "$LVM_TEST_LOCK_TYPE_IDM"; then
+ # make check_lvmlockd_idm
+ echo "starting lvmlockd for idm"
+ lvmlockd -g idm
+
+ elif test -n "$LVM_TEST_LVMLOCKD_TEST_DLM"; then
+ # make check_lvmlockd_test
+ echo "starting lvmlockd --test (dlm)"
+ lvmlockd --test -g dlm
+
+ elif test -n "$LVM_TEST_LVMLOCKD_TEST_SANLOCK"; then
+ # FIXME: add option for this combination of --test and sanlock
+ echo "starting lvmlockd --test (sanlock)"
+ lvmlockd --test -g sanlock -o 2
+
+ elif test -n "$LVM_TEST_LVMLOCKD_TEST_IDM"; then
+ # make check_lvmlockd_test
+ echo "starting lvmlockd --test (idm)"
+ lvmlockd --test -g idm
+
+ else
+ echo "not starting lvmlockd"
+ exit 0
+ fi
+
+ sleep 1
+ if ! pgrep lvmlockd >LOCAL_LVMLOCKD; then
+ echo "Failed to start lvmlockd"
+ exit 1
+ fi
+}
+
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
+ skip "Cannot use fake cluster locking with real clvmd ($(pgrep clvmd)) running."
fi
- # skip if we don't have our own clvmd...
- (which clvmd 2>/dev/null | grep "$abs_builddir") || skip
+ check_daemon_in_builddir clvmd
- # skip if we singlenode is not compiled in
- (clvmd --help 2>&1 | grep "Available cluster managers" | grep "singlenode") || skip
+ test -e "$DM_DEV_DIR/control" || dmsetup table >/dev/null # create control node
+ # skip if singlenode is not compiled in
+ (clvmd --help 2>&1 | grep "Available cluster managers" | grep "singlenode" >/dev/null) || \
+ skip "Compiled clvmd does not support singlenode for testing."
# 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
+ local run_valgrind=""
+ test "${LVM_VALGRIND_CLVMD:-0}" -eq 0 || run_valgrind="run_valgrind"
+ rm -f "$CLVMD_PIDFILE"
+ echo "<======== Starting CLVMD ========>"
+ echo -n "## preparing clvmd..."
+ # lvs is executed from clvmd - use our version
+ LVM_LOG_FILE_EPOCH=CLVMD LVM_LOG_FILE_MAX_LINES=1000000 $run_valgrind clvmd -Isinglenode -d 1 -f &
+ echo $! > LOCAL_CLVMD
+
+ for i in {200..0} ; do
+ test "$i" -eq 0 && die "Startup of clvmd is too slow."
+ test -e "$CLVMD_PIDFILE" && test -e "${CLVMD_PIDFILE%/*}/lvm/clvmd.sock" && break
+ echo -n .
+ sleep .1
+ done
+ echo ok
}
prepare_dmeventd() {
if pgrep dmeventd ; then
- echo "Cannot test dmeventd with real dmeventd ($(pgrep dmeventd)) running."
- skip
+ skip "Cannot test dmeventd with real dmeventd ($(pgrep dmeventd)) running."
fi
- # skip if we don't have our own dmeventd...
- (which dmeventd 2>/dev/null | grep "$abs_builddir") || skip
-
+ check_daemon_in_builddir dmeventd
lvmconf "activation/monitoring = 1"
- dmeventd -f "$@" &
+ local run_valgrind=""
+ test "${LVM_VALGRIND_DMEVENTD:-0}" -eq 0 || run_valgrind="run_valgrind"
+ echo -n "## preparing dmeventd..."
+# LVM_LOG_FILE_EPOCH=DMEVENTD $run_valgrind dmeventd -fddddl "$@" 2>&1 &
+ LVM_LOG_FILE_EPOCH=DMEVENTD $run_valgrind dmeventd -fddddl "$@" >debug.log_DMEVENTD_out 2>&1 &
echo $! > LOCAL_DMEVENTD
# FIXME wait for pipe in /var/run instead
- sleep .3
+ for i in {200..0} ; do
+ test "$i" -eq 0 && die "Startup of dmeventd is too slow."
+ test -e "${DMEVENTD_PIDFILE}" && break
+ echo -n .
+ sleep .1
+ done
+ echo ok
}
-prepare_lvmetad() {
- # skip if we don't have our own lvmetad...
- (which lvmetad 2>/dev/null | grep "$abs_builddir") || skip
+prepare_lvmpolld() {
+ test -e LOCAL_LVMPOLLD || lvmconf "global/use_lvmpolld = 1"
- lvmconf "global/use_lvmetad = 1"
- lvmconf "devices/md_component_detection = 0"
+ local run_valgrind=""
+ test "${LVM_VALGRIND_LVMPOLLD:-0}" -eq 0 || run_valgrind="run_valgrind"
- local run_valgrind=
- test -z "$LVM_VALGRIND_LVMETAD" || run_valgrind="run_valgrind"
+ kill_sleep_kill_ LOCAL_LVMPOLLD "${LVM_VALGRIND_LVMPOLLD:-0}"
- 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 -n "## preparing lvmpolld..."
+ $run_valgrind lvmpolld -f "$@" -s "$TESTDIR/lvmpolld.socket" -B "$TESTDIR/lib/lvm" -l all &
+ echo $! > LOCAL_LVMPOLLD
+ for i in {200..0} ; do
+ test -e "$TESTDIR/lvmpolld.socket" && break
+ echo -n .;
+ sleep .1;
+ done # wait for the socket
+ test "$i" -gt 0 || die "Startup of lvmpolld is too slow."
echo ok
}
-notify_lvmetad() {
- if test -e LOCAL_LVMETAD; then
- pvscan --cache "$@" || true
+lvmpolld_talk() {
+ local use=nc
+ if type -p socat >& /dev/null; then
+ use=socat
+ elif echo | not nc -U "$TESTDIR/lvmpolld.socket" ; then
+ echo "WARNING: Neither socat nor nc -U seems to be available." 1>&2
+ echo "## failed to contact lvmpolld."
+ return 1
+ fi
+
+ if test "$use" = nc ; then
+ nc -U "$TESTDIR/lvmpolld.socket"
+ else
+ socat "unix-connect:$TESTDIR/lvmpolld.socket" -
+ fi | tee -a lvmpolld-talk.txt
+}
+
+lvmpolld_dump() {
+ (echo 'request="dump"'; echo '##') | lvmpolld_talk "$@"
+}
+
+prepare_lvmdbusd() {
+ local lvmdbusdebug=
+ local daemon
+ rm -f debug.log_LVMDBUSD_out
+
+ kill_sleep_kill_ LOCAL_LVMDBUSD 0
+
+ # FIXME: This is not correct! Daemon is auto started.
+ echo -n "## checking lvmdbusd is NOT running..."
+ if pgrep -f -l lvmdbusd | grep python3 || pgrep -x -l lvmdbusd ; then
+ skip "Cannot run lvmdbusd while existing lvmdbusd process exists"
+ fi
+ echo ok
+
+ # skip if we don't have our own lvmdbusd...
+ echo -n "## find lvmdbusd to use..."
+ if test -z "${installed_testsuite+varset}"; then
+ # NOTE: this is always present - additional checks are needed:
+ daemon="$abs_top_builddir/daemons/lvmdbusd/lvmdbusd"
+ if test -x "$daemon" || chmod ugo+x "$daemon"; then
+ echo "$daemon"
+ else
+ echo "Failed to make '$daemon' executable">&2
+ return 1
+ fi
+ # Setup the python path so we can run
+ export PYTHONPATH="$abs_top_builddir/daemons"
+ else
+ daemon=$(which lvmdbusd || :)
+ echo "$daemon"
+ fi
+ test -x "$daemon" || skip "The lvmdbusd daemon is missing"
+ which python3 >/dev/null || skip "Missing python3"
+
+ python3 -c "import pyudev, dbus, gi.repository" || skip "Missing python modules"
+ python3 -c "from json.decoder import JSONDecodeError" || skip "Python json module is missing JSONDecodeError"
+
+ # Copy the needed file to run on the system bus if it doesn't
+ # already exist
+ if [ ! -f /etc/dbus-1/system.d/com.redhat.lvmdbus1.conf ]; then
+ install -m 644 "$abs_top_builddir/scripts/com.redhat.lvmdbus1.conf" /etc/dbus-1/system.d/
fi
+
+ echo "## preparing lvmdbusd..."
+ lvmconf "global/notify_dbus = 1"
+
+ test "${LVM_DEBUG_LVMDBUS:-0}" != "0" && lvmdbusdebug="--debug"
+ "$daemon" $lvmdbusdebug > debug.log_LVMDBUSD_out 2>&1 &
+ local pid=$!
+
+ sleep 1
+ echo -n "## checking lvmdbusd IS running..."
+ comm=
+ # TODO: Is there a better check than wait 1 second and check pid?
+ if ! comm=$(ps -p $pid -o comm=) >/dev/null || [[ $comm != lvmdbusd ]]; then
+ echo "Failed to start lvmdbusd daemon"
+ return 1
+ fi
+ echo "$pid" > LOCAL_LVMDBUSD
+ echo ok
+}
+
+#
+# Temporary solution to create some occupied thin metadata
+# This heavily depends on thin metadata output format to stay as is.
+# Currently it expects 2MB thin metadata and 200MB data volume size
+# Argument specifies how many devices should be created.
+#
+prepare_thin_metadata() {
+ local devices=$1
+ local transaction_id=${2:-0}
+ local data_block_size=${3:-128}
+ local nr_data_blocks=${4:-3200}
+ local i
+
+ echo '<superblock uuid="" time="1" transaction="'"$transaction_id"'" data_block_size="'"$data_block_size"'" nr_data_blocks="'"$nr_data_blocks"'">'
+ for i in $(seq 1 "$devices")
+ do
+ echo ' <device dev_id="'"$i"'" mapped_blocks="37" transaction="'"$i"'" creation_time="0" snap_time="1">'
+ echo ' <range_mapping origin_begin="0" data_begin="0" length="37" time="0"/>'
+ echo ' </device>'
+ done
+ echo "</superblock>"
}
teardown_devs_prefixed() {
local prefix=$1
local stray=${2:-0}
local IFS=$IFS_NL
+ local once=1
local dm
+ rm -rf "${TESTDIR:?}/dev/$prefix*"
+
+ # Send idle message to frozen raids (with hope to unfreeze them)
+ for dm in $(dm_status | grep -E "$prefix.*raid.*frozen"); do
+ echo "## unfreezing: dmsetup message \"${dm%:*}\""
+ dmsetup message "${dm%:*}" 0 "idle" &
+ done
+
# 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
+ for dm in $(dm_info name -S "name=~$PREFIX&&suspended=Suspended"); do
+ test "$dm" != "No devices found" || break
+ echo "## resuming: dmsetup resume \"$dm\""
+ dmsetup clear "$dm"
+ dmsetup resume "$dm" &
done
- local mounts=( $(grep "$prefix" /proc/mounts | cut -d' ' -f1) )
+ wait
+
+ local mounts
+ mounts=( $(grep "$prefix" /proc/mounts | cut -d' ' -f1) ) || true
if test ${#mounts[@]} -gt 0; then
- test "$stray" -eq 0 || echo "Removing stray mounted devices containing $prefix: ${mounts[@]}"
+ 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
+ # Run 'dmsetup remove' in parallel
+ rm -f REMOVE_FAILED
+ #local listdevs=( $(dm_info name,open --sort open,name | grep "$prefix.*:0") )
+ #dmsetup remove --deferred ${listdevs[@]%%:0} || touch REMOVE_FAILED
+
+ # 2nd. loop is trying --force removal which can possibly 'unstuck' some bloked operations
+ for i in 0 1; do
+ test "$i" = 1 && test "$stray" = 0 && break # no stray device removal
+
+ while :; do
+ local sortby="name"
+ local progress=0
+
+ # HACK: sort also by minors - so we try to close 'possibly later' created device first
+ test "$i" = 0 || sortby="-minor"
+
+ for dm in $(dm_info name,open --separator ';' --nameprefixes --unquoted --sort open,"$sortby" -S "name=~$prefix" --mangle none || true) ; do
+ test "$dm" != "No devices found" || break 2
+ eval "$dm"
+ local force="-f"
+ if test "$i" = 0; then
+ if test "$once" = 1 ; then
+ once=0
+ echo "## removing stray mapped devices with names beginning with $prefix: "
+ fi
+ test "$DM_OPEN" = 0 || break # stop loop with 1st. opened device
+ force=""
+ fi
+
+ # Succesfull 'remove' signals progress
+ dmsetup remove $force "$DM_NAME" --mangle none && progress=1
done
- num_remaining_devs=$num_devs
- done
- fi
+
+ test "$i" = 0 || break
+
+ test "$progress" = 1 || break
+
+ udev_wait
+ wait
+ done # looping till there are some removed devices
+ done
}
teardown_devs() {
# Delete any remaining dm/udev semaphores
teardown_udev_cookies
-
- test -z "$PREFIX" || {
- rm -rf "$TESTDIR/dev/$PREFIX"*
- teardown_devs_prefixed "$PREFIX"
- }
+ restore_dm_mirror
+
+ test ! -f MD_DEV || cleanup_md_dev
+ test ! -f DEVICES || teardown_devs_prefixed "$PREFIX"
+ if test -f RAMDISK ; then
+ for i in 1 2 ; do
+ modprobe -r brd && break
+ sleep .1
+ udev_wait
+ done
+ fi
# 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
+ udev_wait
+ test "${LVM_TEST_PARALLEL:-0}" -eq 1 || {
+ for i in 1 2 ; do
+ modprobe -r scsi_debug && break
+ sleep .1
+ udev_wait
+ done
+ }
else
- test ! -f LOOP || losetup -d $(cat LOOP) || true
- test ! -f LOOPFILE || rm -f $(cat LOOPFILE)
+ test ! -f LOOP || losetup -d "$(< LOOP)" || true
+ test ! -f LOOPFILE || rm -f "$(< LOOPFILE)"
fi
- rm -f DEVICES # devs is set in prepare_devs()
- rm -f LOOP
+
+ not diff LOOP BACKING_DEV >/dev/null 2>&1 || rm -f BACKING_DEV
+ rm -f DEVICES LOOP RAMDISK
# 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 "${LVM_TEST_PARALLEL:-0}" -eq 1 || test -z "$COMMON_PREFIX" || {
+ local stray_loops
+ stray_loops=( $(losetup -a | grep "$COMMON_PREFIX" | cut -d: -f1) ) || true
test ${#stray_loops[@]} -eq 0 || {
- echo "Removing stray loop devices containing $COMMON_PREFIX: ${stray_loops[@]}"
- losetup -d "${stray_loops[@]}"
+ teardown_devs_prefixed "$COMMON_PREFIX" 1
+ echo "## removing stray loop devices containing $COMMON_PREFIX:" "${stray_loops[@]}"
+ for i in "${stray_loops[@]}" ; do test ! -b "$i" || losetup -d "$i" || true ; done
+ # Leave test when udev processed all removed devices
+ udev_wait
}
}
}
+kill_sleep_kill_() {
+ local pidfile=$1
+ local slow=$2
+
+ if test -s "$pidfile" ; then
+ pid=$(< "$pidfile")
+ rm -f "$pidfile"
+ kill -TERM "$pid" 2>/dev/null || return 0
+ for i in {0..10} ; do
+ ps "$pid" >/dev/null || return 0
+ if test "$slow" -eq 0 ; then sleep .2 ; else sleep 1 ; fi
+ kill -KILL "$pid" 2>/dev/null || true
+ done
+ fi
+}
+
+print_procs_by_tag_() {
+ (ps -o pid,args ehax | grep -we"LVM_TEST_TAG=${1:-kill_me_$PREFIX}") || true
+}
+
+count_processes_with_tag() {
+ print_procs_by_tag_ | wc -l
+}
+
+kill_tagged_processes() {
+ local pid
+ local wait
+
+ # read uses all vars within pipe subshell
+ local pids=()
+ while read -r pid wait; do
+ if test -n "$pid" ; then
+ echo "## killing tagged process: $pid ${wait:0:120}..."
+ kill -TERM "$pid" 2>/dev/null || true
+ fi
+ pids+=( "$pid" )
+ done < <(print_procs_by_tag_ "$@")
+
+ test ${#pids[@]} -eq 0 && return
+
+ # wait if process exited and eventually -KILL
+ wait=0
+ for pid in "${pids[@]}" ; do
+ while ps "$pid" > /dev/null && test "$wait" -le 10; do
+ sleep .2
+ wait=$(( wait + 1 ))
+ done
+ test "$wait" -le 10 || kill -KILL "$pid" 2>/dev/null || true
+ done
+}
+
teardown() {
+ local TEST_LEAKED_DEVICES=""
echo -n "## teardown..."
- test ! -s LOCAL_LVMETAD || \
- (kill -TERM "$(cat LOCAL_LVMETAD)" && sleep 1 &&
- kill -KILL "$(cat LOCAL_LVMETAD)" 2> /dev/null) || true
+ unset LVM_LOG_FILE_EPOCH
+
+ if test -f TESTNAME ; then
+
+ if test ! -f SKIP_THIS_TEST ; then
+ # Evaluate left devices only for non-skipped tests
+ TEST_LEAKED_DEVICES=$(dmsetup table | grep "$PREFIX" | \
+ grep -Ev "${PREFIX}(pv|[0-9])" | \
+ grep -v "$(cat ERR_DEV_NAME 2>/dev/null)" | \
+ grep -v "$(cat ZERO_DEV_NAME 2>/dev/null)") || true
+ fi
+
+ kill_tagged_processes
+
+ if test -n "$LVM_TEST_LVMLOCKD_TEST" ; then
+ echo ""
+ echo "## stopping lvmlockd in teardown"
+ kill_sleep_kill_ LOCAL_LVMLOCKD 0
+ fi
- dm_table | not egrep -q "$vg|$vg1|$vg2|$vg3|$vg4" || {
+ dm_table | not grep -E -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
+ if dm_info suspended,name | grep "^Suspended:.*$PREFIX" >/dev/null ; then
+ echo "## skipping vgremove, suspended devices detected."
+ else
+ vgremove -ff "$cfg" \
+ "$vg" "$vg1" "$vg2" "$vg3" "$vg4" &>/dev/null || rm -f debug.log strace.log
+ fi
}
- 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
- }
+ kill_sleep_kill_ LOCAL_LVMDBUSD 0
+
+ echo -n .
+
+ kill_sleep_kill_ LOCAL_LVMPOLLD "${LVM_VALGRIND_LVMPOLLD:-0}"
+
+ echo -n .
+
+ kill_sleep_kill_ LOCAL_CLVMD "${LVM_VALGRIND_CLVMD:-0}"
echo -n .
- pgrep dmeventd || true
- test ! -s LOCAL_DMEVENTD || kill -9 "$(cat LOCAL_DMEVENTD)" || true
+ kill_sleep_kill_ LOCAL_DMEVENTD "${LVM_VALGRIND_DMEVENTD:-0}"
echo -n .
@@ -196,31 +583,48 @@ teardown() {
echo -n .
+ fi
+
+ test -z "$TEST_LEAKED_DEVICES" || {
+ echo "## unexpected devices left dm table:"
+ echo "$TEST_LEAKED_DEVICES"
+ return 1
+ }
+
+ if test "${LVM_TEST_PARALLEL:-0}" = 0 && test -z "$RUNNING_DMEVENTD"; then
+ not pgrep dmeventd &>/dev/null # printed in STACKTRACE
+ fi
+
+ echo -n .
+
test -n "$TESTDIR" && {
- cd "$TESTOLDPWD"
- rm -rf "$TESTDIR" || echo BLA
+ cd "$TESTOLDPWD" || die "Failed to enter $TESTOLDPWD"
+ # after this delete no further write is possible
+ rm -rf "${TESTDIR:?}" || echo BLA
}
- echo "ok"
+ # Remove any dangling symlink in /dev/disk (our tests can confuse udev)
+ test -d /dev/disk && {
+ find /dev/disk -type l ! -exec /usr/bin/test -e {} \; -print0 | xargs -0 rm -f || true
+ }
- test ${LVM_TEST_PARALLEL:-0} -eq 1 -o -n "$RUNNING_DMEVENTD" || not pgrep dmeventd #&>/dev/null
-}
+ # Remove any metadata archives and backups from this test on system
+ rm -f /etc/lvm/archive/"${PREFIX}"* /etc/lvm/backup/"${PREFIX}"*
-make_ioerror() {
- echo 0 10000000 error | dmsetup create -u ${PREFIX}-ioerror ioerror
- ln -s "$DM_DEV_DIR/mapper/ioerror" "$DM_DEV_DIR/ioerror"
+ echo "ok"
}
prepare_loop() {
- local size=${1=32}
+ local size=$1
+ shift # all other params are directly passed to all 'losetup' calls
local i
local slash
- test -f LOOP && LOOP=$(cat LOOP)
+ test -f LOOP && LOOP=$(< LOOP)
echo -n "## preparing loop device..."
# skip if prepare_scsi_debug_dev() was used
- if test -f SCSI_DEBUG_DEV -a -f LOOP ; then
+ if test -f SCSI_DEBUG_DEV && test -f LOOP ; then
echo "(skipped)"
return 0
fi
@@ -235,10 +639,11 @@ prepare_loop() {
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
+ rm -f "$LOOPFILE"
+ 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
+ elif LOOP=$(losetup -f) && losetup "$@" "$LOOP" "$LOOPFILE"; then
# no -s support
:
else
@@ -249,7 +654,7 @@ prepare_loop() {
local dev="$DM_DEV_DIR/loop$slash$i"
! losetup "$dev" >/dev/null 2>&1 || continue
# got a free
- losetup "$dev" "$LOOPFILE"
+ losetup "$@" "$dev" "$LOOPFILE"
LOOP=$dev
break
done
@@ -257,43 +662,81 @@ prepare_loop() {
done
fi
test -n "$LOOP" # confirm or fail
+ touch NO_BLKDISCARD_Z # loop devices do not support WRITE_ZEROS
+ BACKING_DEV=$LOOP
echo "$LOOP" > LOOP
+ echo "$LOOP" > BACKING_DEV
echo "ok ($LOOP)"
}
+prepare_ramdisk() {
+ local size=$1
+
+ # if brd is unused, remove and use for test
+ modprobe -r brd || return 0
+
+ echo -n "## preparing ramdisk device..."
+ modprobe brd rd_size=$((size * 1024)) rd_nr=1 || return
+
+ BACKING_DEV=/dev/ram0
+ echo "ok ($BACKING_DEV)"
+ touch RAMDISK
+}
+
+prepare_real_devs() {
+ aux lvmconf 'devices/scan = "/dev"'
+
+ touch REAL_DEVICES
+
+ if test -n "$LVM_TEST_DEVICE_LIST"; then
+ local count=0
+ while read path; do
+ REAL_DEVICES[count]=$path
+ count=$(( count + 1 ))
+ aux extend_filter "a|$path|"
+ dd if=/dev/zero of="$path" bs=32k count=1
+ wipefs -a "$path" 2>/dev/null || true
+ done < "$LVM_TEST_DEVICE_LIST"
+ fi
+ printf "%s\\n" "${REAL_DEVICES[@]}" > REAL_DEVICES
+}
+
# 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}
+ shift # rest of params directly passed to modprobe
+ local DEBUG_DEV
- test -f "SCSI_DEBUG_DEV" && return 0
- test -z "$LOOP"
+ rm -f debug.log strace.log
+ test ! -f "SCSI_DEBUG_DEV" || return 0
+ test ! -f 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
+ lsmod | not grep scsi_debug >/dev/null || 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
+ touch SCSI_DEBUG_DEV
+ modprobe scsi_debug dev_size_mb="$(( DEV_SIZE + 2 ))" "$@" num_tgts=1 || skip
- local DEBUG_DEV="/dev/$(grep -H scsi_debug /sys/block/*/device/model | cut -f4 -d /)"
+ for i in {1..20} ; do
+ sleep .1 # allow for async Linux SCSI device registration
+ DEBUG_DEV="/dev/$(grep -H scsi_debug /sys/block/sd*/device/model | cut -f4 -d /)"
+ test -b "$DEBUG_DEV" && break
+ done
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)"
+ SCSI_DEBUG_DEV="$DM_DEV_DIR/$(basename "$DEBUG_DEV")"
echo "$SCSI_DEBUG_DEV" > SCSI_DEBUG_DEV
- echo "$SCSI_DEBUG_DEV" > LOOP
+ echo "$SCSI_DEBUG_DEV" > BACKING_DEV
# Setting $LOOP provides means for prepare_devs() override
- test "$LVM_TEST_DEVDIR" != "/dev" && ln -snf "$DEBUG_DEV" "$SCSI_DEBUG_DEV"
+ test "$DEBUG_DEV" = "$SCSI_DEBUG_DEV" || ln -snf "$DEBUG_DEV" "$SCSI_DEBUG_DEV"
}
cleanup_scsi_debug_dev() {
@@ -301,32 +744,348 @@ cleanup_scsi_debug_dev() {
rm -f SCSI_DEBUG_DEV LOOP
}
+mdadm_create() {
+ local devid
+ local mddev
+
+ which mdadm >/dev/null || skip "mdadm tool is missing!"
+
+ cleanup_md_dev
+ rm -f debug.log strace.log
+
+ # try to find free MD node
+ # using the old naming /dev/mdXXX
+ # if we need more MD arrays test suite more likely leaked them
+ for devid in {127..150} ; do
+ grep -q "md${devid}" /proc/mdstat || break
+ done
+ test "$devid" -lt "150" || skip "Cannot find free /dev/mdXXX node!"
+ mddev=/dev/md${devid}
+
+ mdadm --create "$mddev" "$@" || {
+ # Some older 'mdadm' version managed to open and close devices internaly
+ # and reporting non-exclusive access on such device
+ # let's just skip the test if this happens.
+ # Note: It's pretty complex to get rid of consequences
+ # the following sequence avoid leaks on f19
+ # TODO: maybe try here to recreate few times....
+ mdadm --stop "$mddev" || true
+ udev_wait
+ while [ "$#" -ne 0 ] ; do
+ case "$1" in
+ *"$PREFIX"*) mdadm --zero-superblock "$1" || true ;;
+ esac
+ shift
+ done
+ udev_wait
+ skip "Test skipped, unreliable mdadm detected!"
+ }
+
+ for i in {10..0} ; do
+ test -e "$mddev" && break
+ echo "Waiting for $mddev."
+ sleep .5
+ done
+
+ test -b "$mddev" || skip "mdadm has not created device!"
+ echo "$mddev" > MD_DEV
+
+ # LVM/DM will see this device
+ case "$DM_DEV_DIR" in
+ "/dev") echo "$mddev" > MD_DEV_PV ;;
+ *) rm -f "$DM_DEV_DIR/md${devid}"
+ cp -LR "$mddev" "$DM_DEV_DIR"
+ echo "${DM_DEV_DIR}/md${devid}" > MD_DEV_PV ;;
+ esac
+
+ rm -f MD_DEVICES
+ while [ "$#" -ne 0 ] ; do
+ case "$1" in
+ *"$PREFIX"*) echo "$1" >> MD_DEVICES ;;
+ esac
+ shift
+ done
+}
+
+mdadm_assemble() {
+ STRACE=
+ [ "$DM_DEV_DIR" = "/dev" ] && mdadm -V 2>&1 | grep " v3.2" && {
+ # use this 'trick' to slow down mdadm which otherwise
+ # is racing with udev rule since mdadm internally
+ # opens and closes raid leg devices in RW mode and then
+ # tries to get exlusive access to the leg device during
+ # insertion to kernel and fails during assembly
+ # There can be some other affected version of mdadm.
+ STRACE="strace -f -o /dev/null"
+ }
+
+ $STRACE mdadm --assemble "$@"
+ udev_wait
+}
+
+cleanup_md_dev() {
+ local IFS=$IFS_NL
+ local i
+ local dev
+ local base
+ local mddev
+
+ test -f MD_DEV || return 0
+ mddev=$(< MD_DEV)
+ base=$(basename "$mddev")
+
+ # try to find and remove any DM device on top of cleaned MD
+ # assume /dev/mdXXX is 9:MINOR
+ local minor=${mddev##/dev/md}
+ for i in $(dmsetup table | grep 9:"$minor" | cut -d: -f1) ; do
+ dmsetup remove "$i" || {
+ dmsetup --force remove "$i" || true
+ }
+ done
+
+ for i in {0..10} ; do
+ grep -q "$base" /proc/mdstat || break
+ test "$i" = 0 || {
+ sleep .1
+ echo "$mddev is still present, stopping again"
+ cat /proc/mdstat
+ }
+ mdadm --stop "$mddev" || true
+ udev_wait # wait till events are process, not zeroing to early
+ done
+
+ test "$DM_DEV_DIR" = "/dev" || rm -f "$(< MD_DEV_PV)"
+
+ for dev in $(< MD_DEVICES); do
+ mdadm --zero-superblock "$dev" 2>/dev/null || true
+ done
+ udev_wait
+ rm -f MD_DEV MD_DEVICES MD_DEV_PV
+}
+
+wipefs_a() {
+ local have_wipefs=
+
+ if test -e HAVE_WIPEFS; then
+ have_wipefs=$(< HAVE_WIPEFS)
+ else
+ wipefs -V >HAVE_WIPEFS 2>/dev/null && have_wipefs=yes
+ fi
+
+ udev_wait
+
+ for dev in "$@"; do
+ if test -n "$LVM_TEST_DEVICES_FILE"; then
+ lvmdevices --deldev "$dev" || true
+ fi
+
+ if test -n "$have_wipefs"; then
+ wipefs -a "$dev" || {
+ echo "$dev: device in-use, retrying wipe again."
+ sleep .1
+ udev_wait
+ wipefs -a "$dev"
+ }
+ else
+ dd if=/dev/zero of="$dev" bs=4096 count=8 oflag=direct >/dev/null || true
+ mdadm --zero-superblock "$dev" 2>/dev/null || true
+ fi
+
+ if test -n "$LVM_TEST_DEVICES_FILE"; then
+ lvmdevices --adddev "$dev" || true
+ fi
+ done
+
+ udev_wait
+}
+
+cleanup_idm_context() {
+ local dev=$1
+
+ if [ -n "$LVM_TEST_LOCK_TYPE_IDM" ]; then
+ sg_dev=$(sg_map26 "${dev}")
+ echo "Cleanup IDM context for drive ${dev} ($sg_dev)"
+ sg_raw -v -r 512 -o idm_tmp_data.bin "$sg_dev" \
+ 88 00 01 00 00 00 00 20 FF 01 00 00 00 01 00 00
+ sg_raw -v -s 512 -i idm_tmp_data.bin "$sg_dev" \
+ 8E 00 FF 00 00 00 00 00 00 00 00 00 00 01 00 00
+ rm idm_tmp_data.bin
+ fi
+}
+
+
+#
+# clear device either with blkdiscard -z or fallback to 'dd'
+# $1 device_path
+# TODO: add support for parametrized [OPTION] usage (Not usable ATM)
+# TODO: -bs blocksize (defaults 512K)
+# TODO: -count count/length (defaults to whole device, otherwise in BS units)
+# TODO: -seek offset/seek (defaults 0, begining of zeroing area in BS unit)
+clear_devs() {
+ local bs=
+ local count=
+ local seek=
+
+ while [ "$#" -ne 0 ] ; do
+ case "$1" in
+ "") ;;
+ "--bs") bs=$2; shift ;;
+ "--count") count=$2; shift ;;
+ "--seek") seek=$2; shift ;;
+ *TEST*) # Protection: only test devices with TEST in its path name can be zeroed
+ test -e NO_BLKDISCARD_Z || {
+ if blkdiscard -f -z "$1" ; then
+ shift
+ continue
+ fi
+ echo "Info: can't use 'blkdiscard -z' switch to 'dd'."
+ touch NO_BLKDISCARD_Z
+ }
+
+ dd if=/dev/zero of="$1" bs=512K oflag=direct $seek $count || true
+ ;;
+ esac
+ shift
+ done
+}
+
+#
+# corrupt device content
+# $1 file_path
+# $2 string/pattern search for curruption
+# $3 string/pattern replacing/corruptiong
+corrupt_dev() {
+ local a
+
+ # search for string on a file
+ # Note: returned string may possibly start with other ASCII chars
+ # a[0] is position in file, a[1] is the actual string
+ a=( $(strings -t d -n 64 "$1" | grep -m 1 "$2") ) || true
+
+ test -n "${a[0]-}" || return 0
+
+ # Seek for the sequence and replace it with corruption pattern
+ echo -n "${a[1]/$2/$3}" | LANG=C dd of="$1" bs=1 seek="${a[0]}" conv=fdatasync
+}
+
+prepare_backing_dev() {
+ local size=${1=32}
+ shift
+
+ if test -n "$LVM_TEST_BACKING_DEVICE"; then
+ IFS=',' read -r -a BACKING_DEVICE_ARRAY <<< "$LVM_TEST_BACKING_DEVICE"
+
+ for d in "${BACKING_DEVICE_ARRAY[@]}"; do
+ if test ! -b "$d"; then
+ echo "Device $d doesn't exist!"
+ return 1
+ fi
+ done
+ fi
+
+ if test -f BACKING_DEV; then
+ BACKING_DEV=$(< BACKING_DEV)
+ return 0
+ elif test -n "$LVM_TEST_BACKING_DEVICE"; then
+ BACKING_DEV=${BACKING_DEVICE_ARRAY[0]}
+ echo "$BACKING_DEV" > BACKING_DEV
+ return 0
+ elif test "${LVM_TEST_PREFER_BRD-1}" = "1" && \
+ test ! -d /sys/block/ram0 && \
+ kernel_at_least 4 16 0 && \
+ test "$size" -lt 16384; then
+ # try to use ramdisk if possible, but for
+ # big allocs (>16G) do not try to use ramdisk
+ # Also we can't use BRD device prior kernel 4.16
+ # since they were DAX based and lvm2 often relies
+ # in save table loading between exiting backend device
+ # and bio-based 'error' device.
+ # However with request based DAX brd device we get this:
+ # device-mapper: ioctl: can't change device type after initial table load.
+ prepare_ramdisk "$size" "$@" && return
+ echo "(failed)"
+ fi
+
+ prepare_loop "$size" "$@"
+}
+
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..."
+ local header_shift=1 # shift header from begin & end of device by 1MiB
- if ! loopsz=$(blockdev --getsz "$LOOP" 2>/dev/null); then
- loopsz=$(blockdev --getsize "$LOOP" 2>/dev/null)
+ # sanlock requires more space for the internal sanlock lv
+ # This could probably be lower, but what are the units?
+ if test -n "$LVM_TEST_LOCK_TYPE_SANLOCK" ; then
+ devsize=1024
fi
- local size=$(($loopsz/$n))
- devs=
+ touch DEVICES
+ prepare_backing_dev $(( n * devsize + 2 * header_shift ))
+ blkdiscard "$BACKING_DEV" 2>/dev/null || true
+ echo -n "## preparing $n devices..."
+ local size=$(( devsize * 2048 )) # sectors
+ local count=0
+ rm -f CREATE_FAILED
init_udev_transaction
- for i in $(seq 1 $n); do
+ 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"
+ DEVICES[count]=$dev
+ count=$(( count + 1 ))
+ # If the backing device number can meet the requirement for PV devices,
+ # then allocate a dedicated backing device for PV; otherwise, rollback
+ # to use single backing device for device-mapper.
+ if [ -n "$LVM_TEST_BACKING_DEVICE" ] && [ "$n" -le ${#BACKING_DEVICE_ARRAY[@]} ]; then
+ echo 0 $size linear "${BACKING_DEVICE_ARRAY[$(( count - 1 ))]}" $(( header_shift * 2048 )) > "$name.table"
+ else
+ echo 0 $size linear "$BACKING_DEV" $(( ( i - 1 ) * size + ( header_shift * 2048 ) )) > "$name.table"
+ fi
+ dmsetup create -u "TEST-$name" "$name" "$name.table" || touch CREATE_FAILED &
+ test -f CREATE_FAILED && break;
done
+ wait
finish_udev_transaction
+ if test -f CREATE_FAILED ; then
+ if test -z "$LVM_TEST_BACKING_DEVICE"; then
+ echo "failed"
+ return 1
+ fi
+ LVM_TEST_BACKING_DEVICE=
+ rm -f BACKING_DEV CREATE_FAILED
+ prepare_devs "$@"
+ return $?
+ fi
+
+ if [ -n "$LVM_TEST_BACKING_DEVICE" ]; then
+ for d in "${BACKING_DEVICE_ARRAY[@]}"; do
+ cnt=$(( $(blockdev --getsize64 "$d") / 1024 / 1024 ))
+ cnt=$(( cnt < 1000 ? cnt : 1000 ))
+ dd if=/dev/zero of="$d" bs=1MB count=$cnt
+ wipefs -a "$d" 2>/dev/null || true
+ cleanup_idm_context "$d"
+ done
+ fi
+
+ # non-ephemeral devices need to be cleared between tests
+ test -f LOOP -o -f RAMDISK || for d in "${DEVICES[@]}"; do
+ # ensure disk header is always zeroed
+ dd if=/dev/zero of="$d" bs=32k count=1
+ wipefs -a "$d" 2>/dev/null || true
+ done
+
+ if test -n "$LVM_TEST_DEVICES_FILE"; then
+ mkdir -p "$TESTDIR/etc/lvm/devices" || true
+ rm "$TESTDIR/etc/lvm/devices/system.devices" || true
+ touch "$TESTDIR/etc/lvm/devices/system.devices"
+ for d in "${DEVICES[@]}"; do
+ lvmdevices --adddev "$d" || true
+ done
+ fi
+
#for i in `seq 1 $n`; do
# local name="${PREFIX}$pvname$i"
# dmsetup info -c $name
@@ -336,44 +1095,299 @@ prepare_devs() {
# dmsetup table $name
#done
- echo $devs > DEVICES
+ printf "%s\\n" "${DEVICES[@]}" > DEVICES
+# ( IFS=$'\n'; echo "${DEVICES[*]}" ) >DEVICES
echo "ok"
}
+common_dev_() {
+ local tgtype=$1
+ local dev=$2
+ local name=${dev##*/}
+ shift 2
+ local read_ms=${1-0}
+ local write_ms=${2-0}
+
+ case "$tgtype" in
+ delay)
+ test "$read_ms" -eq 0 && test "$write_ms" -eq 0 && {
+ # zero delay is just equivalent to 'enable_dev'
+ enable_dev "$dev"
+ return
+ }
+ shift 2
+ ;;
+ delayzero)
+ shift 2
+ # zero delay is just equivalent to 'zero_dev'
+ test "$read_ms" -eq 0 && test "$write_ms" -eq 0 && tgtype="zero"
+ ;;
+ # error|zero target does not take read_ms & write_ms only offset list
+ esac
+
+ local pos
+ local size
+ local type
+ local pvdev
+ local offset
+
+ read -r pos size type pvdev offset < "$name.table"
+
+ for fromlen in "${@-0:}"; do
+ from=${fromlen%%:*}
+ len=${fromlen##*:}
+ if test "$len" = "$fromlen"; then
+ # Missing the colon at the end: empty len
+ len=
+ fi
+ test -n "$len" || len=$(( size - from ))
+ diff=$(( from - pos ))
+ if test $diff -gt 0 ; then
+ echo "$pos $diff $type $pvdev $(( pos + offset ))"
+ pos=$(( pos + diff ))
+ elif test $diff -lt 0 ; then
+ die "Position error"
+ fi
+
+ case "$tgtype" in
+ delay)
+ echo "$from $len delay $pvdev $(( pos + offset )) $read_ms $pvdev $(( pos + offset )) $write_ms" ;;
+ writeerror)
+ echo "$from $len delay $pvdev $(( pos + offset )) 0 $(cat ERR_DEV) 0 0" ;;
+ delayzero)
+ echo "$from $len delay $(cat ZERO_DEV) 0 $read_ms $(cat ZERO_DEV) 0 $write_ms" ;;
+ error|zero)
+ echo "$from $len $tgtype" ;;
+ esac
+ pos=$(( pos + len ))
+ done > "$name.devtable"
+ diff=$(( size - pos ))
+ test "$diff" -gt 0 && echo "$pos $diff $type $pvdev $(( pos + offset ))" >>"$name.devtable"
+
+ restore_from_devtable "$dev"
+}
+
+# Replace linear PV device with its 'delayed' version
+# Could be used to more deterministicaly hit some problems.
+# Parameters: {device path} [read delay ms] [write delay ms] [offset[:[size]]]...
+# Original device is restored when both delay params are 0 (or missing).
+# If the size is missing, the remaing portion of device is taken
+# i.e. delay_dev "$dev1" 0 200 256:
+delay_dev() {
+ if test ! -f HAVE_DM_DELAY ; then
+ target_at_least dm-delay 1 1 0 || return 0
+ touch HAVE_DM_DELAY
+ fi
+ common_dev_ delay "$@"
+}
+
disable_dev() {
local dev
+ local silent=""
+ local error=""
+ local notify=""
+
+ while test -n "$1"; do
+ if test "$1" = "--silent"; then
+ silent=1
+ shift
+ elif test "$1" = "--error"; then
+ error=1
+ shift
+ else
+ break
+ fi
+ done
- init_udev_transaction
+ udev_wait
for dev in "$@"; do
- maj=$(($(stat --printf=0x%t "$dev")))
- min=$(($(stat --printf=0x%T "$dev")))
+ maj=$(($(stat -L --printf=0x%t "$dev")))
+ min=$(($(stat -L --printf=0x%T "$dev")))
echo "Disabling device $dev ($maj:$min)"
- dmsetup remove -f "$dev" || true
- notify_lvmetad --major "$maj" --minor "$min"
+ notify="$notify $maj:$min"
+ if test -n "$error"; then
+ echo 0 10000000 error | dmsetup load "$dev"
+ dmsetup resume "$dev"
+ else
+ dmsetup remove -f "$dev" 2>/dev/null || true
+ fi
done
- finish_udev_transaction
}
enable_dev() {
local dev
+ local silent=""
+ if test "$1" = "--silent"; then
+ silent=1
+ shift
+ fi
+
+ rm -f debug.log strace.log
init_udev_transaction
for dev in "$@"; do
- local name=$(echo "$dev" | sed -e 's,.*/,,')
- dmsetup create -u "TEST-$name" "$name" "$name.table" || \
+ local name=${dev##*/}
+ dmsetup create -u "TEST-$name" "$name" "$name.table" 2>/dev/null || \
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
}
+# Try to remove list of DM device from table
+remove_dm_devs() {
+ local remove=( "$@" )
+ local held
+ local i
+
+ for i in {1..50}; do
+ held=()
+ for d in "${remove[@]}" ; do
+ dmsetup remove "$d" 2>/dev/null || {
+ dmsetup info -c "$d" 2>/dev/null && {
+ held+=( "$d" )
+ dmsetup status "$d"
+ }
+ }
+ done
+ test ${#held[@]} -eq 0 && {
+ rm -f debug.log*
+ return
+ }
+ remove=( "${held[@]}" )
+ done
+ die "Can't remove device(s) ${held[*]}"
+}
+
+# Throttle down performance of kcopyd when mirroring i.e. disk image
+throttle_sys="/sys/module/dm_mirror/parameters/raid1_resync_throttle"
+throttle_dm_mirror() {
+ # if the kernel config file is present, validate whether the kernel uses HZ_1000
+ # and return failure for this 'throttling' when it does NOT as without this setting
+ # whole throttling is pointless on modern hardware
+ local kconfig
+
+ kconfig="/boot/config-$(uname -r)"
+ if test -e "$kconfig" ; then
+ grep -q "CONFIG_HZ_1000=y" "$kconfig" 2>/dev/null || {
+ echo "WARNING: CONFIG_HZ_1000=y is NOT set in $kconfig -> throttling is unusable"
+ return 1
+ }
+ fi
+ test -e "$throttle_sys" || return
+ test -f THROTTLE || cat "$throttle_sys" > THROTTLE
+ echo "${1-1}" > "$throttle_sys"
+}
+
+# Restore original kcopyd throttle value and have mirroring fast again
+restore_dm_mirror() {
+ test ! -f THROTTLE || {
+ cat THROTTLE > "$throttle_sys"
+ rm -f THROTTLE
+ }
+}
+
+
+# Once there is $name.devtable
+# this is a quick way to restore to this table entry
+restore_from_devtable() {
+ local dev
+ local silent=""
+
+ if test "$1" = "--silent"; then
+ silent=1
+ shift
+ fi
+
+ rm -f debug.log strace.log
+ init_udev_transaction
+ for dev in "$@"; do
+ local name=${dev##*/}
+ dmsetup load "$name" "$name.devtable"
+ if not dmsetup resume "$name" ; then
+ dmsetup clear "$name"
+ dmsetup resume "$name"
+ finish_udev_transaction
+ echo "Device $name has unusable table \"$(cat "$name.devtable")\""
+ return 1
+ fi
+ done
+ finish_udev_transaction
+}
+
+#
+# Convert device to device with errors
+# Takes the list of pairs of error segment from:len
+# Combination with zero or delay is unsupported
+# Original device table is replaced with multiple lines
+# i.e. error_dev "$dev1" 8:32 96:8
+error_dev() {
+ common_dev_ error "$@"
+}
+
+#
+# Convert device to device with write errors but normal reads.
+# For this 'delay' dev is used and reroutes 'reads' back to original device
+# and for writes it will use extra new TEST-errordev (huge error target)
+# i.e. writeerror_dev "$dev1" 8:32
+writeerror_dev() {
+ local name=${PREFIX}-errordev
+
+ if test ! -e ERR_DEV; then
+ # delay target is used for error mapping
+ if test ! -f HAVE_DM_DELAY ; then
+ target_at_least dm-delay 1 1 0 || return 0
+ touch HAVE_DM_DELAY
+ fi
+ dmsetup create -u "TEST-$name" "$name" --table "0 4611686018427387904 error"
+ # Take major:minor of our error device
+ echo "$name" > ERR_DEV_NAME
+ dmsetup info -c --noheadings -o major,minor "$name" > ERR_DEV
+ fi
+
+ common_dev_ writeerror "$@"
+}
+
+#
+# Convert device to device with sections of delayed zero read and writes.
+# For this 'delay' dev will use extra new TEST-zerodev (huge zero target)
+# and reroutes reads and writes
+# i.e. delayzero_dev "$dev1" 8:32
+delayzero_dev() {
+ local name=${PREFIX}-zerodev
+
+ if test ! -e ZERO_DEV; then
+ # delay target is used for error mapping
+ if test ! -f HAVE_DM_DELAY ; then
+ target_at_least dm-delay 1 1 0 || return 0
+ touch HAVE_DM_DELAY
+ fi
+ dmsetup create -u "TEST-$name" "$name" --table "0 4611686018427387904 zero"
+ # Take major:minor of our error device
+ echo "$name" > ZERO_DEV_NAME
+ dmsetup info -c --noheadings -o major,minor "$name" > ZERO_DEV
+ fi
+
+ common_dev_ delayzero "$@"
+}
+
+#
+# Convert existing device to a device with zero segments
+# Takes the list of pairs of zero segment from:len
+# Combination with error or delay is unsupported
+# Original device table is replaced with multiple lines
+# i.e. zero_dev "$dev1" 8:32 96:8
+zero_dev() {
+ common_dev_ zero "$@"
+}
+
backup_dev() {
local dev
for dev in "$@"; do
- dd if="$dev" of="$dev.backup" bs=1024
+ dd if="$dev" of="${dev##*/}.backup" bs=16K conv=fdatasync || \
+ die "Cannot backup device: \"$dev\" with size $(blockdev --getsize64 "$dev" || true) bytes."
done
}
@@ -381,121 +1395,420 @@ restore_dev() {
local dev
for dev in "$@"; do
- test -e "$dev.backup" || \
+ test -e "${dev##*/}.backup" || \
die "Internal error: $dev not backed up, can't restore!"
- dd of="$dev" if="$dev.backup" bs=1024
+ dd of="$dev" if="${dev##*/}.backup" bs=16K
done
}
prepare_pvs() {
prepare_devs "$@"
- pvcreate -ff $devs
+ pvcreate -ff "${DEVICES[@]}"
}
prepare_vg() {
teardown_devs
- prepare_pvs "$@"
- vgcreate -c n $vg $devs
+ prepare_devs "$@"
+ vgcreate $SHARED -s 512K "$vg" "${DEVICES[@]}"
}
-lvmconf() {
+extend_devices() {
+ test -z "$LVM_TEST_DEVICES_FILE" && return
+
+ for dev in "$@"; do
+ lvmdevices --adddev "$dev"
+ done
+}
+
+extend_filter() {
+ local filter
+
+ test -n "$LVM_TEST_DEVICES_FILE" && return
+
+ filter=$(grep ^devices/global_filter CONFIG_VALUES | tail -n 1)
+ for rx in "$@"; do
+ filter=$(echo "$filter" | sed -e "s:\\[:[ \"$rx\", :")
+ done
+ lvmconf "$filter" "devices/scan_lvs = 1"
+}
+
+extend_filter_md() {
+ local filter
+
+ test -n "$LVM_TEST_DEVICES_FILE" && return
+
+ filter=$(grep ^devices/global_filter CONFIG_VALUES | tail -n 1)
+ for rx in "$@"; do
+ filter=$(echo "$filter" | sed -e "s:\\[:[ \"$rx\", :")
+ done
+ lvmconf "$filter"
+ lvmconf "devices/scan = [ \"$DM_DEV_DIR\", \"/dev\" ]"
+}
+
+extend_filter_LVMTEST() {
+ extend_filter "a|$DM_DEV_DIR/$PREFIX|" "$@"
+}
+
+hide_dev() {
+ local filter
+
+ if test -n "$LVM_TEST_DEVICES_FILE"; then
+ for dev in "$@"; do
+ lvmdevices --deldev "$dev"
+ done
+ else
+ filter=$(grep ^devices/global_filter CONFIG_VALUES | tail -n 1)
+ for dev in "$@"; do
+ filter=$(echo "$filter" | sed -e "s:\\[:[ \"r|$dev|\", :")
+ done
+ lvmconf "$filter"
+ fi
+}
+
+unhide_dev() {
+ local filter
+
+ if test -n "$LVM_TEST_DEVICES_FILE"; then
+ for dev in "$@"; do
+ lvmdevices -y --adddev "$dev"
+ done
+ else
+ filter=$(grep ^devices/global_filter CONFIG_VALUES | tail -n 1)
+ for dev in "$@"; do
+ filter=$(echo "$filter" | sed -e "s:\"r|$dev|\", ::")
+ done
+ lvmconf "$filter"
+ fi
+}
+
+mkdev_md5sum() {
+ rm -f debug.log strace.log
+ mkfs.ext2 "$DM_DEV_DIR/$1/$2" || return 1
+ md5sum "$DM_DEV_DIR/$1/$2" > "md5.$1-$2"
+}
+
+generate_config() {
+ if test -n "$profile_name"; then
+ config_values="PROFILE_VALUES_$profile_name"
+ config="PROFILE_$profile_name"
+ touch "$config_values"
+ else
+ config_values=CONFIG_VALUES
+ config=CONFIG
+ fi
+
LVM_TEST_LOCKING=${LVM_TEST_LOCKING:-1}
+ LVM_TEST_LVMPOLLD=${LVM_TEST_LVMPOLLD:-0}
+ LVM_TEST_LVMLOCKD=${LVM_TEST_LVMLOCKD:-0}
+ LVM_TEST_DEVICES_FILE=${LVM_TEST_DEVICES_FILE:-0}
+ # FIXME:dct: This is harmful! Variables are unused here and are tested not being empty elsewhere:
+ #LVM_TEST_LOCK_TYPE_SANLOCK=${LVM_TEST_LOCK_TYPE_SANLOCK:-0}
+ #LVM_TEST_LOCK_TYPE_DLM=${LVM_TEST_LOCK_TYPE_DLM:-0}
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
+ test -f "$config_values" || {
+ cat > "$config_values" <<-EOF
+activation/checks = 1
+activation/monitoring = 0
+activation/polling_interval = 1
+activation/retry_deactivation = 1
+activation/snapshot_autoextend_percent = 50
+activation/snapshot_autoextend_threshold = 50
+activation/verify_udev_operations = $LVM_VERIFY_UDEV
+activation/raid_region_size = 512
+allocation/wipe_signatures_when_zeroing_new_lvs = 0
+allocation/vdo_slab_size_mb = 128
+allocation/zero_metadata = 0
+backup/archive = 0
+backup/backup = 0
+devices/cache_dir = "$LVM_SYSTEM_DIR"
+devices/default_data_alignment = 1
devices/dir = "$DM_DEV_DIR"
+devices/md_component_detection = 0
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
+devices/sysfs_scan = 1
+devices/write_cache_state = 0
+devices/use_devicesfile = $LVM_TEST_DEVICES_FILE
+devices/filter = "a|.*|"
+devices/global_filter = [ "a|$DM_DEV_DIR/mapper/${PREFIX}.*pv[0-9_]*$|", "r|.*|" ]
+global/abort_on_internal_errors = 1
+global/cache_check_executable = "$LVM_TEST_CACHE_CHECK_CMD"
+global/cache_dump_executable = "$LVM_TEST_CACHE_DUMP_CMD"
+global/cache_repair_executable = "$LVM_TEST_CACHE_REPAIR_CMD"
+global/cache_restore_executable = "$LVM_TEST_CACHE_RESTORE_CMD"
+global/detect_internal_vg_cache_corruption = 1
+global/fallback_to_local_locking = 0
+global/etc = "$LVM_SYSTEM_DIR"
+global/locking_type=$LVM_TEST_LOCKING
+global/notify_dbus = 0
+global/si_unit_consistency = 1
+global/thin_check_executable = "$LVM_TEST_THIN_CHECK_CMD"
+global/thin_dump_executable = "$LVM_TEST_THIN_DUMP_CMD"
+global/thin_repair_executable = "$LVM_TEST_THIN_REPAIR_CMD"
+global/thin_restore_executable = "$LVM_TEST_THIN_RESTORE_CMD"
+global/use_lvmpolld = $LVM_TEST_LVMPOLLD
+global/use_lvmlockd = $LVM_TEST_LVMLOCKD
+log/activation = 1
+log/file = "$TESTDIR/debug.log"
log/indent = 1
log/level = 9
-log/file = "$TESTDIR/debug.log"
log/overwrite = 1
-log/activation = 1
+log/syslog = 0
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
+EOF
+ # For 'rpm' builds use system installed binaries
+ # and libraries and locking dir and some more built-in
+ # defaults
+ # For test suite run use binaries from builddir.
+ test -z "${abs_top_builddir+varset}" || {
+ cat >> "$config_values" <<-EOF
+dmeventd/executable = "$abs_top_builddir/test/lib/dmeventd"
+activation/udev_rules = 1
+activation/udev_sync = 1
+global/fsadm_executable = "$abs_top_builddir/test/lib/fsadm"
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
+ }
}
+ # append all parameters (avoid adding empty \n)
local v
- for v in "$@"; do
- echo "$v" >> CONFIG_VALUES
- done
+ test $# -gt 0 && printf "%s\\n" "$@" >> "$config_values"
+
+ declare -A CONF 2>/dev/null || {
+ # Associative arrays is not available
+ local s
+ for s in $(cut -f1 -d/ "$config_values" | sort | uniq); do
+ echo "$s {"
+ local k
+ for k in $(grep ^"$s"/ "$config_values" | cut -f1 -d= | sed -e 's, *$,,' | sort | uniq); do
+ grep "^${k}[ \t=]" "$config_values" | tail -n 1 | sed -e "s,^$s/, ," || true
+ done
+ echo "}"
+ echo
+ done | tee "$config" | sed -e "s,^,## LVMCONF: ,"
+ return 0
+ }
+
+ local sec
+ local last_sec=""
+
+ # read sequential list and put into associative array
+ while IFS= read -r v; do
+ CONF["${v%%[={ ]*}"]=${v#*/}
+ done < "$config_values"
+
+ # sort by section and iterate through them
+ printf "%s\\n" "${!CONF[@]}" | sort | while read -r v ; do
+ sec=${v%%/*} # split on section'/'param_name
+ test "$sec" = "$last_sec" || {
+ test -z "$last_sec" || echo "}"
+ echo "$sec {"
+ last_sec=$sec
+ }
+ echo " ${CONF[$v]}"
+ done > "$config"
+ echo "}" >> "$config"
+
+ sed -e "s,^,## LVMCONF: ," "$config"
+}
- 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
+lvmconf() {
+ local profile_name=""
+ test $# -eq 0 || {
+ # Compare if passed args aren't already all in generated lvm.conf
+ local needed=0
+ for i in "$@"; do
+ val=$(grep "${i%%[={ ]*}" CONFIG_VALUES 2>/dev/null | tail -1) || { needed=1; break; }
+ test "$val" = "$i" || { needed=1; break; }
done
- echo "}" >> CONFIG
- echo >> CONFIG
- done
- mv -f CONFIG etc/lvm.conf
+ test "$needed" -eq 0 && {
+ echo "## Skipping reconfiguring for: (" "$@" ")"
+ return 0 # not needed
+ }
+ }
+ generate_config "$@"
+ mv -f CONFIG "$LVM_SYSTEM_DIR/lvm.conf"
}
-apitest() {
- local t=$1
+profileconf() {
+ local pdir="$LVM_SYSTEM_DIR/profile"
+ local profile_name=$1
shift
- test -x "$abs_top_builddir/test/api/$t.t" || skip
- "$abs_top_builddir/test/api/$t.t" "$@" && rm -f debug.log
+ generate_config "$@"
+ mkdir -p "$pdir"
+ mv -f "PROFILE_$profile_name" "$pdir/$profile_name.profile"
}
-api() {
- test -x "$abs_top_builddir/test/api/wrapper" || skip
- "$abs_top_builddir/test/api/wrapper" "$@" && rm -f debug.log
+prepare_profiles() {
+ local pdir="$LVM_SYSTEM_DIR/profile"
+ local profile_name
+ mkdir -p "$pdir"
+ for profile_name in "$@"; do
+ test -L "lib/$profile_name.profile" || skip
+ cp "lib/$profile_name.profile" "$pdir/$profile_name.profile"
+ done
+}
+
+unittest() {
+ test -x "$TESTOLDPWD/unit/unit-test" || skip
+ "$TESTOLDPWD/unit/unit-test" "${@}"
+}
+
+mirror_recovery_works() {
+ case "$(uname -r)" in
+ 3.3.4-5.fc17.i686|3.3.4-5.fc17.x86_64) return 1 ;;
+ esac
+}
+
+raid456_replace_works() {
+# The way kmem_cache aliasing is done in the kernel is broken.
+# It causes RAID 4/5/6 tests to fail.
+#
+# The problem with kmem_cache* is this:
+# *) Assume CONFIG_SLUB is set
+# 1) kmem_cache_create(name="foo-a")
+# - creates new kmem_cache structure
+# 2) kmem_cache_create(name="foo-b")
+# - If identical cache characteristics, it will be merged with the previously
+# created cache associated with "foo-a". The cache's refcount will be
+# incremented and an alias will be created via sysfs_slab_alias().
+# 3) kmem_cache_destroy(<ptr>)
+# - Attempting to destroy cache associated with "foo-a", but instead the
+# refcount is simply decremented. I don't even think the sysfs aliases are
+# ever removed...
+# 4) kmem_cache_create(name="foo-a")
+# - This FAILS because kmem_cache_sanity_check colides with the existing
+# name ("foo-a") associated with the non-removed cache.
+#
+# This is a problem for RAID (specifically dm-raid) because the name used
+# for the kmem_cache_create is ("raid%d-%p", level, mddev). If the cache
+# persists for long enough, the memory address of an old mddev will be
+# reused for a new mddev - causing an identical formulation of the cache
+# name. Even though kmem_cache_destory had long ago been used to delete
+# the old cache, the merging of caches has cause the name and cache of that
+# old instance to be preserved and causes a colision (and thus failure) in
+# kmem_cache_create(). I see this regularly in testing the following
+# kernels:
+#
+# This seems to be finaly resolved with this patch:
+# http://www.redhat.com/archives/dm-devel/2014-March/msg00008.html
+# so we need to put here exlusion for kernes which do trace SLUB
+#
+ case "$(uname -r)" in
+ 3.6.*.fc18.i686*|3.6.*.fc18.x86_64) return 1 ;;
+ 3.9.*.fc19.i686*|3.9.*.fc19.x86_64) return 1 ;;
+ 3.1[0123].*.fc18.i686*|3.1[0123].*.fc18.x86_64) return 1 ;;
+ 3.1[01234].*.fc19.i686*|3.1[01234].*.fc19.x86_64) return 1 ;;
+ 3.1[123].*.fc20.i686*|3.1[123].*.fc20.x86_64) return 1 ;;
+ 3.14.*.fc21.i686*|3.14.*.fc21.x86_64) return 1 ;;
+ 3.15.*rc6*.fc21.i686*|3.15.*rc6*.fc21.x86_64) return 1 ;;
+ 3.16.*rc4*.fc21.i686*|3.16.*rc4*.fc21.x86_64) return 1 ;;
+ esac
+}
+
+#
+# Some 32bit kernel cannot pass some erroring magic which forces
+# thin-pool to be falling into Error state.
+#
+# Skip test on such kernels (see: https://bugzilla.redhat.com/1310661)
+#
+thin_pool_error_works_32() {
+ case "$(uname -r)" in
+ 2.6.32-618.*.i686) return 1 ;;
+ 2.6.32-623.*.i686) return 1 ;;
+ 2.6.32-573.1[28].1.el6.i686) return 1 ;;
+ esac
+}
+
+thin_restore_needs_more_volumes() {
+ case $("$LVM_TEST_THIN_RESTORE_CMD" -V) in
+ # With older version of thin-tool we got slightly more compact metadata
+ 0.[0-6]*|0.7.0*) return 0 ;;
+ 0.8.5-2.el7) return 0 ;;
+ esac
+ return 1
}
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
+ which udevadm &>/dev/null || return 0
+ if test -n "${1-}" ; then
+ udevadm settle --exit-if-exists="$1" 2>/dev/null || true
else
- udevadm settle --timeout=15 || true
+ udevadm settle --timeout=15 2>/dev/null || true
fi
}
# wait_for_sync <VG/LV>
wait_for_sync() {
local i
- for i in {1..500} ; do
- check in_sync $1 $2 && return
+ for i in {1..100} ; do
+ check in_sync "$@" && return
sleep .2
done
echo "Sync is taking too long - assume stuck"
+ echo t >/proc/sysrq-trigger 2>/dev/null
+ return 1
+}
+
+wait_recalc() {
+ local checklv=$1
+
+ for i in {1..100} ; do
+ sync=$(get lv_field "$checklv" sync_percent | cut -d. -f1)
+ echo "sync_percent is $sync"
+
+ test "$sync" = "100" && return
+
+ sleep .1
+ done
+
+ # TODO: There is some strange bug, first leg of RAID with integrity
+ # enabled never gets in sync. I saw this in BB, but not when executing
+ # the commands manually
+# if test -z "$sync"; then
+# echo "TEST\ WARNING: Resync of dm-integrity device '$checklv' failed"
+# dmsetup status "$DM_DEV_DIR/mapper/${checklv/\//-}"
+# exit
+# fi
+ echo "Timeout waiting for recalc"
+ dmsetup status "$DM_DEV_DIR/mapper/${checklv/\//-}"
return 1
}
+# Check if tests are running on 64bit architecture
+can_use_16T() {
+ test "$(getconf LONG_BIT)" -eq 64
+}
+
+# Check if major.minor.revision' string is 'at_least'
+version_at_least() {
+ local major
+ local minor
+ local revision
+ IFS=".-" read -r major minor revision <<< "$1"
+ shift
+
+ test -n "${1:-}" || return 0
+ test -n "$major" || return 1
+ test "$major" -gt "$1" && return 0
+ test "$major" -eq "$1" || return 1
+
+ test -n "${2:-}" || return 0
+ test -n "$minor" || return 1
+ test "$minor" -gt "$2" && return 0
+ test "$minor" -eq "$2" || return 1
+
+ test -n "${3:-}" || return 0
+ test "$revision" -ge "$3" 2>/dev/null || return 1
+}
#
# Check wheter kernel [dm module] target exist
# at least in expected version
@@ -503,49 +1816,255 @@ wait_for_sync() {
# [dm-]target-name major minor revision
#
# i.e. dm_target_at_least dm-thin-pool 1 0
-target_at_least()
-{
+target_at_least() {
+ rm -f debug.log strace.log
case "$1" in
+ dm-vdo) modprobe "kvdo" || true ;;
dm-*) modprobe "$1" || true ;;
esac
- local version=$(dmsetup targets 2>/dev/null | grep "${1##dm-} " 2>/dev/null)
- version=${version##* v}
- shift
+ if test "$1" = dm-raid; then
+ case "$(uname -r)" in
+ 3.12.0*) return 1 ;;
+ esac
+ fi
- 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
+ local version
+ version=$(dmsetup targets 2>/dev/null | grep "^${1##dm-} " 2>/dev/null)
+ version=${version##* v}
- 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
+ version_at_least "$version" "${@:2}" || {
+ echo "Found $1 version $version, but requested ${*:2}." >&2
+ return 1
+ }
+}
- test -z "$3" && return 0
- local revision=$(echo "$version" | cut -d. -f3)
- test "$revision" -ge "$3" 2>/dev/null || return 1
+# Check whether the kernel driver version is greater or equal
+# to the specified version. This can be used to skip tests on
+# kernels where they are known to not be supported.
+#
+# e.g. driver_at_least 4 33
+#
+driver_at_least() {
+ local version
+ version=$(dmsetup version | tail -1 2>/dev/null)
+ version=${version##*:}
+ version_at_least "$version" "$@" || {
+ echo "Found driver version $version, but requested" "$@" "." >&2
+ return 1
+ }
}
-have_thin()
-{
- target_at_least dm-thin-pool "$@" || exit 1
- test "$THIN" = shared || test "$THIN" = internal || exit 1
+have_thin() {
+ lvm segtypes 2>/dev/null | grep thin$ >/dev/null || {
+ echo "Thin is not built-in." >&2
+ return 1
+ }
+ target_at_least dm-thin-pool "$@"
+ declare -a CONF=()
# disable thin_check if not present in system
- which thin_check || lvmconf 'global/thin_check_executable = ""'
+ if test -n "$LVM_TEST_THIN_CHECK_CMD" && test ! -x "$LVM_TEST_THIN_CHECK_CMD"; then
+ CONF[0]="global/thin_check_executable = \"\""
+ fi
+ if test -n "$LVM_TEST_THIN_DUMP_CMD" && test ! -x "$LVM_TEST_THIN_DUMP_CMD"; then
+ CONF[1]="global/thin_dump_executable = \"\""
+ fi
+ if test -n "$LVM_TEST_THIN_REPAIR_CMD" && test ! -x "$LVM_TEST_THIN_REPAIR_CMD"; then
+ CONF[2]="global/thin_repair_executable = \"\""
+ fi
+ if test ${#CONF[@]} -ne 0 ; then
+ echo "TEST WARNING: Reconfiguring" "${CONF[@]}"
+ lvmconf "${CONF[@]}"
+ fi
+}
+
+have_vdo() {
+ lvm segtypes 2>/dev/null | grep 'vdo$' >/dev/null || {
+ echo "VDO is not built-in." >&2
+ return 1
+ }
+ target_at_least dm-vdo "$@"
+}
+
+have_writecache() {
+ lvm segtypes 2>/dev/null | grep 'writecache$' >/dev/null || {
+ echo "writecache is not built-in." >&2
+ return 1
+ }
+ target_at_least dm-writecache "$@"
+}
+
+have_integrity() {
+ lvm segtypes 2>/dev/null | grep 'integrity$' >/dev/null || {
+ echo "integrity is not built-in." >&2
+ return 1
+ }
+ target_at_least dm-integrity "$@"
+}
+
+have_raid() {
+ target_at_least dm-raid "$@"
+
+ # some kernels have broken mdraid bitmaps, don't use them!
+ # may oops kernel, we know for sure all FC24 are currently broken
+ # in general any 4.1, 4.2 is likely useless unless patched
+ case "$(uname -r)" in
+ 4.[12].*fc24*) return 1 ;;
+ esac
+}
+
+have_raid4 () {
+ local r=0
+
+ have_raid 1 8 0 && r=1
+ have_raid 1 9 1 && r=0
+
+ return $r
+}
+
+have_cache() {
+ lvm segtypes 2>/dev/null | grep ' cache-pool$' >/dev/null || {
+ echo "Cache is not built-in." >&2
+ return 1
+ }
+ target_at_least dm-cache "$@"
+
+ declare -a CONF=()
+ # disable cache_check if not present in system
+ if test -n "$LVM_TEST_CACHE_CHECK_CMD" && test ! -x "$LVM_TEST_CACHE_CHECK_CMD" ; then
+ CONF[0]="global/cache_check_executable = \"\""
+ fi
+ if test -n "$LVM_TEST_CACHE_DUMP_CMD" && test ! -x "$LVM_TEST_CACHE_DUMP_CMD" ; then
+ CONF[1]="global/cache_dump_executable = \"\""
+ fi
+ if test -n "$LVM_TEST_CACHE_REPAIR_CMD" && test ! -x "$LVM_TEST_CACHE_REPAIR_CMD" ; then
+ CONF[2]="global/cache_repair_executable = \"\""
+ fi
+ if test ${#CONF[@]} -ne 0 ; then
+ echo "TEST WARNING: Reconfiguring" "${CONF[@]}"
+ lvmconf "${CONF[@]}"
+ fi
+}
+
+have_tool_at_least() {
+ local version
+ version=$("$1" -V 2>/dev/null)
+ version=${version%%-*}
+ version=${version##* }
+ shift
+
+ version_at_least "$version" "$@"
}
# check if lvm shell is build-in (needs readline)
-have_readline()
-{
+have_readline() {
echo version | lvm &>/dev/null
}
-test -f DEVICES && devs=$(cat DEVICES)
+have_multi_core() {
+ which nproc &>/dev/null || return 0
+ [ "$(nproc)" -ne 1 ]
+}
+
+dmsetup_wrapped() {
+ udev_wait
+ dmsetup "$@"
+}
+
+awk_parse_init_count_in_lvmpolld_dump() {
+ printf '%s' \
+ \
+ $'BEGINFILE { x=0; answ=0 }' \
+ $'{' \
+ $'if (/.*{$/) { x++ }' \
+ $'else if (/.*}$/) { x-- }' \
+ $'else if ( x == 2 && $1 ~ "[[:space:]]*"vkey) { value=substr($2, 2); value=substr(value, 1, length(value) - 1); }' \
+ $'if ( x == 2 && value == vvalue && $1 ~ /[[:space:]]*init_requests_count/) { answ=$2 }' \
+ $'if (answ > 0) { exit 0 }' \
+ $'}' \
+ $'END { printf "%d", answ }'
+}
+
+check_lvmpolld_init_rq_count() {
+ local ret
+ ret=$(awk -v vvalue="$2" -v vkey="${3:-lvname}" -F= "$(awk_parse_init_count_in_lvmpolld_dump)" lvmpolld_dump.txt)
+ test "$ret" -eq "$1" || {
+ die "check_lvmpolld_init_rq_count failed. Expected $1, got $ret"
+ }
+}
+
+wait_pvmove_lv_ready() {
+ # given sleep .1 this is about 20 secs of waiting
+ local lvid=()
+ local all
+
+ for i in {100..0}; do
+ if [ -e LOCAL_LVMPOLLD ]; then
+ if test "${#lvid[@]}" -eq "$#" ; then
+ lvmpolld_dump > lvmpolld_dump.txt
+ all=1
+ for l in "${lvid[@]}" ; do
+ check_lvmpolld_init_rq_count 1 "${l##LVM-}" lvid || all=0
+ done
+ test "$all" = 1 && return
+ else
+ # wait till wanted LV really appears
+ lvid=( $(dmsetup info --noheadings -c -o uuid "$@" 2>/dev/null) ) || true
+ fi
+ else
+ dmsetup info -c --noheadings -o tables_loaded "$@" >out 2>/dev/null || true
+ test "$(grep -c Live out)" = "$#" && return
+ fi
+ sleep .1
+ done
+
+ test -e LOCAL_LVMPOLLD && die "Waiting for lvmpolld timed out"
+ die "Waiting for pvmove LV to get activated has timed out"
+}
+
+# Holds device open with sleep which automatically expires after given timeout
+# Prints PID of running holding sleep process in background
+hold_device_open() {
+ local vgname=$1
+ local lvname=$2
+ local sec=${3-20} # default 20sec
+
+ sleep "$sec" < "$DM_DEV_DIR/$vgname/$lvname" >/dev/null 2>&1 &
+ SLEEP_PID=$!
+ # wait till device is openned
+ for i in $(seq 1 50) ; do
+ if test "$(dmsetup info --noheadings -c -o open "$vgname"-"$lvname")" -ne 0 ; then
+ echo "$SLEEP_PID"
+ return
+ fi
+ sleep .1
+ done
+
+ die "$vgname-$lvname expected to be openned, but it's not!"
+}
+
+# return total memory size in kB units
+total_mem() {
+ local a
+ local b
+
+ while IFS=":" read -r a b ; do
+ case "$a" in MemTotal*) echo "${b%% kB}" ; break ;; esac
+ done < /proc/meminfo
+}
+
+kernel_at_least() {
+ version_at_least "$(uname -r)" "$@"
+}
+
+test "${LVM_TEST_AUX_TRACE-0}" = "0" || set -x
+
+test -f DEVICES && devs=$(< DEVICES)
-#unset LVM_VALGRIND
-"$@"
+if test "$1" = "dmsetup" ; then
+ shift
+ dmsetup_wrapped "$@"
+else
+ "$@"
+fi
diff --git a/test/lib/brick-shelltest.h b/test/lib/brick-shelltest.h
new file mode 100644
index 0000000..af28105
--- /dev/null
+++ b/test/lib/brick-shelltest.h
@@ -0,0 +1,1340 @@
+// -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+
+/*
+ * This brick allows you to build a test runner for shell-based functional
+ * tests. It comes with fairly elaborate features (although most are only
+ * available on posix systems), geared toward difficult-to-test software.
+ *
+ * It provides a full-featured "main" function (brick::shelltest::run) that you
+ * can use as a drop-in shell test runner.
+ *
+ * Features include:
+ * - interactive and batch-mode execution
+ * - collects test results and test logs in a simple text-based format
+ * - measures resource use of individual tests
+ * - rugged: suited for running in monitored virtual machines
+ * - supports test flavouring
+ */
+
+/*
+ * (c) 2014 Petr Rockai <me@mornfall.net>
+ * (c) 2014 Red Hat, Inc.
+ */
+
+/* Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE. */
+
+#include <fcntl.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <errno.h>
+
+#include <vector>
+#include <map>
+#include <deque>
+#include <string>
+#include <iostream>
+#include <iomanip>
+#include <fstream>
+#include <sstream>
+#include <cassert>
+#include <iterator>
+#include <algorithm>
+#include <stdexcept>
+
+#include <dirent.h>
+
+#ifdef __unix
+#include <sys/stat.h>
+#include <sys/resource.h> /* rusage */
+#include <sys/select.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/klog.h>
+#include <sys/utsname.h>
+#include <time.h>
+#include <unistd.h>
+#endif
+
+/* Timeout for the whole test suite in hours */
+static const time_t TEST_SUITE_TIMEOUT = 4;
+
+#ifndef BRICK_SHELLTEST_H
+#define BRICK_SHELLTEST_H
+
+namespace brick {
+namespace shelltest {
+
+/* TODO: remove this section in favour of brick-filesystem.h */
+
+inline std::runtime_error syserr( std::string msg, std::string ctx = "" ) {
+ return std::runtime_error( std::string( strerror( errno ) ) + " " + msg + " " + ctx );
+}
+
+struct dir {
+ DIR *d;
+ dir( std::string p ) {
+ d = opendir( p.c_str() );
+ if ( !d )
+ throw syserr( "error opening directory", p );
+ }
+ ~dir() { (void) closedir( d ); }
+};
+
+typedef std::vector< std::string > Listing;
+
+inline void fsync_name( std::string n )
+{
+ int fd = open( n.c_str(), O_WRONLY );
+ if ( fd >= 0 ) {
+ (void) fsync( fd );
+ (void) close( fd );
+ }
+}
+
+inline Listing listdir( std::string p, bool recurse = false, std::string prefix = "" )
+{
+ Listing r;
+
+ dir d( p );
+#if !defined(__GLIBC__) || (__GLIBC__ < 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ < 23))
+ /* readdir_r is deprecated with newer GLIBC */
+ struct dirent entry, *iter = 0;
+ while ( (errno = readdir_r( d.d, &entry, &iter )) == 0 && iter ) {
+ std::string ename( entry.d_name );
+#else
+ struct dirent *entry;
+ errno = 0;
+ while ( (entry = readdir( d.d )) ) {
+ std::string ename( entry->d_name );
+#endif
+
+ if ( ename == "." || ename == ".." )
+ continue;
+
+ if ( recurse ) {
+ struct stat64 stat;
+ std::string s = p + "/" + ename;
+ if ( ::stat64( s.c_str(), &stat ) == -1 ) {
+ errno = 0;
+ continue;
+ }
+ if ( S_ISDIR(stat.st_mode) ) {
+ Listing sl = listdir( s, true, prefix + ename + "/" );
+ for ( Listing::iterator i = sl.begin(); i != sl.end(); ++i )
+ r.push_back( prefix + *i );
+ } else
+ r.push_back( prefix + ename );
+ } else
+ r.push_back( ename );
+ };
+
+ if ( errno != 0 )
+ throw syserr( "error reading directory", p );
+
+ return r;
+}
+
+/* END remove this section */
+
+struct Journal {
+ enum R {
+ STARTED,
+ RETRIED,
+ UNKNOWN,
+ FAILED,
+ INTERRUPTED,
+ KNOWNFAIL,
+ PASSED,
+ SKIPPED,
+ TIMEOUT,
+ WARNED,
+ };
+
+ friend std::ostream &operator<<( std::ostream &o, R r ) {
+ switch ( r ) {
+ case STARTED: return o << "started";
+ case RETRIED: return o << "retried";
+ case FAILED: return o << "failed";
+ case INTERRUPTED: return o << "interrupted";
+ case PASSED: return o << "passed";
+ case SKIPPED: return o << "skipped";
+ case TIMEOUT: return o << "timeout";
+ case WARNED: return o << "warnings";
+ default: return o << "unknown";
+ }
+ }
+
+ friend std::istream &operator>>( std::istream &i, R &r ) {
+ std::string x;
+ i >> x;
+
+ r = UNKNOWN;
+ if ( x == "started" ) r = STARTED;
+ if ( x == "retried" ) r = RETRIED;
+ if ( x == "failed" ) r = FAILED;
+ if ( x == "interrupted" ) r = INTERRUPTED;
+ if ( x == "passed" ) r = PASSED;
+ if ( x == "skipped" ) r = SKIPPED;
+ if ( x == "timeout" ) r = TIMEOUT;
+ if ( x == "warnings" ) r = WARNED;
+ return i;
+ }
+
+ template< typename S, typename T >
+ friend std::istream &operator>>( std::istream &i, std::pair< S, T > &r ) {
+ return i >> r.first >> r.second;
+ }
+
+ typedef std::map< std::string, R > Status;
+ Status status, written;
+
+ std::string location, list;
+ int timeouts;
+
+ void append( std::string path ) {
+ std::ofstream of( path.c_str(), std::fstream::app );
+ Status::iterator writ;
+ for ( Status::iterator i = status.begin(); i != status.end(); ++i ) {
+ writ = written.find( i->first );
+ if ( writ == written.end() || writ->second != i->second )
+ of << i->first << " " << i->second << std::endl;
+ }
+ written = status;
+ of.close();
+ }
+
+ void write( std::string path ) {
+ std::ofstream of( path.c_str() );
+ for ( Status::iterator i = status.begin(); i != status.end(); ++i )
+ of << i->first << " " << i->second << std::endl;
+ of.close();
+ }
+
+ void sync() {
+ append( location );
+ fsync_name( location );
+ write ( list );
+ fsync_name( list );
+ }
+
+ void started( std::string n ) {
+ if ( status.count( n ) && status[ n ] == STARTED )
+ status[ n ] = RETRIED;
+ else
+ status[ n ] = STARTED;
+ sync();
+ }
+
+ void done( std::string n, R r ) {
+ status[ n ] = r;
+ if ( r == TIMEOUT )
+ ++ timeouts;
+ else
+ timeouts = 0;
+ sync();
+ }
+
+ bool done( std::string n ) {
+ if ( !status.count( n ) )
+ return false;
+ return status[ n ] != STARTED && status[ n ] != INTERRUPTED;
+ }
+
+ int count( R r ) {
+ int c = 0;
+ for ( Status::iterator i = status.begin(); i != status.end(); ++i )
+ if ( i->second == r )
+ ++ c;
+ return c;
+ }
+
+ void banner() {
+ std::cout << std::endl << "### " << status.size() << " tests: "
+ << count( PASSED ) << " passed, "
+ << count( SKIPPED ) << " skipped, "
+ << count( TIMEOUT ) << " timed out, " << count( WARNED ) << " warned, "
+ << count( FAILED ) << " failed" << std::endl;
+ }
+
+ void details() {
+ for ( Status::iterator i = status.begin(); i != status.end(); ++i )
+ if ( i->second != PASSED )
+ std::cout << i->second << ": " << i->first << std::endl;
+ }
+
+ void read( std::string n ) {
+ std::ifstream ifs( n.c_str() );
+ typedef std::istream_iterator< std::pair< std::string, R > > It;
+ for ( It i( ifs ); i != It(); ++i )
+ status[ i->first ] = i->second;
+ }
+
+ void read() { read( location ); }
+
+ Journal( std::string dir )
+ : location( dir + "/journal" ),
+ list( dir + "/list" ),
+ timeouts( 0 )
+ {}
+};
+
+struct TimedBuffer {
+ typedef std::pair< time_t, std::string > Line;
+
+ std::deque< Line > data;
+ Line incomplete;
+ bool stamp;
+
+ Line shift( bool force = false ) {
+ Line result = std::make_pair( 0, "" );
+ if ( force && data.empty() )
+ std::swap( result, incomplete );
+ else {
+ result = data.front();
+ data.pop_front();
+ }
+ return result;
+ }
+
+ void push( std::string buf ) {
+ time_t now = stamp ? time( 0 ) : 0;
+ std::string::iterator b = buf.begin(), e = buf.begin();
+
+ while ( e != buf.end() )
+ {
+ e = std::find( b, buf.end(), '\n' );
+ incomplete.second += std::string( b, e );
+
+ if ( !incomplete.first )
+ incomplete.first = now;
+
+ if ( e != buf.end() ) {
+ incomplete.second += "\n";
+ data.push_back( incomplete );
+ if (incomplete.second[0] == '#') {
+ /* Disable timing between '## 0 STACKTRACE' & '## teardown' keywords */
+ if (incomplete.second.find("# 0 STACKTRACE", 1) != std::string::npos ||
+ incomplete.second.find("# timing off", 1) != std::string::npos) {
+ stamp = false;
+ now = 0;
+ } else if (incomplete.second.find("# teardown", 1) != std::string::npos ||
+ incomplete.second.find("# timing on", 1) != std::string::npos) {
+ stamp = true;
+ now = time( 0 );
+ }
+ }
+ incomplete = std::make_pair( now, "" );
+ }
+ b = (e == buf.end() ? e : e + 1);
+ }
+ }
+
+ bool empty( bool force = false ) {
+ if ( force && !incomplete.second.empty() )
+ return false;
+ return data.empty();
+ }
+
+ TimedBuffer() : stamp(true) {}
+};
+
+struct Sink {
+ virtual void outline( bool ) {}
+ virtual void push( std::string x ) = 0;
+ virtual void sync( bool ) {}
+ virtual ~Sink() {}
+};
+
+struct Substitute {
+ typedef std::map< std::string, std::string > Map;
+ std::string testdir; // replace testdir first
+ std::string prefix;
+
+ std::string map( std::string line ) {
+ return line;
+ }
+};
+
+struct Format {
+ time_t start;
+ Substitute subst;
+
+ std::string format( TimedBuffer::Line l ) {
+ std::stringstream result;
+ if ( l.first >= start ) {
+ time_t rel = l.first - start;
+ result << "[" << std::setw( 2 ) << std::setfill( ' ' ) << rel / 60
+ << ":" << std::setw( 2 ) << std::setfill( '0' ) << rel % 60 << "] ";
+ }
+ result << subst.map( l.second );
+ return result.str();
+ }
+
+ Format() : start( time( 0 ) ) {}
+};
+
+struct BufSink : Sink {
+ TimedBuffer data;
+ Format fmt;
+
+ virtual void push( std::string x ) {
+ data.push( x );
+ }
+
+ void dump( std::ostream &o ) {
+ o << std::endl;
+ while ( !data.empty( true ) )
+ o << "| " << fmt.format( data.shift( true ) );
+ }
+};
+
+struct FdSink : Sink {
+ int fd;
+
+ TimedBuffer stream;
+ Format fmt;
+ bool killed;
+
+ virtual void outline( bool force )
+ {
+ TimedBuffer::Line line = stream.shift( force );
+ std::string out = fmt.format( line );
+ if ( write( fd, out.c_str(), out.length() ) < (int)out.length() )
+ perror( "short write" );
+ }
+
+ virtual void sync( bool force ) {
+ if ( killed )
+ return;
+ while ( !stream.empty( force ) )
+ outline( force );
+ }
+
+ virtual void push( std::string x ) {
+ if ( !killed )
+ stream.push( x );
+ }
+
+ FdSink( int _fd ) : fd( _fd ), killed( false ) {}
+};
+
+struct FileSink : FdSink {
+ std::string file;
+ FileSink( std::string n ) : FdSink( -1 ), file( n ) {}
+
+ void sync( bool force ) {
+ if ( fd < 0 && !killed ) {
+#ifdef O_CLOEXEC
+ fd = open( file.c_str(), O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC, 0644 );
+#else
+ fd = open( file.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0644 );
+ if ( fcntl( fd, F_SETFD, FD_CLOEXEC ) < 0 )
+ perror("failed to set FD_CLOEXEC on file");
+#endif
+ if ( fd < 0 )
+ killed = true;
+ }
+ FdSink::sync( force );
+ }
+
+ ~FileSink() {
+ if ( fd >= 0 ) {
+ (void) fsync( fd );
+ (void) close( fd );
+ }
+ }
+};
+
+#define BRICK_SYSLOG_ACTION_READ 2
+#define BRICK_SYSLOG_ACTION_READ_ALL 3
+#define BRICK_SYSLOG_ACTION_READ_CLEAR 4
+#define BRICK_SYSLOG_ACTION_CLEAR 5
+#define BRICK_SYSLOG_ACTION_SIZE_UNREAD 9
+#define BRICK_SYSLOG_ACTION_SIZE_BUFFER 10
+
+struct Source {
+ int fd;
+
+ virtual void sync( Sink *sink ) {
+ ssize_t sz;
+ /* coverity[stack_use_local_overflow] */
+ char buf[ 128 * 1024 ];
+ if ( (sz = read(fd, buf, sizeof(buf) - 1)) > 0 )
+ sink->push( std::string( buf, sz ) );
+
+ /*
+ * On RHEL5 box this code busy-loops here, while
+ * parent process no longer writes anything.
+ *
+ * Unclear why 'select()' is anouncing available
+ * data, while we read 0 bytes with errno == 0.
+ *
+ * Temporarily resolved with usleep() instead of loop.
+ */
+ if (!sz && (!errno || errno == EINTR))
+ usleep(50000);
+
+ if ( sz < 0 && errno != EAGAIN )
+ throw syserr( "reading pipe" );
+ }
+
+ virtual void reset() {}
+
+ virtual int fd_set_( fd_set *set ) {
+ if ( fd >= 0 ) {
+ FD_SET( fd, set );
+ return fd;
+ } else
+ return -1;
+ }
+
+ Source( int _fd = -1 ) : fd( _fd ) {}
+ virtual ~Source() {
+ if ( fd >= 0 )
+ (void) ::close( fd );
+ }
+};
+
+struct FileSource : Source {
+ std::string file;
+ FileSource( std::string n ) : Source( -1 ), file( n ) {}
+
+ int fd_set_( ::fd_set * ) { return -1; } /* reading a file is always non-blocking */
+ void sync( Sink *s ) {
+ if ( fd < 0 ) {
+#ifdef O_CLOEXEC
+ fd = open( file.c_str(), O_RDONLY | O_CLOEXEC | O_NONBLOCK );
+#else
+ fd = open( file.c_str(), O_RDONLY | O_NONBLOCK );
+ if ( fcntl( fd, F_SETFD, FD_CLOEXEC ) < 0 )
+ perror("failed to set FD_CLOEXEC on file");
+#endif
+ if ( fd >= 0 )
+ lseek( fd, 0, SEEK_END );
+ }
+ if ( fd >= 0 )
+ try {
+ Source::sync( s );
+ } catch (...) {
+ perror("failed to sync");
+ }
+ }
+};
+
+struct KMsg : Source {
+ bool can_clear;
+ ssize_t buffer_size;
+
+ KMsg() : can_clear( strcmp(getenv("LVM_TEST_CAN_CLOBBER_DMESG") ? : "0", "0") ),
+ buffer_size(128 * 1024)
+ {
+#ifdef __unix
+ struct utsname uts;
+ unsigned kmaj, kmin, krel;
+ const char *read_msg = "/dev/kmsg";
+
+ // Can't use kmsg on kernels pre 3.5, read /var/log/messages
+ if ( ( ::uname(&uts) == 0 ) &&
+ ( ::sscanf( uts.release, "%u.%u.%u", &kmaj, &kmin, &krel ) == 3 ) &&
+ ( ( kmaj < 3 ) || ( ( kmaj == 3 ) && ( kmin < 5 ) ) ) )
+ can_clear = false, read_msg = "/var/log/messages";
+
+ if ( ( fd = open(read_msg, O_RDONLY | O_NONBLOCK)) < 0 ) {
+ if ( errno != ENOENT ) /* Older kernels (<3.5) do not support /dev/kmsg */
+ fprintf( stderr, "open log %s %s\n", read_msg, strerror( errno ) );
+ if ( can_clear && ( klogctl( BRICK_SYSLOG_ACTION_CLEAR, 0, 0 ) < 0 ) )
+ can_clear = false;
+ } else if ( lseek( fd, 0L, SEEK_END ) == (off_t) -1 ) {
+ fprintf( stderr, "lseek log %s %s\n", read_msg, strerror( errno ) );
+ (void) close(fd);
+ fd = -1;
+ }
+#endif
+ }
+
+ bool dev_kmsg() {
+ return fd >= 0;
+ }
+
+ void sync( Sink *s ) {
+#ifdef __unix
+ ssize_t sz;
+ char buf[ buffer_size ];
+
+ if ( dev_kmsg() ) {
+ while ( (sz = ::read(fd, buf, buffer_size)) > 0 )
+ s->push( std::string( buf, sz ) );
+ } else if ( can_clear ) {
+ while ( ( sz = klogctl( BRICK_SYSLOG_ACTION_READ_CLEAR, buf,
+ ( int) buffer_size ) ) > 0 )
+ s->push( std::string( buf, sz ) );
+ if ( sz < 0 && errno == EPERM )
+ can_clear = false;
+ }
+#endif
+ }
+};
+
+struct Observer : Sink {
+ TimedBuffer stream;
+
+ bool warnings;
+ Observer() : warnings( false ) {}
+
+ void push( std::string s ) {
+ stream.push( s );
+ }
+
+ void sync( bool force ) {
+ while ( !stream.empty( force ) ) {
+ TimedBuffer::Line line = stream.shift( force );
+ if ( line.second.find( "TEST WARNING" ) != std::string::npos )
+ warnings = true;
+ }
+ }
+};
+
+struct IO : Sink {
+ typedef std::vector< Sink* > Sinks;
+ typedef std::vector< Source* > Sources;
+
+ mutable Sinks sinks;
+ mutable Sources sources;
+
+ Observer *_observer;
+
+ virtual void push( std::string x ) {
+ for ( Sinks::iterator i = sinks.begin(); i != sinks.end(); ++i )
+ (*i)->push( x );
+ }
+
+ void sync( bool force ) {
+ for ( Sources::iterator i = sources.begin(); i != sources.end(); ++i )
+ (*i)->sync( this );
+
+ for ( Sinks::iterator i = sinks.begin(); i != sinks.end(); ++i )
+ (*i)->sync( force );
+ }
+
+ void close() {
+ for ( Sources::iterator i = sources.begin(); i != sources.end(); ++i )
+ delete *i;
+ sources.clear();
+ }
+
+ int fd_set_( fd_set *set ) {
+ int max = -1;
+
+ for ( Sources::iterator i = sources.begin(); i != sources.end(); ++i )
+ max = std::max( (*i)->fd_set_( set ), max );
+ return max + 1;
+ }
+
+ Observer &observer() { return *_observer; }
+
+ IO() {
+ clear();
+ }
+
+ /* a stealing copy constructor */
+ IO( const IO &io ) : sinks( io.sinks ), sources( io.sources ), _observer( io._observer )
+ {
+ io.sinks.clear();
+ io.sources.clear();
+ }
+
+ IO &operator= ( const IO &io ) {
+ this->~IO();
+ return *new (this) IO( io );
+ }
+
+ void clear( int to_push = 1 ) {
+ for ( Sinks::iterator i = sinks.begin(); i != sinks.end(); ++i )
+ delete *i;
+ sinks.clear();
+ if ( to_push )
+ sinks.push_back( _observer = new Observer );
+ }
+
+ ~IO() { close(); clear(0); }
+
+};
+
+namespace {
+pid_t kill_pid = 0;
+bool fatal_signal = false;
+bool interrupt = false;
+}
+
+struct Options {
+ bool verbose, batch, interactive, cont, fatal_timeouts, kmsg;
+ std::string testdir, outdir, workdir, heartbeat;
+ std::vector< std::string > flavours, filter, skip, watch;
+ std::string flavour_envvar;
+ int timeout;
+ Options() : verbose( false ), batch( false ), interactive( false ),
+ cont( false ), fatal_timeouts( false ), kmsg( true ),
+ timeout( 180 ) {}
+};
+
+struct TestProcess
+{
+ std::string filename;
+ bool interactive;
+ int fd;
+
+ void exec() __attribute__ ((noreturn)) {
+ assert( fd >= 0 );
+ if ( !interactive ) {
+ int devnull = ::open( "/dev/null", O_RDONLY );
+ if ( devnull >= 0 ) { /* gcc really doesn't like to not have stdin */
+ (void) dup2( devnull, STDIN_FILENO );
+ (void) close( devnull );
+ } else
+ (void) close( STDIN_FILENO );
+ (void) dup2( fd, STDOUT_FILENO );
+ (void) dup2( fd, STDERR_FILENO );
+ (void) close( fd );
+ }
+
+ setpgid( 0, 0 );
+
+ execlp( "bash", "bash", "-noprofile", "-norc", filename.c_str(), NULL );
+ perror( "execlp" );
+ _exit( 202 );
+ }
+
+ TestProcess( std::string file )
+ : filename( file ), interactive( false ), fd( -1 )
+ {}
+};
+
+struct TestCase {
+ TestProcess child;
+ std::string name, flavour;
+ IO io;
+ BufSink *iobuf;
+
+ struct rusage usage;
+ int status;
+ bool timeout;
+ pid_t pid;
+
+ time_t start, end, silent_start, last_update, last_heartbeat;
+ Options options;
+
+ Journal *journal;
+
+ std::string pretty() {
+ if ( options.batch )
+ return flavour + ": " + name;
+ return "[" + flavour + "] " + name;
+ }
+
+ std::string id() {
+ return flavour + ":" + name;
+ }
+
+ void pipe() {
+ int fds[2] = { 0 };
+
+ if (socketpair( PF_UNIX, SOCK_STREAM, 0, fds )) {
+ perror("socketpair");
+ exit(201);
+ }
+
+#if 0
+ if (fcntl( fds[0], F_SETFL, O_NONBLOCK ) == -1) {
+ perror("fcntl on socket");
+ exit(202);
+ }
+#endif
+
+ io.sources.push_back( new Source( fds[0] ) );
+ child.fd = fds[1];
+ child.interactive = options.interactive;
+ }
+
+ bool monitor() {
+ end = time( 0 );
+
+ /* heartbeat */
+ if ( end - last_heartbeat >= 20 && !options.heartbeat.empty() ) {
+ std::ofstream hb( options.heartbeat.c_str(), std::fstream::app );
+ hb << ".";
+ hb.close();
+ fsync_name( options.heartbeat );
+ last_heartbeat = end;
+ }
+
+ if ( wait4(pid, &status, WNOHANG, &usage) != 0 ) {
+ io.sync( true );
+ return false;
+ }
+
+ /* kill off tests after a timeout silence */
+ if ( !options.interactive )
+ if ( end - silent_start > options.timeout ) {
+ kill( pid, SIGINT );
+ sleep( 5 ); /* wait a bit for a reaction */
+ if ( waitpid( pid, &status, WNOHANG ) == 0 ) {
+ system( "echo t > /proc/sysrq-trigger 2> /dev/null" );
+ kill( -pid, SIGKILL );
+ (void) waitpid( pid, &status, 0 );
+ }
+ timeout = true;
+ io.sync( true );
+ return false;
+ }
+
+ struct timeval wait;
+ fd_set set;
+
+ FD_ZERO( &set );
+ int nfds = io.fd_set_( &set );
+ wait.tv_sec = 0;
+ wait.tv_usec = 500000; /* timeout 0.5s */
+
+ if ( !options.verbose && !options.interactive && !options.batch ) {
+ if ( end - last_update >= 1 ) {
+ progress( Update ) << tag( "running" ) << pretty() << " "
+ << end - start << std::flush;
+ last_update = end;
+ }
+ }
+ if ( select( nfds, &set, NULL, NULL, &wait ) > 0 ) {
+ silent_start = end; /* something happened */
+ io.sync( false );
+ }
+
+ return true;
+ }
+
+ std::string timefmt( time_t t ) {
+ std::stringstream ss;
+ ss << t / 60 << ":" << std::setw( 2 ) << std::setfill( '0' ) << t % 60;
+ return ss.str();
+ }
+
+ std::string rusage()
+ {
+ std::stringstream ss;
+ time_t wall = end - start, user = usage.ru_utime.tv_sec,
+ system = usage.ru_stime.tv_sec;
+ size_t rss = usage.ru_maxrss / 1024,
+ inb = usage.ru_inblock / 100,
+ outb = usage.ru_oublock / 100;
+
+ size_t inb_10 = inb % 10, outb_10 = outb % 10;
+ inb /= 10; outb /= 10;
+
+ ss << timefmt( wall ) << " wall " << timefmt( user ) << " user "
+ << timefmt( system ) << " sys " << std::setw( 3 ) << rss << "M RSS | "
+ << "IOPS: " << std::setw( 5 ) << inb << "." << inb_10 << "K in "
+ << std::setw( 5 ) << outb << "." << outb_10 << "K out";
+ return ss.str();
+ }
+
+ std::string tag( std::string n ) {
+ if ( options.batch )
+ return "## ";
+ size_t pad = n.length();
+ pad = (pad < 12) ? 12 - pad : 0;
+ return "### " + std::string( pad, ' ' ) + n + ": ";
+ }
+
+ std::string tag( Journal::R r ) {
+ std::stringstream s;
+ s << r;
+ return tag( s.str() );
+ }
+
+ enum P { First, Update, Last };
+
+ std::ostream &progress( P p = Last )
+ {
+ static struct : std::streambuf {} buf;
+ static std::ostream null(&buf);
+
+ if ( options.batch && p == First )
+ return std::cout;
+
+ if ( isatty( STDOUT_FILENO ) && !options.batch ) {
+ if ( p != First )
+ return std::cout << "\r";
+ return std::cout;
+ }
+
+ if ( p == Last )
+ return std::cout;
+
+ return null;
+ }
+
+ void parent()
+ {
+ (void) ::close( child.fd );
+ setupIO();
+
+ journal->started( id() );
+ silent_start = start = time( 0 );
+
+ progress( First ) << tag( "running" ) << pretty() << std::flush;
+ if ( options.verbose || options.interactive )
+ progress() << std::endl;
+
+ while ( monitor() )
+ /* empty */ ;
+
+ Journal::R r = Journal::UNKNOWN;
+
+ if ( timeout ) {
+ r = Journal::TIMEOUT;
+ } else if ( WIFEXITED( status ) ) {
+ if ( WEXITSTATUS( status ) == 0 )
+ r = Journal::PASSED;
+ else if ( WEXITSTATUS( status ) == 200 )
+ r = Journal::SKIPPED;
+ else
+ r = Journal::FAILED;
+ } else if ( interrupt && WIFSIGNALED( status ) && WTERMSIG( status ) == SIGINT )
+ r = Journal::INTERRUPTED;
+ else
+ r = Journal::FAILED;
+
+ if ( r == Journal::PASSED && io.observer().warnings )
+ r = Journal::WARNED;
+
+ io.close();
+
+ if ( iobuf && ( r == Journal::FAILED || r == Journal::TIMEOUT ) )
+ iobuf->dump( std::cout );
+
+ journal->done( id(), r );
+
+ if ( options.batch ) {
+ int spaces = std::max( 64 - int(pretty().length()), 0 );
+ progress( Last ) << " " << std::string( spaces, '.' ) << " "
+ << std::left << std::setw( 9 ) << std::setfill( ' ' ) << r;
+ if ( r != Journal::SKIPPED )
+ progress( First ) << " " << rusage();
+ progress( Last ) << std::endl;
+ } else
+ progress( Last ) << tag( r ) << pretty() << std::endl;
+
+ io.clear();
+ }
+
+ void run() {
+ pipe();
+ pid = kill_pid = fork();
+ if (pid < 0) {
+ perror("Fork failed.");
+ exit(201);
+ } else if (pid == 0) {
+ io.close();
+ (void) chdir( options.workdir.c_str() );
+ if ( !options.flavour_envvar.empty() )
+ (void) setenv( options.flavour_envvar.c_str(), flavour.c_str(), 1 );
+ child.exec();
+ } else {
+ parent();
+ }
+ }
+
+ void setupIO() {
+ iobuf = 0;
+ if ( options.verbose || options.interactive )
+ io.sinks.push_back( new FdSink( 1 ) );
+ else if ( !options.batch )
+ io.sinks.push_back( iobuf = new BufSink() );
+
+ std::string n = id();
+ std::replace( n.begin(), n.end(), '/', '_' );
+ std::string fn = options.outdir + "/" + n + ".txt";
+ io.sinks.push_back( new FileSink( fn ) );
+
+ for ( std::vector< std::string >::iterator i = options.watch.begin();
+ i != options.watch.end(); ++i )
+ io.sources.push_back( new FileSource( *i ) );
+ if ( options.kmsg )
+ io.sources.push_back( new KMsg );
+ }
+
+ TestCase( Journal &j, Options opt, std::string path, std::string _name, std::string _flavour )
+ : child( path ), name( _name ), flavour( _flavour ),
+ iobuf( NULL ), usage( (struct rusage) { { 0 } } ), status( 0 ), timeout( false ),
+ pid( 0 ), start( 0 ), end( 0 ), silent_start( 0 ),
+ last_update( 0 ), last_heartbeat( 0 ), options( opt ), journal( &j )
+ {
+ }
+};
+
+struct Main {
+ bool die;
+ time_t start;
+
+ typedef std::vector< TestCase > Cases;
+ typedef std::vector< std::string > Flavours;
+
+ Journal journal;
+ Options options;
+ Cases cases;
+
+ void setup() {
+ bool filter;
+ Listing l = listdir( options.testdir, true );
+ std::sort( l.begin(), l.end() );
+
+ for ( Flavours::iterator flav = options.flavours.begin();
+ flav != options.flavours.end(); ++flav ) {
+
+ for ( Listing::iterator i = l.begin(); i != l.end(); ++i ) {
+ if ( ( i->length() < 3 ) || ( i->substr( i->length() - 3, i->length() ) != ".sh" ) )
+ continue;
+ if ( i->substr( 0, 4 ) == "lib/" )
+ continue;
+
+ if (!options.filter.empty()) {
+ filter = true;
+ for ( std::vector< std::string >::iterator filt = options.filter.begin();
+ filt != options.filter.end(); ++filt ) {
+ if ( i->find( *filt ) != std::string::npos ) {
+ filter = false;
+ break;
+ }
+ }
+ if ( filter )
+ continue;
+ }
+
+ if (!options.skip.empty()) {
+ filter = false;
+ for ( std::vector< std::string >::iterator filt = options.skip.begin();
+ filt != options.skip.end(); ++filt ) {
+ if ( i->find( *filt ) != std::string::npos ) {
+ filter = true;
+ break;
+ }
+ }
+ if ( filter )
+ continue;
+ }
+
+ cases.push_back( TestCase( journal, options, options.testdir + *i, *i, *flav ) );
+ cases.back().options = options;
+ }
+ }
+
+ if ( options.cont )
+ journal.read();
+ else
+ (void) ::unlink( journal.location.c_str() );
+ }
+
+ int run() {
+ setup();
+ start = time( 0 );
+ std::cerr << "running " << cases.size() << " tests" << std::endl;
+
+ for ( Cases::iterator i = cases.begin(); i != cases.end(); ++i ) {
+
+ if ( options.cont && journal.done( i->id() ) )
+ continue;
+
+ i->run();
+
+ if ( options.fatal_timeouts && journal.timeouts >= 2 ) {
+ journal.started( i->id() ); // retry the test on --continue
+ std::cerr << "E: Hit 2 timeouts in a row with --fatal-timeouts" << std::endl;
+ std::cerr << "Suspending (please restart the VM)." << std::endl;
+ sleep( 3600 );
+ die = 1;
+ }
+
+ if ( time(0) - start > (TEST_SUITE_TIMEOUT * 3600) ) {
+ std::cerr << TEST_SUITE_TIMEOUT << " hours passed, giving up..." << std::endl;
+ die = 1;
+ }
+
+ if ( die || fatal_signal )
+ break;
+ }
+
+ journal.banner();
+ if ( die || fatal_signal )
+ return 1;
+
+ return journal.count( Journal::FAILED ) || journal.count( Journal::TIMEOUT ) ? 1 : 0;
+ }
+
+ Main( Options o ) : die( false ), start( 0 ), journal( o.outdir ), options( o ) {}
+};
+
+namespace {
+
+void handler( int sig ) {
+ signal( sig, SIG_DFL ); /* die right away next time */
+ if ( kill_pid > 0 )
+ kill( -kill_pid, sig );
+ fatal_signal = true;
+ if ( sig == SIGINT )
+ interrupt = true;
+}
+
+void setup_handlers() {
+ /* set up signal handlers */
+ for ( int i = 0; i <= 32; ++i )
+ switch (i) {
+ case SIGCHLD: case SIGWINCH: case SIGURG:
+ case SIGKILL: case SIGSTOP: break;
+ default: signal(i, handler);
+ }
+}
+
+}
+
+/* TODO remove in favour of brick-commandline.h */
+struct Args {
+ typedef std::vector< std::string > V;
+ V args;
+
+ Args( int argc, const char **argv ) {
+ for ( int i = 1; i < argc; ++ i )
+ args.push_back( argv[ i ] );
+ }
+
+ bool has( std::string fl ) {
+ return std::find( args.begin(), args.end(), fl ) != args.end();
+ }
+
+ // TODO: This does not handle `--option=VALUE`:
+ std::string opt( std::string fl ) {
+ V::iterator i = std::find( args.begin(), args.end(), fl );
+ if ( i == args.end() || i + 1 == args.end() )
+ return "";
+ return *(i + 1);
+ }
+};
+
+namespace {
+
+bool hasenv( const char *name ) {
+ const char *v = getenv( name );
+ if ( !v )
+ return false;
+ if ( strlen( v ) == 0 || !strcmp( v, "0" ) )
+ return false;
+ return true;
+}
+
+template< typename C >
+void split( std::string s, C &c ) {
+ std::stringstream ss( s );
+ std::string item;
+ while ( std::getline( ss, item, ',' ) )
+ c.push_back( item );
+}
+
+}
+
+const char *DEF_FLAVOURS="ndev-vanilla";
+
+std::string resolve_path(std::string a_path, const char *default_path=".")
+{
+ char temp[PATH_MAX];
+ const char *p;
+ p = a_path.empty() ? default_path : a_path.c_str();
+ if ( !realpath( p, temp ) )
+ throw syserr( "Failed to resolve path", p );
+ return temp;
+}
+
+static int run( int argc, const char **argv, std::string fl_envvar = "TEST_FLAVOUR" )
+{
+ Args args( argc, argv );
+ Options opt;
+
+ if ( args.has( "--help" ) ) {
+ std::cout <<
+ " lvm2-testsuite - Run a lvm2 testsuite.\n\n"
+ "lvm2-testsuite"
+ "\n\t"
+ " [--flavours FLAVOURS]"
+ " [--only TESTS]"
+ "\n\t"
+ " [--outdir OUTDIR]"
+ " [--testdir TESTDIR]"
+ " [--workdir WORKDIR]"
+ "\n\t"
+ " [--batch|--verbose|--interactive]"
+ "\n\t"
+ " [--fatal-timeouts]"
+ " [--continue]"
+ " [--heartbeat]"
+ " [--watch WATCH]"
+ " [--timeout TIMEOUT]"
+ " [--nokmsg]\n\n"
+ /* TODO: list of flavours:
+ "lvm2-testsuite"
+ "\n\t"
+ " --list-flavours [--testdir TESTDIR]"
+ */
+ "\n\n"
+ "OPTIONS:\n\n"
+ // TODO: looks like this could be worth a man page...
+ "Filters:\n"
+ " --flavours FLAVOURS\n\t\t- comma separated list of flavours to run.\n\t\t For the list of flavours see `$TESTDIR/lib/flavour-*`.\n\t\t Default: \"" << DEF_FLAVOURS << "\".\n"
+ " --only TESTS\t- comma separated list of tests to run. Default: All tests.\n"
+ "\n"
+ "Directories:\n"
+ " --testdir TESTDIR\n\t\t- directory where tests reside. Default: \"" TESTSUITE_DATA "\".\n"
+ " --workdir WORKDIR\n\t\t- directory to change to when running tests.\n\t\t This is directory containing testing libs. Default: TESTDIR.\n"
+ " --outdir OUTDIR\n\t\t- directory where all the output files should go. Default: \".\".\n"
+ "\n"
+ "Formatting:\n"
+ " --batch\t- Brief format for automated runs.\n"
+ " --verbose\t- More verbose format for automated runs displaying progress on stdout.\n"
+ " --interactive\t- Verbose format for interactive runs.\n"
+ "\n"
+ "Other:\n"
+ " --fatal-timeouts\n\t\t- exit after encountering 2 timeouts in a row.\n"
+ " --continue\t- If set append to journal. Otherwise it will be overwritten.\n"
+ " --heartbeat HEARTBEAT\n\t\t- Name of file to update periodicaly while running.\n"
+ " --watch WATCH\t- Comma separated list of files to watch and print.\n"
+ " --timeout TIMEOUT\n\t\t- Period of silence in seconds considered a timeout. Default: 180.\n"
+ " --nokmsg\t- Do not try to read kernel messages.\n"
+ "\n\n"
+ "ENV.VARIABLES:\n\n"
+ " T\t\t- see --only\n"
+ " INTERACTIVE\t- see --interactive\n"
+ " VERBOSE\t- see --verbose\n"
+ " BATCH\t\t- see --batch\n"
+ " LVM_TEST_CAN_CLOBBER_DMESG\n\t\t- when set and non-empty tests are allowed to flush\n\t\t kmsg in an attempt to read it."
+ "\n\n"
+ "FORMATS:\n\n"
+ "When multiple formats are specified interactive overrides verbose\n"
+ "which overrides batch. Command line options override environment\n"
+ "variables.\n\n"
+ ;
+ return 0;
+ }
+
+ opt.flavour_envvar = fl_envvar;
+
+ if ( args.has( "--continue" ) )
+ opt.cont = true;
+
+ if ( args.has( "--only" ) )
+ split( args.opt( "--only" ), opt.filter );
+ else if ( hasenv( "T" ) )
+ split( getenv( "T" ), opt.filter );
+
+ if ( args.has( "--skip" ) )
+ split( args.opt( "--skip" ), opt.skip );
+ else if ( hasenv( "S" ) )
+ split( getenv( "S" ), opt.skip );
+
+ if ( args.has( "--fatal-timeouts" ) )
+ opt.fatal_timeouts = true;
+
+ if ( args.has( "--heartbeat" ) )
+ opt.heartbeat = args.opt( "--heartbeat" );
+
+ if ( args.has( "--batch" ) || args.has( "--verbose" ) || args.has( "--interactive" ) ) {
+ if ( args.has( "--batch" ) ) {
+ opt.verbose = false;
+ opt.batch = true;
+ }
+
+ if ( args.has( "--verbose" ) ) {
+ opt.batch = false;
+ opt.verbose = true;
+ }
+
+ if ( args.has( "--interactive" ) ) {
+ opt.verbose = false;
+ opt.batch = false;
+ opt.interactive = true;
+ }
+ } else {
+ if ( hasenv( "BATCH" ) ) {
+ opt.verbose = false;
+ opt.batch = true;
+ }
+
+ if ( hasenv( "VERBOSE" ) ) {
+ opt.batch = false;
+ opt.verbose = true;
+ }
+
+ if ( hasenv( "INTERACTIVE" ) ) {
+ opt.verbose = false;
+ opt.batch = false;
+ opt.interactive = true;
+ }
+ }
+
+ if ( args.has( "--flavours" ) )
+ split( args.opt( "--flavours" ), opt.flavours );
+ else
+ split( DEF_FLAVOURS, opt.flavours );
+
+ if ( args.has( "--watch" ) )
+ split( args.opt( "--watch" ), opt.watch );
+
+ if ( args.has( "--timeout" ) )
+ opt.timeout = atoi( args.opt( "--timeout" ).c_str() );
+
+ if ( args.has( "--nokmsg" ) )
+ opt.kmsg = false;
+
+ opt.testdir = resolve_path( args.opt( "--testdir" ), TESTSUITE_DATA ) + "/";
+ opt.workdir = resolve_path( args.opt( "--workdir" ), opt.testdir.c_str() );
+ opt.outdir = resolve_path( args.opt( "--outdir" ), "." );
+
+ setup_handlers();
+
+ Main main( opt );
+ return main.run();
+}
+
+}
+}
+
+#endif
+
+#ifdef BRICK_DEMO
+
+int main( int argc, const char **argv ) {
+ return brick::shelltest::run( argc, argv );
+}
+
+#endif
+
+// vim: syntax=cpp tabstop=4 shiftwidth=4 expandtab
diff --git a/test/lib/check.sh b/test/lib/check.sh
index 6b7849f..1f26194 100644
--- a/test/lib/check.sh
+++ b/test/lib/check.sh
@@ -1,5 +1,5 @@
-#!/bin/bash
-# Copyright (C) 2010-2012 Red Hat, Inc. All rights reserved.
+#!/usr/bin/env bash
+# Copyright (C) 2010-2013 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
@@ -7,7 +7,7 @@
#
# 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
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
# check.sh: assert various things about volumes
@@ -25,7 +25,8 @@
test -z "$BASH" || set -e -o pipefail
die() {
- echo "$@" >&2
+ rm -f debug.log
+ echo -e "$@" >&2
return 1
}
@@ -39,36 +40,71 @@ lvdevices() {
mirror_images_redundant() {
local vg=$1
- local lv=$vg/$2
- lvs -a $vg -o+devices
- for i in $(lvdevices $lv); do
+ local lv="$vg/$2"
+ for i in $(lvdevices "$lv"); do
echo "# $i:"
- lvdevices $vg/$i | sort | uniq
+ 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 || \
+ test "$(wc -l < check.tmp)" -eq 0 || \
die "mirror images of $lv expected redundant, but are not:" \
- $(cat check.tmp.all)
+ "$(cat check.tmp.all)"
}
+lv_err_list_() {
+ (echo "$2" | not grep -m 1 -q "$1") || \
+ echo "$3 on [ $(echo "$2" | grep "$1" | cut -b3- | tr '\n' ' ')] "
+}
+
+lv_on_diff_() {
+ declare -a xdevs=("${!1}") # pass in shell array
+ local expect=( "${@:4}" ) # make an array starting from 4th args...
+ local diff_e
+
+ # Find diff between 2 shell arrays, print them as stdin files
+ printf "%s\\n" "${expect[@]}" | sort | uniq >_lv_on_diff1
+ printf "%s\\n" "${xdevs[@]}" >_lv_on_diff2
+ diff_e=$(diff _lv_on_diff1 _lv_on_diff2) ||
+ die "LV $2/$3 $(lv_err_list_ "^>" "${diff_e}" found)$(lv_err_list_ "^<" "${diff_e}" "not found")."
+}
+
+# list devices for given LV
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)
+ local devs
+
+ devs=( $(lvdevices "$1/$2" | sort | uniq ) )
+
+ lv_on_diff_ devs[@] "$@"
}
+# list devices for given LV and all its subdevices
+lv_tree_on() {
+ local devs
+
+ # Get sorted list of devices
+ devs=( $(get lv_tree_devices "$1" "$2") )
+
+ lv_on_diff_ devs[@] "$@"
+}
+
+# Test if all mimage_X LV legs are sitting on given ordered list of PVs
+# When LV is composed of imagetmp, such leg is decomposed so only
+# real _mimage LVs are always checked
mirror_images_on() {
local vg=$1
local lv=$2
shift 2
- for i in $(lvdevices $lv); do
- lv_on $vg $lv $1
+ local mimages=()
+ local line
+
+ while IFS= read -r line ; do
+ mimages+=( "$line" )
+ done < <( get lv_field_lv_ "$vg" lv_name -a | grep "${lv}_mimage_" )
+
+ for i in "${mimages[@]}"; do
+ lv_on "$vg" "$i" "$1"
shift
done
}
@@ -78,170 +114,263 @@ mirror_log_on() {
local lv=$2
local where=$3
if test "$where" = "core"; then
- get lv_field $vg/$lv mirror_log | not grep mlog
+ get lv_field "$vg/$lv" mirror_log | not grep mlog
else
- lv_on $vg ${lv}_mlog "$where"
+ lv_on "$vg" "${lv}_mlog" "$where"
fi
}
lv_is_contiguous() {
- local lv=$1/$2
- test $(lvl --segments $lv | wc -l) -eq 1 || \
+ 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)
+ "$(lvl --segments "$lv")"
}
lv_is_clung() {
- local lv=$1/$2
- test $(lvdevices $lv | sort | uniq | wc -l) -eq 1 || \
+ 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)
+ "$(lvdevices "$lv" | sort | uniq)"
}
mirror_images_contiguous() {
- for i in $(lvdevices $1/$2); do
- lv_is_contiguous $1 $i
+ 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
+ for i in $(lvdevices "$1/$2"); do
+ lv_is_clung "$1" "$i"
done
}
mirror() {
mirror_nonredundant "$@"
- mirror_images_redundant $1 $2
+ 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
+ local lv="$1/$2"
+ local attr
+ attr=$(get lv_field "$lv" attr)
+ (echo "$attr" | grep "^......m...$" >/dev/null) || {
+ if (echo "$attr" | grep "^o.........$" >/dev/null) &&
+ lvs -a "$1" | grep -F "[${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)
+ "$(lvs "$lv")"
fi
}
- test -z "$3" || mirror_log_on $1 $2 "$3"
+ test -z "$3" || mirror_log_on "$1" "$2" "$3"
}
mirror_legs() {
- local expect=$3
- test "$expect" -eq $(lvdevices $1/$2 | wc -w)
+ local expect_legs=$3
+ test "$expect_legs" -eq "$(lvdevices "$1/$2" | wc -w)"
}
mirror_no_temporaries() {
local vg=$1
local lv=$2
- (lvl -o name $vg | grep $lv | not grep "tmp") || \
+ (lvl -o name "$vg" | grep "$lv" | not grep "tmp") || \
die "$lv has temporary mirror images unexpectedly:" \
- $(lvl $vg | grep $lv)
+ "$(lvl "$vg" | grep "$lv")"
}
linear() {
- local lv=$1/$2
- test $(get lv_field $lv stripes -a) -eq 1 || \
+ local lv="$1/$2"
+ test "$(get lv_field "$lv" stripes -a)" -eq 1 || \
die "$lv expected linear, but is not:" \
- $(lvl $lv -o+devices)
+ "$(lvl "$lv" -o+devices)"
}
-# in_sync <VG> <LV>
+# in_sync <VG> <LV> <ignore 'a'>
# Works for "mirror" and "raid*"
in_sync() {
local a
local b
+ local c
local idx
local type
+ local snap=""
local lvm_name="$1/$2"
- local dm_name=$(echo $lvm_name | sed s:-:--: | sed s:/:-:)
+ local ignore_a=${3:-0}
+ local dm_name="$1-$2"
- if ! a=(`dmsetup status $dm_name`); then
+ a=( $(dmsetup status "$dm_name") ) || \
die "Unable to get sync status of $1"
- elif [ ${a[2]} = "snapshot-origin" ]; then
- if ! a=(`dmsetup status ${dm_name}-real`); then
+
+ if [ "${a[2]}" = "snapshot-origin" ]; then
+ a=( $(dmsetup status "${dm_name}-real") ) || \
die "Unable to get sync status of $1"
- fi
+ snap=": under snapshot"
fi
- if [ ${a[2]} = "raid" ]; then
- # Last argument is the sync ratio for RAID
- idx=$((${#a[@]} - 1))
+ case "${a[2]}" in
+ "raid")
+ # 6th argument is the sync ratio for RAID
+ idx=6
type=${a[3]}
- elif [ ${a[2]} = "mirror" ]; then
+ if [ "${a[$(( idx + 1 ))]}" != "idle" ]; then
+ echo "$lvm_name ($type$snap) is not in-sync " "${a[@]}"
+ return 1
+ fi
+ ;;
+ "mirror")
# 4th Arg tells us how far to the sync ratio
- idx=$((${a[3]} + 4))
+ idx=$(( a[3] + 4 ))
type=${a[2]}
- else
+ ;;
+ *)
die "Unable to get sync ratio for target type '${a[2]}'"
- fi
+ ;;
+ esac
- b=( $(echo ${a[$idx]} | sed s:/:' ':) )
+ b=${a[$idx]%%/*} # split ratio x/y
+ c=${a[$idx]##*/}
- if [ ${b[0]} != ${b[1]} ]; then
- echo "$lvm_name ($type) is not in-sync"
+ if [ "$b" -eq 0 ] || [ "$b" != "$c" ]; then
+ echo "$lvm_name ($type$snap) is not in-sync " "${a[@]}"
return 1
fi
- if [[ ${a[$(($idx - 1))]} =~ a ]]; then
- die "$lvm_name in-sync, but 'a' characters in health status"
+ if [[ ${a[$(( idx - 1 ))]} =~ a ]] ; then
+ [ "$ignore_a" = 0 ] && \
+ die "$lvm_name ($type$snap) in-sync, but 'a' characters in health status"
+ echo "$lvm_name ($type$snap) is not in-sync " "${a[@]}"
+ [ "$ignore_a" = 1 ] && return 0
+ return 1
fi
- echo "$lvm_name ($type) is in-sync"
- return 0
+ echo "$lvm_name ($type$snap) is in-sync " "${a[@]}"
}
active() {
- local lv=$1/$2
- (get lv_field $lv attr | grep "^....a....$" >/dev/null) || \
+ 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 ||
+ "$(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) || \
+ 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!"
+ "$(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=
+ declare -a list=()
while [ $# -gt 1 ]; do
shift
- lv="$lv $vg/$1"
+ list+=( "$vg/$1" )
done
- lvl $lv &>/dev/null || \
- die "$lv expected to exist but does not"
+ test "${#list[@]}" -gt 0 || list=( "$vg" )
+ lvl "${list[@]}" &>/dev/null || \
+ die "${list[@]}" "expected to exist, but does not!"
+}
+
+lv_not_exists() {
+ local vg=$1
+ if test $# -le 1 ; then
+ if lvl "$vg" &>/dev/null ; then
+ die "$vg expected to not exist but it does!"
+ fi
+ else
+ while [ $# -gt 1 ]; do
+ shift
+ not lvl "$vg/$1" &>/dev/null || die "$vg/$1 expected to not exist but it does!"
+ done
+ fi
+ rm -f debug.log
}
pv_field() {
- local actual=$(get pv_field "$1" "$2" "${@:4}")
+ local actual
+ 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}")
+ local actual
+ actual=$(get vg_field "$1" "$2" "${@:4}")
test "$actual" = "$3" || \
die "vg_field: vg=$1, field=\"$2\", actual=\"$actual\", expected=\"$3\""
}
+vg_attr_bit() {
+ local actual
+ local offset=$1
+ actual=$(get vg_field "$2" vg_attr "${@:4}")
+ case "$offset" in
+ perm*) offset=0 ;;
+ resiz*) offset=1 ;;
+ export*) offset=2 ;;
+ partial) offset=3 ;;
+ alloc*) offset=4 ;;
+ cluster*) offset=5 ;;
+ esac
+ test "${actual:$offset:1}" = "$3" || \
+ die "vg_attr_bit: vg=$2, ${offset} bit of \"$actual\" is \"${actual:$offset:1}\", but expected \"$3\""
+}
+
lv_field() {
- local actual=$(get lv_field $1 "$2" "${@:4}")
+ local actual
+ actual=$(get lv_field "$1" "$2" "${@:4}")
test "$actual" = "$3" || \
- die "lv_field: lv=$lv, field=\"$2\", actual=\"$actual\", expected=\"$3\""
+ die "lv_field: lv=$1, field=\"$2\", actual=\"$actual\", expected=\"$3\""
+}
+
+lv_first_seg_field() {
+ local actual
+ actual=$(get lv_first_seg_field "$1" "$2" "${@:4}")
+ test "$actual" = "$3" || \
+ die "lv_field: lv=$1, field=\"$2\", actual=\"$actual\", expected=\"$3\""
+}
+
+lvh_field() {
+ local actual
+ actual=$(get lvh_field "$1" "$2" "${@:4}")
+ test "$actual" = "$3" || \
+ die "lvh_field: lv=$1, field=\"$2\", actual=\"$actual\", expected=\"$3\""
+}
+
+lva_field() {
+ local actual
+ actual=$(get lva_field "$1" "$2" "${@:4}")
+ test "$actual" = "$3" || \
+ die "lva_field: lv=$1, field=\"$2\", actual=\"$actual\", expected=\"$3\""
+}
+
+lv_attr_bit() {
+ local actual
+ local offset=$1
+ actual=$(get lv_field "$2" lv_attr "${@:4}")
+ case "$offset" in
+ type) offset=0 ;;
+ perm*) offset=1 ;;
+ alloc*) offset=2 ;;
+ fixed*) offset=3 ;;
+ state) offset=4 ;;
+ open) offset=5 ;;
+ target) offset=6 ;;
+ zero) offset=7 ;;
+ health) offset=8 ;;
+ skip) offset=9 ;;
+ esac
+ test "${actual:$offset:1}" = "$3" || \
+ die "lv_attr_bit: lv=$2, ${offset} bit of \"$actual\" is \"${actual:$offset:1}\", but expected \"$3\""
}
compare_fields() {
@@ -251,8 +380,10 @@ compare_fields() {
local cmd2=$4
local obj2=$5
local field2=$6
- local val1=$($cmd1 --noheadings -o "$field1" "$obj1")
- local val2=$($cmd2 --noheadings -o "$field2" "$obj2")
+ local val1
+ local val2
+ val1=$("$cmd1" --noheadings -o "$field1" "$obj1")
+ val2=$("$cmd2" --noheadings -o "$field2" "$obj2")
test "$val1" = "$val2" || \
die "compare_fields $obj1($field1): $val1 $obj2($field2): $val2"
}
@@ -261,8 +392,10 @@ 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)
+ local val1
+ local val2
+ val1=$(vgs --noheadings -o "$field" "$vg1")
+ val2=$(vgs --noheadings -o "$field" "$vg2")
test "$val1" = "$val2" || \
die "compare_vg_field: $vg1: $val1, $vg2: $val2"
}
@@ -272,11 +405,62 @@ pvlv_counts() {
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
+ 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"
+}
+
+# Compare md5 check generated from get dev_md5sum
+dev_md5sum() {
+ md5sum -c "md5.$1-$2" || \
+ (get lv_field "$1/$2" "name,size,seg_pe_ranges"
+ die "LV $1/$2 has different MD5 check sum!")
+}
+
+sysfs() {
+ # read maj min and also convert hex to decimal
+ local maj
+ local min
+ local P
+ local val
+ maj=$(($(stat -L --printf=0x%t "$1")))
+ min=$(($(stat -L --printf=0x%T "$1")))
+ P="/sys/dev/block/$maj:$min/$2"
+ val=$(< "$P") || return 0 # no sysfs ?
+ test "$val" -eq "$3" || \
+ die "$1: $P = $val differs from expected value $3!"
+}
+
+# check raid_leg_status $vg $lv "Aaaaa"
+raid_leg_status() {
+ local st
+ local val
+
+ # Ignore inconsisten raid status 0/xxxxx idle
+ for i in {100..0} ; do
+ st=( $(dmsetup status "$1-$2") ) || die "Unable to get status of $vg/$lv1"
+ b=( $(echo "${st[6]}" | sed s:/:' ':) )
+ [ "${b[0]}" = "0" ] || {
+ test "${st[5]}" = "$3" || break
+ return 0
+ }
+ sleep .1
+ done
+
+ die "$1-$2 status ${st[5]} != $3 (${st[*]})"
+}
+
+grep_dmsetup() {
+ dmsetup "$1" "$2" | tee out
+ grep -q "${@:3}" out || die "Expected output \"" "${@:3}" "\" from dmsetup $1 not found!"
+}
+
+grep_lvmlockd_dump() {
+ lvmlockctl --dump | tee out
+ grep -q "${@:1}" out || die "Expected output \"" "${@:1}" "\" from lvmlockctl --dump not found!"
}
+#set -x
unset LVM_VALGRIND
"$@"
diff --git a/test/lib/dmsecuretest.c b/test/lib/dmsecuretest.c
new file mode 100644
index 0000000..19265bf
--- /dev/null
+++ b/test/lib/dmsecuretest.c
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2018 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Test sample code to check for leftovers from secure table loading in
+ * userspace memory (initial sample provided by Milan Broz).
+ *
+ * Compile with: gcc -O2 -g -o tst dmcrypt.c -ldevmapper
+ *
+ * Search for string in coredump (needs 'raise', or using 'gcore' tool)
+ *
+ * grep "434e0cbab02ca68ffba9268222c3789d703fe62427b78b308518b3228f6a2122" core
+ *
+ */
+
+#include "device_mapper/all.h"
+
+#include <unistd.h>
+#include <signal.h>
+
+/* Comment out this define to get coredump instead of sleeping */
+#define SLEEP 1
+
+static void rot13(char *s)
+{
+ unsigned i;
+
+ for (i = 0; s[i]; i++)
+ if (s[i] >= 'a' && s[i] <= 'm')
+ s[i] += 13;
+ else if (s[i] >= 'n' && s[i] <= 'z')
+ s[i] -= 13;
+}
+
+int main (int argc, char *argv[])
+{
+ const unsigned sz = 8192;
+ /* rot13: 434e0cbab02ca68ffba9268222c3789d703fe62427b78b308518b3228f6a2122 */
+ char aes[] = "434r0pono02pn68sson9268222p3789q703sr62427o78o308518o3228s6n2122";
+ const char *device = (argc > 1) ? argv[1] : "/dev/loop0"; /* device for use */
+ const char *devname = (argc > 2) ? argv[2] : "test-secure"; /* name of dm device */
+ const char *cipher = (argc > 3) ? argv[3] : "aes-xts-plain64"; /* name of dm device */
+ uint32_t cookie = 0;
+ char table[300];
+ struct dm_task *dmt;
+
+ if (geteuid() != 0) {
+ fprintf(stderr, "Needs root UID for execution!\n");
+ exit(1);
+ }
+
+ printf("Going to create %s dm device using backend device: %s\n", devname, device);
+
+ if ((dmt = dm_task_create(DM_DEVICE_CREATE))) {
+ (void) dm_task_set_name(dmt, devname);
+ (void) dm_task_secure_data(dmt);
+ rot13(aes);
+ snprintf(table, sizeof(table), "%s %s 0 %s %u", cipher, aes, device, sz);
+ memset(aes, 0, sizeof(aes));
+ (void) dm_task_add_target(dmt, 0, sz, "crypt", table);
+ memset(table, 0, sizeof(table));
+ asm volatile ("" ::: "memory");/* Compiler barrier. */
+ (void) dm_task_set_cookie(dmt, &cookie, DM_UDEV_DISABLE_LIBRARY_FALLBACK);
+ (void) dm_task_run(dmt);
+ (void) dm_task_destroy(dmt);
+ (void) dm_udev_wait(cookie); /* Finish udev processing */
+ }
+
+ /* At this point there should be no memory trace from a secure table line */
+
+#ifdef SLEEP
+ sleep(4); /* Give time to other process to capture 'gcore pid' */
+#else
+ raise(SIGABRT); /* Generate core for search of any forgotten traces of key */
+#endif
+ return 0;
+}
diff --git a/test/lib/flavour-ndev-cluster-lvmpolld.sh b/test/lib/flavour-ndev-cluster-lvmpolld.sh
new file mode 100644
index 0000000..fe31bb4
--- /dev/null
+++ b/test/lib/flavour-ndev-cluster-lvmpolld.sh
@@ -0,0 +1,2 @@
+export LVM_TEST_LOCKING=3
+export LVM_TEST_LVMPOLLD=1
diff --git a/test/lib/flavour-ndev-cluster.sh b/test/lib/flavour-ndev-cluster.sh
new file mode 100644
index 0000000..3629069
--- /dev/null
+++ b/test/lib/flavour-ndev-cluster.sh
@@ -0,0 +1 @@
+export LVM_TEST_LOCKING=3
diff --git a/test/lib/flavour-ndev-devicesfile.sh b/test/lib/flavour-ndev-devicesfile.sh
new file mode 100644
index 0000000..21168fd
--- /dev/null
+++ b/test/lib/flavour-ndev-devicesfile.sh
@@ -0,0 +1,2 @@
+export LVM_TEST_LOCKING=1
+export LVM_TEST_DEVICES_FILE=1
diff --git a/test/lib/flavour-ndev-lvmpolld.sh b/test/lib/flavour-ndev-lvmpolld.sh
new file mode 100644
index 0000000..0a70703
--- /dev/null
+++ b/test/lib/flavour-ndev-lvmpolld.sh
@@ -0,0 +1,2 @@
+export LVM_TEST_LOCKING=1
+export LVM_TEST_LVMPOLLD=1
diff --git a/test/lib/flavour-ndev-vanilla.sh b/test/lib/flavour-ndev-vanilla.sh
new file mode 100644
index 0000000..1899c94
--- /dev/null
+++ b/test/lib/flavour-ndev-vanilla.sh
@@ -0,0 +1 @@
+export LVM_TEST_LOCKING=1
diff --git a/test/lib/flavour-udev-cluster-lvmpolld.sh b/test/lib/flavour-udev-cluster-lvmpolld.sh
new file mode 100644
index 0000000..abf76e9
--- /dev/null
+++ b/test/lib/flavour-udev-cluster-lvmpolld.sh
@@ -0,0 +1,3 @@
+export LVM_TEST_LOCKING=3
+export LVM_TEST_LVMPOLLD=1
+export LVM_TEST_DEVDIR=/dev
diff --git a/test/lib/flavour-udev-cluster.sh b/test/lib/flavour-udev-cluster.sh
new file mode 100644
index 0000000..a9025a6
--- /dev/null
+++ b/test/lib/flavour-udev-cluster.sh
@@ -0,0 +1,2 @@
+export LVM_TEST_LOCKING=3
+export LVM_TEST_DEVDIR=/dev
diff --git a/test/lib/flavour-udev-lvmlockd-dlm.sh b/test/lib/flavour-udev-lvmlockd-dlm.sh
new file mode 100644
index 0000000..93d7877
--- /dev/null
+++ b/test/lib/flavour-udev-lvmlockd-dlm.sh
@@ -0,0 +1,6 @@
+export LVM_TEST_LOCKING=1
+export LVM_TEST_LVMPOLLD=1
+export LVM_TEST_LVMLOCKD=1
+export LVM_TEST_LVMLOCKD_TEST=1
+export LVM_TEST_LOCK_TYPE_DLM=1
+export LVM_TEST_DEVDIR=/dev
diff --git a/test/lib/flavour-udev-lvmlockd-idm.sh b/test/lib/flavour-udev-lvmlockd-idm.sh
new file mode 100644
index 0000000..e9f8908
--- /dev/null
+++ b/test/lib/flavour-udev-lvmlockd-idm.sh
@@ -0,0 +1,5 @@
+export LVM_TEST_LOCKING=1
+export LVM_TEST_LVMPOLLD=1
+export LVM_TEST_LVMLOCKD=1
+export LVM_TEST_LOCK_TYPE_IDM=1
+export LVM_TEST_DEVDIR=/dev
diff --git a/test/lib/flavour-udev-lvmlockd-sanlock.sh b/test/lib/flavour-udev-lvmlockd-sanlock.sh
new file mode 100644
index 0000000..52f3cea
--- /dev/null
+++ b/test/lib/flavour-udev-lvmlockd-sanlock.sh
@@ -0,0 +1,5 @@
+export LVM_TEST_LOCKING=1
+export LVM_TEST_LVMPOLLD=1
+export LVM_TEST_LVMLOCKD=1
+export LVM_TEST_LOCK_TYPE_SANLOCK=1
+export LVM_TEST_DEVDIR=/dev
diff --git a/test/lib/flavour-udev-lvmlockd-test.sh b/test/lib/flavour-udev-lvmlockd-test.sh
new file mode 100644
index 0000000..f9cd527
--- /dev/null
+++ b/test/lib/flavour-udev-lvmlockd-test.sh
@@ -0,0 +1,8 @@
+export LVM_TEST_LOCKING=1
+export LVM_TEST_LVMPOLLD=1
+export LVM_TEST_LVMLOCKD=1
+export LVM_TEST_LVMLOCKD_TEST=1
+export LVM_TEST_DEVDIR=/dev
+
+# FIXME:dct: add option to allow --test with sanlock
+export LVM_TEST_LVMLOCKD_TEST_DLM=1
diff --git a/test/lib/flavour-udev-lvmpolld.sh b/test/lib/flavour-udev-lvmpolld.sh
new file mode 100644
index 0000000..c7f40b5
--- /dev/null
+++ b/test/lib/flavour-udev-lvmpolld.sh
@@ -0,0 +1,3 @@
+export LVM_TEST_LOCKING=1
+export LVM_TEST_LVMPOLLD=1
+export LVM_TEST_DEVDIR=/dev
diff --git a/test/lib/flavour-udev-vanilla.sh b/test/lib/flavour-udev-vanilla.sh
new file mode 100644
index 0000000..ca778a6
--- /dev/null
+++ b/test/lib/flavour-udev-vanilla.sh
@@ -0,0 +1,2 @@
+export LVM_TEST_LOCKING=1
+export LVM_TEST_DEVDIR=/dev
diff --git a/test/lib/get.sh b/test/lib/get.sh
index 4197f47..3b0d1f2 100644
--- a/test/lib/get.sh
+++ b/test/lib/get.sh
@@ -1,5 +1,5 @@
-#!/bin/sh
-# Copyright (C) 2011-2012 Red Hat, Inc. All rights reserved.
+#!/usr/bin/env bash
+# Copyright (C) 2011-2017 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
@@ -7,7 +7,7 @@
#
# 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
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
# get.sh: get various values from volumes
#
@@ -18,28 +18,104 @@
#
# get lv_devices LV [lvs params]
+test -z "$BASH" || set -e -o pipefail
-# trims only leading prefix, we should not need trim trailing spaces
+# trims only leading prefix and suffix
trim_() {
- #local var=${var%"${var##*[! ]}"} # remove trailing space characters
- echo ${1#"${1%%[! ]*}"} # remove leading space characters
+ rm -f debug.log # drop log, command was ok
+ local var=${1%"${1##*[! ]}"} # remove trailing space characters
+ echo "${var#"${var%%[! ]*}"}" # remove leading space characters
}
pv_field() {
- trim_ "$(pvs --noheadings -o $2 ${@:3} $1)"
+ local r
+ r=$(pvs --config 'log{prefix=""}' --noheadings -o "$2" "${@:3}" "$1")
+ trim_ "$r"
}
vg_field() {
- trim_ "$(vgs --noheadings -o $2 ${@:3} $1)"
+ local r
+ r=$(vgs --config 'log{prefix=""}' --noheadings -o "$2" "${@:3}" "$1")
+ trim_ "$r"
}
lv_field() {
- trim_ "$(lvs --noheadings -o $2 ${@:3} $1)"
+ local r
+ r=$(lvs --config 'log{prefix=""}' --noheadings -o "$2" "${@:3}" "$1")
+ trim_ "$r"
+}
+
+lv_first_seg_field() {
+ local r
+ r=$(head -1 < <(lvs --config 'log{prefix=""}' --unbuffered --noheadings -o "$2" "${@:3}" "$1"))
+ trim_ "$r"
+}
+
+lvh_field() {
+ local r
+ r=$(lvs -H --config 'log{prefix=""}' --noheadings -o "$2" "${@:3}" "$1")
+ trim_ "$r"
+}
+
+lva_field() {
+ local r
+ r=$(lvs -a --config 'log{prefix=""}' --noheadings -o "$2" "${@:3}" "$1")
+ trim_ "$r"
}
lv_devices() {
- lv_field $1 devices -a "${@:2}" | sed 's/([^)]*)//g; s/,/ /g'
+ lv_field "$1" devices -a "${@:2}" | sed 's/([^)]*)//g; s/,/\n/g'
+}
+
+lv_field_lv_() {
+ lv_field "$1" "$2" -a --unbuffered | tr -d '[]'
+}
+
+lv_tree_devices_() {
+ local lv="$1/$2"
+ local type
+ type=$(lv_first_seg_field "$lv" segtype -a)
+ #local orig
+ #orig=$(lv_field_lv_ "$lv" origin)
+ # FIXME: should we count in also origins ?
+ #test -z "$orig" || lv_tree_devices_ $1 $orig
+ case "$type" in
+ linear|striped)
+ lv_devices "$lv"
+ ;;
+ mirror|raid*)
+ local log
+ log=$(lv_field_lv_ "$lv" mirror_log)
+ test -z "$log" || lv_tree_devices_ "$1" "$log"
+ for i in $(lv_devices "$lv")
+ do lv_tree_devices_ "$1" "$i"; done
+ ;;
+ thin)
+ lv_tree_devices_ "$1" "$(lv_field_lv_ "$lv" pool_lv)"
+ ;;
+ thin-pool)
+ lv_tree_devices_ "$1" "$(lv_field_lv_ "$lv" data_lv)"
+ lv_tree_devices_ "$1" "$(lv_field_lv_ "$lv" metadata_lv)"
+ ;;
+ cache)
+ lv_tree_devices_ "$1" "$(lv_devices "$lv")"
+ ;;
+ cache-pool)
+ lv_tree_devices_ "$1" "$(lv_field_lv_ "$lv" data_lv)"
+ lv_tree_devices_ "$1" "$(lv_field_lv_ "$lv" metadata_lv)"
+ ;;
+ esac
+}
+
+lv_tree_devices() {
+ lv_tree_devices_ "$@" | sort | uniq
+}
+
+first_extent_sector() {
+ pv_field "$@" pe_start --units s --nosuffix
}
+#set -x
unset LVM_VALGRIND
+unset LVM_LOG_FILE_EPOCH
"$@"
diff --git a/test/lib/harness.c b/test/lib/harness.c
index 929bfc8..a97f5db 100644
--- a/test/lib/harness.c
+++ b/test/lib/harness.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2010-2012 Red Hat, Inc. All rights reserved.
+ * Copyright (C) 2010-2013 Red Hat, Inc. All rights reserved.
*
* This file is part of LVM2.
*
@@ -9,24 +9,33 @@
*
* 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
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
-#define _GNU_SOURCE
+#include <errno.h>
#include <fcntl.h>
-#include <string.h>
+#include <limits.h>
#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/klog.h>
+#include <sys/resource.h> /* rusage */
+#include <sys/select.h>
#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/types.h>
#include <sys/wait.h>
-#include <unistd.h>
-#include <stdlib.h>
#include <time.h>
-#include <sys/time.h>
+#include <unistd.h>
+#include <stdint.h>
static pid_t pid;
static int fds[2];
#define MAX 1024
+#define MAX_LOG_SIZE (32*1024*1024) /* Default max size of test log */
+#define WRITE_TIMEOUT (180 * 2) /* 3 minutes */
struct stats {
int nfailed;
@@ -34,17 +43,28 @@ struct stats {
int npassed;
int nknownfail;
int nwarned;
+ int ninterrupted;
int status[MAX];
};
static struct stats s;
static char *readbuf = NULL;
-static int readbuf_sz = 0, readbuf_used = 0;
+static size_t readbuf_sz = 0, readbuf_used = 0;
static int die = 0;
static int verbose = 0; /* >1 with timestamps */
static int interactive = 0; /* disable all redirections */
+static int quiet = 0;
+static const char *results;
+static unsigned fullbuffer = 0;
+static int unlimited = 0;
+static int write_timeout = WRITE_TIMEOUT;
+
+static time_t harness_start;
+
+static FILE *outfile = NULL;
+char testdirdebug[PATH_MAX];
struct subst {
const char *key;
@@ -53,19 +73,24 @@ struct subst {
static struct subst subst[2];
-#define PASSED 0
-#define SKIPPED 1
-#define FAILED 2
-#define WARNED 3
-#define KNOWNFAIL 4
+enum {
+ UNKNOWN,
+ FAILED,
+ INTERRUPTED,
+ KNOWNFAIL,
+ PASSED,
+ SKIPPED,
+ TIMEOUT,
+ WARNED,
+};
static void handler( int sig ) {
signal( sig, SIG_DFL );
- kill( pid, sig );
+ kill( -pid, sig );
die = sig;
}
-static int outline(char *buf, int start, int force) {
+static int outline(FILE *out, char *buf, int start, int force) {
char *from = buf + start;
char *next = strchr(buf + start, '\n');
@@ -79,9 +104,12 @@ static int outline(char *buf, int start, int force) {
if (!strncmp(from, "@TESTDIR=", 9)) {
subst[0].key = "@TESTDIR@";
+ free(subst[0].value);
subst[0].value = strndup(from + 9, next - from - 9 - 1);
+ snprintf(testdirdebug, sizeof(testdirdebug), "%s/debug.log", subst[0].value);
} else if (!strncmp(from, "@PREFIX=", 8)) {
subst[1].key = "@PREFIX@";
+ free(subst[1].value);
subst[1].value = strndup(from + 8, next - from - 8 - 1);
} else {
char *line = strndup(from, next - from);
@@ -100,11 +128,11 @@ static int outline(char *buf, int start, int force) {
}
}
}
- fwrite(a, 1, b - a, stdout);
+ fwrite(a, 1, b - a, out);
a = b;
if ( idx >= 0 ) {
- fprintf(stdout, "%s", subst[idx].key);
+ fprintf(out, "%s", subst[idx].key);
a += strlen(subst[idx].value);
}
} while (b < line + strlen(line));
@@ -117,27 +145,26 @@ static int outline(char *buf, int start, int force) {
static void dump(void) {
int counter_last = -1, counter = 0;
- while ( counter < readbuf_used && counter != counter_last ) {
+ while ((counter < (int) readbuf_used) && (counter != counter_last)) {
counter_last = counter;
- counter = outline( readbuf, counter, 1 );
+ counter = outline( stdout, readbuf, counter, 1 );
}
}
-static void trickle(void) {
- static int counter_last = -1, counter = 0;
-
- if (counter_last > readbuf_used) {
- counter_last = -1;
- counter = 0;
+static void trickle(FILE *out, int *last, int *counter) {
+ if (*last > (int) readbuf_used) {
+ *last = -1;
+ *counter = 0;
}
- while ( counter < readbuf_used && counter != counter_last ) {
- counter_last = counter;
- counter = outline( readbuf, counter, 1 );
+ while ((*counter < (int) readbuf_used) && (*counter != *last)) {
+ *last = *counter;
+ *counter = outline( out, readbuf, *counter, 1 );
}
}
static void clear(void) {
readbuf_used = 0;
+ fullbuffer = 0;
}
static int64_t _get_time_us(void)
@@ -151,7 +178,12 @@ static int64_t _get_time_us(void)
static void _append_buf(const char *buf, size_t len)
{
if ((readbuf_used + len) >= readbuf_sz) {
- readbuf_sz = readbuf_sz ? 2 * readbuf_sz : 4096;
+ if ((readbuf_sz >= MAX_LOG_SIZE) && !unlimited) {
+ if (fullbuffer++ == 0)
+ kill(-pid, SIGINT);
+ return;
+ }
+ readbuf_sz = 2 * (readbuf_used + len + readbuf_sz);
readbuf = realloc(readbuf, readbuf_sz);
}
@@ -197,16 +229,19 @@ static const char *_append_with_stamp(const char *buf, int stamp)
return bb;
}
-static void drain(void) {
- char buf[4096];
+static int drain(int fd)
+{
+ char buf[2 * 1024 * 1024 + 1]; /* try to capture large sysrq trace */
const char *bp;
int stamp = 0;
int sz;
- while ((sz = read(fds[1], buf, sizeof(buf) - 1)) > 0) {
+ static int stdout_last = -1, stdout_counter = 0;
+ static int outfile_last = -1, outfile_counter = 0;
+
+ if ((sz = read(fd, 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 */
@@ -216,32 +251,91 @@ static void drain(void) {
readbuf[readbuf_used] = 0;
if (verbose)
- trickle();
+ trickle(stdout, &stdout_last, &stdout_counter);
+ if (outfile)
+ trickle(outfile, &outfile_last, &outfile_counter);
}
+
+ return sz;
}
-static const char *duration(time_t start)
+static int drain_fds(int fd1, int fd2, long timeout)
{
- static char buf[16];
+ return -1;
+}
+
+#define SYSLOG_ACTION_READ_CLEAR 4
+#define SYSLOG_ACTION_CLEAR 5
+
+static void clear_dmesg(void)
+{
+ klogctl(SYSLOG_ACTION_CLEAR, 0, 0);
+}
+
+static void drain_dmesg(void)
+{
+ char buf[1024 * 1024 + 1];
+ int sz = klogctl(SYSLOG_ACTION_READ_CLEAR, buf, sizeof(buf) - 1);
+ if (sz > 0) {
+ buf[sz] = 0;
+ _append_buf(buf, sz);
+ }
+}
+
+static const char *duration(time_t start, const struct rusage *usage)
+{
+ static char buf[100];
int t = (int)(time(NULL) - start);
- sprintf(buf, "%2d:%02d", t / 60, t % 60);
+ int p = sprintf(buf, "%2d:%02d", t / 60, t % 60);
+
+ if (usage)
+ sprintf(buf + p, " %2ld:%02ld.%03ld/%ld:%02ld.%03ld%5ld%8ld/%ld",
+ usage->ru_utime.tv_sec / 60, usage->ru_utime.tv_sec % 60,
+ usage->ru_utime.tv_usec / 1000,
+ usage->ru_stime.tv_sec / 60, usage->ru_stime.tv_sec % 60,
+ usage->ru_stime.tv_usec / 1000,
+ usage->ru_maxrss / 1024,
+ usage->ru_inblock, usage->ru_oublock);
+
return buf;
}
-static void passed(int i, char *f, time_t t) {
+static void passed(int i, char *f, time_t t, const struct rusage *usage) {
if (readbuf && strstr(readbuf, "TEST EXPECT FAIL")) {
++ s.npassed;
s.status[i] = PASSED;
- printf("passed (UNEXPECTED). %s\n", duration(t));
+ printf("passed (UNEXPECTED). %s\n", duration(t, usage));
} else if (readbuf && strstr(readbuf, "TEST WARNING")) {
++s.nwarned;
s.status[i] = WARNED;
- printf("warnings %s\n", duration(t));
+ printf("warnings %s\n", duration(t, usage));
} else {
++ s.npassed;
s.status[i] = PASSED;
- printf("passed. %s\n", duration(t));
+ printf("passed. %s\n", duration(t, usage));
+ }
+}
+
+static void interrupted(int i, char *f) {
+ ++ s.ninterrupted;
+ s.status[i] = INTERRUPTED;
+ printf("\ninterrupted.\n");
+ if (!quiet && !verbose && fullbuffer) {
+ printf("-- Interrupted %s ------------------------------------\n", f);
+ dump();
+ printf("\n-- Interrupted %s (end) ------------------------------\n", f);
+ }
+}
+
+static void timeout(int i, char *f) {
+ ++ s.ninterrupted;
+ s.status[i] = TIMEOUT;
+ printf("timeout.\n");
+ if (!quiet && !verbose && readbuf) {
+ printf("-- Timed out %s ------------------------------------\n", f);
+ dump();
+ printf("\n-- Timed out %s (end) ------------------------------\n", f);
}
}
@@ -261,12 +355,8 @@ static void failed(int i, char *f, int st) {
++ s.nfailed;
s.status[i] = FAILED;
- if(die == 2) {
- printf("interrupted.\n");
- return;
- }
- printf("FAILED.\n");
- if (!verbose) {
+ printf("FAILED (status %d).\n", WEXITSTATUS(st));
+ if (!quiet && !verbose && readbuf) {
printf("-- FAILED %s ------------------------------------\n", f);
dump();
printf("-- FAILED %s (end) ------------------------------\n", f);
@@ -274,59 +364,181 @@ static void failed(int i, char *f, int st) {
}
static void run(int i, char *f) {
+ struct rusage usage;
+ char flavour[512], script[512];
+
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(STDIN_FILENO);
+ dup2(fds[1], STDOUT_FILENO);
+ dup2(fds[1], STDERR_FILENO);
close(fds[1]);
}
- execlp("bash", "bash", f, NULL);
+ close(fds[0]);
+ if (strchr(f, ':')) {
+ strcpy(flavour, f);
+ *strchr(flavour, ':') = 0;
+ setenv("LVM_TEST_FLAVOUR", flavour, 1);
+ strcpy(script, strchr(f, ':') + 1);
+ } else {
+ strcpy(script, f);
+ }
+ setpgid(0, 0);
+ execlp("bash", "bash", "-noprofile", "-norc", script, NULL);
perror("execlp");
fflush(stderr);
_exit(202);
} else {
- int st, w;
+ int st = -1, w;
time_t start = time(NULL);
char buf[128];
- snprintf(buf, 128, "%s ...", f);
- buf[127] = 0;
- printf("Running %-50s ", buf);
+ char outpath[PATH_MAX];
+ char *c = outpath + strlen(results) + 1;
+ struct stat statbuf;
+ int runaway = 0;
+ int no_write = 0;
+ int clobber_dmesg = 0;
+ int collect_debug = 0;
+ int fd_debuglog = -1;
+ int fd_kmsg;
+ fd_set set;
+ int ret;
+
+ //close(fds[1]);
+ testdirdebug[0] = '\0'; /* Capture RUNTESTDIR */
+ snprintf(buf, sizeof(buf), "%s ...", f);
+ printf("Running %-60s%c", buf, verbose ? '\n' : ' ');
fflush(stdout);
- while ((w = waitpid(pid, &st, WNOHANG)) == 0) {
- drain();
- usleep(20000);
+ snprintf(outpath, sizeof(outpath), "%s/%s.txt", results, f);
+ while ((c = strchr(c, '/')))
+ *c = '_';
+ if (!(outfile = fopen(outpath, "w")))
+ perror("fopen");
+
+ /* Mix-in kernel log message */
+ if ((fd_kmsg = open("/dev/kmsg", O_RDONLY | O_NONBLOCK)) < 0) {
+ if (errno != ENOENT) /* Older kernels (<3.5) do not support /dev/kmsg */
+ perror("open /dev/kmsg");
+ } else if (lseek(fd_kmsg, 0L, SEEK_END) == (off_t) -1)
+ perror("lseek /dev/kmsg");
+
+ if ((fd_kmsg < 0) &&
+ (clobber_dmesg = strcmp(getenv("LVM_TEST_CAN_CLOBBER_DMESG") ? : "0", "0")))
+ clear_dmesg();
+
+ while ((w = wait4(pid, &st, WNOHANG, &usage)) == 0) {
+ struct timeval selectwait = { .tv_usec = 500000 }; /* 0.5s */
+
+ if ((fullbuffer && fullbuffer++ == 8000) ||
+ (write_timeout > 0 && no_write > write_timeout))
+ {
+ timeout:
+ kill(pid, SIGINT);
+ sleep(5); /* wait a bit for a reaction */
+ if ((w = waitpid(pid, &st, WNOHANG)) == 0) {
+ if (write_timeout > 0 && no_write > write_timeout)
+ /*
+ * Kernel traces needed, when stuck for
+ * too long in userspace without producing
+ * any output, in other case it should be
+ * user space problem
+ */
+ system("echo t > /proc/sysrq-trigger");
+ collect_debug = 1;
+ kill(-pid, SIGKILL);
+ w = pid; // waitpid(pid, &st, NULL);
+ }
+ runaway = 1;
+ break;
+ }
+
+ if (clobber_dmesg)
+ drain_dmesg();
+
+ FD_ZERO(&set);
+ FD_SET(fds[0], &set);
+ if (fd_kmsg >= 0)
+ FD_SET(fd_kmsg, &set);
+
+ if ((ret = select(fd_kmsg > fds[0] ? fd_kmsg + 1 : fds[0] + 1, &set, NULL, NULL, &selectwait)) <= 0) {
+ /* Still checking debug log size if it's not growing too much */
+ if (!unlimited && testdirdebug[0] &&
+ (stat(testdirdebug, &statbuf) == 0) &&
+ statbuf.st_size > 32 * 1024 * 1024) { /* 32MB command log size */
+ printf("Killing test since debug.log has gone wild (size %ld)\n",
+ statbuf.st_size);
+ goto timeout;
+ }
+ no_write++;
+ continue;
+ }
+
+ if (FD_ISSET(fds[0], &set) && drain(fds[0]) > 0)
+ no_write = 0;
+ else if (fd_kmsg >= 0 && FD_ISSET(fd_kmsg, &set) && (drain(fd_kmsg) < 0)) {
+ close(fd_kmsg);
+ fd_kmsg = -1; /* Likely /dev/kmsg is not readable */
+ if ((clobber_dmesg = strcmp(getenv("LVM_TEST_CAN_CLOBBER_DMESG") ? : "0", "0")))
+ clear_dmesg();
+ }
}
if (w != pid) {
perror("waitpid");
exit(206);
}
- drain();
- if (WIFEXITED(st)) {
- if (WEXITSTATUS(st) == 0) {
- passed(i, f, start);
- } else if (WEXITSTATUS(st) == 200) {
+
+ while (!fullbuffer && (drain_fds(fds[0], fd_kmsg, 0) > 0))
+ /* read out what was left */;
+
+ if (die == 2)
+ interrupted(i, f);
+ else if (runaway) {
+ if (collect_debug &&
+ (fd_debuglog = open(testdirdebug, O_RDONLY)) != -1) {
+ runaway = unlimited ? INT32_MAX : 4 * 1024 * 1024;
+ while (!fullbuffer && runaway > 0 && (ret = drain(fd_debuglog)) > 0)
+ runaway -= ret;
+ close(fd_debuglog);
+ }
+ timeout(i, f);
+ } else if (WIFEXITED(st)) {
+ if (WEXITSTATUS(st) == 0)
+ passed(i, f, start, &usage);
+ else if (WEXITSTATUS(st) == 200)
skipped(i, f);
- } else {
+ else
failed(i, f, st);
- }
- } else {
+ } else
failed(i, f, st);
- }
+
+ if (fd_kmsg >= 0)
+ close(fd_kmsg);
+ else if (clobber_dmesg)
+ drain_dmesg();
+ if (outfile)
+ fclose(outfile);
+ if (fullbuffer)
+ printf("\nTest was interrupted, output has got too large (>%u) (loop:%u)\n"
+ "Set LVM_TEST_UNLIMITED=1 for unlimited log.\n",
+ (unsigned) readbuf_sz, fullbuffer);
clear();
}
}
int main(int argc, char **argv) {
+ char results_list[PATH_MAX];
+ const char *result;
const char *be_verbose = getenv("VERBOSE"),
- *be_interactive = getenv("INTERACTIVE");
+ *be_interactive = getenv("INTERACTIVE"),
+ *be_quiet = getenv("QUIET"),
+ *be_write_timeout = getenv("WRITE_TIMEOUT");
time_t start = time(NULL);
int i;
+ FILE *list;
if (argc >= MAX) {
fprintf(stderr, "Sorry, my head exploded. Please increase MAX.\n");
@@ -339,55 +551,102 @@ int main(int argc, char **argv) {
if (be_interactive)
interactive = atoi(be_interactive);
+ if (be_quiet)
+ quiet = atoi(be_quiet);
+
+ if (be_write_timeout)
+ write_timeout = atoi(be_write_timeout) * 2;
+
+ results = getenv("LVM_TEST_RESULTS") ? : "results";
+ unlimited = getenv("LVM_TEST_UNLIMITED") ? 1 : 0;
+ (void) snprintf(results_list, sizeof(results_list), "%s/list", results);
+
+ //if (pipe(fds)) {
if (socketpair(PF_UNIX, SOCK_STREAM, 0, fds)) {
perror("socketpair");
return 201;
}
- if ( fcntl( fds[1], F_SETFL, O_NONBLOCK ) == -1 ) {
+ if (fcntl(fds[0], 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);
- }
+ for (i = 0; i <= 32; ++i)
+ switch (i) {
+ case SIGCHLD: case SIGWINCH: case SIGURG:
+ case SIGKILL: case SIGSTOP: break;
+ default: signal(i, handler);
+ }
+ harness_start = time(NULL);
/* run the tests */
- for (i = 1; i < argc; ++ i) {
+ for (i = 1; !die && i < argc; ++i) {
run(i, argv[i]);
- if (die)
- break;
+ if ( time(NULL) - harness_start > 48 * 360 ) { /* 04:48 */
+ printf("Nearly 5 hours passed, giving up...\n");
+ die = 1;
+ }
}
- 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);
+ free(subst[0].value);
+ free(subst[1].value);
+ free(readbuf);
+
+ printf("\n## %d tests %s : %d OK, %d warnings, %d failures (%d interrupted), %d known failures; "
+ "%d skipped\n",
+ s.nwarned + s.npassed + s.nfailed + s.nskipped + s.ninterrupted,
+ duration(start, NULL),
+ s.npassed, s.nwarned, s.nfailed + s.ninterrupted, s.ninterrupted,
+ s.nknownfail, s.nskipped);
+
+ /* dump a list to results */
+ if ((list = fopen(results_list, "w"))) {
+ for (i = 1; i < argc; ++ i) {
+ switch (s.status[i]) {
+ case FAILED: result = "failed"; break;
+ case INTERRUPTED: result = "interrupted"; break;
+ case PASSED: result = "passed"; break;
+ case SKIPPED: result = "skipped"; break;
+ case TIMEOUT: result = "timeout"; break;
+ case WARNED: result = "warnings"; break;
+ default: result = "unknown"; break;
+ }
+ fprintf(list, "%s %s\n", argv[i], result);
+ }
+ fclose(list);
+ } else
+ perror("fopen result");
/* print out a summary */
- if (s.nfailed || s.nskipped || s.nknownfail) {
+ if (s.nfailed || s.nskipped || s.nknownfail || s.ninterrupted || s.nwarned) {
for (i = 1; i < argc; ++ i) {
switch (s.status[i]) {
case FAILED:
printf("FAILED: %s\n", argv[i]);
break;
+ case INTERRUPTED:
+ printf("INTERRUPTED: %s\n", argv[i]);
+ break;
case KNOWNFAIL:
printf("FAILED (expected): %s\n", argv[i]);
break;
case SKIPPED:
printf("skipped: %s\n", argv[i]);
break;
+ case TIMEOUT:
+ printf("TIMEOUT: %s\n", argv[i]);
+ break;
+ case WARNED:
+ printf("WARNED: %s\n", argv[i]);
+ break;
+ default: /* do nothing */ ;
}
}
printf("\n");
- return s.nfailed > 0 || die;
+ return (s.nfailed > 0) || (s.ninterrupted > 0) || die;
}
- free(readbuf);
-
return die;
}
diff --git a/test/lib/idm_inject_failure.c b/test/lib/idm_inject_failure.c
new file mode 100644
index 0000000..4998b58
--- /dev/null
+++ b/test/lib/idm_inject_failure.c
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2020-2021 Seagate Ltd.
+ *
+ * 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.
+ */
+
+#include <errno.h>
+#include <limits.h>
+#include <signal.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/inotify.h>
+#include <uuid/uuid.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <ilm.h>
+
+int main(int argc, char *argv[])
+{
+ int pecent = atoi(argv[1]);
+ int ret, s;
+
+ ret = ilm_connect(&s);
+ if (ret == 0) {
+ printf("ilm_connect: SUCCESS\n");
+ } else {
+ printf("ilm_connect: FAIL\n");
+ exit(-1);
+ }
+
+ ret = ilm_inject_fault(s, pecent);
+ if (ret == 0) {
+ printf("ilm_inject_fault (100): SUCCESS\n");
+ } else {
+ printf("ilm_inject_fault (100): FAIL\n");
+ exit(-1);
+ }
+
+ ret = ilm_disconnect(s);
+ if (ret == 0) {
+ printf("ilm_disconnect: SUCCESS\n");
+ } else {
+ printf("ilm_disconnect: FAIL\n");
+ exit(-1);
+ }
+
+ return 0;
+}
diff --git a/test/lib/inittest.sh b/test/lib/inittest.sh
new file mode 100644
index 0000000..40ea98f
--- /dev/null
+++ b/test/lib/inittest.sh
@@ -0,0 +1,197 @@
+#!/usr/bin/env bash
+# Copyright (C) 2011-2017 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+initskip() {
+ test $# -eq 0 || echo "TEST SKIPPED:" "$@"
+ exit 200
+}
+
+# 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
+
+LVM_TEST_FLAVOUR=${LVM_TEST_FLAVOUR-ndev-vanilla}
+
+LVM_TEST_BACKING_DEVICE=${LVM_TEST_BACKING_DEVICE-}
+LVM_TEST_DEVDIR=${LVM_TEST_DEVDIR-}
+LVM_TEST_NODEBUG=${LVM_TEST_NODEBUG-}
+LVM_TEST_LVM1=${LVM_TEST_LVM1-}
+LVM_TEST_FAILURE=${LVM_TEST_FAILURE-}
+LVM_TEST_MULTI_HOST=${LVM_TEST_MULTI_HOST-}
+# TODO: LVM_TEST_SHARED
+SHARED=${SHARED-}
+
+LVM_TEST_LVMLOCKD=${LVM_TEST_LVMLOCKD-}
+LVM_TEST_LVMLOCKD_TEST=${LVM_TEST_LVMLOCKD_TEST-}
+LVM_TEST_LVMPOLLD=${LVM_TEST_LVMPOLLD-}
+LVM_TEST_DEVICES_FILE=${LVM_TEST_DEVICES_FILE-}
+LVM_TEST_LOCK_TYPE_DLM=${LVM_TEST_LOCK_TYPE_DLM-}
+LVM_TEST_LOCK_TYPE_SANLOCK=${LVM_TEST_LOCK_TYPE_SANLOCK-}
+LVM_TEST_LOCK_TYPE_IDM=${LVM_TEST_LOCK_TYPE_IDM-}
+
+SKIP_WITHOUT_CLVMD=${SKIP_WITHOUT_CLVMD-}
+SKIP_WITH_CLVMD=${SKIP_WITH_CLVMD-}
+
+SKIP_WITH_LVMPOLLD=${SKIP_WITH_LVMPOLLD-}
+SKIP_WITH_LVMLOCKD=${SKIP_WITH_LVMLOCKD-}
+SKIP_ROOT_DM_CHECK=${SKIP_ROOT_DM_CHECK-}
+SKIP_WITH_LOW_SPACE=${SKIP_WITH_LOW_SPACE-50}
+
+test -n "$LVM_TEST_FLAVOUR" || { echo "NOTE: Empty flavour">&2; initskip; }
+test -f "lib/flavour-$LVM_TEST_FLAVOUR" || { echo "NOTE: Flavour '$LVM_TEST_FLAVOUR' does not exist">&2; initskip; }
+. "lib/flavour-$LVM_TEST_FLAVOUR"
+
+test -n "$SKIP_WITHOUT_CLVMD" && test "$LVM_TEST_LOCKING" -ne 3 && initskip
+test -n "$SKIP_WITH_CLVMD" && test "$LVM_TEST_LOCKING" = 3 && initskip
+
+test -n "$SKIP_WITH_LVMPOLLD" && test -n "$LVM_TEST_LVMPOLLD" && test -z "$LVM_TEST_LVMLOCKD" && initskip
+
+test -n "$SKIP_WITH_LVMLOCKD" && test -n "$LVM_TEST_LVMLOCKD" && initskip
+
+test -n "$SKIP_WITH_DEVICES_FILE" && test -n "$LVM_TEST_DEVICES_FILE" && initskip
+
+unset CDPATH
+
+export LVM_TEST_BACKING_DEVICE LVM_TEST_DEVDIR LVM_TEST_NODEBUG LVM_TEST_FAILURE
+export LVM_TEST_MULTI_HOST
+export LVM_TEST_LVMLOCKD LVM_TEST_LVMLOCKD_TEST
+export LVM_TEST_LVMPOLLD LVM_TEST_LOCK_TYPE_DLM LVM_TEST_LOCK_TYPE_SANLOCK LVM_TEST_LOCK_TYPE_IDM
+export LVM_TEST_DEVICES_FILE
+# grab some common utilities
+. lib/utils
+
+TESTOLDPWD=$(pwd)
+COMMON_PREFIX="LVMTEST"
+PREFIX="${COMMON_PREFIX}$$"
+
+# Check we are not conflickting with some exiting setup
+if test -z "$SKIP_ROOT_DM_CHECK" ; then
+ dmsetup table | not grep "${PREFIX}[^0-9]" || die "DM table already has devices with prefix $PREFIX!"
+fi
+
+test -n "$LVM_TEST_DIR" || LVM_TEST_DIR=${TMPDIR:-/tmp}
+test "$LVM_TEST_DIR" = "/dev" && die "Setting LVM_TEST_DIR=/dev is not supported!"
+
+TESTDIR=$(mkdtemp "$LVM_TEST_DIR" "$PREFIX.XXXXXXXXXX") || \
+ die "failed to create temporary directory in \"$LVM_TEST_DIR\""
+RUNNING_DMEVENTD=$(pgrep dmeventd || true)
+
+export TESTOLDPWD TESTDIR COMMON_PREFIX PREFIX RUNNING_DMEVENTD
+LVM_LOG_FILE_EPOCH=DEBUG
+LVM_LOG_FILE_MAX_LINES=${LVM_LOG_FILE_MAX_LINES-1000000}
+LVM_EXPECTED_EXIT_STATUS=1
+export LVM_LOG_FILE_EPOCH LVM_LOG_FILE_MAX_LINES LVM_EXPECTED_EXIT_STATUS
+
+if test -z "$SKIP_ROOT_DM_CHECK" ; then
+ # Teardown only with root
+ test -n "$BASH" && trap 'set +vx; STACKTRACE; set -vx' ERR
+ trap 'aux teardown' EXIT # don't forget to clean up
+else
+ trap 'cd $TESTOLDPWD; rm -rf "${TESTDIR:?}"' EXIT
+fi
+
+cd "$TESTDIR"
+mkdir lib tmp
+
+# Setting up symlink from $i to $TESTDIR/lib
+# library libdevmapper-event-lvm2.so.2.03 is needed with name
+test -n "${abs_top_builddir+varset}" && \
+ find "$abs_top_builddir/daemons/dmeventd/plugins/" -name '*.so*' \
+ -exec ln -s -t lib "{}" +
+find "$TESTOLDPWD/lib" ! \( -name '*.sh' -o -name '*.[cdo]' \
+ -o -name '*~' \) -exec ln -s -t lib "{}" +
+LD_LIBRARY_PATH="$TESTDIR/lib:$LD_LIBRARY_PATH"
+
+DM_DEFAULT_NAME_MANGLING_MODE=none
+DM_DEV_DIR="$TESTDIR/dev"
+LVM_SYSTEM_DIR="$TESTDIR/etc"
+TMPDIR="$TESTDIR/tmp"
+# abort on the internal dm errors in the tests (allowing test user override)
+DM_ABORT_ON_INTERNAL_ERRORS=${DM_ABORT_ON_INTERNAL_ERRORS:-1}
+DM_DEBUG_WITH_LINE_NUMBERS=${DM_DEBUG_WITH_LINE_NUMBERS:-1}
+
+export DM_DEFAULT_NAME_MANGLING_MODE DM_DEV_DIR LVM_SYSTEM_DIR DM_ABORT_ON_INTERNAL_ERRORS
+mkdir "$LVM_SYSTEM_DIR" "$DM_DEV_DIR"
+MACHINEID=$(uuidgen 2>/dev/null || echo "abcdefabcdefabcdefabcdefabcdefab")
+echo "${MACHINEID//-/}" > "$LVM_SYSTEM_DIR/machine-id" # remove all '-'
+if test -n "$LVM_TEST_DEVDIR" ; then
+ test -d "$LVM_TEST_DEVDIR" || die "Test device directory LVM_TEST_DEVDIR=\"$LVM_TEST_DEVDIR\" is not valid."
+ DM_DEV_DIR=$LVM_TEST_DEVDIR
+elif test -z "$SKIP_ROOT_DM_CHECK" ; then
+ 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?)"
+ # dmsetup makes here needed control entry if still missing
+ dmsetup version || \
+ die "Dmsetup in $DM_DEV_DIR can't report version?"
+fi
+
+echo "$TESTNAME" >TESTNAME
+# Require 50M of free space in testdir
+test "$(df -k -P . | awk '/\// {print $4}')" -gt $(( SKIP_WITH_LOW_SPACE * 1024 )) || \
+ skip "Testing requires more then ${SKIP_WITH_LOW_SPACE}M of free space in directory $TESTDIR!\\n$(df -H | sed -e 's,^,## DF: ,')"
+
+echo "Kernel is $(uname -a)"
+# Report SELinux mode
+echo "Selinux mode is $(getenforce 2>/dev/null || echo not installed)."
+free -m || true
+
+df -h || true
+
+# Set vars from utils now that we have TESTDIR/PREFIX/...
+prepare_test_vars
+
+# Set strict shell mode
+# see: http://redsymbol.net/articles/unofficial-bash-strict-mode
+test -n "$BASH" && set -euE -o pipefail
+
+# Vars for harness
+echo "@TESTDIR=$TESTDIR"
+echo "@PREFIX=$PREFIX"
+
+if test -z "$SKIP_ROOT_DM_CHECK" ; then
+ aux lvmconf
+fi
+
+test -n "$LVM_TEST_LVMPOLLD" && {
+ export LVM_LVMPOLLD_SOCKET="$TESTDIR/lvmpolld.socket"
+ export LVM_LVMPOLLD_PIDFILE="$TESTDIR/lvmpolld.pid"
+ aux prepare_lvmpolld
+}
+
+export SHARED=""
+
+if test -n "$LVM_TEST_LVMLOCKD" ; then
+ if test -n "$LVM_TEST_LOCK_TYPE_SANLOCK" ; then
+ aux lvmconf 'local/host_id = 1'
+ fi
+
+ export SHARED="--shared"
+fi
+
+# for check_lvmlockd_test, lvmlockd is restarted for each shell test.
+# for check_lvmlockd_{sanlock,dlm}, lvmlockd is started once by
+# aa-lvmlockd-{sanlock,dlm}-prepare.sh and left running for all shell tests.
+
+if test -n "$LVM_TEST_LVMLOCKD_TEST" ; then
+ aux prepare_lvmlockd
+fi
+
+echo "<======== Processing test: \"$TESTNAME\" ========>"
+
+set -vx
diff --git a/test/lib/lvm-wrapper.sh b/test/lib/lvm-wrapper.sh
index d3a2a36..469154a 100644
--- a/test/lib/lvm-wrapper.sh
+++ b/test/lib/lvm-wrapper.sh
@@ -1,5 +1,5 @@
#!/bin/sh
-# Copyright (C) 2011-2012 Red Hat, Inc.
+# Copyright (C) 2011-2017 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
@@ -7,26 +7,47 @@
#
# 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
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
. lib/paths
CMD=${0##*/}
test "$CMD" != lvm || unset CMD
+# When needed to trace command from test suite use env var before program
+# and run program directly via shell in test dir i.e.:
+# sh shell/activate-mirror.sh
+# 'LVM_GDB=1 lvcreate -l1 $vg'
+# > run
+test -z "$LVM_GDB" || exec gdb --readnow --args "$abs_top_builddir/tools/lvm" $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
+ RUN_DBG="${VALGRIND:-valgrind}";
+fi
+
+if test -n "$LVM_STRACE"; then
+ RUN_DBG="strace $LVM_STRACE -o strace.log"
fi
-$RUN_VALGRIND "$abs_top_builddir/tools/lvm" $CMD "$@" && \
- rm -f debug.log # Remove log for successful command
+case "$CMD" in
+ lvs|pvs|vgs|vgck|vgscan)
+ test "${LVM_DEBUG_LEVEL:-0}" -lt 2 && RUN_DBG="" ;;
+ pvcreate|pvremove|lvremove|vgcreate|vgremove)
+ test "${LVM_DEBUG_LEVEL:-0}" -lt 1 && RUN_DBG="" ;;
+esac
+
+# Capture parallel users of debug.log file
+#test -z "$(fuser debug.log 2>/dev/null)" || {
+# echo "TEST WARNING: \"debug.log\" is still in use while running $CMD $@" >&2
+# fuser -v debug.log >&2
+#}
+
+# the exec is important, because otherwise fatal signals inside "not" go unnoticed
+if test -n "$abs_top_builddir"; then
+ exec $RUN_DBG "$abs_top_builddir/tools/lvm" $CMD "$@"
+else # we are testing the lvm on $PATH
+ PATH=$(echo "$PATH" | sed -e 's,[^:]*lvm2-testsuite[^:]*:,,g')
+ exec $RUN_DBG lvm $CMD "$@"
+fi
diff --git a/test/lib/lvm_vdo_wrapper.sh b/test/lib/lvm_vdo_wrapper.sh
new file mode 100755
index 0000000..8333256
--- /dev/null
+++ b/test/lib/lvm_vdo_wrapper.sh
@@ -0,0 +1,364 @@
+#!/bin/bash
+#
+# Wrapper script for 'naive' emulation of vdo manager tool for systems
+# that no longer have this tool present
+#
+
+set -euE -o pipefail
+
+# tool for formatting 'old' VDO metadata format
+LVM_VDO_FORMAT=${LVM_VDO_FORMAT-"oldvdoformat"}
+# tool for shifting VDO metadata header by 2MiB
+LVM_VDO_PREPARE=${LVM_VDO_PREPARE-"oldvdoprepareforlvm"}
+# default vdo conf file
+LVM_VDO_DEFAULT_CONF=${LVM_VDO_DEFAULT_CONF-"${TMPDIR:-/tmp}/vdoconf.yml"}
+
+vdo_die_() {
+ echo -e "$@" >&2
+ return 1
+}
+
+vdo_verbose_() {
+ test -z "$vdo_verbose" || echo "$0:" "$@"
+}
+
+vdo_dry_() {
+ if test -n "$vdo_dry"; then
+ vdo_verbose_ "Dry execution" "$@"
+ return 0
+ fi
+ vdo_verbose_ "Executing" "$@"
+ "$@"
+}
+
+vdo_get_kb_size_with_unit_() {
+ local sz=${2-1} # 2nd. arg as unit - default 'k'
+
+ case "$sz" in
+ [mM]) sz=1024 ;;
+ esac
+
+ case "$1" in
+ *[kK]) sz=1 ;;
+ *[mM]) sz=1024 ;;
+ *[gG]) sz=$(( 1024 * 1024 )) ;;
+ *[tT]) sz=$(( 1024 * 1024 * 1024 )) ;;
+ *[pP]) sz=$(( 1024 * 1024 * 1024 * 1024 )) ;;
+ esac
+
+ echo $(( sz * ${1%[kKmMgGtTpP]} ))
+}
+
+#
+# Emulate functionality of deprecated 'vdo create'
+#
+vdo_create_() {
+local cachesize=
+local devsize=
+local emulate512=disabled
+local logicalsize=
+local maxdiscardsize=
+local slabbits=0 # 4k
+local slabsize=
+local sparse=
+local table=
+local vdo_compression_msg=
+local vdo_dry=
+local vdo_index_msg=
+local vdo_logicalBlockSize=
+local vdo_verbose=
+
+local vdo_ackThreads=${vdo_ackThreads-1}
+local vdo_bioRotationInterval=${vdo_bioRotationInterval-64}
+local vdo_bioThreads=${vdo_bioThreads-4}
+local vdo_blockMapCacheSize=${vdo_blockMapCacheSize-128M}
+local vdo_blockMapPeriod=${vdo_blockMapPeriod-16380}
+local vdo_compression=${vdo_compression-enabled}
+local vdo_confFile=$LVM_VDO_DEFAULT_CONF # place some file in /tmp
+local vdo_cpuThreads=${vdo_cpuThreads-2}
+local vdo_deduplication=${vdo_deduplication-enabled}
+local vdo_hashZoneThreads=${vdo_hashZoneThreads-1}
+local vdo_indexCfreq=${vdo_indexCfreq-0}
+local vdo_indexMemory=${vdo_indexMemory-0.25}
+local vdo_indexSparse=${vdo_indexSparse-disabled}
+local vdo_indexThreads=${vdo_indexThreads-0}
+local vdo_logicalSize=${vdo_logicalSize-0}
+local vdo_logicalThreads=${vdo_logicalThreads-1}
+local vdo_maxDiscardSize=${vdo_maxDiscardSize-4K}
+local vdo_name=${vdo_name-VDONAME}
+local vdo_physicalThreads=${vdo_physicalThreads-1}
+local vdo_slabSize=${vdo_slabSize-2G}
+local vdo_writePolicy=${vdo_writePolicy-auto}
+local vdo_uuid
+
+vdo_uuid="VDO-$(uuidgen || echo \"f7a3ecdc-40a0-4e43-814c-4a7039a75de4\")"
+
+while [ "$#" -ne 0 ]
+do
+ case "$1" in
+ "--blockMapCacheSize") shift; vdo_blockMapCacheSize=$1 ;;
+ "--blockMapPeriod") shift; vdo_blockMapPeriod=$1 ;;
+ "--compression") shift; vdo_compression=$1 ;;
+ "--confFile"|"-f") shift; vdo_confFile=$1 ;;
+ "--deduplication") shift; vdo_deduplication=$1 ;;
+ "--device") shift; vdo_device=$1 ;;
+ "--emulate512") shift; emulate512=$1 ;;
+ "--indexMem") shift; vdo_indexMemory=$1 ;;
+ "--maxDiscardSize") shift; vdo_maxDiscardSize=$1 ;;
+ "--name"|"-n") shift; vdo_name=$1 ;;
+ "--sparseIndex") shift; vdo_indexSparse=$1 ;;
+ "--uuid") shift ;; # ignored
+ "--vdoAckThreads") shift; vdo_ackThreads=$1 ;;
+ "--vdoBioRotationInterval") shift; vdo_bioRotationInterval=$1 ;;
+ "--vdoBioThreads") shift; vdo_bioThreads=$1 ;;
+ "--vdoCpuThreads") shift; vdo_cpuThreads=$1 ;;
+ "--vdoHashZoneThreads") shift; vdo_hashZoneThreads=$1 ;;
+ "--vdoLogicalSize") shift; vdo_logicalSize=$1 ;;
+ "--vdoLogicalThreads") shift; vdo_logicalThreads=$1 ;;
+ "--vdoLogLevel") shift ;; # ignored
+ "--vdoPhysicalThreads") shift; vdo_physicalThreads=$1 ;;
+ "--vdoSlabSize") shift; vdo_slabSize=$1 ;;
+ "--verbose"|"-d"|"--debug") vdo_verbose="-v" ;;
+ "--writePolicy") shift; vdo_writePolicy=$1 ;;
+ esac
+ shift
+done
+
+# Convert when set
+case "$emulate512" in
+ "enabled") vdo_logicalBlockSize=512 ;;
+ "disabled") vdo_logicalBlockSize=4096 ;;
+ *) vdo_die_ "Invalid emulate512 setting."
+esac
+
+case "$vdo_deduplication" in
+ "enabled") vdo_index_msg="index-enable" ;;
+ "disabled") vdo_index_msg="index-disable";;
+ *) vdo_die_ "Invalid deduplication setting."
+esac
+
+case "$vdo_compression" in
+ "enabled") vdo_compression_msg="compression on" ;;
+ "disabled") vdo_compression_msg="compression off";;
+ *) vdo_die_ "Invalid compression setting."
+esac
+
+test -n "${vdo_device-}" || vdo_die_ "VDO device is missing"
+
+blkid -c /dev/null -s UUID -o value "${vdo_device}" || true
+
+devsize=$(blockdev --getsize64 "$vdo_device")
+devsize=$(( devsize / 4096 )) # convert to 4KiB units
+
+logicalsize=$(vdo_get_kb_size_with_unit_ "$vdo_logicalSize" M)
+logicalsize=$(( logicalsize * 2 )) # 512B units
+
+cachesize=$(vdo_get_kb_size_with_unit_ "$vdo_blockMapCacheSize" M)
+cachesize=$(( cachesize / 4 )) # 4KiB units
+
+maxdiscardsize=$(vdo_get_kb_size_with_unit_ "$vdo_maxDiscardSize" M)
+maxdiscardsize=$(( maxdiscardsize / 4 )) # 4KiB units
+
+test -e "$vdo_confFile" || {
+ cat > "$vdo_confFile" <<EOF
+####################################################################
+# THIS FILE IS MACHINE GENERATED. DO NOT EDIT THIS FILE BY HAND.
+####################################################################
+config: !Configuration
+ vdos:
+EOF
+}
+
+cat >> "$vdo_confFile" <<EOF
+ $vdo_name: !VDOService
+ _operationState: finished
+ ackThreads: $vdo_ackThreads
+ activated: enabled
+ bioRotationInterval: $vdo_bioRotationInterval
+ bioThreads: $vdo_bioThreads
+ blockMapCacheSize: $(( cachesize * 4 ))K
+ blockMapPeriod: $vdo_blockMapPeriod
+ compression: $vdo_compression
+ cpuThreads: $vdo_cpuThreads
+ deduplication: $vdo_deduplication
+ device: $vdo_device
+ hashZoneThreads: $vdo_hashZoneThreads
+ indexCfreq: $vdo_indexCfreq
+ indexMemory: $vdo_indexMemory
+ indexSparse: $vdo_indexSparse
+ indexThreads: $vdo_indexThreads
+ logicalBlockSize: $vdo_logicalBlockSize
+ logicalSize: $(( logicalsize / 2 ))K
+ logicalThreads: $vdo_logicalThreads
+ maxDiscardSize: $(( maxdiscardsize * 4 ))K
+ name: $vdo_name
+ physicalSize: $(( devsize * 4 ))K
+ physicalThreads: $vdo_physicalThreads
+ slabSize: $vdo_slabSize
+ uuid: $vdo_uuid
+ writePolicy: $vdo_writePolicy
+ version: 538380551
+EOF
+
+slabsize=$(vdo_get_kb_size_with_unit_ "$vdo_slabSize")
+while test "$slabsize" -gt 4 ; do
+ slabbits=$(( slabbits + 1 ))
+ slabsize=$(( slabsize / 2 ))
+done
+
+case "$vdo_indexSparse" in
+ "enabled") sparse="--uds-sparse" ;;
+esac
+
+vdo_dry_ "$LVM_VDO_FORMAT" $vdo_verbose $sparse\
+ --logical-size "$vdo_logicalSize" --slab-bits "$slabbits"\
+ --uds-checkpoint-frequency "$vdo_indexCfreq"\
+ --uds-memory-size "$vdo_indexMemory" "$vdo_device"
+
+# V2 format
+table="0 $logicalsize vdo V2 $vdo_device\
+ $devsize\
+ $vdo_logicalBlockSize\
+ $cachesize\
+ $vdo_blockMapPeriod\
+ on\
+ $vdo_writePolicy\
+ $vdo_name\
+ maxDiscard $maxdiscardsize\
+ ack $vdo_ackThreads\
+ bio $vdo_bioThreads\
+ bioRotationInterval $vdo_bioRotationInterval\
+ cpu $vdo_cpuThreads\
+ hash $vdo_hashZoneThreads\
+ logical $vdo_logicalThreads\
+ physical $vdo_physicalThreads"
+
+vdo_dry_ dmsetup create "$vdo_name" --uuid "$vdo_uuid" --table "$table"
+vdo_dry_ dmsetup message "$vdo_name" 0 "$vdo_index_msg"
+vdo_dry_ dmsetup message "$vdo_name" 0 "$vdo_compression_msg"
+}
+
+#
+# vdo stop
+#
+vdo_stop_() {
+local vdo_confFile=$LVM_VDO_DEFAULT_CONF
+local vdo_dry=
+local vdo_force=
+local vdo_name=
+local vdo_verbose=
+
+while [ "$#" -ne 0 ]
+do
+ case "$1" in
+ "--confFile"|"-f") shift; vdo_confFile=$1 ;;
+ "--name"|"-n") shift; vdo_name=$1 ;;
+ "--verbose"|"-d"|"--debug") vdo_verbose="-v" ;;
+ "--force") vdo_force="--force" ;;
+ esac
+ shift
+done
+
+vdo_dry_ dmsetup status --target vdo "$vdo_name" 2>/dev/null || return 0
+vdo_dry_ dmsetup remove $vdo_force "$vdo_name" || true
+}
+
+#
+# vdo remove
+#
+vdo_remove_() {
+local vdo_confFile=$LVM_VDO_DEFAULT_CONF
+local vdo_name=
+
+vdo_stop_ "$@"
+while [ "$#" -ne 0 ]
+do
+ case "$1" in
+ "--confFile"|"-f") shift; vdo_confFile=$1 ;;
+ "--name"|"-n") shift; vdo_name=$1 ;;
+ esac
+ shift
+done
+
+# remove entry from conf file
+awk -v vdovolname="$vdo_name" 'BEGIN { have=0 }
+ $0 ~ "!VDOService" { have=0 }
+ $0 ~ vdovolname":" { have=1 }
+ { if (have==0) { print } ;}
+ ' "$vdo_confFile" >"${vdo_confFile}.new"
+
+mv "${vdo_confFile}.new" "$vdo_confFile"
+grep "!VDOService" "$vdo_confFile" || rm -f "$vdo_confFile"
+}
+
+
+#
+# print_config_file
+#
+vdo_print_config_file_() {
+local vdo_confFile=$LVM_VDO_DEFAULT_CONF
+
+while [ "$#" -ne 0 ]
+do
+ case "$1" in
+ "--confFile"|"-f") shift; vdo_confFile=$1 ;;
+ "--verbose"|"-d"|"--debug") ;;
+ "--logfile") shift ;; # ignore
+ esac
+ shift
+done
+
+cat "$vdo_confFile"
+}
+
+#
+# vdo convert
+#
+vdo_convert_() {
+local vdo_confFile=$LVM_VDO_DEFAULT_CONF
+local vdo_dry=
+local vdo_force=
+local vdo_name=
+local vdo_verbose=
+local vdo_device=
+local vdo_dry_run=
+local vdo_check=
+local vdo_version=
+local vdo_help=
+
+while [ "$#" -ne 0 ]
+do
+ case "$1" in
+ "--confFile"|"-f") shift; vdo_confFile=$1 ;;
+ "--name"|"-n") shift; vdo_name=$1 ;;
+ "--verbose"|"-d"|"--debug") vdo_verbose="-v" ;;
+ "--force") vdo_force="--force" ;;
+ "--dry-run") vdo_dry_run="--dry-run" ;;
+ "--check") vdo_check="--check" ;;
+ "--version") vdo_version="--version" ;;
+ "--help") vdo_help="--help" ;;
+ esac
+ shift
+done
+
+vdo_device=$(awk -v vdovolname="$vdo_name" 'BEGIN { have=0 }
+ $0 ~ "!VDOService" { have=0 }
+ $0 ~ vdovolname":" { have=1 }
+ { if (have==1 && $0 ~ "device:" ) { print $2 } ;}'\
+ "$vdo_confFile")
+
+#dmsetup status --target vdo "$vdo_name" || true
+vdo_dry_ "$LVM_VDO_PREPARE" $vdo_dry_run $vdo_check $vdo_version $vdo_help "$vdo_device"
+vdo_dry_ vdo_remove_ -f "$vdo_confFile" -n "$vdo_name" || true
+}
+
+#
+# MAIN
+#
+case "${1-}" in
+ "create") shift; vdo_create_ "$@" ;;
+ "remove") shift; vdo_remove_ "$@" ;;
+ "stop") shift; vdo_stop_ "$@" ;;
+ "convert") shift; vdo_convert_ "$@" ;;
+ "printConfigFile") shift; vdo_print_config_file_ "$@" ;;
+esac
diff --git a/test/lib/mke2fs.conf b/test/lib/mke2fs.conf
new file mode 100644
index 0000000..81bed21
--- /dev/null
+++ b/test/lib/mke2fs.conf
@@ -0,0 +1,45 @@
+[defaults]
+ base_features = sparse_super,filetype,resize_inode,dir_index,ext_attr
+ enable_periodic_fsck = 1
+ blocksize = 4096
+ inode_size = 256
+ inode_ratio = 16384
+
+[fs_types]
+ ext3 = {
+ features = has_journal
+ }
+ ext4 = {
+ features = has_journal,extent,huge_file,flex_bg,dir_nlink,extra_isize
+ inode_size = 256
+ }
+ ext4dev = {
+ features = has_journal,extent,huge_file,flex_bg,dir_nlink,extra_isize
+ inode_size = 256
+ options = test_fs=1
+ }
+ small = {
+ blocksize = 1024
+ inode_size = 128
+ inode_ratio = 4096
+ }
+ floppy = {
+ blocksize = 1024
+ inode_size = 128
+ inode_ratio = 8192
+ }
+ news = {
+ inode_ratio = 4096
+ }
+ largefile = {
+ inode_ratio = 1048576
+ blocksize = -1
+ }
+ largefile4 = {
+ inode_ratio = 4194304
+ blocksize = -1
+ }
+ hurd = {
+ blocksize = 4096
+ inode_size = 128
+ }
diff --git a/test/lib/not.c b/test/lib/not.c
index 9f6b988..751c95b 100644
--- a/test/lib/not.c
+++ b/test/lib/not.c
@@ -9,28 +9,55 @@
*
* 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
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <unistd.h>
#include <stdio.h>
+#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
-static int finished(const char *cmd, int status) {
+static int _finished(const char *cmd, int status, int pid) {
+ int ret;
if (!strcmp(cmd, "not"))
return !status;
if (!strcmp(cmd, "should")) {
- if (status)
+ if (status) {
fprintf(stderr, "TEST WARNING: Ignoring command failure.\n");
+ /* TODO: avoid using shell here */
+ /* Show log for failing command which should be passing */
+ ret = system("ls debug.log*${LVM_LOG_FILE_EPOCH}* 2>/dev/null");
+ if (WIFEXITED(ret) && WEXITSTATUS(ret) == 0) {
+ printf("## timing off\n<======== Debug log ========>\n"); /* timing off */
+ fflush(stdout);
+ if (system("sed -e 's,^,## DEBUG: ,' debug.log*${LVM_LOG_FILE_EPOCH}* 2>/dev/null")) {
+ /* Ignore result code */;
+ }
+ printf("## timing on\n"); /* timing on */
+ if (system("rm -f debug.log*${LVM_LOG_FILE_EPOCH}*")) {
+ /* Ignore result code */;
+ }
+ fflush(stdout);
+ }
+ }
return 0;
+ } else if (!strcmp(cmd, "invalid")) {
+ if (status == 3)
+ return 0;
+ fprintf(stderr, "Test expected exit code 3 (invalid), but got %d.\n", status);
+ } else if (!strcmp(cmd, "fail")) {
+ if (status == 5)
+ return 0;
+ fprintf(stderr, "Test expected exit code 5 (fail), but got %d.\n", status);
}
return 6;
}
int main(int args, char **argv) {
+ const char *val = NULL;
pid_t pid;
int status;
int FAILURE = 6;
@@ -45,11 +72,26 @@ int main(int args, char **argv) {
fprintf(stderr, "Could not fork\n");
return FAILURE;
} else if (pid == 0) { /* child */
+ if (!strcmp(argv[0], "not"))
+ val = ">1";
+ else if (!strcmp(argv[0], "invalid"))
+ val = "3";
+ else if (!strcmp(argv[0], "fail"))
+ val = "5";
+
+ if (val)
+ (void) setenv("LVM_EXPECTED_EXIT_STATUS", val, 1);
+
+ /* coverity[os_cmd_sink] intentionally passing argv + 1 */
execvp(argv[1], &argv[1]);
/* should not be accessible */
return FAILURE;
} else { /* parent */
- waitpid(pid, &status, 0);
+ if (waitpid(pid, &status, 0) < 0) {
+ fprintf(stderr, "Process %d failed on waitpid.\n", pid);
+ return FAILURE;
+ }
+
if (!WIFEXITED(status)) {
if (WIFSIGNALED(status))
fprintf(stderr,
@@ -59,7 +101,7 @@ int main(int args, char **argv) {
return FAILURE;
}
- return finished(argv[0], WEXITSTATUS(status));
+ return _finished(argv[0], WEXITSTATUS(status), pid);
}
/* not accessible */
return FAILURE;
diff --git a/test/lib/runner.cpp b/test/lib/runner.cpp
new file mode 100644
index 0000000..d522228
--- /dev/null
+++ b/test/lib/runner.cpp
@@ -0,0 +1,46 @@
+/* -*- C++ -*- copyright (c) 2014 Red Hat, Inc.
+ *
+ * This file is part of LVM2.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "brick-shelltest.h"
+
+int main(int argc, const char **argv)
+{
+
+ if (getuid() != 0) {
+ std::cout << "Skipping tests, root is required, current UID: " << getuid() << "\n";
+ return 0;
+ }
+
+ try {
+ return brick::shelltest::run( argc, argv, "LVM_TEST_FLAVOUR" );
+ } catch (std::exception const& e) {
+ std::cout << "Exception: " << e.what() << "\n";
+ }
+
+ return 1;
+}
+
diff --git a/test/lib/test-corosync-conf b/test/lib/test-corosync-conf
new file mode 100644
index 0000000..e04be73
--- /dev/null
+++ b/test/lib/test-corosync-conf
@@ -0,0 +1,28 @@
+# created by lvm test suite
+totem {
+ version: 2
+ secauth: off
+ cluster_name: test
+ interface {
+ ingnumber: 0
+ bindnetaddr: 127.0.0.1
+ mcastaddr: 239.255.255.100
+ mcastport: 5405
+ ttl: 1
+ }
+}
+nodelist {
+ node {
+ ring0_addr: @LOCAL_NODE@
+ nodeid: 1
+ }
+}
+quorum {
+ provider: corosync_votequorum
+ expected_votes: 1
+ two_node: 0
+}
+logging {
+ to_syslog: yes
+}
+
diff --git a/test/lib/test-dlm-conf b/test/lib/test-dlm-conf
new file mode 100644
index 0000000..a93c93f
--- /dev/null
+++ b/test/lib/test-dlm-conf
@@ -0,0 +1,4 @@
+# created by lvm test suite
+log_debug=1
+enable_fencing=0
+
diff --git a/test/lib/test-sanlock-conf b/test/lib/test-sanlock-conf
new file mode 100644
index 0000000..6285d63
--- /dev/null
+++ b/test/lib/test-sanlock-conf
@@ -0,0 +1,2 @@
+# created by lvm test suite
+use_watchdog=0
diff --git a/test/lib/test.sh b/test/lib/test.sh
deleted file mode 100644
index 3729749..0000000
--- a/test/lib/test.sh
+++ /dev/null
@@ -1,79 +0,0 @@
-#!/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
index 70d9f66..24b7f89 100644
--- a/test/lib/utils.sh
+++ b/test/lib/utils.sh
@@ -1,4 +1,4 @@
-#!/bin/bash
+#!/usr/bin/env bash
# Copyright (C) 2011-2012 Red Hat, Inc. All rights reserved.
#
# This copyrighted material is made available to anyone wishing to use,
@@ -7,7 +7,7 @@
#
# 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
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
set -e
MAX_TRIES=4
@@ -15,7 +15,8 @@ IFS_NL='
'
die() {
- echo "$@" >&2
+ rm -f debug.log*
+ echo -e "$@" >&2
return 1
}
@@ -34,16 +35,16 @@ rand_bytes() {
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)
+ n_plus_50=$(( 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;
+ len=${#data} # number of chars in $data
+ 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 \
+ echo "$data" | dd bs=1 skip=50 count="$n" 2>/dev/null \
| tr -c "$chars" "01234567$chars$chars$chars"
}
@@ -56,6 +57,8 @@ mkdtemp() {
destdir=$1
template=$2
+ test -d "$destdir" || die "DIR ('$destdir') does not exist."
+
case "$template" in
*XXXX) ;;
*) die "Invalid template: $template (must have a suffix of at least 4 X's)";;
@@ -84,7 +87,7 @@ mkdtemp() {
base_template=$(echo "$template" | sed 's/XX*$//')
# Calculate how many X's we've just removed.
- nx=$(expr length "$template" - length "$base_template")
+ nx=$(( ${#template} - ${#base_template} ))
err=
i=1
@@ -94,62 +97,136 @@ mkdtemp() {
err=$(mkdir -m 0700 "$candidate_dir" 2>&1) && \
{ echo "$candidate_dir"; return; }
test $MAX_TRIES -le $i && break;
- i=$(expr $i + 1)
+ i=$(( i + 1 ))
done
die "$err"
}
+# Like grep, just always print 1st. line
+grep1_() {
+ awk -v pattern="${1}" 'NR==1 || $0~pattern' "${@:2}"
+}
+
+stacktrace() {
+ trap - ERR
+ # i=1 - ignoring innermost frame - it is always stacktrace function
+ local i=1 n=${#BASH_LINENO[*]}
+ # n-=1 - ignoring last frame as well - it is not interesting
+ n=$(( n - 1 ))
+
+ echo "## - $0:${BASH_LINENO[$((n-1))]}"
+ while [[ $i -lt $n ]]; do
+ echo "## $i ${FUNCNAME[$i]}() called from ${BASH_SOURCE[$((i+1))]}:${BASH_LINENO[$i]}"
+ i=$(( i + 1 ))
+ done
+}
+
STACKTRACE() {
trap - ERR
- local i=0
+ local i
- 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
+ stacktrace
- 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!"
- }
+ test "${LVM_TEST_PARALLEL:-0}" -eq 0 && test -z "$RUNNING_DMEVENTD" && \
+ test ! -f LOCAL_DMEVENTD && pgrep dmeventd >DPID 2>/dev/null && {
+ echo "## ERROR: The test started dmeventd ($(< DPID)) unexpectedly."
+ kill "$(< DPID)"
+ }
# 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
+ # Check for all cores newer then TESTNAME file
+ # Assume users keep prefix 'core'
+ # TODO: possibly better integrate with coredumpctl & systemd
+ while IFS= read -r i; do
+ bin=$(gdb -batch -c "$i" 2>&1 | grep "generated by" | \
+ sed -e "s,.*generated by \`\([^ ']*\).*,\1,") || continue
+ {
+ echo bt full
+ echo l
+ echo quit
+ } > gdb_commands.txt || rm -f gdb_commands.txt
+
+ if test ! -s gdb_commands.txt ; then
+ echo "Out of disk space, can't check coredump $i generated by $bin."
+ continue
+ fi
+
+ echo "## Checking coredump: $i generated by $bin."
+ gdb -batch -c "$i" -x gdb_commands.txt "$(which "$bin")" 2>/dev/null | \
+ sed -e "s,^,## GDB: ," || continue
+ done < <(find . "$(dirname "$(sysctl -n kernel.core_pattern)")" \
+ "/var/lib/systemd/coredump/" -name 'core*' -newer TESTNAME 2>/dev/null || true)
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
+
+ test -z "$LVM_TEST_NODEBUG" && test -f TESTNAME && {
+ local name
+ local idx=0
+ for i in debug.log* ; do
+ test -f "$i" || break # nothing is found (expands to debug.log*)
+ name=${i##debug.log_}
+ name=${name%%_*}
+ test "$name" = "DEBUG" && { name="$name$idx" ; idx=$(( idx + 1 )) ; }
+ echo "<======== Debug log $i ========>"
+ sed -e "s,^,## $name: ," "$i"
+ mv -f "$i" "debug_${i#debug.}"
+ done
+ if test -e strace.log ; then
+ echo "<======== Strace debug log ========>"
+ sed -e "s,^,## STRACE: ," strace.log
+ fi
+ if dmsetup info -c | grep -q "$PREFIX" ; then
+ echo "<======== Info ========>"
+ dmsetup info -c | grep1_ "$PREFIX"| sed -e "s,^,## DMINFO: ,"
+ echo "<======== Active table ========>"
+ dmsetup table | grep "$PREFIX" | sed -e "s,^,## DMTABLE: ,"
+ echo "<======== Inactive table ========>"
+ dmsetup table --inactive | grep "$PREFIX" | sed -e "s,^,## DMITABLE: ,"
+ echo "<======== Status ========>"
+ dmsetup status --noflush | grep "$PREFIX" | sed -e "s,^,## DMSTATUS: ,"
+ echo "<======== Tree ========>"
+ dmsetup ls --tree | sed -e "s,^,## DMTREE: ,"
+ echo "<======== Recursive list of $DM_DEV_DIR ========>"
+ ls -lR -I bsg -I bus -I char -Idma_heap -I dri \
+ -I hugepages -I input -I mqueue \
+ -I net -I pts -I shm -I snd \
+ -I tty?* -I usb -I vfio -I vcs?* \
+ -I virtio-ports \
+ "$DM_DEV_DIR" | sed -e "s,^,## LS_LR: ,"
+ echo "<======== Udev DB content ========>"
+ for i in /sys/block/dm-* /sys/block/loop* ; do
+ udevadm info --query=all --path "$i" 2>/dev/null || true
+ done | sed -e "s,^,## UDEV: ,"
+ fi
+ echo "<======== Free space ========>"
+ df -h | sed -e "s,^,## DF_H: ,"
+ echo "<======== Script file \"$(< TESTNAME)\" ========>"
+ local script=$0
+ test -f "$script" || script="$TESTOLDPWD/$0"
+ awk '{print "## Line:", NR, "\t", $0}' "$script"
+ }
}
init_udev_transaction() {
- if test "$DM_UDEV_SYNCHRONISATION" = 1; then
- local cookie=$(dmsetup udevcreatecookie)
+ if test "$DM_UDEV_SYNCHRONIZATION" = 1; then
+ local cookie
+ 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
+ if test "$DM_UDEV_SYNCHRONIZATION" = 1 && test -n "${DM_UDEV_COOKIE-}" ; then
+ dmsetup udevreleasecookie || true
unset DM_UDEV_COOKIE
fi
}
teardown_udev_cookies() {
- if test "$DM_UDEV_SYNCHRONISATION" = 1; then
+ if test "$DM_UDEV_SYNCHRONIZATION" = 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
@@ -161,55 +238,73 @@ dm_info() {
should dmsetup info --noheadings -c -o "$@"
}
+dm_status() {
+ should dmsetup status --noheadings "$@"
+}
+
dm_table() {
should dmsetup table "$@"
}
skip() {
+ set +vx # debug off
+ if test "$#" -eq 0; then
+ stacktrace
+ else
+ echo -e "TEST SKIPPED:" "$@"
+ fi
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
+get_real_devs() {
+ REAL_DEVICES=( $(<REAL_DEVICES) )
+ export REAL_DEVICES
+}
- 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
+get_devs() {
+ local IFS=$IFS_NL
+ DEVICES=( $(<DEVICES) )
+ export DEVICES
+# local DEVS=( $(<DEVICES) )
+# eval "$1"'=("${DEVS[@]}")'
}
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"
+ lv="LV"
+
+ for i in {1..16}; do
+ 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"
+ if test -n "$LVM_TEST_DEVICE_LIST"; then
+ local count=0
+ while read path; do
+ count=$(( count + 1 ))
+ eval "dev$count=\"$path\""
+ done < "$LVM_TEST_DEVICE_LIST"
+ else
+ for i in {1..16}; do
+ eval "dev$i=\"$DM_DEV_DIR/mapper/${PREFIX}pv$i\""
+ done
+ fi
+}
-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
+if test -z "${abs_top_builddir+varset}" && test -z "${installed_testsuite+varset}"; then
+ . lib/paths || die "something went wrong -- lib/paths is missing?"
+fi
+
+if test -z "${installed_testsuite+varset}"; then
+ case "$PATH" in
+ *"$abs_top_builddir/test/lib"*) ;;
+ *)
+ PATH="$abs_top_builddir/test/lib:$abs_top_builddir/test/api:$PATH"
+ LVM_BINARY=$(which lvm)
+ LD_LIBRARY_PATH="$abs_top_builddir/daemons/dmeventd:$abs_top_builddir/tools:$abs_top_builddir/libdm:$LD_LIBRARY_PATH"
+ export PATH LD_LIBRARY_PATH LVM_BINARY ;;
+ esac
+fi
test -z "$PREFIX" || prepare_test_vars
diff --git a/test/shell/000-basic.sh b/test/shell/000-basic.sh
index 83e6efe..15f2a60 100644
--- a/test/shell/000-basic.sh
+++ b/test/shell/000-basic.sh
@@ -1,4 +1,5 @@
-#!/bin/sh
+#!/usr/bin/env bash
+
# Copyright (C) 2009-2011 Red Hat, Inc. All rights reserved.
#
# This copyrighted material is made available to anyone wishing to use,
@@ -7,23 +8,41 @@
#
# 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
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
-. lib/test
-lvm version
+SKIP_WITH_LVMPOLLD=1
-v=$abs_top_builddir/lib/misc/lvm-version.h
-sed -n "/#define LVM_VERSION ./s///p" "$v" | sed "s/ .*//" > expected
+. lib/inittest
+
+lvm version
-lvm pvmove --version|sed -n "1s/.*: *\([0-9][^ ]*\) .*/\1/p" > actual
+lvm pvmove --version|sed -n "1s/.*: *\([0-9][^ ]*\) .*/\1/p" | tee version
# ensure they are the same
-diff -u actual expected
+diff -u version lib/version-expected
+
+dmstats version |sed -n "1s/.*: *\([0-9][^ ]*\) .*/\1/p" | tee dmstats-version
+
+# ensure dmstats version matches build
+diff -u dmstats-version lib/dm-version-expected
# ensure we can create devices (uses dmsetup, etc)
aux prepare_devs 5
+get_devs
# ensure we do not crash on a bug in config file
aux lvmconf 'log/prefix = 1""'
-not lvs $(cat DEVICES)
+not lvs "${DEVICES[@]}"
+
+# validate testing machine with its services is in expected state and will not interfere with tests
+if systemctl -a >out 2>/dev/null ; then
+ for i in dm-event lvm2-lvmpolld lvm2-monitor ; do
+ grep $i out > mout || continue
+ grep -v masked mout || continue
+ should not echo "Present unmasked $i service/socket may randomize testing results!"
+ echo "+++++ Stop & Mask with systemctl +++++"
+ touch show_out
+ done
+ test ! -e show_out || cat out
+fi
diff --git a/test/shell/aa-lvmlockd-dlm-prepare.sh b/test/shell/aa-lvmlockd-dlm-prepare.sh
new file mode 100644
index 0000000..c261c1d
--- /dev/null
+++ b/test/shell/aa-lvmlockd-dlm-prepare.sh
@@ -0,0 +1,23 @@
+#!/usr/bin/env bash
+
+# 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+test_description='Set up things to run tests with dlm'
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+[ -z "$LVM_TEST_LOCK_TYPE_DLM" ] && skip;
+
+aux prepare_dlm
+aux prepare_lvmlockd
+
diff --git a/test/shell/aa-lvmlockd-idm-prepare.sh b/test/shell/aa-lvmlockd-idm-prepare.sh
new file mode 100644
index 0000000..fc9d75b
--- /dev/null
+++ b/test/shell/aa-lvmlockd-idm-prepare.sh
@@ -0,0 +1,22 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2021 Seagate. 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 v2.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+test_description='Set up things to run tests with idm'
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+[ -z "$LVM_TEST_LOCK_TYPE_IDM" ] && skip;
+
+aux prepare_idm
+aux prepare_lvmlockd
diff --git a/test/shell/aa-lvmlockd-sanlock-prepare.sh b/test/shell/aa-lvmlockd-sanlock-prepare.sh
new file mode 100644
index 0000000..6db14fe
--- /dev/null
+++ b/test/shell/aa-lvmlockd-sanlock-prepare.sh
@@ -0,0 +1,46 @@
+#!/usr/bin/env bash
+
+# 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+test_description='Set up things to run tests with sanlock'
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+[ -z "$LVM_TEST_LOCK_TYPE_SANLOCK" ] && skip;
+
+# Create a device and a VG that are both outside the scope of
+# the standard lvm test suite so that they will not be removed
+# and will remain in place while all the tests are run.
+#
+# Use this VG to hold the sanlock global lock which will be used
+# by lvmlockd during other tests.
+#
+# This script will be run before any standard tests are run.
+# After all the tests are run, another script will be run
+# to remove this VG and device.
+
+GL_DEV="/dev/mapper/GL_DEV"
+GL_FILE="$PWD/gl_file.img"
+dmsetup remove GL_DEV || true
+rm -f "$GL_FILE"
+dd if=/dev/zero of="$GL_FILE" bs=$((1024*1024)) count=1024 2> /dev/null
+GL_LOOP=$(losetup -f "$GL_FILE" --show)
+echo "0 $(blockdev --getsize $GL_LOOP linear $GL_LOOP 0)" | dmsetup create GL_DEV
+
+aux prepare_sanlock
+aux prepare_lvmlockd
+
+vgcreate --config 'devices { global_filter=["a|GL_DEV|", "r|.*|"] filter=["a|GL_DEV|", "r|.*|"]}' --lock-type sanlock glvg $GL_DEV
+
+vgs --config 'devices { global_filter=["a|GL_DEV|", "r|.*|"] filter=["a|GL_DEV|", "r|.*|"]}' -o+locktype,lockargs glvg
+
diff --git a/test/shell/activate-minor.sh b/test/shell/activate-minor.sh
index 5433f01..1b1ea8b 100644
--- a/test/shell/activate-minor.sh
+++ b/test/shell/activate-minor.sh
@@ -1,4 +1,5 @@
-#!/bin/bash
+#!/usr/bin/env bash
+
# Copyright (C) 2012 Red Hat, Inc. All rights reserved.
#
# This copyrighted material is made available to anyone wishing to use,
@@ -7,13 +8,22 @@
#
# 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
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+
+SKIP_WITH_LVMPOLLD=1
-. lib/test
+. lib/inittest
+
+# Just skip this test if minor is already in use...
+dmsetup info | tee info
+grep -E "^Major, minor: *[0-9]+, 123" info && skip
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
+grep -E "^Major, minor: *[0-9]+, 123" info
+
+vgremove -ff $vg
diff --git a/test/shell/activate-missing-segment.sh b/test/shell/activate-missing-segment.sh
index 55ec7ec..f066e58 100644
--- a/test/shell/activate-missing-segment.sh
+++ b/test/shell/activate-missing-segment.sh
@@ -1,4 +1,5 @@
-#!/bin/sh
+#!/usr/bin/env bash
+
# Copyright (C) 2010 Red Hat, Inc. All rights reserved.
#
# This copyrighted material is made available to anyone wishing to use,
@@ -7,7 +8,7 @@
#
# 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
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
# Test activation behaviour with devices missing.
# - snapshots and their origins are only activated together; if one fails, both
@@ -16,7 +17,10 @@
# instead lvconvert --repair them?)
# - linear LVs with bits missing are not activated
-. lib/test
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
aux prepare_vg 2
@@ -27,3 +31,5 @@ aux disable_dev "$dev1"
not vgchange -a y $vg
vgchange -a y --partial $vg
check active $vg span
+
+vgremove -ff $vg
diff --git a/test/shell/activate-missing.sh b/test/shell/activate-missing.sh
index 4676ee1..c1c02d8 100644
--- a/test/shell/activate-missing.sh
+++ b/test/shell/activate-missing.sh
@@ -1,4 +1,5 @@
-#!/bin/sh
+#!/usr/bin/env bash
+
# Copyright (C) 2010 Red Hat, Inc. All rights reserved.
#
# This copyrighted material is made available to anyone wishing to use,
@@ -7,7 +8,7 @@
#
# 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
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
# Test activation behaviour with devices missing.
# - snapshots and their origins are only activated together; if one fails, both
@@ -16,7 +17,10 @@
# instead lvconvert --repair them?)
# - linear LVs with bits missing are not activated
-. lib/test
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
aux prepare_vg 4
@@ -24,11 +28,11 @@ 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 -aey -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"
+lvcreate -aey -l1 --type mirror -m1 -n mirror12 --mirrorlog core $vg "$dev1" "$dev2"
+lvcreate -aey -l1 --type mirror -m1 -n mirror123 $vg "$dev1" "$dev2" "$dev3"
vgchange -a n $vg
aux disable_dev "$dev1"
@@ -46,7 +50,7 @@ check inactive $vg mirror123
vgchange -a n $vg
aux enable_dev "$dev1"
aux disable_dev "$dev2"
-not vgchange -a y $vg
+not vgchange -aey $vg
not vgck $vg
check active $vg linear1
@@ -60,7 +64,7 @@ check inactive $vg mirror123
vgchange -a n $vg
aux enable_dev "$dev2"
aux disable_dev "$dev3"
-not vgchange -a y $vg
+not vgchange -aey $vg
not vgck $vg
check active $vg origin1
@@ -74,7 +78,7 @@ check active $vg mirror12
vgchange -a n $vg
aux enable_dev "$dev3"
aux disable_dev "$dev4"
-vgchange -a y $vg
+vgchange -aey $vg
not vgck $vg
check active $vg origin1
@@ -84,3 +88,5 @@ check active $vg linear2
check active $vg linear12
check active $vg mirror12
check active $vg mirror123
+
+vgremove -ff $vg
diff --git a/test/shell/activate-partial.sh b/test/shell/activate-partial.sh
index 4a06fc1..70c50bc 100644
--- a/test/shell/activate-partial.sh
+++ b/test/shell/activate-partial.sh
@@ -1,4 +1,5 @@
-#!/bin/sh
+#!/usr/bin/env bash
+
# Copyright (C) 2010 Red Hat, Inc. All rights reserved.
#
# This copyrighted material is made available to anyone wishing to use,
@@ -7,25 +8,28 @@
#
# 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
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+
+SKIP_WITH_LVMPOLLD=1
-. lib/test
+. lib/inittest
aux prepare_vg 3
-lvcreate -m 1 -l 1 -n mirror $vg
+lvcreate -aey --type mirror -m 1 -l 1 --nosync -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 -aey $vg/mirror
+lvchange -v --partial -aey $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
+vgchange -aey --partial $vg
# check vgremove
-vgremove -f $vg
+vgremove -ff $vg
diff --git a/test/shell/activation-skip.sh b/test/shell/activation-skip.sh
new file mode 100644
index 0000000..b0b3206
--- /dev/null
+++ b/test/shell/activation-skip.sh
@@ -0,0 +1,38 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2014 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+# Test skip activation flag -k|--setactivationskip
+
+aux prepare_vg
+
+lvcreate -an --zero n -l 1 -n $lv1 $vg
+lvcreate -ky -K -l1 -n $lv2 $vg
+get lv_field $vg/$lv2 lv_attr | grep -- "-wi-a----k"
+
+lvchange -ay -K $vg
+check active $vg $lv1
+lvchange -an $vg
+
+lvchange -ay --setactivationskip y $vg/$lv1
+check inactive $vg $lv1
+
+get lv_field $vg/$lv1 lv_attr | grep -- "-wi------k"
+
+lvchange -ay -K $vg
+check active $vg $lv1
+
+vgremove -ff $vg
diff --git a/test/shell/allow-mixed-block-sizes.sh b/test/shell/allow-mixed-block-sizes.sh
new file mode 100644
index 0000000..d6983cc
--- /dev/null
+++ b/test/shell/allow-mixed-block-sizes.sh
@@ -0,0 +1,71 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2019-2021 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+SKIP_WITH_LVMLOCKD=1
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+losetup -h | grep sector-size || skip
+which fallocate || skip
+
+fallocate -l 2M loopa
+fallocate -l 2M loopb
+
+# Fight a weird occasional race in losetup usage:
+#
+# losetup: loopa: failed to set up loop device: Resource temporarily unavailable
+# loop0: detected capacity change from 0 to 4096
+# loop_set_block_size: loop0 () has still dirty pages (nrpages=2)
+for i in {1..5} ; do
+ LOOP1=$(losetup -f loopa --sector-size 4096 --show || true)
+ test -n "$LOOP1" && break
+done
+for i in {1..5} ; do
+ LOOP2=$(losetup -f loopb --show || true)
+ test -n "$LOOP2" && break
+done
+
+# prepare devX mapping so it works for real & fake dev dir
+d=1
+for i in "$LOOP1" "$LOOP2"; do
+ echo "$i"
+ m=${i##*loop}
+ test -e "$DM_DEV_DIR/loop$m" || mknod "$DM_DEV_DIR/loop$m" b 7 "$m"
+ eval "dev$d=\"$DM_DEV_DIR/loop$m\""
+ d=$(( d + 1 ))
+done
+
+aux extend_filter "a|$dev1|" "a|$dev2|"
+aux extend_devices "$dev1" "$dev2"
+
+not vgcreate --config 'devices/allow_mixed_block_sizes=0' $vg "$dev1" "$dev2"
+vgcreate --config 'devices/allow_mixed_block_sizes=1' $vg "$dev1" "$dev2"
+vgs --config 'devices/allow_mixed_block_sizes=1' $vg
+
+for i in "$dev1" "$dev2" ; do
+ aux wipefs_a "$i"
+ # FIXME - we are not missing notification for hinting
+ # likely in more places - as the test should be able to work without
+ # system's udev working only on real /dev dir.
+ # aux notify_lvmetad "$i"
+done
+
+vgcreate --config 'devices/allow_mixed_block_sizes=1' $vg "$dev1"
+vgs --config 'devices/allow_mixed_block_sizes=1' $vg
+not vgextend --config 'devices/allow_mixed_block_sizes=0' $vg "$dev2"
+vgextend --config 'devices/allow_mixed_block_sizes=1' $vg "$dev2"
+
+losetup -d "$LOOP1"
+losetup -d "$LOOP2"
+rm loopa
+rm loopb
diff --git a/test/shell/autoactivation-metadata.sh b/test/shell/autoactivation-metadata.sh
new file mode 100644
index 0000000..3cdb5b3
--- /dev/null
+++ b/test/shell/autoactivation-metadata.sh
@@ -0,0 +1,336 @@
+
+SKIP_WITH_LVMPOLLD=1
+SKIP_WITH_LVMLOCKD=1
+
+RUNDIR="/run"
+test -d "$RUNDIR" || RUNDIR="/var/run"
+PVS_ONLINE_DIR="$RUNDIR/lvm/pvs_online"
+VGS_ONLINE_DIR="$RUNDIR/lvm/vgs_online"
+PVS_LOOKUP_DIR="$RUNDIR/lvm/pvs_lookup"
+
+_clear_online_files() {
+ # wait till udev is finished
+ aux udev_wait
+ rm -f "$PVS_ONLINE_DIR"/*
+ rm -f "$VGS_ONLINE_DIR"/*
+ rm -f "$PVS_LOOKUP_DIR"/*
+}
+
+. lib/inittest
+
+aux prepare_devs 1
+
+#
+# test lvchange --setautoactivation
+#
+
+# default
+vgcreate $vg "$dev1"
+lvcreate -n $lv1 -l1 -an $vg
+check vg_field $vg autoactivation "enabled"
+check lv_field $vg/$lv1 autoactivation "enabled"
+
+lvchange -aay $vg/$lv1
+check lv_field $vg/$lv1 lv_active "active"
+lvchange -an $vg/$lv1
+lvchange -aay $vg
+check lv_field $vg/$lv1 lv_active "active"
+lvchange -an $vg/$lv1
+vgchange -aay $vg
+check lv_field $vg/$lv1 lv_active "active"
+lvchange -an $vg/$lv1
+pvscan --cache -aay "$dev1"
+check lv_field $vg/$lv1 lv_active "active"
+lvchange -an $vg/$lv1
+_clear_online_files
+
+# --aa=n
+lvchange --setautoactivation n $vg/$lv1
+check vg_field $vg autoactivation "enabled"
+check lv_field $vg/$lv1 autoactivation ""
+
+lvchange -aay $vg/$lv1
+check lv_field $vg/$lv1 lv_active ""
+lvchange -aay $vg
+check lv_field $vg/$lv1 lv_active ""
+vgchange -aay $vg
+check lv_field $vg/$lv1 lv_active ""
+pvscan --cache -aay "$dev1"
+check lv_field $vg/$lv1 lv_active ""
+_clear_online_files
+
+# --aa=y
+lvchange --setautoactivation y $vg/$lv1
+check vg_field $vg autoactivation "enabled"
+check lv_field $vg/$lv1 autoactivation "enabled"
+
+lvchange -aay $vg/$lv1
+check lv_field $vg/$lv1 lv_active "active"
+lvchange -an $vg/$lv1
+lvchange -aay $vg
+check lv_field $vg/$lv1 lv_active "active"
+lvchange -an $vg/$lv1
+vgchange -aay $vg
+check lv_field $vg/$lv1 lv_active "active"
+lvchange -an $vg/$lv1
+pvscan --cache -aay "$dev1"
+check lv_field $vg/$lv1 lv_active "active"
+lvchange -an $vg/$lv1
+_clear_online_files
+
+vgremove -y $vg
+
+#
+# test vgchange --setautoactivation
+#
+
+# default
+vgcreate $vg "$dev1"
+lvcreate -n $lv1 -l1 -an $vg
+
+# --aa=n
+vgchange --setautoactivation n $vg
+check vg_field $vg autoactivation ""
+check lv_field $vg/$lv1 autoactivation "enabled"
+
+lvchange -aay $vg/$lv1
+check lv_field $vg/$lv1 lv_active ""
+lvchange -aay $vg
+check lv_field $vg/$lv1 lv_active ""
+vgchange -aay $vg
+check lv_field $vg/$lv1 lv_active ""
+pvscan --cache -aay "$dev1"
+check lv_field $vg/$lv1 lv_active ""
+_clear_online_files
+
+# --aa=y
+vgchange --setautoactivation y $vg
+check vg_field $vg autoactivation "enabled"
+check lv_field $vg/$lv1 autoactivation "enabled"
+
+lvchange -aay $vg/$lv1
+check lv_field $vg/$lv1 lv_active "active"
+lvchange -an $vg/$lv1
+lvchange -aay $vg
+check lv_field $vg/$lv1 lv_active "active"
+lvchange -an $vg/$lv1
+vgchange -aay $vg
+check lv_field $vg/$lv1 lv_active "active"
+lvchange -an $vg/$lv1
+pvscan --cache -aay "$dev1"
+check lv_field $vg/$lv1 lv_active "active"
+lvchange -an $vg/$lv1
+_clear_online_files
+
+vgremove -y $vg
+
+#
+# test vgcreate --setautoactivation, lvcreate --setautoactivation
+#
+
+vgcreate $vg "$dev1"
+lvcreate -n $lv1 -l1 -an $vg
+lvcreate -n $lv2 -l1 --setautoactivation y -an $vg
+lvcreate -n $lv3 -l1 --setautoactivation n -an $vg
+check vg_field $vg autoactivation "enabled"
+check lv_field $vg/$lv1 autoactivation "enabled"
+check lv_field $vg/$lv2 autoactivation "enabled"
+check lv_field $vg/$lv3 autoactivation ""
+vgchange -aay $vg
+check lv_field $vg/$lv1 lv_active "active"
+check lv_field $vg/$lv2 lv_active "active"
+check lv_field $vg/$lv3 lv_active ""
+vgchange -an $vg
+lvchange -aay $vg/$lv1
+lvchange -aay $vg/$lv2
+lvchange -aay $vg/$lv3
+check lv_field $vg/$lv1 lv_active "active"
+check lv_field $vg/$lv2 lv_active "active"
+check lv_field $vg/$lv3 lv_active ""
+vgchange -an $vg
+pvscan --cache -aay "$dev1"
+check lv_field $vg/$lv1 lv_active "active"
+check lv_field $vg/$lv2 lv_active "active"
+check lv_field $vg/$lv3 lv_active ""
+vgchange -an $vg
+vgremove -y $vg
+_clear_online_files
+
+vgcreate --setautoactivation y $vg "$dev1"
+lvcreate -n $lv1 -l1 -an $vg
+lvcreate -n $lv2 -l1 --setautoactivation y -an $vg
+lvcreate -n $lv3 -l1 --setautoactivation n -an $vg
+check vg_field $vg autoactivation "enabled"
+check lv_field $vg/$lv1 autoactivation "enabled"
+check lv_field $vg/$lv2 autoactivation "enabled"
+check lv_field $vg/$lv3 autoactivation ""
+vgchange -aay $vg
+check lv_field $vg/$lv1 lv_active "active"
+check lv_field $vg/$lv2 lv_active "active"
+check lv_field $vg/$lv3 lv_active ""
+vgchange -an $vg
+lvchange -aay $vg/$lv1
+lvchange -aay $vg/$lv2
+lvchange -aay $vg/$lv3
+check lv_field $vg/$lv1 lv_active "active"
+check lv_field $vg/$lv2 lv_active "active"
+check lv_field $vg/$lv3 lv_active ""
+vgchange -an $vg
+pvscan --cache -aay "$dev1"
+check lv_field $vg/$lv1 lv_active "active"
+check lv_field $vg/$lv2 lv_active "active"
+check lv_field $vg/$lv3 lv_active ""
+vgchange -an $vg
+vgremove -y $vg
+_clear_online_files
+
+vgcreate --setautoactivation n $vg "$dev1"
+lvcreate -n $lv1 -l1 -an $vg
+lvcreate -n $lv2 -l1 --setautoactivation y -an $vg
+lvcreate -n $lv3 -l1 --setautoactivation n -an $vg
+check vg_field $vg autoactivation ""
+check lv_field $vg/$lv1 autoactivation "enabled"
+check lv_field $vg/$lv2 autoactivation "enabled"
+check lv_field $vg/$lv3 autoactivation ""
+vgchange -aay $vg
+check lv_field $vg/$lv1 lv_active ""
+check lv_field $vg/$lv2 lv_active ""
+check lv_field $vg/$lv3 lv_active ""
+lvchange -aay $vg/$lv1
+lvchange -aay $vg/$lv2
+lvchange -aay $vg/$lv3
+check lv_field $vg/$lv1 lv_active ""
+check lv_field $vg/$lv2 lv_active ""
+check lv_field $vg/$lv3 lv_active ""
+pvscan --cache -aay "$dev1"
+check lv_field $vg/$lv1 lv_active ""
+check lv_field $vg/$lv2 lv_active ""
+check lv_field $vg/$lv3 lv_active ""
+vgremove -y $vg
+_clear_online_files
+
+
+#
+# test combination of --aa and auto_activation_volume_list
+#
+
+vgcreate $vg "$dev1"
+lvcreate -n $lv1 -l1 -an $vg
+lvcreate -n $lv2 -l1 --setautoactivation n -an $vg
+check vg_field $vg autoactivation "enabled"
+check lv_field $vg/$lv1 autoactivation "enabled"
+check lv_field $vg/$lv2 autoactivation ""
+
+# list prevents all aa, metadata settings don't matter
+aux lvmconf "activation/auto_activation_volume_list = [ ]"
+vgchange -aay $vg
+check lv_field $vg/$lv1 lv_active ""
+check lv_field $vg/$lv2 lv_active ""
+vgchange -an $vg
+lvchange -aay $vg/$lv1
+lvchange -aay $vg/$lv2
+check lv_field $vg/$lv1 lv_active ""
+check lv_field $vg/$lv2 lv_active ""
+vgchange -an $vg
+pvscan --cache -aay "$dev1"
+check lv_field $vg/$lv1 lv_active ""
+check lv_field $vg/$lv2 lv_active ""
+vgchange -an $vg
+_clear_online_files
+
+# list allows all vg aa, metadata allows lv1 -> lv1 activated
+aux lvmconf "activation/auto_activation_volume_list = [ \"$vg\" ]"
+vgchange -aay $vg
+check lv_field $vg/$lv1 lv_active "active"
+check lv_field $vg/$lv2 lv_active ""
+vgchange -an $vg
+lvchange -aay $vg/$lv1
+lvchange -aay $vg/$lv2
+check lv_field $vg/$lv1 lv_active "active"
+check lv_field $vg/$lv2 lv_active ""
+vgchange -an $vg
+pvscan --cache -aay "$dev1"
+check lv_field $vg/$lv1 lv_active "active"
+check lv_field $vg/$lv2 lv_active ""
+vgchange -an $vg
+_clear_online_files
+
+# list allows lv1, metadata allows lv1 -> lv1 activated
+aux lvmconf "activation/auto_activation_volume_list = [ \"$vg/$lv1\" ]"
+vgchange -aay $vg
+check lv_field $vg/$lv1 lv_active "active"
+check lv_field $vg/$lv2 lv_active ""
+vgchange -an $vg
+lvchange -aay $vg/$lv1
+lvchange -aay $vg/$lv2
+check lv_field $vg/$lv1 lv_active "active"
+check lv_field $vg/$lv2 lv_active ""
+vgchange -an $vg
+pvscan --cache -aay "$dev1"
+check lv_field $vg/$lv1 lv_active "active"
+check lv_field $vg/$lv2 lv_active ""
+vgchange -an $vg
+_clear_online_files
+
+# list allows lv2, metadata allows lv1 -> nothing activated
+aux lvmconf "activation/auto_activation_volume_list = [ \"$vg/$lv2\" ]"
+vgchange -aay $vg
+check lv_field $vg/$lv1 lv_active ""
+check lv_field $vg/$lv2 lv_active ""
+vgchange -an $vg
+lvchange -aay $vg/$lv1
+lvchange -aay $vg/$lv2
+check lv_field $vg/$lv1 lv_active ""
+check lv_field $vg/$lv2 lv_active ""
+vgchange -an $vg
+pvscan --cache -aay "$dev1"
+check lv_field $vg/$lv1 lv_active ""
+check lv_field $vg/$lv2 lv_active ""
+vgchange -an $vg
+_clear_online_files
+
+vgremove -y $vg
+
+vgcreate --setautoactivation n $vg "$dev1"
+lvcreate -n $lv1 -l1 -an $vg
+lvcreate -n $lv2 -l1 --setautoactivation n -an $vg
+check vg_field $vg autoactivation ""
+check lv_field $vg/$lv1 autoactivation "enabled"
+check lv_field $vg/$lv2 autoactivation ""
+
+# list prevents all aa, metadata settings don't matter
+aux lvmconf "activation/auto_activation_volume_list = [ ]"
+vgchange -aay $vg
+check lv_field $vg/$lv1 lv_active ""
+check lv_field $vg/$lv2 lv_active ""
+vgchange -an $vg
+lvchange -aay $vg/$lv1
+lvchange -aay $vg/$lv2
+check lv_field $vg/$lv1 lv_active ""
+check lv_field $vg/$lv2 lv_active ""
+vgchange -an $vg
+pvscan --cache -aay "$dev1"
+check lv_field $vg/$lv1 lv_active ""
+check lv_field $vg/$lv2 lv_active ""
+vgchange -an $vg
+_clear_online_files
+
+# list allows lv1, metadata disallows vg -> nothing activated
+aux lvmconf "activation/auto_activation_volume_list = [ \"$vg/$lv1\" ]"
+vgchange -aay $vg
+check lv_field $vg/$lv1 lv_active ""
+check lv_field $vg/$lv2 lv_active ""
+vgchange -an $vg
+lvchange -aay $vg/$lv1
+lvchange -aay $vg/$lv2
+check lv_field $vg/$lv1 lv_active ""
+check lv_field $vg/$lv2 lv_active ""
+vgchange -an $vg
+pvscan --cache -aay "$dev1"
+check lv_field $vg/$lv1 lv_active ""
+check lv_field $vg/$lv2 lv_active ""
+vgchange -an $vg
+_clear_online_files
+
+vgremove -y $vg
+
diff --git a/test/shell/backup-read-only.sh b/test/shell/backup-read-only.sh
new file mode 100644
index 0000000..331e846
--- /dev/null
+++ b/test/shell/backup-read-only.sh
@@ -0,0 +1,84 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2015 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+
+SKIP_WITH_CLVMD=1
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+which mkfs.ext3 || skip
+
+aux prepare_vg 2
+
+# Note: inittest.sh sets LVM_SYSTEM_DIR to 'just' etc
+etc_lv="$DM_DEV_DIR/$vg/$lv1"
+
+cleanup_mounted_and_teardown()
+{
+ umount "$mount_dir" || true
+ aux teardown
+}
+
+vgreduce $vg "$dev2"
+
+lvcreate -n $lv1 -l 20%FREE $vg
+mkfs.ext3 -b4096 -j "$etc_lv"
+
+#
+# check read-only archive dir
+#
+mount_dir="etc/archive"
+trap 'cleanup_mounted_and_teardown' EXIT
+mkdir -p "$mount_dir"
+mount -n -r "$etc_lv" "$mount_dir"
+
+aux lvmconf "backup/archive = 1" "backup/backup = 1"
+
+# cannot archive to read-only - requires user to specify -An
+not lvcreate -n $lv2 -l 10%FREE $vg
+lvcreate -An -n $lv2 -l 10%FREE $vg
+
+not vgextend $vg "$dev2"
+vgextend -An $vg "$dev2"
+
+umount "$mount_dir" || true
+
+vgreduce $vg "$dev2"
+
+#
+# check read-only backup dir
+#
+mount_dir="etc/backup"
+mount -n -r "$etc_lv" "$mount_dir"
+
+# Must not fail on making backup
+vgscan
+
+lvcreate -An -n $lv3 -l 10%FREE $vg
+
+vgextend $vg "$dev2"
+
+#
+# Now check both archive & backup read-only
+#
+rm -rf etc/archive
+ln -s backup etc/archive
+
+# Must not fail on making backup
+vgscan
+lvcreate -An -n $lv4 -l 10%FREE $vg
+
+umount "$mount_dir" || true
+
+# TODO maybe also support --ignorelockingfailure ??
+vgremove -ff $vg
diff --git a/test/shell/cache-metadata2.sh b/test/shell/cache-metadata2.sh
new file mode 100644
index 0000000..0270f5d
--- /dev/null
+++ b/test/shell/cache-metadata2.sh
@@ -0,0 +1,100 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2017 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+# Exercise usage of metadata2 cache metadata format
+
+
+SKIP_WITH_LVMPOLLD=1
+
+# Until new version of cache_check tools - no integrity validation
+LVM_TEST_CACHE_CHECK_CMD=""
+
+. lib/inittest
+
+META2=
+aux have_cache 1 10 0 || {
+ META2=not
+ aux have_cache 1 3 0 || skip
+}
+
+aux prepare_vg 5 80
+
+lvcreate -L2 -n $lv1 $vg
+
+lvcreate --type cache-pool -L1 $vg/cpool1
+# no parameter - no format is stored
+check lv_field $vg/cpool1 cachemetadataformat ""
+
+lvcreate --type cache-pool -L1 --config 'allocation/cache_metadata_format=1' $vg/cpool
+# format is in configuration - would be applied during actual caching
+# so not stored in this moment
+check lv_field $vg/cpool cachemetadataformat ""
+
+
+lvcreate --type cache-pool -L1 --cachemetadataformat 1 $vg/cpool2
+# format was specified on cmdline - preserve it metadata
+check lv_field $vg/cpool2 cachemetadataformat "1"
+
+lvconvert --yes -H --cachepool $vg/cpool --config 'allocation/cache_metadata_format=1' $vg/$lv1
+check lv_field $vg/cpool2 cachemetadataformat "1"
+
+lvs -a -o+cachemetadataformat $vg
+
+lvremove -f $vg
+
+lvcreate --type cache-pool --cachepolicy cleaner --cachemetadataformat 1 -L1 $vg/cpool
+lvcreate -H -L10 -n $lv1 --cachepool $vg/cpool
+check lv_field $vg/$lv1 cachemetadataformat "1"
+lvremove -f $vg
+
+if [ -z "$META2" ]; then
+# for these test we need kernel with metadata2 support
+
+lvcreate --type cache-pool -L1 $vg/cpool
+lvcreate -H -L10 -n $lv1 --cachepool $vg/cpool
+check lv_field $vg/$lv1 cachemetadataformat "2"
+lvremove -f $vg
+
+lvcreate -L10 -n $lv1 $vg
+lvcreate --type cache-pool -L1 $vg/cpool
+lvconvert -y -H --cachepool $vg/cpool $vg/$lv1
+check lv_field $vg/$lv1 cachemetadataformat "2"
+lvremove -f $vg
+
+
+lvcreate -L10 -n $lv1 $vg
+lvcreate --type cache-pool -L1 $vg/cpool
+lvconvert --cachemetadataformat 1 -y -H --cachepool $vg/cpool $vg/$lv1
+check lv_field $vg/$lv1 cachemetadataformat "1"
+lvremove -f $vg
+
+lvcreate -L10 -n $lv1 $vg
+lvcreate --type cache-pool -L1 $vg/cpool
+lvconvert --config 'allocation/cache_metadata_format=1' -y -H --cachepool $vg/cpool $vg/$lv1
+check lv_field $vg/$lv1 cachemetadataformat "1"
+lvremove -f $vg
+
+lvcreate --type cache-pool --cachepolicy cleaner -L1 $vg/cpool
+lvcreate -H -L10 -n $lv1 --cachepool $vg/cpool
+check lv_field $vg/$lv1 cachemetadataformat "2"
+lvremove -f $vg
+
+lvcreate --type cache-pool --cachepolicy mq --cachemetadataformat 1 -L1 $vg/cpool
+check lv_field $vg/cpool cachemetadataformat "1"
+lvcreate -H -L10 -n $lv1 --cachemetadataformat 2 --cachepool $vg/cpool
+check lv_field $vg/$lv1 cachemetadataformat "2"
+lvremove -f $vg
+
+fi
+#lvs -a -o name,cachemetadataformat,kernelmetadataformat,chunksize,cachepolicy,cachemode $vg
+
+vgremove -f $vg
diff --git a/test/shell/cache-no-discard.sh b/test/shell/cache-no-discard.sh
new file mode 100644
index 0000000..4593622
--- /dev/null
+++ b/test/shell/cache-no-discard.sh
@@ -0,0 +1,45 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2019 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+# Check reporting of no_discard_passdown
+
+SKIP_WITH_LVMPOLLD=1
+
+# Until new version of cache_check tools - no integrity validation
+LVM_TEST_CACHE_CHECK_CMD=""
+
+. lib/inittest
+
+aux kernel_at_least 5 1 || skip
+
+aux have_cache 2 0
+
+aux prepare_vg 1
+
+# Create thinLV without discard
+lvcreate --discards=ignore -T -V20 -L20 -n $lv $vg/pool
+
+aux extend_filter_LVMTEST
+
+# Use discard-less LV as PV for $vg1
+pvcreate "$DM_DEV_DIR/$vg/$lv"
+vgcreate -s 128K $vg1 "$DM_DEV_DIR/$vg/$lv"
+
+# Create simple cache LV
+lvcreate -aey -L2 -n $lv1 $vg1
+lvcreate -H -L2 $vg1/$lv1
+
+#lvs -ao+kernel_discards $vg1
+check lv_field $vg1/$lv1 kernel_discards "nopassdown"
+
+vgremove -f $vg1
+vgremove -f $vg
diff --git a/test/shell/cache-single-options.sh b/test/shell/cache-single-options.sh
new file mode 100644
index 0000000..c736e52
--- /dev/null
+++ b/test/shell/cache-single-options.sh
@@ -0,0 +1,273 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2018 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+# Test single lv cache options
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+aux have_cache 1 10 0 || skip
+which mkfs.xfs || skip
+
+mount_dir="mnt"
+mkdir -p "$mount_dir"
+
+# generate random data
+dd if=/dev/urandom of=pattern1 bs=512K count=1
+
+aux prepare_devs 5 310
+
+vgcreate $SHARED $vg "$dev1" "$dev2" "$dev3" "$dev4" "$dev5"
+
+lvcreate -n $lv1 -L 300 -an $vg "$dev1"
+lvcreate -n $lv2 -l 4 -an $vg "$dev2"
+lvcreate -n $lv3 -l 4 -an $vg "$dev3"
+lvcreate -n $lv4 -l 4 -an $vg "$dev4"
+lvcreate -n $lv5 -l 8 -an $vg "$dev5"
+
+mkfs_mount_umount()
+{
+ lvt=$1
+
+ lvchange -ay $vg/$lvt
+
+ mkfs.xfs -f -s size=4096 "$DM_DEV_DIR/$vg/$lvt"
+ mount "$DM_DEV_DIR/$vg/$lvt" "$mount_dir"
+ cp pattern1 "$mount_dir/pattern1"
+ dd if=/dev/zero of="$mount_dir/zeros2M" bs=1M count=2 conv=fdatasync
+ umount "$mount_dir"
+
+ lvchange -an $vg/$lvt
+}
+
+mount_umount()
+{
+ lvt=$1
+
+ lvchange -ay $vg/$lvt
+
+ mount "$DM_DEV_DIR/$vg/$lvt" "$mount_dir"
+ diff pattern1 "$mount_dir/pattern1"
+ dd if="$mount_dir/zeros2M" of=/dev/null bs=1M count=2
+ umount "$mount_dir"
+
+ lvchange -an $vg/$lvt
+}
+
+#
+# Test --cachemetadataformat
+#
+
+# 1 shouldn't be used any longer
+not lvconvert --cachemetadataformat 1 -y --type cache --cachevol $lv2 $vg/$lv1
+
+# 3 doesn't exist
+not lvconvert --cachemetadataformat 3 -y --type cache --cachevol $lv2 $vg/$lv1
+
+# 2 is used by default
+lvconvert -y --type cache --cachevol $lv2 $vg/$lv1
+
+check lv_field $vg/$lv1 cachemetadataformat "2"
+
+lvconvert --splitcache $vg/$lv1
+check lv_field $vg/$lv1 segtype linear
+check lv_field $vg/$lv2 segtype linear
+
+# 2 can be set explicitly
+lvconvert --cachemetadataformat 2 -y --type cache --cachevol $lv2 $vg/$lv1
+
+check lv_field $vg/$lv1 cachemetadataformat "2"
+
+lvconvert --splitcache $vg/$lv1
+
+# "auto" means 2
+lvconvert --cachemetadataformat auto -y --type cache --cachevol $lv2 $vg/$lv1
+
+check lv_field $vg/$lv1 cachemetadataformat "2"
+
+mkfs_mount_umount $lv1
+
+lvconvert --splitcache $vg/$lv1
+check lv_field $vg/$lv1 segtype linear
+check lv_field $vg/$lv2 segtype linear
+mount_umount $lv1
+
+
+#
+# Test --poolmetadatasize
+#
+
+lvconvert -y --type cache --cachevol $lv2 --poolmetadatasize 4m $vg/$lv1
+
+check lv_field $vg/$lv1 lv_metadata_size "4.00m"
+
+mkfs_mount_umount $lv1
+
+lvconvert --splitcache $vg/$lv1
+check lv_field $vg/$lv1 segtype linear
+check lv_field $vg/$lv2 segtype linear
+mount_umount $lv1
+
+
+#
+# Test --chunksize
+#
+
+lvconvert -y --type cache --cachevol $lv2 --chunksize 32k $vg/$lv1
+
+check lv_field $vg/$lv1 chunksize "32.00k"
+
+mkfs_mount_umount $lv1
+
+lvconvert --splitcache $vg/$lv1
+check lv_field $vg/$lv1 segtype linear
+check lv_field $vg/$lv2 segtype linear
+mount_umount $lv1
+
+
+#
+# Test --cachemode
+#
+
+lvconvert -y --type cache --cachevol $lv2 --cachemode writethrough $vg/$lv1
+
+check lv_field $vg/$lv1 cachemode "writethrough"
+
+mkfs_mount_umount $lv1
+
+lvconvert --splitcache $vg/$lv1
+check lv_field $vg/$lv1 segtype linear
+check lv_field $vg/$lv2 segtype linear
+mount_umount $lv1
+
+# FIXME: kernel errors for other cache modes
+
+#lvconvert -y --type cache --cachevol $lv2 --cachemode passthrough $vg/$lv1
+
+#check lv_field $vg/$lv1 cachemode "passthrough"
+
+#mkfs_mount_umount $lv1
+
+#lvconvert --splitcache $vg/$lv1
+#check lv_field $vg/$lv1 segtype linear
+#check lv_field $vg/$lv2 segtype linear
+#mount_umount $lv1
+
+
+lvconvert -y --type cache --cachevol $lv2 --cachemode writeback $vg/$lv1
+
+check lv_field $vg/$lv1 cachemode "writeback"
+
+mkfs_mount_umount $lv1
+
+lvconvert --splitcache $vg/$lv1
+check lv_field $vg/$lv1 segtype linear
+check lv_field $vg/$lv2 segtype linear
+mount_umount $lv1
+
+
+#
+# Test --cachepolicy
+#
+
+lvconvert -y --type cache --cachevol $lv2 --cachepolicy smq $vg/$lv1
+
+check lv_field $vg/$lv1 cachepolicy "smq"
+
+mkfs_mount_umount $lv1
+
+lvchange --cachepolicy cleaner $vg/$lv1
+lvchange -ay $vg/$lv1
+check lv_field $vg/$lv1 cachepolicy "cleaner"
+lvchange -an $vg/$lv1
+
+lvconvert --splitcache $vg/$lv1
+check lv_field $vg/$lv1 segtype linear
+check lv_field $vg/$lv2 segtype linear
+mount_umount $lv1
+
+
+#
+# Test --cachesettings
+# (only for mq policy, no settings for smq)
+#
+
+lvconvert -y --type cache --cachevol $lv2 --cachemode writethrough --cachepolicy mq --cachesettings 'migration_threshold = 233 sequential_threshold=13 random_threshold =1' $vg/$lv1
+
+check lv_field $vg/$lv1 cachemode "writethrough"
+check lv_field $vg/$lv1 cachepolicy "mq"
+
+lvs -o cachesettings $vg/$lv1 > settings
+grep "migration_threshold=233" settings
+grep "sequential_threshold=13" settings
+grep "random_threshold=1" settings
+
+mkfs_mount_umount $lv1
+
+lvconvert --splitcache $vg/$lv1
+check lv_field $vg/$lv1 segtype linear
+check lv_field $vg/$lv2 segtype linear
+mount_umount $lv1
+
+
+#
+# Test lvchange of --cachemode, --cachepolicy, --cachesettings
+#
+
+lvconvert -y --type cache --cachevol $lv2 $vg/$lv1
+
+lvchange -ay $vg/$lv1
+
+lvchange -y --cachemode writeback $vg/$lv1
+
+check lv_field $vg/$lv1 cachemode "writeback"
+
+lvchange --cachemode writethrough $vg/$lv1
+
+check lv_field $vg/$lv1 cachemode "writethrough"
+
+lvchange --cachemode passthrough $vg/$lv1
+
+check lv_field $vg/$lv1 cachemode "passthrough"
+
+lvchange -an $vg/$lv1
+
+lvchange --cachepolicy mq --cachesettings 'migration_threshold=100' $vg/$lv1
+
+check lv_field $vg/$lv1 cachepolicy "mq"
+check lv_field $vg/$lv1 cachesettings "migration_threshold=100"
+
+lvconvert --splitcache $vg/$lv1
+
+
+#
+# Test --poolmetadata
+#
+
+# causes a cache-pool type LV to be created
+lvconvert -y --type cache --cachepool $lv3 --poolmetadata $lv4 $vg/$lv5
+
+lvs -a -o+segtype $vg
+
+check lv_field $vg/$lv5 segtype cache
+
+# check lv_field doesn't work for hidden lvs
+lvs -a -o segtype $vg/${lv3}_cpool > segtype
+grep cache-pool segtype
+
+lvconvert --splitcache $vg/$lv5
+check lv_field $vg/$lv5 segtype linear
+check lv_field $vg/$lv3 segtype cache-pool
+
+
+vgremove -ff $vg
diff --git a/test/shell/cache-single-split.sh b/test/shell/cache-single-split.sh
new file mode 100644
index 0000000..025a086
--- /dev/null
+++ b/test/shell/cache-single-split.sh
@@ -0,0 +1,423 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2018 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+# Test single lv cache options
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+case "$(uname -r)" in
+6.[0123]*|5.19*) skip "Skippen test that kills this kernel" ;;
+esac
+
+mkfs_mount_umount()
+{
+ lvt=$1
+
+ lvchange -ay $vg/$lvt
+
+ mkfs.xfs -f -s size=4096 "$DM_DEV_DIR/$vg/$lvt"
+ mount "$DM_DEV_DIR/$vg/$lvt" "$mount_dir"
+ cp pattern1 "$mount_dir/pattern1"
+ dd if=/dev/zero of="$mount_dir/zeros2M" bs=1M count=32 conv=fdatasync
+ umount "$mount_dir"
+
+ lvchange -an $vg/$lvt
+}
+
+mount_umount()
+{
+ lvt=$1
+
+ lvchange -ay $vg/$lvt
+
+ mount "$DM_DEV_DIR/$vg/$lvt" "$mount_dir"
+ diff pattern1 "$mount_dir/pattern1"
+ dd if="$mount_dir/zeros2M" of=/dev/null bs=1M count=32
+ umount "$mount_dir"
+
+ lvchange -an $vg/$lvt
+}
+
+aux have_cache 1 10 0 || skip
+which mkfs.xfs || skip
+
+case $(cache_check -V) in
+# support for v2 starts with version 0.7
+0.[0-6]*) skip 'At least version 0.7 of cache_check tool is needed.' ;;
+esac
+
+mount_dir="mnt"
+mkdir -p "$mount_dir"
+
+# generate random data
+dd if=/dev/urandom of=pattern1 bs=512K count=1
+
+aux prepare_devs 4 310
+
+vgcreate $SHARED $vg "$dev1" "$dev2" "$dev3" "$dev4"
+
+lvcreate -n $lv1 -L 300 -an $vg "$dev1" "$dev4"
+lvcreate -n $lv2 -l 4 -an $vg "$dev2"
+
+#
+# split when no devs are missing
+# while inactive
+# both cachemodes work the same
+#
+
+lvconvert -y --type cache --cachevol $lv2 --cachemode writethrough $vg/$lv1
+
+check lv_field $vg/$lv1 segtype "cache"
+check lv_field $vg/$lv1 cachemode "writethrough"
+
+mkfs_mount_umount $lv1
+
+lvconvert --splitcache $vg/$lv1
+lvs -o segtype $vg/$lv1 | grep linear
+lvs -o segtype $vg/$lv2 | grep linear
+
+lvchange -ay $vg/$lv2
+cache_check "$DM_DEV_DIR/$vg/$lv2"
+lvchange -an $vg/$lv2
+
+lvconvert -y --type cache --cachevol $lv2 --cachemode writeback $vg/$lv1
+
+check lv_field $vg/$lv1 segtype "cache"
+check lv_field $vg/$lv1 cachemode "writeback"
+
+mkfs_mount_umount $lv1
+
+lvconvert --splitcache $vg/$lv1
+lvs -o segtype $vg/$lv1 | grep linear
+lvs -o segtype $vg/$lv2 | grep linear
+
+lvchange -ay $vg/$lv2
+cache_check "$DM_DEV_DIR/$vg/$lv2"
+lvchange -an $vg/$lv2
+
+mount_umount $lv1
+
+
+#
+# split when no devs are missing
+# while active
+# both cachemodes work the same
+#
+
+lvconvert -y --type cache --cachevol $lv2 --cachemode writethrough $vg/$lv1
+
+check lv_field $vg/$lv1 segtype "cache"
+check lv_field $vg/$lv1 cachemode "writethrough"
+
+mkfs_mount_umount $lv1
+
+lvchange -ay $vg/$lv1
+
+lvconvert --splitcache $vg/$lv1
+lvs -o segtype $vg/$lv1 | grep linear
+lvs -o segtype $vg/$lv2 | grep linear
+
+lvchange -ay $vg/$lv2
+cache_check "$DM_DEV_DIR/$vg/$lv2"
+lvchange -an $vg/$lv2
+
+mount_umount $lv1
+
+lvconvert -y --type cache --cachevol $lv2 --cachemode writeback $vg/$lv1
+
+check lv_field $vg/$lv1 segtype "cache"
+check lv_field $vg/$lv1 cachemode "writeback"
+
+lvchange -an $vg/$lv1
+
+mkfs_mount_umount $lv1
+
+lvchange -ay $vg/$lv1
+
+lvconvert --splitcache $vg/$lv1
+lvs -o segtype $vg/$lv1 | grep linear
+lvs -o segtype $vg/$lv2 | grep linear
+
+lvchange -ay $vg/$lv2
+cache_check "$DM_DEV_DIR/$vg/$lv2"
+lvchange -an $vg/$lv2
+
+#
+# split while cachevol is missing
+# writethrough
+#
+
+lvconvert -y --type cache --cachevol $lv2 --cachemode writethrough $vg/$lv1
+
+check lv_field $vg/$lv1 segtype "cache"
+check lv_field $vg/$lv1 cachemode "writethrough"
+
+lvchange -an $vg/$lv1
+
+mkfs_mount_umount $lv1
+
+lvchange -ay $vg/$lv1
+
+aux disable_dev "$dev2"
+
+lvconvert --splitcache $vg/$lv1
+
+lvs -o segtype $vg/$lv1 | grep linear
+
+aux enable_dev "$dev2"
+
+lvs -o segtype $vg/$lv2 | grep linear
+
+lvchange -ay --activationmode partial $vg/$lv2
+cache_check "$DM_DEV_DIR/$vg/$lv2"
+lvchange -an $vg/$lv2
+
+vgck --updatemetadata $vg
+lvs $vg
+vgchange -an $vg
+vgextend --restoremissing $vg "$dev2"
+
+mount_umount $lv1
+
+#
+# split while cachevol is missing
+# writeback
+#
+
+lvremove $vg/$lv2
+lvcreate -n $lv2 -l 4 -an $vg "$dev2"
+
+lvconvert -y --type cache --cachevol $lv2 --cachemode writeback $vg/$lv1
+
+check lv_field $vg/$lv1 segtype "cache"
+check lv_field $vg/$lv1 cachemode "writeback"
+
+mkfs_mount_umount $lv1
+
+aux disable_dev "$dev2"
+
+not lvconvert --splitcache $vg/$lv1
+lvconvert --splitcache --force --yes $vg/$lv1
+
+lvs -o segtype $vg/$lv1 | grep linear
+
+aux enable_dev "$dev2"
+
+lvs -o segtype $vg/$lv2 | grep linear
+
+lvchange -ay --activationmode partial $vg/$lv2
+cache_check "$DM_DEV_DIR/$vg/$lv2"
+lvchange -an $vg/$lv2
+
+vgck --updatemetadata $vg
+lvs $vg
+vgchange -an $vg
+vgextend --restoremissing $vg "$dev2"
+
+#
+# split while cachevol has 1 of 2 PVs
+# writethrough
+#
+
+lvremove $vg/$lv2
+lvcreate -n $lv2 -l 14 -an $vg "$dev2:0-10" "$dev3"
+
+lvconvert -y --type cache --cachevol $lv2 --cachemode writethrough $vg/$lv1
+
+check lv_field $vg/$lv1 segtype "cache"
+check lv_field $vg/$lv1 cachemode "writethrough"
+
+mkfs_mount_umount $lv1
+
+aux disable_dev "$dev3"
+
+lvconvert --splitcache $vg/$lv1
+
+lvs -o segtype $vg/$lv1 | grep linear
+
+aux enable_dev "$dev3"
+
+lvs -o segtype $vg/$lv2 | grep linear
+
+lvchange -ay --activationmode partial $vg/$lv2
+cache_check "$DM_DEV_DIR/$vg/$lv2"
+lvchange -an $vg/$lv2
+
+vgck --updatemetadata $vg
+lvs $vg
+vgchange -an $vg
+vgextend --restoremissing $vg "$dev3"
+
+mount_umount $lv1
+
+#
+# split while cachevol has 1 of 2 PVs
+# writeback
+#
+
+lvremove $vg/$lv2
+lvcreate -n $lv2 -l 14 -an $vg "$dev2:0-10" "$dev3"
+
+lvconvert -y --type cache --cachevol $lv2 --cachemode writeback $vg/$lv1
+
+check lv_field $vg/$lv1 segtype "cache"
+check lv_field $vg/$lv1 cachemode "writeback"
+
+mkfs_mount_umount $lv1
+
+aux disable_dev "$dev3"
+
+not lvconvert --splitcache $vg/$lv1
+lvconvert --splitcache --force --yes $vg/$lv1
+
+lvs -o segtype $vg/$lv1 | grep linear
+
+aux enable_dev "$dev3"
+
+lvs -o segtype $vg/$lv2 | grep linear
+
+lvchange -ay --activationmode partial $vg/$lv2
+cache_check "$DM_DEV_DIR/$vg/$lv2"
+lvchange -an $vg/$lv2
+
+vgck --updatemetadata $vg
+lvs $vg
+vgchange -an $vg
+vgextend --restoremissing $vg "$dev3"
+
+#
+# uncache when no devs are missing
+# while inactive
+# both cachemodes work the same
+#
+
+lvremove $vg/$lv1
+lvremove $vg/$lv2
+
+lvcreate -n $lv1 -L 300 -an $vg "$dev1:0-10" "$dev4"
+lvcreate -n $lv2 -l 4 -an $vg "$dev2"
+
+lvconvert -y --type cache --cachevol $lv2 --cachemode writethrough $vg/$lv1
+
+mkfs_mount_umount $lv1
+
+lvconvert --uncache $vg/$lv1
+lvs -o segtype $vg/$lv1 | grep linear
+
+lvcreate -n $lv2 -l 4 -an $vg "$dev2"
+
+lvconvert -y --type cache --cachevol $lv2 --cachemode writeback $vg/$lv1
+
+mkfs_mount_umount $lv1
+
+lvconvert --uncache $vg/$lv1
+lvs -o segtype $vg/$lv1 | grep linear
+
+mount_umount $lv1
+
+#
+# uncache when no devs are missing
+# while active
+# both cachemodes work the same
+#
+
+lvremove $vg/$lv1
+
+lvcreate -n $lv1 -L 300 -an $vg "$dev1:0-10" "$dev4"
+lvcreate -n $lv2 -l 4 -an $vg "$dev2"
+
+lvconvert -y --type cache --cachevol $lv2 --cachemode writethrough $vg/$lv1
+
+mkfs_mount_umount $lv1
+
+lvchange -ay $vg/$lv1
+
+lvconvert --uncache $vg/$lv1
+lvs -o segtype $vg/$lv1 | grep linear
+
+lvcreate -n $lv2 -l 4 -an $vg "$dev2"
+
+lvconvert -y --type cache --cachevol $lv2 --cachemode writeback $vg/$lv1
+
+lvchange -an $vg/$lv1
+
+mkfs_mount_umount $lv1
+
+lvchange -ay $vg/$lv1
+
+lvconvert --uncache $vg/$lv1
+lvs -o segtype $vg/$lv1 | grep linear
+
+mount_umount $lv1
+
+#
+# uncache while cachevol is missing
+# writethrough
+#
+
+lvremove $vg/$lv1
+
+lvcreate -n $lv1 -L 300 -an $vg "$dev1:0-10" "$dev4"
+lvcreate -n $lv2 -l 4 -an $vg "$dev2"
+
+lvconvert -y --type cache --cachevol $lv2 --cachemode writethrough $vg/$lv1
+
+mkfs_mount_umount $lv1
+
+aux disable_dev "$dev2"
+
+lvconvert --uncache $vg/$lv1
+
+lvs -o segtype $vg/$lv1 | grep linear
+
+aux enable_dev "$dev2"
+
+not lvs -o segtype $vg/$lv2
+
+vgck --updatemetadata $vg
+lvs $vg
+
+vgchange -an $vg
+
+mount_umount $lv1
+
+#
+# uncache while cachevol is missing
+# writeback
+#
+
+lvremove $vg/$lv1
+
+lvcreate -n $lv1 -L 300 -an $vg "$dev1:0-10" "$dev4"
+lvcreate -n $lv2 -l 4 -an $vg "$dev2"
+
+lvconvert -y --type cache --cachevol $lv2 --cachemode writeback $vg/$lv1
+
+mkfs_mount_umount $lv1
+
+aux disable_dev "$dev2"
+
+not lvconvert --uncache $vg/$lv1
+lvconvert --uncache --force --yes $vg/$lv1
+
+lvs -o segtype $vg/$lv1 | grep linear
+
+aux enable_dev "$dev2"
+
+not lvs -o segtype $vg/$lv2
+
+vgck --updatemetadata $vg
+lvs $vg
+
+vgremove -ff $vg
diff --git a/test/shell/cache-single-thin.sh b/test/shell/cache-single-thin.sh
new file mode 100644
index 0000000..6b478fb
--- /dev/null
+++ b/test/shell/cache-single-thin.sh
@@ -0,0 +1,46 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2018 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+# Test single lv cache
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+aux have_cache 1 10 0 || skip
+aux have_thin 1 0 0 || skip
+
+aux prepare_devs 5 80
+
+vgcreate $SHARED $vg "$dev1" "$dev2" "$dev3" "$dev4" "$dev5"
+
+# lv1 starts as a standard linear LV
+# lv1 is then sped up by attaching fast device lv2 using dm-cache
+# lv1 is then used as the data device in a thin pool
+
+lvcreate -L10 -an -n $lv1 $vg "$dev1"
+lvcreate -L10 -an -n $lv2 $vg "$dev2"
+
+lvconvert -y --type cache --cachevol $lv2 $vg/$lv1
+lvconvert -y --type thin-pool $vg/$lv1
+
+lvcreate --type thin -V10 -n lvthin --thinpool $vg/$lv1
+
+lvchange -an $vg/lvthin
+lvchange -an $vg/$lv1
+
+# detach the cache (lv2) from lv1
+
+lvconvert --splitcache $vg/$lv1
+
+vgremove -ff $vg
+
diff --git a/test/shell/cache-single-types.sh b/test/shell/cache-single-types.sh
new file mode 100644
index 0000000..1e67e7e
--- /dev/null
+++ b/test/shell/cache-single-types.sh
@@ -0,0 +1,88 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2018 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+# Test single lv cache with non-linear lvs
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+aux have_cache 1 10 0 || skip
+aux have_raid 1 3 5 || skip
+which mkfs.xfs || skip
+
+mount_dir="mnt"
+mkdir -p "$mount_dir"
+
+# generate random data
+dd if=/dev/urandom of=pattern1 bs=512K count=1
+
+aux prepare_devs 4 310
+
+vgcreate $SHARED $vg "$dev1" "$dev2" "$dev3" "$dev4"
+
+lvcreate --type raid1 -m 1 -n $lv1 -L 300 --nosync $vg "$dev1" "$dev2"
+
+lvcreate --type raid1 -m 1 -n $lv2 -l 4 $vg "$dev3" "$dev4"
+
+# test1: create fs on LV before cache is attached
+
+mkfs.xfs -f -s size=4096 "$DM_DEV_DIR/$vg/$lv1"
+
+mount "$DM_DEV_DIR/$vg/$lv1" "$mount_dir"
+
+cp pattern1 "$mount_dir/pattern1"
+
+umount "$mount_dir"
+lvchange -an $vg/$lv1
+
+lvconvert -y --type cache --cachevol $lv2 $vg/$lv1
+
+check lv_field $vg/$lv1 segtype cache
+
+lvs -a $vg/${lv2}_cvol --noheadings -o segtype >out
+grep raid1 out
+
+lvchange -ay $vg/$lv1
+
+mount "$DM_DEV_DIR/$vg/$lv1" "$mount_dir"
+
+diff pattern1 "$mount_dir/pattern1"
+
+cp pattern1 "$mount_dir/pattern1b"
+
+ls -l "$mount_dir"
+
+umount "$mount_dir"
+
+lvchange -an $vg/$lv1
+
+lvconvert --splitcache $vg/$lv1
+
+check lv_field $vg/$lv1 segtype raid1
+check lv_field $vg/$lv2 segtype raid1
+
+lvchange -ay $vg/$lv1
+lvchange -ay $vg/$lv2
+
+mount "$DM_DEV_DIR/$vg/$lv1" "$mount_dir"
+
+ls -l "$mount_dir"
+
+diff pattern1 "$mount_dir/pattern1"
+diff pattern1 "$mount_dir/pattern1b"
+
+umount "$mount_dir"
+lvchange -an $vg/$lv1
+lvchange -an $vg/$lv2
+
+vgremove -ff $vg
diff --git a/test/shell/cache-single-usage.sh b/test/shell/cache-single-usage.sh
new file mode 100644
index 0000000..2c47d05
--- /dev/null
+++ b/test/shell/cache-single-usage.sh
@@ -0,0 +1,146 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2018 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+# Test single lv cache
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+lvm segtypes 2>/dev/null | grep writecache$ >/dev/null || {
+ skip 'Writecache is not built-in.'
+}
+aux have_cache 1 10 0 || skip
+which mkfs.xfs || skip
+
+mount_dir="mnt"
+mkdir -p "$mount_dir"
+
+# generate random data
+dd if=/dev/urandom of=pattern1 bs=512K count=1
+
+aux prepare_devs 2 310
+
+vgcreate $SHARED $vg "$dev1"
+
+vgextend $vg "$dev2"
+
+lvcreate -n $lv1 -L 300 -an $vg "$dev1"
+
+lvcreate -n $lv2 -l 4 -an $vg "$dev2"
+
+# test1: create fs on LV before cache is attached
+
+lvchange -ay $vg/$lv1
+
+mkfs.xfs -f -s size=4096 "$DM_DEV_DIR/$vg/$lv1"
+
+mount "$DM_DEV_DIR/$vg/$lv1" "$mount_dir"
+
+cp pattern1 "$mount_dir/pattern1"
+
+umount "$mount_dir"
+lvchange -an $vg/$lv1
+
+lvconvert -y --type cache --cachevol $lv2 $vg/$lv1
+
+check lv_field $vg/$lv1 segtype cache
+
+lvs -a $vg/${lv2}_cvol --noheadings -o segtype >out
+grep linear out
+
+lvchange -ay $vg/$lv1
+
+mount "$DM_DEV_DIR/$vg/$lv1" "$mount_dir"
+
+diff pattern1 "$mount_dir/pattern1"
+
+cp pattern1 "$mount_dir/pattern1b"
+
+ls -l "$mount_dir"
+
+umount "$mount_dir"
+
+lvchange -an $vg/$lv1
+
+lvconvert --splitcache $vg/$lv1
+
+check lv_field $vg/$lv1 segtype linear
+check lv_field $vg/$lv2 segtype linear
+
+lvchange -ay $vg/$lv1
+lvchange -ay $vg/$lv2
+
+mount "$DM_DEV_DIR/$vg/$lv1" "$mount_dir"
+
+ls -l "$mount_dir"
+
+diff pattern1 "$mount_dir/pattern1"
+diff pattern1 "$mount_dir/pattern1b"
+
+umount "$mount_dir"
+lvchange -an $vg/$lv1
+lvchange -an $vg/$lv2
+
+# test2: create fs on LV after cache is attached
+
+lvconvert -y --type cache --cachevol $lv2 $vg/$lv1
+
+check lv_field $vg/$lv1 segtype cache
+
+lvs -a $vg/${lv2}_cvol --noheadings -o segtype >out
+grep linear out
+
+lvchange -ay $vg/$lv1
+
+mkfs.xfs -f -s size=4096 "$DM_DEV_DIR/$vg/$lv1"
+
+mount "$DM_DEV_DIR/$vg/$lv1" "$mount_dir"
+
+cp pattern1 "$mount_dir/pattern1"
+ls -l "$mount_dir"
+
+umount "$mount_dir"
+lvchange -an $vg/$lv1
+
+lvconvert --splitcache $vg/$lv1
+
+check lv_field $vg/$lv1 segtype linear
+check lv_field $vg/$lv2 segtype linear
+
+lvchange -ay $vg/$lv1
+lvchange -ay $vg/$lv2
+
+mount "$DM_DEV_DIR/$vg/$lv1" "$mount_dir"
+
+ls -l "$mount_dir"
+
+diff pattern1 "$mount_dir/pattern1"
+
+umount "$mount_dir"
+lvchange -an $vg/$lv1
+lvchange -an $vg/$lv2
+
+# misc tests
+
+lvremove $vg
+
+lvcreate -n $lv1 -l 2 -an $vg "$dev1"
+lvcreate -n $lv2 -l 2 -an $vg "$dev1"
+lvcreate -n $lv3 -l 2 -an $vg "$dev2"
+
+lvconvert -y --type writecache --cachevol $lv3 $vg/$lv1
+not lvconvert -y --type writecache --cachevol ${lv3}_cvol $vg/$lv2
+not lvconvert -y --type cache --cachevol ${lv3}_cvol $vg/$lv2
+not lvconvert -y --type cache --cachepool ${lv3}_cvol $vg/$lv2
+
+vgremove -ff $vg
diff --git a/test/shell/cachevol-cachedevice.sh b/test/shell/cachevol-cachedevice.sh
new file mode 100644
index 0000000..2695c98
--- /dev/null
+++ b/test/shell/cachevol-cachedevice.sh
@@ -0,0 +1,235 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2018 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+aux have_cache 1 10 0 || skip
+aux have_writecache 1 0 0 || skip
+
+aux prepare_devs 4 64
+
+vgcreate $SHARED $vg "$dev1" "$dev2"
+
+## cache
+
+# use existing cachevol
+lvcreate -n $lv1 -l8 -an $vg "$dev1"
+lvcreate --type cache -n $lv2 -L40M --cachevol $lv1 -y $vg "$dev2"
+check lv_field $vg/$lv2 segtype cache
+check lv_field $vg/${lv1}_cvol segtype linear -a
+lvremove -y $vg/$lv2
+
+# use entire cachedevice for cachevol
+lvcreate --type cache -n $lv2 -L40M --cachedevice "$dev1" -y $vg "$dev2"
+check lv_field $vg/$lv2 segtype cache
+check lv_field $vg/${lv2}_cache_cvol segtype linear -a
+lvremove -y $vg/$lv2
+
+# use part of cachedevice for cachevol
+lvcreate --type cache -n $lv2 -L20M --cachedevice "$dev1" --cachesize 16M -y $vg "$dev2"
+check lv_field $vg/$lv2 segtype cache
+check lv_field $vg/${lv2}_cache_cvol segtype linear -a
+lvcreate --type cache -n $lv3 -L20M --cachedevice "$dev1" --cachesize 16M -y $vg "$dev2"
+check lv_field $vg/$lv3 segtype cache
+check lv_field $vg/${lv3}_cache_cvol segtype linear -a
+lvremove -y $vg/$lv2
+lvremove -y $vg/$lv3
+
+## writecache
+
+# use existing cachevol
+lvcreate -n $lv1 -l8 -an $vg "$dev1"
+lvcreate --type writecache -n $lv2 -L40M --cachevol $lv1 -y $vg "$dev2"
+check lv_field $vg/$lv2 segtype writecache
+check lv_field $vg/${lv1}_cvol segtype linear -a
+lvremove -y $vg/$lv2
+
+# use entire cachedevice for cachevol
+lvcreate --type writecache -n $lv2 -L40M --cachedevice "$dev1" -y $vg "$dev2"
+check lv_field $vg/$lv2 segtype writecache
+check lv_field $vg/${lv2}_cache_cvol segtype linear -a
+lvremove -y $vg/$lv2
+
+# use part of cachedevice for cachevol
+lvcreate --type writecache -n $lv2 -L20M --cachedevice "$dev1" --cachesize 16M -y $vg "$dev2"
+check lv_field $vg/$lv2 segtype writecache
+check lv_field $vg/${lv2}_cache_cvol segtype linear -a
+lvcreate --type writecache -n $lv3 -L20M --cachedevice "$dev1" --cachesize 16M -y $vg "$dev2"
+check lv_field $vg/$lv3 segtype writecache
+check lv_field $vg/${lv3}_cache_cvol segtype linear -a
+lvremove -y $vg/$lv2
+lvremove -y $vg/$lv3
+
+## multiple cachedevs
+
+vgextend $vg "$dev3" "$dev4"
+
+lvcreate --type writecache -n $lv2 -L100M --cachedevice "$dev1" --cachedevice "$dev3" -y $vg "$dev2" "$dev4"
+check lv_field $vg/${lv2}_cache_cvol lv_size "120.00m"
+lvremove -y $vg/$lv2
+
+lvcreate --type writecache -n $lv2 -L100M --cachedevice "$dev1" --cachedevice "$dev3" --cachesize 80M -y $vg "$dev2" "$dev4"
+check lv_field $vg/${lv2}_cache_cvol lv_size "80.00m"
+lvremove -y $vg/$lv2
+
+pvchange --addtag slow "$dev2"
+pvchange --addtag slow "$dev4"
+pvchange --addtag fast "$dev1"
+pvchange --addtag fast "$dev3"
+
+lvcreate --type writecache -n $lv2 -L100M --cachedevice @fast --cachesize 80M -y $vg @slow
+check lv_field $vg/${lv2}_cache_cvol lv_size "80.00m"
+lvremove -y $vg/$lv2
+
+lvcreate --type cache -n $lv2 -L100M --cachedevice @fast --cachesize 80M -y $vg @slow
+check lv_field $vg/${lv2}_cache_cvol lv_size "80.00m"
+lvremove -y $vg/$lv2
+
+## error cases
+
+# cachevol doesn't exist
+not lvcreate --type cache -n $lv2 -l8 --cachevol asdf -y $vg "$dev2"
+not lvs $vg/$lv1
+not lvs $vg/$lv2
+
+# cachedevice doesn't exist
+not lvcreate --type cache -n $lv2 -l8 --cachedevice asdf -y $vg "$dev2"
+not lvs $vg/$lv1
+not lvs $vg/$lv2
+
+# cachevol doesn't exist
+not lvcreate --type writecache -n $lv2 -l8 --cachevol asdf -y $vg "$dev2"
+not lvs $vg/$lv1
+not lvs $vg/$lv2
+
+# cachedevice doesn't exist
+not lvcreate --type writecache -n $lv2 -l8 --cachedevice asdf -y $vg "$dev2"
+not lvs $vg/$lv1
+not lvs $vg/$lv2
+
+# when cachedevice is already being used, cachesize is required to use a part of it
+lvcreate -n asdf -l1 $vg "$dev1"
+not lvcreate --type writecache -n $lv2 -l8 --cachedevice "$dev1" -y $vg "$dev2"
+not lvcreate --type writecache -n $lv2 -l8 --cachedevice "$dev1" --cachedevice "$dev3" -y $vg "$dev2"
+not lvs $vg/$lv1
+not lvs $vg/$lv2
+lvcreate --type writecache -n $lv2 -l8 --cachedevice "$dev1" --cachesize 8M -y $vg "$dev2"
+lvs $vg/$lv2
+check lv_field $vg/${lv2}_cache_cvol lv_size "8.00m"
+lvremove -y $vg/$lv2
+
+vgremove -ff $vg
+
+# lvconvert single step cachevol creation and attachment
+# . cache and writecache
+# . one or two cachedevices
+# . with or without --cachesize
+# . using tags for devices
+
+vgcreate $SHARED $vg "$dev1" "$dev2" "$dev3" "$dev4"
+
+lvcreate -n $lv1 -l8 -an $vg "$dev1"
+lvconvert -y --type cache --cachedevice "$dev2" $vg/$lv1
+check lv_field $vg/$lv1 segtype cache
+check lv_field $vg/${lv1}_cache_cvol segtype linear -a
+check lv_field $vg/${lv1}_cache_cvol lv_size "60.00m"
+lvs -o chunksize $vg/$lv1 |tee out
+grep 64.00k out
+lvchange -ay $vg/$lv1
+lvchange -an $vg/$lv1
+lvremove $vg/$lv1
+
+lvcreate -n $lv1 -l8 -an $vg "$dev1"
+lvconvert -y --type cache --cachedevice "$dev2" --chunksize 128k $vg/$lv1
+check lv_field $vg/$lv1 segtype cache
+check lv_field $vg/${lv1}_cache_cvol segtype linear -a
+check lv_field $vg/${lv1}_cache_cvol lv_size "60.00m"
+lvs -o chunksize $vg/$lv1 |tee out
+grep 128.00k out
+lvchange -ay $vg/$lv1
+lvchange -an $vg/$lv1
+lvremove $vg/$lv1
+
+lvcreate -n $lv1 -l8 -an $vg "$dev1"
+lvconvert -y --type cache --cachedevice "$dev2" --cachedevice "$dev3" $vg/$lv1
+check lv_field $vg/$lv1 segtype cache
+check lv_field $vg/${lv1}_cache_cvol lv_size "120.00m"
+lvchange -ay $vg/$lv1
+lvchange -an $vg/$lv1
+lvremove $vg/$lv1
+
+lvcreate -n $lv1 -l8 -an $vg "$dev1"
+lvconvert -y --type cache --cachedevice "$dev2" --cachedevice "$dev3" --cachesize 8M $vg/$lv1
+check lv_field $vg/$lv1 segtype cache
+check lv_field $vg/${lv1}_cache_cvol lv_size "8.00m"
+lvchange -ay $vg/$lv1
+lvchange -an $vg/$lv1
+lvremove $vg/$lv1
+
+lvcreate -n $lv1 -l8 -an $vg "$dev1"
+lvconvert -y --type writecache --cachedevice "$dev2" $vg/$lv1
+check lv_field $vg/$lv1 segtype writecache
+check lv_field $vg/${lv1}_cache_cvol lv_size "60.00m"
+lvchange -ay $vg/$lv1
+lvchange -an $vg/$lv1
+lvremove $vg/$lv1
+
+lvcreate -n $lv1 -l8 -an $vg "$dev1"
+lvconvert -y --type writecache --cachedevice "$dev2" --cachedevice "$dev3" $vg/$lv1
+check lv_field $vg/$lv1 segtype writecache
+check lv_field $vg/${lv1}_cache_cvol lv_size "120.00m"
+lvchange -ay $vg/$lv1
+lvchange -an $vg/$lv1
+lvremove $vg/$lv1
+
+lvcreate -n $lv1 -l8 -an $vg "$dev1"
+lvconvert -y --type writecache --cachedevice "$dev2" --cachedevice "$dev3" --cachesize 8M $vg/$lv1
+check lv_field $vg/$lv1 segtype writecache
+check lv_field $vg/${lv1}_cache_cvol lv_size "8.00m"
+lvchange -ay $vg/$lv1
+lvchange -an $vg/$lv1
+lvremove $vg/$lv1
+
+pvchange --addtag slow "$dev1"
+pvchange --addtag fast "$dev2"
+pvchange --addtag fast "$dev3"
+
+lvcreate -n $lv1 -l8 -an $vg @slow
+lvconvert -y --type cache --cachedevice @fast --cachesize 8M $vg/$lv1
+check lv_field $vg/$lv1 segtype cache
+check lv_field $vg/${lv1}_cache_cvol lv_size "8.00m"
+lvchange -ay $vg/$lv1
+lvchange -an $vg/$lv1
+lvremove $vg/$lv1
+
+lvcreate -n $lv1 -l8 -an $vg @slow
+lvconvert -y --type writecache --cachedevice @fast --cachesize 8M $vg/$lv1
+check lv_field $vg/$lv1 segtype writecache
+check lv_field $vg/${lv1}_cache_cvol lv_size "8.00m"
+lvchange -ay $vg/$lv1
+lvchange -an $vg/$lv1
+lvremove $vg/$lv1
+
+# if the cache name is used generate a new name
+lvcreate -n $lv1 -l8 -an $vg @slow
+lvcreate -n ${lv1}_cache -l1 -an $vg @slow
+lvconvert -y --type writecache --cachedevice @fast --cachesize 8M $vg/$lv1
+check lv_field $vg/$lv1 segtype writecache
+check lv_field $vg/${lv1}_cache0_cvol lv_size "8.00m"
+lvchange -ay $vg/$lv1
+lvchange -an $vg/$lv1
+lvremove $vg/$lv1
+
+vgremove -ff $vg
+
diff --git a/test/shell/caching-snapshot.sh b/test/shell/caching-snapshot.sh
new file mode 100644
index 0000000..d73f4ad
--- /dev/null
+++ b/test/shell/caching-snapshot.sh
@@ -0,0 +1,162 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2018 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+# Test snapshot on cache|writecache
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+lvm segtypes 2>/dev/null | grep writecache$ >/dev/null || {
+ skip 'Writecache is not built-in.'
+}
+aux have_cache 1 10 0 || skip
+which mkfs.ext4 || skip
+
+mount_dir="mnt"
+mkdir -p "$mount_dir"
+
+mount_dir_snap="mnt_snap"
+mkdir -p "$mount_dir_snap"
+
+# generate random data
+dd if=/dev/urandom of=pattern1 bs=512K count=1
+
+aux prepare_devs 2 310
+
+vgcreate $SHARED $vg "$dev1" "$dev2"
+
+# creating a snapshot on top of a cache|writecache
+
+test_snap_create() {
+ # cache | writecache
+ local convert_type=$1
+
+ # --cachepool | --cachevol
+ local convert_option=$2
+
+ lvcreate -n $lv1 -L 300 -an $vg "$dev1"
+ lvcreate -n fast -l 4 -an $vg "$dev2"
+ lvconvert -y --type $convert_type $convert_option fast $vg/$lv1
+ lvchange -ay $vg/$lv1
+ mkfs.ext4 "$DM_DEV_DIR/$vg/$lv1"
+ mount "$DM_DEV_DIR/$vg/$lv1" "$mount_dir"
+ cp pattern1 "$mount_dir/pattern1a"
+ lvcreate -s -L 32 -n snap $vg/$lv1
+ cp pattern1 "$mount_dir/pattern1b"
+ mount "$DM_DEV_DIR/$vg/snap" "$mount_dir_snap"
+ not ls "$mount_dir_snap/pattern1b"
+ rm "$mount_dir/pattern1a"
+ diff pattern1 "$mount_dir_snap/pattern1a"
+ umount "$mount_dir_snap"
+ lvconvert --splitcache $vg/$lv1
+ umount "$mount_dir"
+ lvchange -an $vg/$lv1
+ lvchange -an $vg/fast
+ lvremove $vg/snap
+ lvremove $vg/$lv1
+ lvremove $vg/fast
+}
+
+test_snap_create cache --cachepool
+test_snap_create cache --cachevol
+test_snap_create writecache --cachevol
+
+# removing cache|writecache while snapshot exists
+
+test_snap_remove() {
+ # cache | writecache
+ local convert_type=$1
+
+ # --cachepool | --cachevol
+ local convert_option=$2
+
+ lvcreate -n $lv1 -L 300 -an $vg "$dev1"
+ lvcreate -n fast -l 4 -an $vg "$dev2"
+ lvconvert -y --type $convert_type $convert_option fast $vg/$lv1
+ lvchange -ay $vg/$lv1
+ mkfs.ext4 "$DM_DEV_DIR/$vg/$lv1"
+ mount "$DM_DEV_DIR/$vg/$lv1" "$mount_dir"
+ cp pattern1 "$mount_dir/pattern1a"
+ lvcreate -s -L 32 -n snap $vg/$lv1
+ cp pattern1 "$mount_dir/pattern1b"
+ lvconvert --splitcache $vg/$lv1
+ mount "$DM_DEV_DIR/$vg/snap" "$mount_dir_snap"
+ not ls "$mount_dir_snap/pattern1b"
+ rm "$mount_dir/pattern1a"
+ diff pattern1 "$mount_dir_snap/pattern1a"
+ umount "$mount_dir_snap"
+ umount "$mount_dir"
+ lvchange -an $vg/$lv1
+ lvchange -an $vg/fast
+ lvremove $vg/snap
+ lvremove $vg/$lv1
+ lvremove $vg/fast
+}
+
+test_snap_remove cache --cachepool
+test_snap_remove cache --cachevol
+test_snap_remove writecache --cachevol
+
+# adding cache|writecache to an LV that has a snapshot
+
+test_caching_with_snap() {
+ # cache | writecache
+ local convert_type=$1
+
+ # --cachepool | --cachevol
+ local convert_option=$2
+
+ lvcreate -n $lv1 -L 300 -an $vg "$dev1"
+ lvcreate -n fast -l 4 -an $vg "$dev2"
+ lvchange -ay $vg/$lv1
+ mkfs.ext4 "$DM_DEV_DIR/$vg/$lv1"
+ mount "$DM_DEV_DIR/$vg/$lv1" "$mount_dir"
+ cp pattern1 "$mount_dir/pattern1a"
+ lvcreate -s -L 32 -n snap $vg/$lv1
+ lvconvert -y --type $convert_type $convert_option fast $vg/$lv1
+ cp pattern1 "$mount_dir/pattern1b"
+ mount "$DM_DEV_DIR/$vg/snap" "$mount_dir_snap"
+ not ls "$mount_dir_snap/pattern1b"
+ mv "$mount_dir/pattern1a" "$mount_dir/pattern1c"
+ diff pattern1 "$mount_dir_snap/pattern1a"
+ lvconvert --splitcache $vg/$lv1
+ diff pattern1 "$mount_dir/pattern1c"
+ diff pattern1 "$mount_dir_snap/pattern1a"
+ umount "$mount_dir_snap"
+ umount "$mount_dir"
+ lvchange -an $vg/$lv1
+ lvchange -an $vg/fast
+ lvremove $vg/snap
+ lvremove $vg/$lv1
+ lvremove $vg/fast
+}
+
+test_caching_with_snap cache --cachepool
+test_caching_with_snap cache --cachevol
+test_caching_with_snap writecache --cachevol
+
+# adding cache|writecache to a snapshot is not allowed
+
+lvcreate -n $lv1 -L 300 $vg "$dev1"
+lvcreate -n fast -l 4 $vg "$dev2"
+mkfs.ext4 "$DM_DEV_DIR/$vg/$lv1"
+lvcreate -s -L 32 -n snap $vg/$lv1
+not lvconvert -y --type writecache --cachevol fast $vg/snap
+not lvconvert -y --type cache --cachevol fast $vg/snap
+not lvconvert -y --type cache --cachepool fast $vg/snap
+vgchange -an $vg
+lvremove $vg/snap
+lvremove $vg/$lv1
+lvremove $vg/fast
+
+vgremove -ff $vg
diff --git a/test/shell/clvmd-restart.sh b/test/shell/clvmd-restart.sh
deleted file mode 100644
index 2b341e5..0000000
--- a/test/shell/clvmd-restart.sh
+++ /dev/null
@@ -1,53 +0,0 @@
-#!/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/component-cache.sh b/test/shell/component-cache.sh
new file mode 100644
index 0000000..7234504
--- /dev/null
+++ b/test/shell/component-cache.sh
@@ -0,0 +1,92 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2018 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+# Exercise activation of cache component devices
+
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+aux have_cache 1 3 0 || skip
+
+aux prepare_vg 5 80
+
+lvcreate --type cache-pool -L 2 -n cpool $vg
+lvcreate -H -L 4 -n corigin --cachepool $vg/cpool
+lvchange -an $vg
+
+for j in 1 2
+do
+
+# Activate supported components
+for i in cpool_cpool_cmeta cpool_cpool_cdata corigin_corig
+do
+ test ! -e "$DM_DEV_DIR/$vg/$i"
+ lvchange -ay -y $vg/$i
+ # check usable link is there
+ test -e "$DM_DEV_DIR/$vg/$i"
+
+ # cannot take snapshot of any active component LV
+ test "$j" -eq 2 || not lvcreate -s -L1 $vg/$i
+done
+
+# After 1st. phase deactivation works
+# Volumes are left active for vgremove on 2nd.. pass
+test "$j" -eq 2 || lvchange -an $vg
+
+done
+
+# Cannot active cached LV while any component LV is active
+not lvchange -ay $vg/corigin |& tee err
+grep "prohibited" err
+
+lvs -a $vg
+
+# Can split for writethrough|passthrough
+# deactivates all components as well...
+lvconvert --splitcache $vg/corigin
+lvs -a $vg
+
+# Cannot cache LV while components are active
+lvcreate -L 4 -n $lv2 $vg
+lvchange -ay -y $vg/cpool_cmeta
+
+not lvconvert -y --cachepool $vg/cpool -H $lv2
+
+lvremove -f $vg
+lvs -a $vg
+
+if aux have_thin 1 0 0 ; then
+
+lvcreate --type cache-pool -L 2 -n cpool $vg
+lvcreate -H -L 4 -n tpool --cachepool $vg/cpool
+lvchange -an $vg
+lvs -a $vg
+# Cannot convert to thin-pool with component LV active
+lvchange -ay -y $vg/cpool_cpool_cmeta
+
+# Conversion does not need to activate data device, so it can proceed ??
+lvconvert -y --thinpool $vg/tpool
+
+# Thin-pool cannot be activated
+not lvchange -ay $vg/tpool |& tee err
+grep "prohibited" err
+
+lvs -a $vg
+
+fi
+
+lvs -a $vg
+
+# And final removal works
+vgremove -f $vg
diff --git a/test/shell/component-mirror.sh b/test/shell/component-mirror.sh
new file mode 100644
index 0000000..b565c98
--- /dev/null
+++ b/test/shell/component-mirror.sh
@@ -0,0 +1,70 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2018 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+# Exercise activation of mirror component devices
+
+SKIP_WITH_LVMLOCKD=1
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+aux have_cache 1 3 0 || skip
+
+aux prepare_vg 5 80
+
+lvcreate -aey --type mirror -L 2 -m 1 -n $lv1 $vg
+lvchange -an $vg
+
+lvs -a
+
+lvchange -an $vg
+
+for k in 1 2
+do
+
+# Activate supported components
+for i in ${lv1}_mimage_0 ${lv1}_mimage_1 ${lv1}_mlog
+do
+ test ! -e "$DM_DEV_DIR/$vg/$i"
+ lvchange -ay -y $vg/$i
+ # check usable link is there
+ test -e "$DM_DEV_DIR/$vg/$i"
+done
+
+# Deactivation works in 1st. pass
+test $k -eq 2 || lvchange -an $vg
+
+done
+
+# Cannot be resized
+not lvextend -L+20 $vg/$lv1 |& tee err
+grep "Cannot resize" err
+
+not lvresize -L-20 $vg/$lv1 |& tee err
+grep "Cannot resize" err
+
+# Cannot be converted
+lvcreate -aey -L10 -n $lv2 $vg
+not lvconvert -y -s $vg/$lv1 $lv2 |& tee err
+grep "Cannot use" err
+
+# Cannot be splitted
+not lvconvert --splitmirrors 1 -n split $vg/$lv1 |& tee err
+grep "Cannot convert" err
+
+# Cannot add new leg
+not lvconvert -m+1 $vg/$lv1 |& tee err
+grep "Cannot convert" err
+
+lvs -a
+
+vgremove -f $vg
diff --git a/test/shell/component-raid.sh b/test/shell/component-raid.sh
new file mode 100644
index 0000000..bff56d4
--- /dev/null
+++ b/test/shell/component-raid.sh
@@ -0,0 +1,50 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2018 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+# Exercise activation of raid component devices
+
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+aux have_raid 1 3 0 || skip
+
+aux prepare_vg 5 80
+
+lvcreate --type raid1 -L 2 -m 1 -n $lv1 $vg
+lvchange -an $vg
+
+lvs -a $vg
+
+for k in 1 2
+do
+
+# Activate supported components
+for j in 0 1
+do
+for i in ${lv1}_rimage_$j ${lv1}_rmeta_$j
+do
+ test ! -e "$DM_DEV_DIR/$vg/$i"
+ lvchange -ay -y $vg/$i
+ # check usable link is there
+ test -e "$DM_DEV_DIR/$vg/$i"
+done
+done
+
+# Deactivation works in 1st. pass
+test $k -eq 2 || lvchange -an $vg
+
+done
+
+# And final removal works
+vgremove -f $vg
diff --git a/test/shell/component-thin.sh b/test/shell/component-thin.sh
new file mode 100644
index 0000000..ddadd0f
--- /dev/null
+++ b/test/shell/component-thin.sh
@@ -0,0 +1,43 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2018 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+# Exercise activation of thin component devices
+
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+aux have_thin 1 0 0 || skip
+
+aux prepare_vg 5 80
+
+lvcreate -T -L2 -V20 $vg/pool -n $lv1
+
+lvs -a
+
+lvchange -an $vg
+
+for i in pool_tdata pool_tmeta
+do
+ lvchange -ay -y $vg/$i
+ # check usable is there
+ test -e "$DM_DEV_DIR/$vg/$i"
+done
+
+lvs -a
+
+# When component LVs are active, thin-pool cannot be actived
+not lvcreate -V20 $vg/pool
+
+# Rremoval of thin volumes should not need to activate thin-pool.
+vgremove -f $vg
diff --git a/test/shell/covercmd.sh b/test/shell/covercmd.sh
index b77d378..16b2e6c 100644
--- a/test/shell/covercmd.sh
+++ b/test/shell/covercmd.sh
@@ -1,5 +1,6 @@
-#!/bin/sh
-# Copyright (C) 2008-2012 Red Hat, Inc. All rights reserved.
+#!/usr/bin/env bash
+
+# Copyright (C) 2008-2014 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
@@ -7,96 +8,74 @@
#
# 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
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
#
-# tests basic functionality of read-ahead and ra regressions
+# tests functionality we don't have in other special test files yet
+# to improve code coverage
#
-. lib/test
-aux prepare_devs 5
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
-TEST_UUID="aaaaaa-aaaa-aaaa-aaaa-aaaa-aaaa-aaaaaa"
+aux prepare_pvs 5
+get_devs
-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
+# FIXME takes very long time
+#pvck "$dev1"
+vgcreate $SHARED "$vg" "${DEVICES[@]}"
-# test vgexport vgimport tools
-vgchange -an $vg
-vgexport $vg
-vgimport $vg
-vgchange -ay $vg
+lvcreate -l 5 -i5 -I256 -n $lv $vg
+lvcreate -aey -l 5 -n $lv1 $vg
+lvcreate -s -l 5 -n $lv2 $vg/$lv1
+pvck "$dev1"
# "-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
+for i in pr "p rw" "-monitor y" "-monitor n" -refresh; 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"
+invalid lvrename $vg
+invalid lvrename $vg $vg/$lv-rename $vg1/$lv
+invalid lvrename $vg/$lv-rename $vg1/$lv $vg
+invalid lvrename $vg/$lv-rename $vg/012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789
+invalid lvrename $vg/$lv-rename $vg/""
+invalid lvrename $vg/$lv-rename "$vg/!@#$%"
+invalid lvrename $vg/$lv-rename $vg/$lv-rename
+fail lvrename $vg1/$lv-rename $vg1/$lv
+
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
+
+# test pvresize functionality
+# missing params
+not pvresize
+# negative size
+not pvresize --setphysicalvolumesize -10M -y "$dev1"
+# not existing device
+not pvresize --setphysicalvolumesize 10M -y "$dev7"
+pvresize --setphysicalvolumesize 10M -y "$dev1"
+pvresize "$dev1"
+
+
+# test various lvm utils
+lvm dumpconfig
+lvm devtypes
+lvm formats
+lvm segtypes
+lvm tags
+
+
+# test obsoleted tools
+not lvm lvmchange
+not lvm lvmsadc
+not lvm lvmsar
+not lvm pvdata
diff --git a/test/shell/creation-time.sh b/test/shell/creation-time.sh
new file mode 100644
index 0000000..2a4a387
--- /dev/null
+++ b/test/shell/creation-time.sh
@@ -0,0 +1,40 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2019 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+# Check we can read metadata with out-of-range creation time
+
+# Due to a bug in 32-bit version lvm2 <2.02.169 produced metadata
+# contained invalid number for creation_time
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+aux prepare_vg 1
+
+lvcreate -an -L1 -n $lv1 $vg
+
+vgcfgbackup -f back $vg
+
+sed -e 's/creation_time = \(.*\)$/creation_time = 12029933779523993599/g' back >backnew
+
+vgcfgrestore -f backnew $vg |& tee err
+
+# Check the time was spotted
+grep Invalid err
+
+vgcfgbackup -f back $vg |& tee err
+
+# Check the time is not a problem anymore
+not grep Invalid err
+
+vgremove -ff $vg
diff --git a/test/shell/dev-aliases.sh b/test/shell/dev-aliases.sh
new file mode 100644
index 0000000..c3e4c7c
--- /dev/null
+++ b/test/shell/dev-aliases.sh
@@ -0,0 +1,53 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2021 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+aux have_cache 1 10 0 || skip
+
+aux prepare_vg 3
+
+#
+# This lvconvert command will deactivate LV1, then internally create a new
+# lv, lvol0, as a poolmetadataspare, then activate lvol0 to zero it.
+# lvol0 will get the same major:minor that LV1 had. When the code gets
+# the struct dev for lvol0, the new path to lvol0 is added to the
+# dev-cache with it's major:minor. That major:minor already exists in
+# dev-cache and has the stale LV1 as an alias. So the path to lvol0 is
+# added as an alias to the existing struct dev (with the correct
+# major:minor), but that struct dev has the stale LV1 path on its aliases
+# list. The code will now validate all the aliases before returning the
+# dev for lvol0, and will find that the LV1 path is stale and remove it
+# from the aliases. That will prevent the stale path from being used for
+# the dev in place of the new path.
+#
+# The preferred_name is set to /dev/mapper so that if the stale path still
+# exists, that stale path would be used as the name for the dev, and the
+# wiping code would fail to open that stale name.
+#
+
+lvcreate -n $lv1 -L32M $vg "$dev1"
+lvcreate -n $lv2 -L16M $vg "$dev2"
+lvconvert -y --type cache-pool --poolmetadata $lv2 --cachemode writeback $vg/$lv1 --config='devices { preferred_names=["/dev/mapper/"] }'
+lvremove -y $vg/$lv1
+
+lvcreate -n $lv1 -L32M $vg "$dev1"
+lvcreate -n $lv2 -L16M $vg "$dev2"
+lvconvert -y --type cache-pool --poolmetadata $lv2 $vg/$lv1
+lvremove -y $vg/$lv1
+
+# TODO: add more validation of dev aliases being specified as command
+# args in combination with various preferred_names settings.
+
+vgremove -ff $vg
diff --git a/test/shell/devicesfile-basic.sh b/test/shell/devicesfile-basic.sh
new file mode 100644
index 0000000..c96bab7
--- /dev/null
+++ b/test/shell/devicesfile-basic.sh
@@ -0,0 +1,687 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2020 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+test_description='devices file'
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+aux prepare_devs 7
+
+RUNDIR="/run"
+test -d "$RUNDIR" || RUNDIR="/var/run"
+PVS_ONLINE_DIR="$RUNDIR/lvm/pvs_online"
+VGS_ONLINE_DIR="$RUNDIR/lvm/vgs_online"
+PVS_LOOKUP_DIR="$RUNDIR/lvm/pvs_lookup"
+
+_clear_online_files() {
+ # wait till udev is finished
+ aux udev_wait
+ rm -f "$PVS_ONLINE_DIR"/*
+ rm -f "$VGS_ONLINE_DIR"/*
+ rm -f "$PVS_LOOKUP_DIR"/*
+}
+
+wipe_all() {
+ aux wipefs_a "$dev1" "$dev2" "$dev3" "$dev4" "$dev5" "$dev6" "$dev7"
+}
+
+# The tests run with system dir of "/etc" but lvm when running
+# normally has cmd->system_dir set to "/etc/lvm".
+DFDIR="$LVM_SYSTEM_DIR/devices"
+mkdir -p "$DFDIR" || true
+DF="$DFDIR/system.devices"
+
+#
+# Test with use_devicesfile=0 (no devices file is being applied by default)
+#
+
+aux lvmconf 'devices/use_devicesfile = 0'
+
+wipe_all
+rm -f "$DF"
+pvcreate "$dev1"
+not ls "$DF"
+
+wipe_all
+rm -f "$DF"
+vgcreate $vg1 "$dev1"
+not ls "$DF"
+
+wipe_all
+rm -f "$DF"
+
+# create one VG in a non-system devices file
+vgcreate --devicesfile test.devices $vg1 "$dev1"
+vgextend --devicesfile test.devices $vg1 "$dev2"
+cat "$DFDIR/test.devices"
+grep "$dev1" "$DFDIR/test.devices"
+grep "$dev2" "$DFDIR/test.devices"
+not ls "$DFDIR/system.devices"
+
+# create two VGs outside the special devices file
+vgcreate $vg2 "$dev3" "$dev4"
+vgcreate $vg3 "$dev5" "$dev6"
+not grep "$dev3" "$DFDIR/test.devices"
+not grep "$dev5" "$DFDIR/test.devices"
+not ls "$DFDIR/system.devices"
+
+PVID1=`pvs "$dev1" --noheading -o uuid | tr -d - | awk '{print $1}'`
+PVID2=`pvs "$dev2" --noheading -o uuid | tr -d - | awk '{print $1}'`
+PVID3=`pvs "$dev3" --noheading -o uuid | tr -d - | awk '{print $1}'`
+PVID4=`pvs "$dev4" --noheading -o uuid | tr -d - | awk '{print $1}'`
+PVID5=`pvs "$dev5" --noheading -o uuid | tr -d - | awk '{print $1}'`
+PVID6=`pvs "$dev6" --noheading -o uuid | tr -d - | awk '{print $1}'`
+
+lvcreate -l4 -an -i2 -n $lv1 $vg1
+lvcreate -l4 -an -i2 -n $lv2 $vg2
+lvcreate -l4 -an -i2 -n $lv3 $vg3
+
+cat "$DFDIR/test.devices"
+grep "$PVID1" "$DFDIR/test.devices"
+grep "$PVID2" "$DFDIR/test.devices"
+not grep "$PVID3" "$DFDIR/test.devices"
+not grep "$PVID4" "$DFDIR/test.devices"
+not grep "$PVID5" "$DFDIR/test.devices"
+not grep "$PVID6" "$DFDIR/test.devices"
+not ls "$DFDIR/system.devices"
+
+# verify devices file is working
+vgs --devicesfile test.devices $vg1
+not vgs --devicesfile test.devices $vg2
+
+# misspelled override name fails
+not vgs --devicesfile doesnotexist $vg1
+not vgs --devicesfile doesnotexist $vg2
+not vgs --devicesfile doesnotexist
+
+# devicesfile and devices cannot be used together
+not vgs --devicesfile test.devices --devices "$dev1","$dev1" $vg1
+
+# verify correct vgs are seen / not seen when devices are specified
+vgs --devices "$dev1","$dev2" $vg1
+vgs --devices "$dev3","$dev4" $vg2
+vgs --devices "$dev5","$dev6" $vg3
+not vgs --devices "$dev1","$dev2" $vg2
+not vgs --devices "$dev1","$dev2" $vg3
+not vgs --devices "$dev1","$dev2" $vg2
+not vgs --devices "$dev5","$dev6" $vg2
+not vgs --devices "$dev1","$dev2" $vg3
+not vgs --devices "$dev3","$dev4" $vg3
+
+vgs --devices "$dev1","$dev2" |tee out
+grep $vg1 out
+not grep $vg2 out
+not grep $vg3 out
+vgs --devices "$dev3","$dev4" |tee out
+not grep $vg1 out
+grep $vg2 out
+not grep $vg3 out
+
+# verify correct pvs are seen / not seen when devices are specified
+pvs --devices "$dev1","$dev2" "$dev1" "$dev2"
+pvs --devices "$dev3","$dev4" "$dev3" "$dev4"
+pvs --devices "$dev5","$dev6" "$dev5" "$dev6"
+not pvs --devices "$dev1","$dev2" "$dev3" "$dev4"
+not pvs --devices "$dev1","$dev2" "$dev5" "$dev6"
+not pvs --devices "$dev3","$dev4" "$dev1" "$dev2" "$dev5" "$dev6"
+
+pvs --devices "$dev1","$dev2" |tee out
+grep "$dev1" out
+grep "$dev2" out
+not grep "$dev3" out
+not grep "$dev4" out
+not grep "$dev5" out
+not grep "$dev6" out
+pvs --devices "$dev3","$dev4" |tee out
+not grep "$dev1" out
+not grep "$dev2" out
+grep "$dev3" out
+grep "$dev4" out
+not grep "$dev5" out
+not grep "$dev6" out
+
+# verify correct lvs are activated / not activated when devices are specified
+vgchange --devices "$dev1","$dev2" -ay
+check lv_field $vg1/$lv1 lv_active "active"
+check lv_field $vg2/$lv2 lv_active ""
+check lv_field $vg3/$lv3 lv_active ""
+vgchange --devices "$dev1","$dev2" -an
+check lv_field $vg1/$lv1 lv_active ""
+
+vgchange --devices "$dev3","$dev4" -ay
+check lv_field $vg1/$lv1 lv_active ""
+check lv_field $vg2/$lv2 lv_active "active"
+check lv_field $vg3/$lv3 lv_active ""
+vgchange --devices "$dev3","$dev4" -an
+check lv_field $vg2/$lv2 lv_active ""
+
+# verify devices covering multiple vgs
+vgs --devices "$dev1","$dev2","$dev3","$dev4" $vg1 $vg2 |tee out
+grep $vg1 out
+grep $vg2 out
+not grep $vg3 out
+vgs --devices "$dev1","$dev2","$dev3","$dev4","$dev5","$dev6" $vg1 $vg2 $vg3 |tee out
+grep $vg1 out
+grep $vg2 out
+grep $vg3 out
+
+# verify vgs seen when incomplete devices are specified
+vgs --devices "$dev1" $vg1
+vgs --devices "$dev3" $vg2
+vgs --devices "$dev5" $vg3
+
+# incomplete vg because of --devices is the same as vg incomplete because
+# of missing device
+not lvcreate --devices "$dev1" -l1 $vg1
+not lvchange --devices "$dev1" -ay $vg1/$lv1
+not lvextend --devices "$dev1" -l+1 $vg1/$lv1
+not vgremove --devices "$dev1" $vg1
+not lvcreate --devices "$dev3" -l1 $vg2
+not lvchange --devices "$dev3" -ay $vg2/$lv2
+not lvextend --devices "$dev3" -l+1 $vg2/$lv2
+not vgremove --devices "$dev3" $vg2
+
+# verify various commands with --devices for vg in a devicesfile
+not lvcreate --devices "$dev1","$dev2" -l1 -n $lv2 -an $vg1 "$dev7"
+lvcreate --devices "$dev1","$dev2" -l1 -n $lv2 -an $vg1
+lvs --devices "$dev1","$dev2" $vg1/$lv2
+lvextend --devices "$dev1","$dev2" -l2 $vg1/$lv2
+lvchange --devices "$dev1","$dev2" -ay $vg1/$lv2
+lvchange --devices "$dev1","$dev2" -an $vg1/$lv2
+lvremove --devices "$dev1","$dev2" $vg1/$lv2
+vgchange --devices "$dev1","$dev2" -ay $vg1
+vgchange --devices "$dev1","$dev2" -an $vg1
+not vgextend --devices "$dev1","$dev2" $vg1 "$dev7"
+vgextend --devices "$dev1","$dev2","$dev7" $vg1 "$dev7"
+vgreduce --devices "$dev1","$dev2","$dev7" $vg1 "$dev7"
+vgexport --devices "$dev1","$dev2" $vg1
+vgimport --devices "$dev1","$dev2" $vg1
+not pvremove --devices "$dev1","$dev2" "$dev7"
+not pvcreate --devices "$dev1","$dev2" "$dev7"
+not vgcreate --devices "$dev1","$dev2" $vg7 "$dev7"
+pvremove --devices "$dev7" "$dev7"
+pvcreate --devices "$dev7" "$dev7"
+vgcreate --devices "$dev7" $vg7 "$dev7"
+vgremove --devices "$dev7" $vg7
+pvremove --devices "$dev7" "$dev7"
+
+# verify various commands with --devices for vg not in a devicesfile
+not lvcreate --devices "$dev3","$dev4" -l1 -n $lv4 -an $vg2 "$dev7"
+lvcreate --devices "$dev3","$dev4" -l1 -n $lv4 -an $vg2
+lvs --devices "$dev3","$dev4" $vg2/$lv4
+lvextend --devices "$dev3","$dev4" -l2 $vg2/$lv4
+lvchange --devices "$dev3","$dev4" -ay $vg2/$lv4
+lvchange --devices "$dev3","$dev4" -an $vg2/$lv4
+lvremove --devices "$dev3","$dev4" $vg2/$lv4
+vgchange --devices "$dev3","$dev4" -ay $vg2
+vgchange --devices "$dev3","$dev4" -an $vg2
+not vgextend --devices "$dev3","$dev4" $vg2 "$dev7"
+vgextend --devices "$dev3","$dev4","$dev7" $vg2 "$dev7"
+vgreduce --devices "$dev3","$dev4","$dev7" $vg2 "$dev7"
+vgexport --devices "$dev3","$dev4" $vg2
+vgimport --devices "$dev3","$dev4" $vg2
+not pvremove --devices "$dev3","$dev4" "$dev7"
+not pvcreate --devices "$dev3","$dev4" "$dev7"
+not vgcreate --devices "$dev3","$dev4" $vg7 "$dev7"
+pvremove --devices "$dev7" "$dev7"
+pvcreate --devices "$dev7" "$dev7"
+vgcreate --devices "$dev7" $vg7 "$dev7"
+vgremove --devices "$dev7" $vg7
+pvremove --devices "$dev7" "$dev7"
+
+# verify pvscan with devices file and devices list
+
+# arg not in devices file
+_clear_online_files
+pvscan --devicesfile test.devices --cache -aay "$dev3"
+not ls "$RUNDIR/lvm/pvs_online/$PVID3"
+pvscan --devicesfile test.devices --cache -aay "$dev4"
+not ls "$RUNDIR/lvm/pvs_online/$PVID4"
+check lv_field $vg1/$lv1 lv_active ""
+check lv_field $vg2/$lv2 lv_active ""
+
+# arg in devices file
+_clear_online_files
+pvscan --devicesfile test.devices --cache "$dev1"
+pvscan --devicesfile test.devices --cache "$dev2"
+ls "$RUNDIR/lvm/pvs_online/$PVID1"
+ls "$RUNDIR/lvm/pvs_online/$PVID2"
+
+# autoactivate with devices file
+_clear_online_files
+pvscan --devicesfile test.devices --cache -aay "$dev1"
+pvscan --devicesfile test.devices --cache -aay "$dev2"
+check lv_field $vg1/$lv1 lv_active "active"
+vgchange -an $vg1
+
+# autoactivate with no devices file
+_clear_online_files
+pvscan --cache -aay "$dev3"
+pvscan --cache -aay "$dev4"
+check lv_field $vg2/$lv2 lv_active "active"
+vgchange -an $vg2
+
+# arg not in devices list
+_clear_online_files
+pvscan --devices "$dev1","$dev2" --cache "$dev3"
+not ls "$RUNDIR/lvm/pvs_online/$PVID3"
+pvscan --devices "$dev4" --cache "$dev3"
+not ls "$RUNDIR/lvm/pvs_online/$PVID3"
+pvscan --devices "$dev5" --cache "$dev3"
+not ls "$RUNDIR/lvm/pvs_online/$PVID3"
+
+# arg in devices list
+_clear_online_files
+pvscan --devices "$dev3" --cache -aay "$dev3"
+pvscan --devices "$dev4","$dev3" --cache -aay "$dev4"
+check lv_field $vg2/$lv2 lv_active "active"
+vgchange -an $vg2
+
+vgchange --devicesfile "" -an
+vgremove --devicesfile "" -y $vg1
+vgremove --devicesfile "" -y $vg2
+vgremove --devicesfile "" -y $vg3
+
+#
+# Test with use_devicesfile=1 (system devices file is in use by default)
+#
+
+aux lvmconf 'devices/use_devicesfile = 1'
+
+DF="$DFDIR/system.devices"
+touch "$DF"
+
+# create one VG in a non-system devices file
+vgcreate --devicesfile test.devices $vg1 "$dev1" "$dev2"
+
+# create one VG in the default system devices file
+vgcreate $vg2 "$dev3" "$dev4"
+
+# create one VG in neither devices file
+vgcreate --devicesfile "" $vg3 "$dev5" "$dev6"
+
+lvcreate --devicesfile test.devices -l4 -an -i2 -n $lv1 $vg1
+lvcreate -l4 -an -i2 -n $lv2 $vg2
+lvcreate --devicesfile "" -l4 -an -i2 -n $lv3 $vg3
+
+# system.devices only sees vg2
+vgs |tee out
+not grep $vg1 out
+grep $vg2 out
+not grep $vg3 out
+not vgs $vg1
+vgs $vg2
+not vgs $vg3
+pvs |tee out
+not grep "$dev1" out
+not grep "$dev2" out
+grep "$dev3" out
+grep "$dev4" out
+not grep "$dev5" out
+not grep "$dev6" out
+
+# test.devices only sees vg1
+vgs --devicesfile test.devices |tee out
+grep $vg1 out
+not grep $vg2 out
+not grep $vg3 out
+pvs --devicesfile test.devices |tee out
+grep "$dev1" out
+grep "$dev2" out
+not grep "$dev3" out
+not grep "$dev4" out
+not grep "$dev5" out
+not grep "$dev6" out
+
+# no devices file sees all
+vgs --devicesfile "" |tee out
+grep $vg1 out
+grep $vg2 out
+grep $vg3 out
+vgs --devicesfile "" $vg1
+vgs --devicesfile "" $vg2
+vgs --devicesfile "" $vg3
+pvs --devicesfile "" |tee out
+grep "$dev1" out
+grep "$dev2" out
+grep "$dev3" out
+grep "$dev4" out
+grep "$dev5" out
+grep "$dev6" out
+
+vgchange -ay
+lvs --devicesfile test.devices -o active $vg1/$lv1 |tee out
+not grep active out
+lvs -o active $vg2/$lv2 |tee out
+grep active out
+lvs --devicesfile "" -o active $vg3/$lv3 |tee out
+not grep active out
+vgchange -an
+lvs -o active $vg2/$lv2 |tee out
+not grep active out
+
+vgchange --devicesfile test.devices -ay
+lvs --devicesfile test.devices -o active $vg1/$lv1 |tee out
+grep active out
+lvs -o active $vg2/$lv2 |tee out
+not grep active out
+lvs --devicesfile "" -o active $vg3/$lv3 |tee out
+not grep active out
+vgchange --devicesfile test.devices -an
+lvs --devicesfile test.devices -o active $vg1/$lv1 |tee out
+not grep active out
+
+# --devices overrides all three cases:
+# always gives access to the specified devices
+# always denies access to unspecified devices
+
+vgs --devices "$dev1","$dev2" $vg1
+vgs --devices "$dev3","$dev4" $vg2
+vgs --devices "$dev5","$dev6" $vg3
+
+pvs --devices "$dev1" "$dev1"
+pvs --devices "$dev3" "$dev3"
+pvs --devices "$dev5" "$dev5"
+
+not pvs --devices "$dev1" "$dev1" "$dev2" |tee out
+grep "$dev1" out
+not grep "$dev2" out
+
+not pvs --devices "$dev3" "$dev3" "$dev4" |tee out
+grep "$dev3" out
+not grep "$dev4" out
+
+not pvs --devices "$dev5" "$dev1" "$dev2" "$dev3" "$dev4" "$dev5" |tee out
+grep "$dev5" out
+not grep "$dev1" out
+not grep "$dev2" out
+not grep "$dev3" out
+not grep "$dev4" out
+not grep "$dev6" out
+
+pvs --devices "$dev1","$dev2","$dev3","$dev4","$dev5" "$dev5" |tee out
+grep "$dev5" out
+not grep "$dev1" out
+not grep "$dev2" out
+not grep "$dev3" out
+not grep "$dev4" out
+not grep "$dev6" out
+
+pvs --devices "$dev1","$dev2","$dev3","$dev4","$dev5" "$dev1" "$dev2" "$dev3" "$dev4" "$dev5" |tee out
+grep "$dev1" out
+grep "$dev2" out
+grep "$dev3" out
+grep "$dev4" out
+grep "$dev5" out
+
+vgchange --devices "$dev1","$dev2" -ay
+lvs --devices "$dev1","$dev2","$dev3","$dev4","$dev5","$dev6" -o name,active | grep active |tee out
+grep $lv1 out
+not grep $lv2 out
+not grep $lv3 out
+vgchange --devices "$dev1","$dev2" -an
+lvs --devices "$dev1","$dev2","$dev3","$dev4","$dev5","$dev6" -o name,active | tee out
+not grep active out
+
+vgchange --devices "$dev3","$dev4" -ay
+lvs --devices "$dev1","$dev2","$dev3","$dev4","$dev5","$dev6" -o name,active | grep active |tee out
+not grep $lv1 out
+grep $lv2 out
+not grep $lv3 out
+vgchange --devices "$dev3","$dev4" -an
+lvs --devices "$dev1","$dev2","$dev3","$dev4","$dev5","$dev6" -o name,active |tee out
+not grep active out
+
+vgchange --devices "$dev5","$dev6" -ay
+lvs --devices "$dev1","$dev2","$dev3","$dev4","$dev5","$dev6" -o name,active | grep active |tee out
+not grep $lv1 out
+not grep $lv2 out
+grep $lv3 out
+vgchange --devices "$dev5","$dev6" -an
+lvs --devices "$dev1","$dev2","$dev3","$dev4","$dev5","$dev6" -o name,active |tee out
+not grep active out
+
+lvcreate --devices "$dev1","$dev2" -l1 -an -n $lv4 $vg1
+lvremove --devices "$dev1","$dev2" $vg1/$lv4
+lvcreate --devices "$dev3","$dev4" -l1 -an -n $lv4 $vg2
+lvremove --devices "$dev3","$dev4" $vg2/$lv4
+lvcreate --devices "$dev5","$dev6" -l1 -an -n $lv4 $vg3
+lvremove --devices "$dev5","$dev6" $vg3/$lv4
+
+not vgchange --devices "$dev1","$dev2" -ay $vg2
+not vgchange --devices "$dev1","$dev2" -ay $vg3
+not vgchange --devices "$dev3","$dev4" -ay $vg1
+not vgchange --devices "$dev3","$dev4" -ay $vg3
+not vgchange --devices "$dev5","$dev6" -ay $vg1
+not vgchange --devices "$dev5","$dev6" -ay $vg2
+
+not lvcreate --devices "$dev1","$dev2" -an -l1 $vg2
+not lvcreate --devices "$dev1","$dev2" -an -l1 $vg3
+not lvcreate --devices "$dev3","$dev4" -an -l1 $vg1
+not lvcreate --devices "$dev3","$dev4" -an -l1 $vg3
+not lvcreate --devices "$dev5","$dev6" -an -l1 $vg1
+not lvcreate --devices "$dev5","$dev6" -an -l1 $vg2
+
+# autoactivate devs in default devices file
+_clear_online_files
+pvscan --cache -aay "$dev3"
+pvscan --cache -aay "$dev4"
+check lv_field $vg2/$lv2 lv_active "active"
+vgchange -an $vg2
+pvscan --cache -aay "$dev1"
+not ls "$RUNDIR/lvm/pvs_online/$PVID1"
+pvscan --cache -aay "$dev2"
+not ls "$RUNDIR/lvm/pvs_online/$PVID2"
+pvscan --cache -aay "$dev5"
+not ls "$RUNDIR/lvm/pvs_online/$PVID5"
+_clear_online_files
+pvscan --devices "$dev3" --cache -aay "$dev3"
+pvscan --devices "$dev3","$dev4" --cache -aay "$dev4"
+lvs --devices "$dev3","$dev4" -o active $vg2/$lv2 | grep active
+vgchange --devices "$dev3","$dev4" -an $vg2
+
+not vgchange -ay $vg1
+vgchange --devicesfile test.devices -ay $vg1
+lvs --devices "$dev1","$dev2","$dev3","$dev4","$dev5","$dev6" -o name,active | grep active |tee out
+grep $lv1 out
+not grep $lv2 out
+not grep $lv3 out
+
+vgchange -ay $vg2
+lvs --devices "$dev1","$dev2","$dev3","$dev4","$dev5","$dev6" -o name,active | grep active |tee out
+grep $lv1 out
+grep $lv2 out
+not grep $lv3 out
+
+not vgchange -ay $vg3
+vgchange --devicesfile "" -ay $vg3
+lvs --devices "$dev1","$dev2","$dev3","$dev4","$dev5","$dev6" -o name,active | grep active |tee out
+grep $lv1 out
+grep $lv2 out
+grep $lv3 out
+
+vgchange -an
+lvs --devices "$dev1","$dev2","$dev3","$dev4","$dev5","$dev6" -o name,active | grep active |tee out
+grep $lv1 out
+not grep $lv2 out
+grep $lv3 out
+
+vgchange -ay
+lvs --devices "$dev1","$dev2","$dev3","$dev4","$dev5","$dev6" -o name,active | grep active |tee out
+grep $lv1 out
+grep $lv2 out
+grep $lv3 out
+
+vgchange --devicesfile "" -an
+lvs --devices "$dev1","$dev2","$dev3","$dev4","$dev5","$dev6" -o name,active |tee out
+not grep active out
+
+not vgremove $vg1
+not vgremove $vg3
+vgremove -y $vg2
+vgremove --devicesfile test.devices -y $vg1
+vgremove --devicesfile "" -y $vg3
+
+#
+# Test when system.devices is created by lvm
+#
+
+# no pvs exist, pvcreate creates DF, e.g. system installation
+
+wipe_all
+rm -f "$DF"
+pvcreate "$dev1"
+ls "$DF"
+grep "$dev1" "$DF"
+
+# no pvs exist, vgcreate creates DF, e.g. system installation
+
+wipe_all
+rm -f "$DF"
+vgcreate $vg1 "$dev1"
+ls "$DF"
+grep "$dev1" "$DF"
+
+# no pvs exist, touch DF, pvcreate uses it
+
+wipe_all
+rm -f "$DF"
+touch "$DF"
+pvcreate "$dev1"
+grep "$dev1" "$DF"
+
+# no vgs exist, touch DF, vgcreate uses it
+
+wipe_all
+rm -f "$DF"
+touch "$DF"
+vgcreate $vg1 "$dev1"
+grep "$dev1" "$DF"
+
+# vgs exist, pvcreate/vgcreate do not create DF
+
+wipe_all
+rm -f "$DF"
+vgcreate $vg1 "$dev1"
+ls "$DF"
+rm "$DF"
+pvcreate "$dev2"
+not ls "$DF"
+vgcreate $vg3 "$dev3"
+not ls "$DF"
+
+# vgs exist, pvcreate/vgcreate --devicesfile system.devices creates DF
+
+wipe_all
+rm -f "$DF"
+vgcreate $vg1 "$dev1"
+ls "$DF"
+rm "$DF"
+pvcreate --devicesfile system.devices "$dev2"
+ls "$DF"
+grep "$dev2" "$DF"
+rm "$DF"
+vgcreate --devicesfile system.devices $vg3 "$dev3"
+ls "$DF"
+grep "$dev3" "$DF"
+
+# pvcreate/vgcreate always create non-system DF if it doesn't exist
+
+wipe_all
+rm -f "$DF"
+vgcreate $vg1 "$dev1"
+rm "$DF"
+rm "$DFDIR/test.devices"
+pvcreate --devicesfile test.devices "$dev2"
+grep "$dev2" "$DFDIR/test.devices"
+rm "$DFDIR/test.devices"
+vgcreate --devicesfile test.devices $vg3 "$dev3"
+grep "$dev3" "$DFDIR/test.devices"
+
+# vgchange uuid handles stacked PVs on VGs
+
+wipe_all
+rm -f "$DF"
+vgcreate $vg1 "$dev1"
+lvcreate -l8 -n $lv1 $vg1
+aux lvmconf 'devices/scan_lvs = 1'
+pvcreate "$DM_DEV_DIR/$vg1/$lv1"
+pvs "$DM_DEV_DIR/$vg1/$lv1"
+grep "$DM_DEV_DIR/$vg1/$lv1" $DF
+vgchange -an $vg1
+vgchange --uuid $vg1
+vgchange -ay $vg1
+pvs "$DM_DEV_DIR/$vg1/$lv1"
+vgchange -an $vg1
+not pvs "$DM_DEV_DIR/$vg1/$lv1"
+aux lvmconf 'devices/scan_lvs = 0'
+vgremove -y $vg1
+
+#
+# verify --devicesfile and --devices are not affected by a filter
+# This is last because it sets lvm.conf filter and
+# I haven't found a way of removing the filter from
+# the config after setting it.
+#
+
+aux lvmconf 'devices/use_devicesfile = 0'
+wipe_all
+rm -f "$DF"
+rm -f "$DFDIR/test.devices"
+
+vgcreate --devicesfile test.devices $vg1 "$dev1" "$dev2"
+grep "$dev1" "$DFDIR/test.devices"
+grep "$dev2" "$DFDIR/test.devices"
+not ls "$DFDIR/system.devices"
+
+# create two VGs outside the special devices file
+vgcreate $vg2 "$dev3" "$dev4"
+vgcreate $vg3 "$dev5" "$dev6"
+not grep "$dev3" "$DFDIR/test.devices"
+not grep "$dev5" "$DFDIR/test.devices"
+not ls "$DFDIR/system.devices"
+
+lvcreate -l4 -an -i2 -n $lv1 $vg1
+lvcreate -l4 -an -i2 -n $lv2 $vg2
+lvcreate -l4 -an -i2 -n $lv3 $vg3
+
+aux lvmconf "devices/filter = [ \"r|$dev2|\" \"r|$dev4|\" ]"
+
+pvs --devicesfile test.devices "$dev1"
+pvs --devicesfile test.devices "$dev2"
+not pvs --devicesfile test.devices "$dev3"
+not pvs --devicesfile test.devices "$dev4"
+pvs --devices "$dev1" "$dev1"
+pvs --devices "$dev2" "$dev2"
+pvs --devices "$dev3" "$dev3"
+pvs --devices "$dev4" "$dev4"
+pvs --devices "$dev5" "$dev5"
+pvs --devices "$dev1","$dev2","$dev3","$dev4","$dev5" "$dev1" "$dev2" "$dev3" "$dev4" "$dev5" | tee out
+grep "$dev1" out
+grep "$dev2" out
+grep "$dev3" out
+grep "$dev4" out
+grep "$dev5" out
+vgchange --devices "$dev1","$dev2" -ay $vg1
+check lv_field $vg1/$lv1 lv_active "active"
+lvchange --devices "$dev1","$dev2" -an $vg1/$lv1
+vgchange --devices "$dev3","$dev4" -ay $vg2
+check lv_field $vg2/$lv2 lv_active "active"
+lvchange --devices "$dev3","$dev4" -an $vg2/$lv2
+
+vgchange -an --devicesfile test.devices $vg1
+vgremove -y --devicesfile test.devices $vg1
+vgremove -y $vg2
+vgremove -y $vg3
+
diff --git a/test/shell/devicesfile-devname.sh b/test/shell/devicesfile-devname.sh
new file mode 100644
index 0000000..1ff87c2
--- /dev/null
+++ b/test/shell/devicesfile-devname.sh
@@ -0,0 +1,628 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2020 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+test_description='devices file with devnames'
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+aux prepare_devs 7
+
+RUNDIR="/run"
+test -d "$RUNDIR" || RUNDIR="/var/run"
+PVS_ONLINE_DIR="$RUNDIR/lvm/pvs_online"
+VGS_ONLINE_DIR="$RUNDIR/lvm/vgs_online"
+PVS_LOOKUP_DIR="$RUNDIR/lvm/pvs_lookup"
+
+_clear_online_files() {
+ # wait till udev is finished
+ aux udev_wait
+ rm -f "$PVS_ONLINE_DIR"/*
+ rm -f "$VGS_ONLINE_DIR"/*
+ rm -f "$PVS_LOOKUP_DIR"/*
+}
+
+DFDIR="$LVM_SYSTEM_DIR/devices"
+mkdir "$DFDIR" || true
+DF="$DFDIR/system.devices"
+ORIG="$DFDIR/orig.devices"
+
+aux lvmconf 'devices/use_devicesfile = 1'
+
+pvcreate "$dev1"
+ls "$DF"
+grep "$dev1" "$DF"
+
+pvcreate "$dev2"
+grep "$dev2" "$DF"
+
+pvcreate "$dev3"
+grep "$dev3" "$DF"
+
+vgcreate $vg1 "$dev1" "$dev2"
+
+# PVID with dashes for matching pvs -o+uuid output
+OPVID1=`pvs "$dev1" --noheading -o uuid | awk '{print $1}'`
+OPVID2=`pvs "$dev2" --noheading -o uuid | awk '{print $1}'`
+OPVID3=`pvs "$dev3" --noheading -o uuid | awk '{print $1}'`
+
+# PVID without dashes for matching devices file fields
+PVID1=`pvs "$dev1" --noheading -o uuid | tr -d - | awk '{print $1}'`
+PVID2=`pvs "$dev2" --noheading -o uuid | tr -d - | awk '{print $1}'`
+PVID3=`pvs "$dev3" --noheading -o uuid | tr -d - | awk '{print $1}'`
+
+lvmdevices --deldev "$dev3"
+
+not grep "$dev3" "$DF"
+not grep "$PVID3" "$DF"
+not pvs "$dev3"
+
+cp "$DF" "$ORIG"
+
+lvcreate -l4 -an -i2 -n $lv1 $vg1
+
+#
+# when wrong idname devname is outside DF it's corrected if search_for=1
+# by a general cmd, or by lvmdevices --addpvid
+#
+# when wrong idname devname is outside DF it's not found or corrected if
+# search_for=0 by a general cmd, but will be by lvmdevices --addpvid
+#
+# when wrong idname devname is inside DF it's corrected if search_for=0|1
+# by a general cmd, or by lvmdevices --addpvid
+#
+# pvscan --cache -aay does not update DF when devname= is wrong
+#
+# pvscan --cache -aay when idname devname is wrong:
+# every dev is read and then skipped if pvid is not in DF
+#
+# commands still work with incorrect devname=
+# . and they automatically correct the devname=
+#
+
+
+#
+# idname changes to become incorrect, devname remains unchanged and correct
+# . change idname to something outside DF
+# . change idname to match another DF entry
+# . swap idname of two DF entries
+#
+
+# edit DF idname, s/dev1/dev3/, where new dev is not in DF
+
+sed -e "s|IDNAME=$dev1|IDNAME=$dev3|" "$ORIG" > "$DF"
+cat "$DF"
+# pvs reports correct info
+pvs -o+uuid | tee pvs.out
+grep $vg1 pvs.out > out
+not grep "$OPVID3" out
+not grep "$dev3" out
+grep "$OPVID1" out |tee out2
+grep "$dev1" out2
+# pvs fixed the DF
+not grep "$PVID3" "$DF"
+not grep "$dev3" "$DF"
+grep "$PVID1" "$DF" |tee out
+grep "IDNAME=$dev1" out
+cat "$DF"
+
+sed -e "s|IDNAME=$dev1|IDNAME=$dev3|" "$ORIG" > "$DF"
+cat "$DF"
+# lvcreate uses correct dev
+lvcreate -l1 -n $lv2 -an $vg1 "$dev1"
+# lvcreate fixed the DF
+not grep "$PVID3" "$DF"
+not grep "$dev3" "$DF"
+grep "$PVID1" "$DF" |tee out
+grep "IDNAME=$dev1" out
+# pvs reports correct dev
+pvs -o+uuid | tee pvs.out
+grep $vg1 pvs.out > out
+not grep "$OPVID3" out
+not grep "$dev3" out
+grep "$OPVID1" out |tee out2
+grep "$dev1" out2
+lvremove $vg1/$lv2
+cat "$DF"
+
+sed -e "s|IDNAME=$dev1|IDNAME=$dev3|" "$ORIG" > "$DF"
+cat "$DF"
+# lvmdevices fixes the DF
+lvmdevices --update
+not grep "$PVID3" "$DF"
+not grep "$dev3" "$DF"
+grep "$PVID1" "$DF" |tee out
+grep "IDNAME=$dev1" out
+cat "$DF"
+
+# edit DF idname, s/dev1/dev2/, creating two entries with same idname
+
+sed -e "s|IDNAME=$dev1|IDNAME=$dev2|" "$ORIG" > "$DF"
+cat "$DF"
+# pvs reports correct info
+pvs -o+uuid | tee pvs.out
+grep $vg1 pvs.out > out
+grep "$OPVID1" out |tee out2
+grep "$dev1" out2
+grep "$OPVID2" out |tee out2
+grep "$dev2" out2
+# pvs fixed the DF
+grep "$PVID1" "$DF" |tee out
+grep "IDNAME=$dev1" out
+grep "$PVID2" "$DF" |tee out
+grep "IDNAME=$dev2" out
+cat "$DF"
+
+sed -e "s|IDNAME=$dev1|IDNAME=$dev2|" "$ORIG" > "$DF"
+cat "$DF"
+# lvcreate uses correct dev
+lvcreate -l1 -n $lv2 -an $vg1 "$dev1"
+# lvcreate fixed the DF
+grep "$PVID1" "$DF" |tee out
+grep "IDNAME=$dev1" out
+grep "$PVID2" "$DF" |tee out
+grep "IDNAME=$dev2" out
+# pvs reports correct info
+pvs -o+uuid | tee pvs.out
+grep $vg1 pvs.out > out
+grep "$OPVID1" out |tee out2
+grep "$dev1" out2
+grep "$OPVID2" out |tee out2
+grep "$dev2" out2
+lvremove $vg1/$lv2
+cat "$DF"
+
+sed -e "s|IDNAME=$dev1|IDNAME=$dev2|" "$ORIG" > "$DF"
+cat "$DF"
+# lvmdevices fixes the DF
+lvmdevices --update
+grep "$PVID1" "$DF" |tee out
+grep "IDNAME=$dev1" out
+grep "$PVID2" "$DF" |tee out
+grep "IDNAME=$dev2" out
+cat "$DF"
+
+# edit DF idname, swap dev1 and dev2
+
+sed -e "s|IDNAME=$dev1|IDNAME=tmpname|" "$ORIG" > tmp1.devices
+sed -e "s|IDNAME=$dev2|IDNAME=$dev1|" tmp1.devices > tmp2.devices
+sed -e "s|IDNAME=tmpname|IDNAME=$dev2|" tmp2.devices > "$DF"
+cat "$DF"
+# pvs reports correct info
+pvs -o+uuid | tee pvs.out
+grep $vg1 pvs.out > out
+grep "$OPVID1" out |tee out2
+grep "$dev1" out2
+grep "$OPVID2" out |tee out2
+grep "$dev2" out2
+# pvs fixed the DF
+grep "$PVID1" "$DF" |tee out
+grep "IDNAME=$dev1" out
+grep "$PVID2" "$DF" |tee out
+grep "IDNAME=$dev2" out
+cat "$DF"
+
+sed -e "s|IDNAME=$dev1|IDNAME=tmpname|" "$ORIG" > tmp1.devices
+sed -e "s|IDNAME=$dev2|IDNAME=$dev1|" tmp1.devices > tmp2.devices
+sed -e "s|IDNAME=tmpname|IDNAME=$dev2|" tmp2.devices > "$DF"
+cat "$DF"
+# lvcreate uses correct dev
+lvcreate -l1 -n $lv2 -an $vg1 "$dev1"
+# lvcreate fixed the DF
+grep "$PVID1" "$DF" |tee out
+grep "IDNAME=$dev1" out
+grep "$PVID2" "$DF" |tee out
+grep "IDNAME=$dev2" out
+# pvs reports correct info
+pvs -o+uuid | tee pvs.out
+grep $vg1 pvs.out > out
+grep "$OPVID1" out |tee out2
+grep "$dev1" out2
+grep "$OPVID2" out |tee out2
+grep "$dev2" out2
+lvremove $vg1/$lv2
+cat "$DF"
+
+sed -e "s|IDNAME=$dev1|IDNAME=tmpname|" "$ORIG" > tmp1.devices
+sed -e "s|IDNAME=$dev2|IDNAME=$dev1|" tmp1.devices > tmp2.devices
+sed -e "s|IDNAME=tmpname|IDNAME=$dev2|" tmp2.devices > "$DF"
+cat "$DF"
+# lvmdevices fixes the DF
+lvmdevices --update
+grep "$PVID1" "$DF" |tee out
+grep "IDNAME=$dev1" out
+grep "$PVID2" "$DF" |tee out
+grep "IDNAME=$dev2" out
+cat "$DF"
+
+
+#
+# idname remains correct, devname changes to become incorrect
+# . change devname to something outside DF
+# . change devname to match another DF entry
+# . swap devname of two DF entries
+#
+
+# edit DF devname, s/dev1/dev3/, where new dev is not in DF
+
+sed -e "s|DEVNAME=$dev1|DEVNAME=$dev3|" "$ORIG" > "$DF"
+cat "$DF"
+# pvs reports correct info
+pvs -o+uuid | tee pvs.out
+grep $vg1 pvs.out > out
+not grep "$OPVID3" out
+not grep "$dev3" out
+grep "$OPVID1" out |tee out2
+grep "$dev1" out2
+# pvs fixed the DF
+not grep "$PVID3" "$DF"
+not grep "$dev3" "$DF"
+grep "$PVID1" "$DF" |tee out
+grep "DEVNAME=$dev1" out
+cat "$DF"
+
+sed -e "s|DEVNAME=$dev1|DEVNAME=$dev3|" "$ORIG" > "$DF"
+cat "$DF"
+# lvmdevices fixes the DF
+lvmdevices --update
+not grep "$PVID3" "$DF"
+not grep "$dev3" "$DF"
+grep "$PVID1" "$DF" |tee out
+grep "IDNAME=$dev1" out
+cat "$DF"
+
+# edit DF devname, s/dev1/dev2/, creating two entries with same devname
+
+sed -e "s|DEVNAME=$dev1|DEVNAME=$dev2|" "$ORIG" > "$DF"
+cat "$DF"
+# pvs reports correct info
+pvs -o+uuid | tee pvs.out
+grep $vg1 pvs.out > out
+grep "$OPVID1" out |tee out2
+grep "$dev1" out2
+grep "$OPVID2" out |tee out2
+grep "$dev2" out2
+# pvs fixed the DF
+grep "$PVID1" "$DF" |tee out
+grep "DEVNAME=$dev1" out
+grep "$PVID2" "$DF" |tee out
+grep "DEVNAME=$dev2" out
+cat "$DF"
+
+sed -e "s|DEVNAME=$dev1|DEVNAME=$dev2|" "$ORIG" > "$DF"
+cat "$DF"
+# lvmdevices fixes the DF
+lvmdevices --update
+grep "$PVID1" "$DF" |tee out
+grep "IDNAME=$dev1" out
+grep "$PVID2" "$DF" |tee out
+grep "IDNAME=$dev2" out
+cat "$DF"
+
+# edit DF devname, swap dev1 and dev2
+
+sed -e "s|DEVNAME=$dev1|DEVNAME=tmpname|" "$ORIG" > tmp1.devices
+sed -e "s|DEVNAME=$dev2|DEVNAME=$dev1|" tmp1.devices > tmp2.devices
+sed -e "s|DEVNAME=tmpname|DEVNAME=$dev2|" tmp2.devices > "$DF"
+cat "$DF"
+# pvs reports correct info
+pvs -o+uuid | tee pvs.out
+grep $vg1 pvs.out > out
+grep "$OPVID1" out |tee out2
+grep "$dev1" out2
+grep "$OPVID2" out |tee out2
+grep "$dev2" out2
+# pvs fixed the DF
+grep "$PVID1" "$DF" |tee out
+grep "DEVNAME=$dev1" out
+grep "$PVID2" "$DF" |tee out
+grep "DEVNAME=$dev2" out
+cat "$DF"
+
+sed -e "s|DEVNAME=$dev1|DEVNAME=tmpname|" "$ORIG" > tmp1.devices
+sed -e "s|DEVNAME=$dev2|DEVNAME=$dev1|" tmp1.devices > tmp2.devices
+sed -e "s|DEVNAME=tmpname|DEVNAME=$dev2|" tmp2.devices > "$DF"
+cat "$DF"
+# lvmdevices fixes the DF
+lvmdevices --update
+grep "$PVID1" "$DF" |tee out
+grep "IDNAME=$dev1" out
+grep "$PVID2" "$DF" |tee out
+grep "IDNAME=$dev2" out
+cat "$DF"
+
+
+#
+# idname and devname change, both become incorrect
+# . change idname&devname to something outside DF
+# . change idname&devname to match another DF entry
+# . swap idname&devname of two DF entries
+#
+
+# edit DF idname&devname, s/dev1/dev3/, where new dev is not in DF
+
+sed -e "s|DEVNAME=$dev1|DEVNAME=$dev3|" "$ORIG" > tmp1.devices
+sed -e "s|IDNAME=$dev1|IDNAME=$dev3|" tmp1.devices > "$DF"
+cat "$DF"
+# pvs reports correct info
+pvs -o+uuid | tee pvs.out
+grep $vg1 pvs.out > out
+not grep "$OPVID3" out
+not grep "$dev3" out
+grep "$OPVID1" out |tee out2
+grep "$dev1" out2
+# pvs fixed the DF
+not grep "$PVID3" "$DF"
+not grep "$dev3" "$DF"
+grep "$PVID1" "$DF" |tee out
+grep "DEVNAME=$dev1" out
+grep "IDNAME=$dev1" out
+cat "$DF"
+
+sed -e "s|DEVNAME=$dev1|DEVNAME=$dev3|" "$ORIG" > tmp1.devices
+sed -e "s|IDNAME=$dev1|IDNAME=$dev3|" tmp1.devices > "$DF"
+cat "$DF"
+# lvmdevices fixes the DF
+lvmdevices --update
+not grep "$PVID3" "$DF"
+not grep "$dev3" "$DF"
+grep "$PVID1" "$DF" |tee out
+grep "DEVNAME=$dev1" out
+grep "IDNAME=$dev1" out
+cat "$DF"
+
+# edit DF idname&devname, s/dev1/dev2/, creating two entries with same devname
+
+sed -e "s|DEVNAME=$dev1|DEVNAME=$dev2|" tmp1.devices > "$DF"
+sed -e "s|IDNAME=$dev1|IDNAME=$dev2|" tmp1.devices > "$DF"
+cat "$DF"
+# pvs reports correct info
+pvs -o+uuid | tee pvs.out
+grep $vg1 pvs.out > out
+grep "$OPVID1" out |tee out2
+grep "$dev1" out2
+grep "$OPVID2" out |tee out2
+grep "$dev2" out2
+# pvs fixed the DF
+grep "$PVID1" "$DF" |tee out
+grep "DEVNAME=$dev1" out
+grep "IDNAME=$dev1" out
+grep "$PVID2" "$DF" |tee out
+grep "DEVNAME=$dev2" out
+grep "IDNAME=$dev2" out
+cat "$DF"
+
+sed -e "s|DEVNAME=$dev1|DEVNAME=$dev2|" tmp1.devices > "$DF"
+sed -e "s|IDNAME=$dev1|IDNAME=$dev2|" tmp1.devices > "$DF"
+cat "$DF"
+# lvmdevices fixes the DF
+lvmdevices --update
+grep "$PVID1" "$DF" |tee out
+grep "DEVNAME=$dev1" out
+grep "IDNAME=$dev1" out
+grep "$PVID2" "$DF" |tee out
+grep "DEVNAME=$dev2" out
+grep "IDNAME=$dev2" out
+cat "$DF"
+
+# edit DF devname, swap dev1 and dev2
+
+sed -e "s|DEVNAME=$dev1|DEVNAME=tmpname|" "$ORIG" > tmp1.devices
+sed -e "s|DEVNAME=$dev2|DEVNAME=$dev1|" tmp1.devices > tmp2.devices
+sed -e "s|DEVNAME=tmpname|DEVNAME=$dev2|" tmp2.devices > tmp3.devices
+sed -e "s|IDNAME=$dev1|IDNAME=tmpname|" tmp3.devices > tmp4.devices
+sed -e "s|IDNAME=$dev2|IDNAME=$dev1|" tmp4.devices > tmp5.devices
+sed -e "s|IDNAME=tmpname|IDNAME=$dev2|" tmp5.devices > "$DF"
+cat "$DF"
+# pvs reports correct info
+pvs -o+uuid | tee pvs.out
+grep $vg1 pvs.out > out
+grep "$OPVID1" out |tee out2
+grep "$dev1" out2
+grep "$OPVID2" out |tee out2
+grep "$dev2" out2
+# pvs fixed the DF
+grep "$PVID1" "$DF" |tee out
+grep "DEVNAME=$dev1" out
+grep "IDNAME=$dev1" out
+grep "$PVID2" "$DF" |tee out
+grep "DEVNAME=$dev2" out
+grep "IDNAME=$dev2" out
+cat "$DF"
+
+sed -e "s|DEVNAME=$dev1|DEVNAME=tmpname|" "$ORIG" > tmp1.devices
+sed -e "s|DEVNAME=$dev2|DEVNAME=$dev1|" tmp1.devices > tmp2.devices
+sed -e "s|DEVNAME=tmpname|DEVNAME=$dev2|" tmp2.devices > tmp3.devices
+sed -e "s|IDNAME=$dev1|IDNAME=tmpname|" tmp3.devices > tmp4.devices
+sed -e "s|IDNAME=$dev2|IDNAME=$dev1|" tmp4.devices > tmp5.devices
+sed -e "s|IDNAME=tmpname|IDNAME=$dev2|" tmp5.devices > "$DF"
+cat "$DF"
+# lvmdevices fixes the DF
+lvmdevices --update
+grep "$PVID1" "$DF" |tee out
+grep "DEVNAME=$dev1" out
+grep "IDNAME=$dev1" out
+grep "$PVID2" "$DF" |tee out
+grep "DEVNAME=$dev2" out
+grep "IDNAME=$dev2" out
+cat "$DF"
+
+#
+# check that pvscan --cache -aay does the right thing:
+#
+# idname and devname change, both become incorrect
+# . change idname&devname to something outside DF
+# . swap idname&devname of two DF entries
+#
+
+# edit DF idname&devname, s/dev1/dev3/, where new dev is not in DF
+
+sed -e "s|DEVNAME=$dev1|DEVNAME=$dev3|" "$ORIG" > tmp1.devices
+sed -e "s|IDNAME=$dev1|IDNAME=$dev3|" tmp1.devices > "$DF"
+cat "$DF"
+_clear_online_files
+pvscan --cache -aay "$dev1"
+pvscan --cache -aay "$dev2"
+pvscan --cache -aay "$dev3"
+cat "$DF"
+# pvscan does not fix DF
+grep "$dev3" "$DF"
+not grep "$dev1" "$DF"
+ls "$RUNDIR/lvm/pvs_online/$PVID1"
+ls "$RUNDIR/lvm/pvs_online/$PVID2"
+not ls "$RUNDIR/lvm/pvs_online/$PVID3"
+check lv_field $vg1/$lv1 lv_active "active"
+# pvs updates the DF
+pvs |tee out
+grep "$dev1" out
+grep "$dev2" out
+not grep "$dev3" out
+grep "$dev1" "$DF"
+grep "$dev2" "$DF"
+not grep "$dev3" "$DF"
+vgchange -an $vg1
+
+# edit DF idname&devname, swap dev1 and dev2
+
+vgremove -y $vg1
+vgcreate $vg1 "$dev1"
+lvcreate -n $lv1 -l1 -an $vg1
+vgcreate $vg2 "$dev2"
+lvcreate -n $lv2 -l1 -an $vg2
+
+cat "$DF"
+sed -e "s|DEVNAME=$dev1|DEVNAME=tmpname|" "$ORIG" > tmp1.devices
+sed -e "s|DEVNAME=$dev2|DEVNAME=$dev1|" tmp1.devices > tmp2.devices
+sed -e "s|DEVNAME=tmpname|DEVNAME=$dev2|" tmp2.devices > tmp3.devices
+sed -e "s|IDNAME=$dev1|IDNAME=tmpname|" tmp3.devices > tmp4.devices
+sed -e "s|IDNAME=$dev2|IDNAME=$dev1|" tmp4.devices > tmp5.devices
+sed -e "s|IDNAME=tmpname|IDNAME=$dev2|" tmp5.devices > "$DF"
+cat "$DF"
+
+_clear_online_files
+
+# pvscan creates the correct online files and activates correct vg
+pvscan --cache -aay "$dev1"
+ls "$RUNDIR/lvm/pvs_online/$PVID1"
+ls "$RUNDIR/lvm/vgs_online/$vg1"
+not ls "$RUNDIR/lvm/pvs_online/$PVID2"
+not ls "$RUNDIR/lvm/vgs_online/$vg2"
+# don't use lvs because it would fix DF before we check it
+dmsetup status $vg1-$lv1
+not dmsetup status $vg2-$lv2
+
+pvscan --cache -aay "$dev2"
+ls "$RUNDIR/lvm/pvs_online/$PVID2"
+ls "$RUNDIR/lvm/vgs_online/$vg2"
+dmsetup status $vg2-$lv2
+
+pvscan --cache -aay "$dev3"
+not ls "$RUNDIR/lvm/pvs_online/$PVID3"
+
+# pvscan did not correct DF
+cat "$DF"
+grep "$PVID1" "$DF" |tee out
+grep "$dev2" out
+not grep "$dev1" out
+grep "$PVID2" "$DF" |tee out
+grep "$dev1" out
+not grep "$dev2" out
+
+# pvs corrects DF
+pvs
+grep "$PVID1" "$DF" |tee out
+grep "$dev1" out
+not grep "$dev2" out
+grep "$PVID2" "$DF" |tee out
+grep "$dev2" out
+not grep "$dev1" out
+
+vgchange -an $vg1
+vgchange -an $vg2
+vgremove -ff $vg1
+vgremove -ff $vg2
+
+# bz 2119473
+
+aux lvmconf "devices/search_for_devnames = \"none\""
+sed -e "s|DEVNAME=$dev1|DEVNAME=.|" "$ORIG" > tmp1.devices
+sed -e "s|IDNAME=$dev1|IDNAME=.|" tmp1.devices > "$DF"
+pvs
+lvmdevices
+pvcreate -ff --yes --uuid "$PVID1" --norestorefile $dev1
+grep "$PVID1" "$DF" |tee out
+grep "DEVNAME=$dev1" out
+grep "IDNAME=$dev1" out
+aux lvmconf "devices/search_for_devnames = \"auto\""
+
+# devnames change so the new devname now refers to a filtered device,
+# e.g. an mpath or md component, which is not scanned
+
+wait_md_create() {
+ local md=$1
+
+ while :; do
+ if ! grep "$(basename $md)" /proc/mdstat; then
+ echo "$md not ready"
+ cat /proc/mdstat
+ sleep 2
+ else
+ break
+ fi
+ done
+ echo "$md" > WAIT_MD_DEV
+}
+
+aux wipefs_a "$dev1" "$dev2" "$dev3" "$dev4"
+
+rm "$DF"
+touch "$DF"
+vgcreate $vg1 "$dev1" "$dev2"
+cat "$DF"
+cp "$DF" "$ORIG"
+
+# PVID with dashes for matching pvs -o+uuid output
+OPVID1=`pvs "$dev1" --noheading -o uuid | awk '{print $1}'`
+OPVID2=`pvs "$dev2" --noheading -o uuid | awk '{print $1}'`
+
+# PVID without dashes for matching devices file fields
+PVID1=`pvs "$dev1" --noheading -o uuid | tr -d - | awk '{print $1}'`
+PVID2=`pvs "$dev2" --noheading -o uuid | tr -d - | awk '{print $1}'`
+
+aux mdadm_create --metadata=1.0 --level 1 --raid-devices=2 "$dev3" "$dev4"
+mddev=$(< MD_DEV)
+
+wait_md_create "$mddev"
+
+sed -e "s|DEVNAME=$dev1|DEVNAME=$dev3|" "$ORIG" > tmp1.devices
+sed -e "s|IDNAME=$dev1|IDNAME=$dev3|" tmp1.devices > "$DF"
+cat "$DF"
+pvs -o+uuid |tee out
+grep "$dev1" out
+grep "$dev2" out
+grep "$OPVID1" out
+grep "$OPVID2" out
+not grep "$dev3" out
+not grep "$dev4" out
+
+grep "$dev1" "$DF"
+grep "$dev2" "$DF"
+grep "$PVID1" "$DF"
+grep "$PVID2" "$DF"
+not grep "$dev3" "$DF"
+not grep "$dev4" "$DF"
+
+mdadm --stop "$mddev"
+aux udev_wait
+
+vgremove -ff $vg1
diff --git a/test/shell/devicesfile-edit.sh b/test/shell/devicesfile-edit.sh
new file mode 100644
index 0000000..0ccafaf
--- /dev/null
+++ b/test/shell/devicesfile-edit.sh
@@ -0,0 +1,257 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2020 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+test_description='devices file editing with lvmdevices'
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+aux lvmconf 'devices/scan = "/dev"'
+
+aux prepare_devs 1
+
+# The tests run with system dir of "/etc" but lvm when running
+# normally has cmd->system_dir set to "/etc/lvm".
+DFDIR="$LVM_SYSTEM_DIR/devices"
+mkdir -p "$DFDIR" || true
+DF="$DFDIR/system.devices"
+
+aux lvmconf 'devices/use_devicesfile = 1'
+
+losetup -h | grep sector-size || skip
+which fallocate || skip
+
+fallocate -l 2M loopa
+fallocate -l 2M loopb
+
+setup_loop_devs() {
+ for i in {1..5} ; do
+ LOOP1=$(losetup -f loopa --show || true)
+ test -n "$LOOP1" && break
+ done
+ for i in {1..5} ; do
+ LOOP2=$(losetup -f loopb --show || true)
+ test -n "$LOOP2" && break
+ done
+}
+
+setup_loop_devs
+
+# Tests of devices without PV on them.
+
+# add/del with default idtype loop_file
+lvmdevices --adddev "$LOOP1"
+grep "$LOOP1" $DF
+lvmdevices --adddev "$LOOP2"
+grep "$LOOP2" $DF
+grep "IDTYPE=loop_file" $DF
+not grep "IDTYPE=devname" $DF
+lvmdevices --deldev "$LOOP1"
+not grep "$LOOP1" $DF
+lvmdevices --deldev "$LOOP2"
+not grep "$LOOP2" $DF
+
+# add/del with non-default idtype devname
+lvmdevices --adddev "$LOOP1" --deviceidtype devname
+grep "$LOOP1" $DF
+lvmdevices --adddev "$LOOP2" --deviceidtype devname
+grep "$LOOP2" $DF
+grep "IDTYPE=devname" $DF
+not grep "IDTYPE=loop_file" $DF
+lvmdevices --deldev "$LOOP1"
+not grep "$LOOP1" $DF
+lvmdevices --deldev "$LOOP2"
+not grep "$LOOP2" $DF
+
+# add/del when dev is missing, using default idtype
+lvmdevices --adddev "$LOOP1"
+grep "$LOOP1" $DF
+lvmdevices --adddev "$LOOP2"
+grep "$LOOP2" $DF
+losetup -D
+grep "$LOOP1" $DF
+grep "$LOOP2" $DF
+lvmdevices --deldev "$LOOP1"
+not grep "$LOOP1" $DF
+lvmdevices --deldev "$LOOP2"
+not grep "$LOOP2" $DF
+not lvmdevices --adddev "$LOOP1"
+not lvmdevices --adddev "$LOOP2"
+not grep "$LOOP1" $DF
+not grep "$LOOP2" $DF
+setup_loop_devs
+rm $DF
+
+# add/del when dev is missing, using devname idtype
+lvmdevices --adddev "$LOOP1" --deviceidtype devname
+grep "$LOOP1" $DF
+lvmdevices --adddev "$LOOP2" --deviceidtype devname
+grep "$LOOP2" $DF
+losetup -D
+grep "$LOOP1" $DF
+grep "$LOOP2" $DF
+lvmdevices --deldev "$LOOP1"
+not grep "$LOOP1" $DF
+lvmdevices --deldev "$LOOP2"
+not grep "$LOOP2" $DF
+setup_loop_devs
+rm $DF
+
+# Tests of devices with PV on them.
+
+touch $DF
+pvcreate "$LOOP1"
+pvcreate "$LOOP2"
+# PVID without dashes for matching devices file fields
+PVID1=`pvs "$LOOP1" --noheading -o uuid | tr -d - | awk '{print $1}'`
+PVID2=`pvs "$LOOP2" --noheading -o uuid | tr -d - | awk '{print $1}'`
+# PVID with dashes for matching pvs -o+uuid output
+OPVID1=`pvs "$LOOP1" --noheading -o uuid | awk '{print $1}'`
+OPVID2=`pvs "$LOOP2" --noheading -o uuid | awk '{print $1}'`
+grep "$LOOP1" $DF
+grep "$LOOP2" $DF
+grep "$PVID1" $DF
+grep "$PVID2" $DF
+rm $DF
+
+# add/deldev with default idtype loop_file
+lvmdevices --adddev "$LOOP1"
+grep "$LOOP1" $DF
+grep "$PVID1" $DF
+lvmdevices --adddev "$LOOP2"
+grep "$LOOP2" $DF
+grep "$PVID2" $DF
+grep "IDTYPE=loop_file" $DF
+not grep "IDTYPE=devname" $DF
+lvmdevices --deldev "$LOOP1"
+not grep "$LOOP1" $DF
+lvmdevices --deldev "$LOOP2"
+not grep "$LOOP2" $DF
+rm $DF
+
+# deldev using idname
+lvmdevices --adddev "$LOOP1"
+lvmdevices --adddev "$LOOP2"
+vgcreate $vg "$LOOP1" "$LOOP2"
+IDNAME1=`pvs "$LOOP1" --noheading -o deviceid | awk '{print $1}'`
+IDNAME2=`pvs "$LOOP2" --noheading -o deviceid | awk '{print $1}'`
+lvmdevices --deldev "$IDNAME2" --deviceidtype loop_file
+not grep "$IDNAME2" $DF
+not grep "$LOOP2" $DF
+lvmdevices --deldev "$IDNAME1" --deviceidtype loop_file
+not grep "$IDNAME1" $DF
+not grep "$LOOP1" $DF
+lvmdevices --adddev "$LOOP1"
+lvmdevices --adddev "$LOOP2"
+vgremove $vg
+rm $DF
+
+# add/delpvid with default idtype loop_file
+lvmdevices --addpvid "$PVID1"
+grep "$LOOP1" $DF
+grep "$PVID1" $DF
+lvmdevices --addpvid "$PVID2"
+grep "$LOOP2" $DF
+grep "$PVID2" $DF
+grep "IDTYPE=loop_file" $DF
+not grep "IDTYPE=devname" $DF
+lvmdevices --delpvid "$PVID1"
+not grep "$LOOP1" $DF
+not grep "$PVID1" $DF
+lvmdevices --delpvid "$PVID2"
+not grep "$LOOP2" $DF
+not grep "$PVID2" $DF
+rm $DF
+
+# add/deldev with non-default idtype devname
+lvmdevices --adddev "$LOOP1" --deviceidtype devname
+grep "$LOOP1" $DF
+grep "$PVID1" $DF
+lvmdevices --adddev "$LOOP2" --deviceidtype devname
+grep "$LOOP2" $DF
+grep "$PVID2" $DF
+grep "IDTYPE=devname" $DF
+not grep "IDTYPE=loop_file" $DF
+lvmdevices --deldev "$LOOP1"
+not grep "$LOOP1" $DF
+lvmdevices --deldev "$LOOP2"
+not grep "$LOOP2" $DF
+rm $DF
+
+# add/delpvid with non-default idtype devname
+lvmdevices --addpvid "$PVID1" --deviceidtype devname
+grep "$LOOP1" $DF
+grep "$PVID1" $DF
+lvmdevices --addpvid "$PVID2" --deviceidtype devname
+grep "$LOOP2" $DF
+grep "$PVID2" $DF
+grep "IDTYPE=devname" $DF
+not grep "IDTYPE=loop_file" $DF
+lvmdevices --deldev "$LOOP1"
+not grep "$LOOP1" $DF
+lvmdevices --deldev "$LOOP2"
+not grep "$LOOP2" $DF
+rm $DF
+
+# add/deldev when dev is missing, using default idtype
+lvmdevices --adddev "$LOOP1"
+grep "$LOOP1" $DF
+grep "$PVID1" $DF
+lvmdevices --adddev "$LOOP2"
+grep "$LOOP2" $DF
+grep "$PVID2" $DF
+losetup -D
+grep "$LOOP1" $DF
+grep "$LOOP2" $DF
+lvmdevices --deldev "$LOOP1"
+not grep "$LOOP1" $DF
+not grep "$PVID1" $DF
+lvmdevices --deldev "$LOOP2"
+not grep "$LOOP2" $DF
+not grep "$PVID2" $DF
+setup_loop_devs
+rm $DF
+
+# add/delpvid when dev is missing, using devname idtype
+lvmdevices --addpvid "$PVID1" --deviceidtype devname
+grep "$LOOP1" $DF
+grep "$PVID1" $DF
+lvmdevices --addpvid "$PVID2" --deviceidtype devname
+grep "$LOOP2" $DF
+grep "$PVID2" $DF
+losetup -D
+grep "$LOOP1" $DF
+grep "$LOOP2" $DF
+lvmdevices --delpvid "$PVID1"
+not grep "$LOOP1" $DF
+not grep "$PVID1" $DF
+lvmdevices --delpvid "$PVID2"
+not grep "$LOOP2" $DF
+not grep "$PVID2" $DF
+setup_loop_devs
+rm $DF
+
+# test delnotfound
+lvmdevices --addpvid "$PVID1"
+echo "IDTYPE=sys_wwid IDNAME=naa.123 DEVNAME=/dev/sdx1 PVID=aaa PART=1" >> $DF
+echo "IDTYPE=devname IDNAME=/dev/sdy DEVNAME=/dev/sdy PVID=bbb" >> $DF
+lvmdevices
+lvmdevices --update --delnotfound
+not grep PVID=aaa $DF
+not grep PVID=bbb $DF
+
+
+# TODO: add/rem of partitions of same device
+
+losetup -D
+rm loopa loopb
diff --git a/test/shell/devicesfile-realdevs.sh b/test/shell/devicesfile-realdevs.sh
new file mode 100644
index 0000000..0f62e9b
--- /dev/null
+++ b/test/shell/devicesfile-realdevs.sh
@@ -0,0 +1,612 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2020 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+test_description='devices file with real devs'
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+#
+# To use this test, add two or more devices with real device ids,
+# e.g. wwids, to a file, e.g.
+# $ cat /tmp/devs
+# /dev/sdb
+# /dev/sdc
+# /dev/sdd
+#
+# Specify this file as LVM_TEST_DEVICE_LIST=/tmp/devs
+# when running the test.
+#
+# This test will wipe these devices.
+#
+
+if [ -z ${LVM_TEST_DEVICE_LIST+x} ]; then echo "LVM_TEST_DEVICE_LIST is unset" && skip; else echo "LVM_TEST_DEVICE_LIST is set to '$LVM_TEST_DEVICE_LIST'"; fi
+
+test -e "$LVM_TEST_DEVICE_LIST" || skip
+
+num_devs=$(cat $LVM_TEST_DEVICE_LIST | wc -l)
+
+RUNDIR="/run"
+test -d "$RUNDIR" || RUNDIR="/var/run"
+PVS_ONLINE_DIR="$RUNDIR/lvm/pvs_online"
+VGS_ONLINE_DIR="$RUNDIR/lvm/vgs_online"
+PVS_LOOKUP_DIR="$RUNDIR/lvm/pvs_lookup"
+
+_clear_online_files() {
+ # wait till udev is finished
+ aux udev_wait
+ rm -f "$PVS_ONLINE_DIR"/*
+ rm -f "$VGS_ONLINE_DIR"/*
+ rm -f "$PVS_LOOKUP_DIR"/*
+}
+
+test -d "$PVS_ONLINE_DIR" || mkdir -p "$PVS_ONLINE_DIR"
+test -d "$VGS_ONLINE_DIR" || mkdir -p "$VGS_ONLINE_DIR"
+test -d "$PVS_LOOKUP_DIR" || mkdir -p "$PVS_LOOKUP_DIR"
+_clear_online_files
+
+aux prepare_real_devs
+
+aux lvmconf 'devices/dir = "/dev"'
+aux lvmconf 'devices/use_devicesfile = 1'
+DFDIR="$LVM_SYSTEM_DIR/devices"
+DF="$DFDIR/system.devices"
+mkdir $DFDIR || true
+not ls $DF
+
+get_real_devs
+
+wipe_all() {
+ for dev in "${REAL_DEVICES[@]}"; do
+ wipefs -a $dev
+ done
+}
+
+wipe_all
+
+# check each dev is added correctly to df
+
+touch $DF
+for dev in "${REAL_DEVICES[@]}"; do
+ pvcreate $dev
+
+ pvs -o+uuid $dev
+ maj=$(get pv_field "$dev" major)
+ min=$(get pv_field "$dev" minor)
+ pvid=`pvs $dev --noheading -o uuid | tr -d - | awk '{print $1}'`
+
+ sys_wwid_file="/sys/dev/block/$maj:$min/device/wwid"
+ sys_serial_file="/sys/dev/block/$maj:$min/device/serial"
+ sys_dm_uuid_file="/sys/dev/block/$maj:$min/dm/uuid"
+ sys_md_uuid_file="/sys/dev/block/$maj:$min/md/uuid"
+ sys_loop_file="/sys/dev/block/$maj:$min/loop/backing_file"
+
+ if test -e $sys_wwid_file; then
+ sys_file=$sys_wwid_file
+ idtype="sys_wwid"
+ elif test -e $sys_serial_file; then
+ sys_file=$sys_serial_file
+ idtype="sys_serial"
+ elif test -e $sys_dm_uuid_file; then
+ sys_file=$sys_dm_uuid_file
+ idtype="mpath_uuid"
+ elif test -e $sys_md_uuid_file; then
+ sys_file=$sys_md_uuid_file
+ idtype="md_uuid"
+ elif test -e $sys_loop_file; then
+ sys_file=$sys_loop_file
+ idtype="loop_file"
+ else
+ echo "no id type for device"
+ skip
+ fi
+
+ idname=$(< $sys_file)
+
+ rm -f idline
+ grep IDNAME=$idname $DF | tee idline
+ grep IDTYPE=$idtype idline
+ grep DEVNAME=$dev idline
+ grep PVID=$pvid idline
+done
+
+cp $DF df2
+
+# vgcreate from existing pvs, already in df
+
+vgcreate $vg "${REAL_DEVICES[@]}"
+
+vgremove $vg
+rm $DF
+
+# vgcreate from existing pvs, adding to df
+
+touch $DF
+vgcreate $vg "${REAL_DEVICES[@]}"
+
+grep IDNAME $DF > df.ids
+grep IDNAME df2 > df2.ids
+diff df.ids df2.ids
+
+# check device id metadata fields
+
+for dev in "${REAL_DEVICES[@]}"; do
+ grep $dev $DF
+ deviceid=`pvs $dev --noheading -o deviceid | awk '{print $1}'`
+ deviceidtype=`pvs $dev --noheading -o deviceidtype | awk '{print $1}'`
+ grep $dev $DF | grep $deviceid
+ grep $dev $DF | grep $deviceidtype
+ lvcreate -l1 $vg $dev
+done
+
+vgchange -an $vg
+vgremove -y $vg
+
+# check pvremove leaves devs in df but without pvid
+
+for dev in "${REAL_DEVICES[@]}"; do
+ maj=$(get pv_field "$dev" major)
+ min=$(get pv_field "$dev" minor)
+ pvid=`pvs $dev --noheading -o uuid | tr -d - | awk '{print $1}'`
+
+ pvremove $dev
+ grep $dev $DF
+ not grep $pvid $DF
+done
+
+# Many of remaining tests require two or three devices
+test $num_devs -gt 2 || skip
+
+# check vgextend adds new dev to df, vgreduce leaves dev in df
+
+rm $DF
+
+touch $DF
+vgcreate $vg $dev1
+vgextend $vg $dev2
+grep $dev1 $DF
+grep $dev2 $DF
+id1=`pvs $dev1 --noheading -o deviceid | awk '{print $1}'`
+id2=`pvs $dev2 --noheading -o deviceid | awk '{print $1}'`
+grep $id1 $DF
+grep $id2 $DF
+vgreduce $vg $dev2
+grep $dev2 $DF
+vgremove $vg
+
+# check devs are not visible to lvm until added to df
+
+rm $DF
+
+# df needs to exist otherwise devicesfile feature turned off
+touch $DF
+
+not pvs $dev1
+not pvs $dev2
+pvs -a |tee all
+not grep $dev1 all
+not grep $dev2 all
+not grep $dev1 $DF
+not grep $dev2 $DF
+
+pvcreate $dev1
+
+pvs $dev1
+not pvs $dev2
+pvs -a |tee all
+grep $dev1 all
+not grep $dev2 all
+grep $dev1 $DF
+not grep $dev2 $DF
+
+pvcreate $dev2
+
+pvs $dev1
+pvs $dev2
+pvs -a |tee all
+grep $dev1 all
+grep $dev2 all
+grep $dev1 $DF
+grep $dev2 $DF
+
+vgcreate $vg $dev1
+
+pvs $dev1
+pvs $dev2
+pvs -a |tee all
+grep $dev1 all
+grep $dev2 all
+grep $dev1 $DF
+grep $dev2 $DF
+
+vgextend $vg $dev2
+
+pvs $dev1
+pvs $dev2
+pvs -a |tee all
+grep $dev1 all
+grep $dev2 all
+grep $dev1 $DF
+grep $dev2 $DF
+
+# check vgimportdevices VG
+
+rm $DF
+wipe_all
+
+vgcreate $vg "${REAL_DEVICES[@]}"
+rm $DF
+touch $DF
+
+for dev in "${REAL_DEVICES[@]}"; do
+ not pvs $dev
+done
+
+vgimportdevices $vg
+
+for dev in "${REAL_DEVICES[@]}"; do
+ pvs $dev
+done
+
+# check vgimportdevices -a
+
+rm $DF
+wipe_all
+
+vgcreate $vg1 $dev1
+vgcreate $vg2 $dev2
+
+rm $DF
+
+vgimportdevices -a
+
+ls $DF
+
+vgs $vg1
+vgs $vg2
+
+pvs $dev1
+pvs $dev2
+
+# check vgimportclone --importdevices
+
+rm $DF
+wipe_all
+
+vgcreate $vg1 $dev1
+vgimportdevices $vg1
+
+dd if=$dev1 of=$dev2 bs=1M count=1
+
+pvs $dev1
+not pvs $dev2
+
+grep $dev1 $DF
+not grep $dev2 $DF
+
+not vgimportclone $dev2
+
+not grep $dev2 $DF
+
+vgimportclone --basevgname $vg2 --importdevices $dev2
+
+pvid1=`pvs $dev1 --noheading -o uuid | tr -d - | awk '{print $1}'`
+pvid2=`pvs $dev2 --noheading -o uuid | tr -d - | awk '{print $1}'`
+test "$pvid1" != "$pvid2" || die "same uuid"
+
+id1=`pvs $dev1 --noheading -o deviceid | tr -d - | awk '{print $1}'`
+id2=`pvs $dev2 --noheading -o deviceid | tr -d - | awk '{print $1}'`
+test "$id1" != "$id2" || die "same device id"
+
+grep $dev1 $DF
+grep $dev2 $DF
+grep $pvid1 $DF
+grep $pvid2 $DF
+grep $id1 $DF
+grep $id2 $DF
+
+vgs $vg1
+vgs $vg2
+
+#
+# check lvmdevices
+#
+
+wipe_all
+rm $DF
+
+# set up pvs and save pvids/deviceids
+touch $DF
+count=0
+for dev in "${REAL_DEVICES[@]}"; do
+ pvcreate $dev
+ vgcreate ${vg}_${count} $dev
+ pvid=`pvs $dev --noheading -o uuid | tr -d - | awk '{print $1}'`
+ did=`pvs $dev --noheading -o deviceid | awk '{print $1}'`
+ echo dev $dev pvid $pvid did $did
+ PVIDS[$count]=$pvid
+ DEVICEIDS[$count]=$did
+ count=$(( count + 1 ))
+done
+
+rm $DF || true
+not lvmdevices
+touch $DF
+lvmdevices
+
+# check lvmdevices --adddev
+count=0
+for dev in "${REAL_DEVICES[@]}"; do
+ pvid=${PVIDS[$count]}
+ did=${DEVICEIDS[$count]}
+ echo $dev pvid: $pvid did: $did
+ not pvs $dev
+ lvmdevices --adddev $dev
+ lvmdevices |tee out
+ grep $dev out |tee idline
+ grep $pvid idline
+ grep $did idline
+ grep $dev $DF
+ pvs $dev
+ count=$(( count + 1 ))
+done
+
+# check lvmdevices --deldev
+count=0
+for dev in "${REAL_DEVICES[@]}"; do
+ pvid=${PVIDS[$count]}
+ did=${DEVICEIDS[$count]}
+ pvs $dev
+ lvmdevices --deldev $dev
+ lvmdevices |tee out
+ not grep $dev out
+ not grep $pvid out
+ not grep $did out
+ not grep $dev $DF
+ not pvs $dev
+ count=$(( count + 1 ))
+done
+
+# check lvmdevices --addpvid
+count=0
+for dev in "${REAL_DEVICES[@]}"; do
+ pvid=${PVIDS[$count]}
+ did=${DEVICEIDS[$count]}
+ not pvs $dev
+ lvmdevices --addpvid $pvid
+ lvmdevices |tee out
+ grep $dev out |tee idline
+ grep $pvid idline
+ grep $did idline
+ grep $dev $DF
+ pvs $dev
+ count=$(( count + 1 ))
+done
+
+# check lvmdevices --delpvid
+count=0
+for dev in "${REAL_DEVICES[@]}"; do
+ pvid=${PVIDS[$count]}
+ did=${DEVICEIDS[$count]}
+ pvs $dev
+ lvmdevices --delpvid $pvid
+ lvmdevices |tee out
+ not grep $dev out
+ not grep $pvid out
+ not grep $did out
+ not grep $dev $DF
+ not pvs $dev
+ count=$(( count + 1 ))
+done
+
+# wrong pvid in df
+rm $DF
+pvid1=${PVIDS[0]}
+pvid2=${PVIDS[1]}
+did1=${DEVICEIDS[0]}
+did2=${DEVICEIDS[1]}
+lvmdevices --adddev $dev1
+lvmdevices --adddev $dev2
+
+# test bad pvid
+cp $DF $DF.orig
+rm $DF
+sed "s/$pvid1/badpvid/" "$DF.orig" |tee $DF
+not grep $pvid1 $DF
+grep $did1 $DF
+
+not lvmdevices --check 2>&1|tee out
+grep $dev1 out
+grep badpvid out
+grep $pvid1 out
+not grep $dev2 out
+
+lvmdevices |tee out
+grep $dev1 out |tee out1
+grep badpvid out1
+not grep $pvid1 out1
+grep $dev2 out
+
+lvmdevices --update
+
+lvmdevices 2>&1|tee out
+grep $dev1 out
+grep $dev2 out
+not grep badpvid
+grep $pvid1 out
+grep $did1 out
+grep $pvid1 $DF
+grep $did1 $DF
+
+# wrong deviceid in df
+# the devicesfile logic and behavior is based on the idname being
+# the primary identifier that we trust over everything else, i.e.
+# we'll never assume that the deviceid is wrong and some other
+# field is correct, and "fix" the deviceid. We always assume the
+# deviceid correct and other values are wrong (since pvid and devname
+# have known, common ways of becoming wrong, but the deviceid doesn't
+# really have any known way of becoming wrong apart from random
+# file corruption.)
+# So, if the deviceid *is* corrupted, as we do here, then standard
+# commands won't correct it. We need to use delpvid/addpvid explicitly
+# to say that we are targetting the given pvid.
+
+rm $DF
+sed "s/$did1/baddid/" "$DF.orig" |tee $DF
+
+lvmdevices --check 2>&1|tee out
+grep $dev1 out
+grep baddid out
+not grep $dev2 out
+
+lvmdevices 2>&1|tee out
+grep $pvid1 out
+grep $pvid2 out
+grep baddid out
+grep $did2 out
+grep $dev2 out
+
+lvmdevices --delpvid $pvid1
+lvmdevices --addpvid $pvid1
+
+lvmdevices |tee out
+grep $dev1 out
+grep $dev2 out
+not grep baddid
+grep $pvid1 out
+grep $did1 out
+grep $pvid1 $DF
+grep $did1 $DF
+
+# wrong devname in df, this is expected to become incorrect regularly
+# given inconsistent dev names after reboot
+
+rm $DF
+d1=$(basename $dev1)
+d3=$(basename $dev3)
+sed "s/$d1/$d3/" "$DF.orig" |tee $DF
+not lvmdevices --check 2>&1 |tee out
+grep $dev1 out
+
+lvmdevices --update
+
+lvmdevices |tee out
+grep $dev1 out |tee out1
+grep $pvid1 out1
+grep $did1 out1
+grep $dev2 out |tee out2
+grep $pvid2 out2
+grep $did2 out2
+
+# swap devnames for two existing entries
+
+rm $DF
+d1=$(basename $dev1)
+d2=$(basename $dev2)
+sed "s/$d1/tmp/" "$DF.orig" |tee ${DF}_1
+sed "s/$d2/$d1/" "${DF}_1" |tee ${DF}_2
+sed "s/tmp/$d2/" "${DF}_2" |tee $DF
+rm ${DF}_1 ${DF}_2
+not lvmdevices --check 2>&1 |tee out
+grep $dev1 out
+grep $dev2 out
+
+lvmdevices --update
+
+lvmdevices |tee out
+grep $dev1 out |tee out1
+grep $pvid1 out1
+grep $did1 out1
+grep $dev2 out |tee out2
+grep $pvid2 out2
+grep $did2 out2
+
+# ordinary command is not confused by wrong devname and fixes
+# the wrong devname in df
+
+rm $DF
+d1=$(basename $dev1)
+d3=$(basename $dev3)
+sed "s/$d1/$d3/" "$DF.orig" |tee $DF
+not lvmdevices --check 2>&1 |tee out
+grep $dev1 out
+
+pvs -o+uuid,deviceid | grep $vg |tee out
+grep $dev1 out |tee out1
+grep $dev2 out |tee out2
+grep $did1 out1
+grep $did2 out2
+not grep $dev3 out
+
+# same dev info reported after df is fixed
+pvs -o+uuid,deviceid | grep $vg |tee out3
+diff out out3
+
+pvid=`pvs $dev1 --noheading -o uuid | tr -d - | awk '{print $1}'`
+test "$pvid" == "$pvid1" || die "wrong uuid"
+pvid=`pvs $dev2 --noheading -o uuid | tr -d - | awk '{print $1}'`
+test "$pvid" == "$pvid2" || die "wrong uuid"
+
+lvmdevices |tee out
+grep $dev1 out |tee out1
+grep $pvid1 out1
+grep $did1 out1
+grep $dev2 out |tee out2
+grep $pvid2 out2
+grep $did2 out2
+
+# pvscan --cache doesn't fix wrong devname but still works correctly with
+# the correct device
+
+wipe_all
+rm $DF
+touch $DF
+vgcreate $vg $dev1 $dev2
+vgcreate $vg3 $dev3
+lvcreate -an -n $lv1 -l1 $vg $dev1
+lvcreate -an -n $lv2 -l1 $vg $dev2
+lvcreate -an -n $lv3 -l1 $vg3 $dev3
+PVID1=`pvs $dev1 --noheading -o uuid | tr -d - | awk '{print $1}'`
+PVID2=`pvs $dev2 --noheading -o uuid | tr -d - | awk '{print $1}'`
+PVID3=`pvs $dev3 --noheading -o uuid | tr -d - | awk '{print $1}'`
+rm $DF
+lvmdevices --adddev $dev1
+lvmdevices --adddev $dev2
+cp $DF $DF.orig
+d1=$(basename $dev1)
+d3=$(basename $dev3)
+sed "s/$d1/$d3/" "$DF.orig" |tee $DF
+_clear_online_files
+pvscan --cache -aay $dev1
+pvscan --cache -aay $dev2
+# pvscan should ignore dev3 since it's not in DF
+pvscan --cache -aay $dev3
+# pvscan does not fix the devname field in DF
+grep $dev3 $DF
+ls "$RUNDIR/lvm/pvs_online/$PVID1"
+ls "$RUNDIR/lvm/pvs_online/$PVID2"
+not ls "$RUNDIR/lvm/pvs_online/$PVID3"
+check lv_field $vg/$lv1 lv_active "active"
+check lv_field $vg/$lv2 lv_active "active"
+# pvs updates the DF
+pvs |tee out
+grep $dev1 out
+grep $dev2 out
+not grep $dev3 out
+grep $dev1 $DF
+grep $dev2 $DF
+not grep $dev3 $DF
+not pvs $dev3
+vgchange -an $vg
+wipe_all
+
diff --git a/test/shell/devicesfile-serial.sh b/test/shell/devicesfile-serial.sh
new file mode 100644
index 0000000..3123e9e
--- /dev/null
+++ b/test/shell/devicesfile-serial.sh
@@ -0,0 +1,890 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2020-23 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+test_description='device id wwid from vpd_pg83'
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+test -d /sys/block/ram0 && skip "Ramdisk already loaded"
+
+test "$DM_DEV_DIR" = "/dev" || skip "Only works with /dev access -> make check LVM_TEST_DEVDIR=/dev"
+
+# requires trailing / to match dm
+SYS_DIR="$PWD/test/sys"
+aux lvmconf "devices/use_devicesfile = 1" \
+ "devices/device_id_sysfs_dir = \"$SYS_DIR/\""
+
+# The string format of the serial numbers
+# encoded in the pg80 files
+SERIAL1="003dd33a331c183c2300e1d883604609"
+SERIAL2="003dd33a441c183c2300e1d883604609"
+SERIAL3="003dd33a551c183c2300e1d883604609"
+SERIAL4="003dd33a661c183c2300e1d883604609"
+
+create_base() {
+ mkdir -p "$SYS_DIR/dev/block/$MAJOR1:$MINOR1/device"
+ mkdir -p "$SYS_DIR/dev/block/$MAJOR2:$MINOR2/device"
+ mkdir -p "$SYS_DIR/dev/block/$MAJOR3:$MINOR3/device"
+ mkdir -p "$SYS_DIR/dev/block/$MAJOR4:$MINOR4/device"
+
+ # Create four different pg80 serial numbers that
+ # can be assigned to devs
+
+ echo -n "0080 0020 3030 3364 6433 3361 3333 3163 \
+ 3138 3363 3233 3030 6531 6438 3833 3630 3436 3039" | xxd -r -p > pg80_1
+
+ echo -n "0080 0020 3030 3364 6433 3361 3434 3163 \
+ 3138 3363 3233 3030 6531 6438 3833 3630 3436 3039" | xxd -r -p > pg80_2
+
+ echo -n "0080 0020 3030 3364 6433 3361 3535 3163 \
+ 3138 3363 3233 3030 6531 6438 3833 3630 3436 3039" | xxd -r -p > pg80_3
+
+ echo -n "0080 0020 3030 3364 6433 3361 3636 3163 \
+ 3138 3363 3233 3030 6531 6438 3833 3630 3436 3039" | xxd -r -p > pg80_4
+}
+
+remove_base() {
+ rm -rf "$SYS_DIR"
+}
+
+cleanup_and_teardown()
+{
+ remove_base
+ rmmod brd
+
+ aux teardown
+}
+
+trap 'cleanup_and_teardown' EXIT
+
+modprobe brd rd_nr=4 || skip
+sleep 1
+remove_base
+
+dev1="/dev/ram0"
+dev2="/dev/ram1"
+dev3="/dev/ram2"
+dev4="/dev/ram3"
+
+devs=( "$dev1" "$dev2" "$dev3" "$dev4" )
+
+DFDIR="$LVM_SYSTEM_DIR/devices"
+mkdir -p "$DFDIR" || true
+DF="$DFDIR/system.devices"
+ORIG="$DFDIR/orig.devices"
+touch "$DF"
+
+aux wipefs_a "${devs[@]}"
+
+vgcreate $vg1 "$dev1"
+eval "$(pvs --noheading --nameprefixes -o major,minor,uuid "$dev1")"
+MAJOR1=$LVM2_PV_MAJOR
+MINOR1=$LVM2_PV_MINOR
+OPVID1=$LVM2_PV_UUID
+PVID1=${OPVID1//-/}
+
+vgcreate $vg2 "$dev2"
+eval "$(pvs --noheading --nameprefixes -o major,minor,uuid "$dev2")"
+MAJOR2=$LVM2_PV_MAJOR
+MINOR2=$LVM2_PV_MINOR
+OPVID2=$LVM2_PV_UUID
+PVID2=${OPVID2//-/}
+
+vgcreate $vg3 "$dev3"
+eval "$(pvs --noheading --nameprefixes -o major,minor,uuid "$dev3")"
+MAJOR3=$LVM2_PV_MAJOR
+MINOR3=$LVM2_PV_MINOR
+OPVID3=$LVM2_PV_UUID
+PVID3=${OPVID3//-/}
+
+vgcreate $vg4 "$dev4"
+eval "$(pvs --noheading --nameprefixes -o major,minor,uuid "$dev4")"
+MAJOR4=$LVM2_PV_MAJOR
+MINOR4=$LVM2_PV_MINOR
+OPVID4=$LVM2_PV_UUID
+PVID4=${OPVID4//-/}
+
+create_base
+
+
+# get serial number from pg80
+cp pg80_1 "$SYS_DIR/dev/block/$MAJOR1:$MINOR1/device/vpd_pg80"
+cp pg80_2 "$SYS_DIR/dev/block/$MAJOR2:$MINOR2/device/vpd_pg80"
+cp pg80_3 "$SYS_DIR/dev/block/$MAJOR3:$MINOR3/device/vpd_pg80"
+cp pg80_4 "$SYS_DIR/dev/block/$MAJOR4:$MINOR4/device/vpd_pg80"
+
+grep -r "" "$SYS_DIR/dev/block/"
+
+declare -A serials=( ["$dev1"]=$SERIAL1 ["$dev2"]=$SERIAL2 \
+ ["$dev3"]=$SERIAL3 ["$dev4"]=$SERIAL4 )
+
+rm -f "$DF"
+
+for i in "${devs[@]}"
+do
+ lvmdevices --adddev "$i"
+ grep "${serials["$i"]}" "$DF" || {
+ cat "$DF"
+ die "Cannot find ${serials["$i"]}"
+ }
+done
+cat "$DF"
+cp "$DF" "$ORIG"
+pvs
+# run command to update metadata so deviceids are written to metadata
+vgchange --addtag x $vg1
+vgchange --addtag x $vg2
+vgchange --addtag x $vg3
+vgchange --addtag x $vg4
+pvs -o uuid,deviceidtype,deviceid "$dev1" |tee out
+grep "$OPVID1" out
+grep sys_serial out
+grep "$SERIAL1" out
+pvs -o uuid,deviceidtype,deviceid "$dev2" |tee out
+grep "$OPVID2" out
+grep sys_serial out
+grep "$SERIAL2" out
+
+# get serial number from device/serial
+
+aux wipefs_a "${devs[@]}"
+
+rm "$SYS_DIR/dev/block/$MAJOR1:$MINOR1/device/vpd_pg80"
+rm "$SYS_DIR/dev/block/$MAJOR2:$MINOR2/device/vpd_pg80"
+rm "$SYS_DIR/dev/block/$MAJOR3:$MINOR3/device/vpd_pg80"
+rm "$SYS_DIR/dev/block/$MAJOR4:$MINOR4/device/vpd_pg80"
+echo "$SERIAL1" > "$SYS_DIR/dev/block/$MAJOR1:$MINOR1/device/serial"
+echo "$SERIAL2" > "$SYS_DIR/dev/block/$MAJOR2:$MINOR2/device/serial"
+echo "$SERIAL3" > "$SYS_DIR/dev/block/$MAJOR3:$MINOR3/device/serial"
+echo "$SERIAL4" > "$SYS_DIR/dev/block/$MAJOR4:$MINOR4/device/serial"
+
+rm "$DF"
+touch "$DF"
+pvcreate "$dev1"
+pvcreate "$dev2"
+pvcreate "$dev3"
+pvcreate "$dev4"
+grep "$SERIAL1" "$DF"
+grep "$SERIAL2" "$DF"
+grep "$SERIAL3" "$DF"
+grep "$SERIAL4" "$DF"
+
+# all pvs have the same serial number
+
+aux wipefs_a "${devs[@]}"
+
+echo "$SERIAL1" > "$SYS_DIR/dev/block/$MAJOR1:$MINOR1/device/serial"
+echo "$SERIAL1" > "$SYS_DIR/dev/block/$MAJOR2:$MINOR2/device/serial"
+echo "$SERIAL1" > "$SYS_DIR/dev/block/$MAJOR3:$MINOR3/device/serial"
+echo "$SERIAL1" > "$SYS_DIR/dev/block/$MAJOR4:$MINOR4/device/serial"
+
+rm "$DF"
+touch "$DF"
+vgcreate $vg1 "$dev1"
+vgcreate $vg2 "$dev2"
+vgcreate $vg3 "$dev3"
+vgcreate $vg4 "$dev4"
+cp "$DF" "$ORIG"
+OPVID1=$(echo $(pvs --noheading -o uuid "$dev1") )
+OPVID2=$(echo $(pvs --noheading -o uuid "$dev2") )
+OPVID3=$(echo $(pvs --noheading -o uuid "$dev3") )
+OPVID4=$(echo $(pvs --noheading -o uuid "$dev4") )
+PVID1=${OPVID1//-/}
+PVID2=${OPVID2//-/}
+PVID3=${OPVID3//-/}
+PVID4=${OPVID4//-/}
+
+grep "$PVID1" "$DF" |tee out
+grep "$SERIAL1" out
+grep "$dev1" out
+grep "$PVID2" "$DF" |tee out
+grep "$SERIAL1" out
+grep "$dev2" out
+grep "$PVID3" "$DF" |tee out
+grep "$SERIAL1" out
+grep "$dev3" out
+grep "$PVID4" "$DF" |tee out
+grep "$SERIAL1" out
+grep "$dev4" out
+
+pvs -o+uuid,deviceidtype,deviceid "${devs[@]}" |tee out
+grep "$dev1" out
+grep "$dev2" out
+grep "$dev3" out
+grep "$dev4" out
+grep "$OPVID1" out
+grep "$OPVID2" out
+grep "$OPVID3" out
+grep "$OPVID4" out
+grep $vg1 out
+grep $vg2 out
+grep $vg3 out
+grep $vg4 out
+grep sys_serial out
+grep "$SERIAL1" out
+
+pvs -o+uuid,deviceid "$dev1" |tee out
+grep "$OPVID1" out
+grep "$SERIAL1" out
+grep $vg1 out
+
+pvs -o+uuid,deviceid "$dev2" |tee out
+grep "$OPVID2" out
+grep "$SERIAL1" out
+grep $vg2 out
+
+pvs -o+uuid,deviceid "$dev3" |tee out
+grep "$OPVID3" out
+grep "$SERIAL1" out
+grep $vg3 out
+
+pvs -o+uuid,deviceid "$dev4" |tee out
+grep "$OPVID4" out
+grep "$SERIAL1" out
+grep $vg4 out
+
+
+# all pvs have the same serial number, df devnames are stale
+# edit DF to make devnames stale
+
+cp "$ORIG" orig
+sed -e "s|DEVNAME=$dev1|DEVNAME=tmpnm|" orig > tmp1
+sed -e "s|DEVNAME=$dev2|DEVNAME=$dev1|" tmp1 > tmp2
+sed -e "s|DEVNAME=tmpnm|DEVNAME=$dev2|" tmp2 > tmp3
+sed -e "s|DEVNAME=$dev3|DEVNAME=tmpnm|" tmp3 > tmp4
+sed -e "s|DEVNAME=$dev4|DEVNAME=$dev3|" tmp4 > tmp5
+sed -e "s|DEVNAME=tmpnm|DEVNAME=$dev4|" tmp5 > "$DF"
+cat "$DF"
+
+# pvs should report the correct info and fix the DF
+pvs -o+uuid,deviceid "${devs[@]}" |tee out
+grep "$dev1" out |tee out1
+grep "$dev2" out |tee out2
+grep "$dev3" out |tee out3
+grep "$dev4" out |tee out4
+grep "$OPVID1" out1
+grep "$OPVID2" out2
+grep "$OPVID3" out3
+grep "$OPVID4" out4
+grep "$SERIAL1" out1
+grep "$SERIAL1" out2
+grep "$SERIAL1" out3
+grep "$SERIAL1" out4
+
+grep "$PVID1" "$DF" |tee out
+grep "$SERIAL1" out
+grep "$dev1" out
+grep "$PVID2" "$DF" |tee out
+grep "$SERIAL1" out
+grep "$dev2" out
+grep "$PVID3" "$DF" |tee out
+grep "$SERIAL1" out
+grep "$dev3" out
+grep "$PVID4" "$DF" |tee out
+grep "$SERIAL1" out
+grep "$dev4" out
+
+pvs -o+uuid,deviceid "$dev1"|tee out1
+pvs -o+uuid,deviceid "$dev2"|tee out2
+pvs -o+uuid,deviceid "$dev3"|tee out3
+pvs -o+uuid,deviceid "$dev4"|tee out4
+grep "$OPVID1" out1
+grep "$OPVID2" out2
+grep "$OPVID3" out3
+grep "$OPVID4" out4
+
+# all pvs have the same serial number,
+# dev1 and dev2 have devnames swapped,
+# dev3 has stale PVID in the DF.
+# lvm fixes the stale devnames but does not fix the stale PVID
+# because of the duplicate serial numbers, so dev3 is not found
+
+cp "$ORIG" orig
+sed -e "s|DEVNAME=$dev1|DEVNAME=tmpnm|" orig > tmp1
+sed -e "s|DEVNAME=$dev2|DEVNAME=$dev1|" tmp1 > tmp2
+sed -e "s|PVID=$PVID4|PVID=4SqT4onBxSiv4dot0GRDPtrWqOlrOPH1|" tmp2 > "$DF"
+
+# pvs should report the correct info and fix the DF
+pvs -o+uuid,deviceid "${devs[@]}" > out || true
+cat out
+not grep "$dev4" out
+not grep "$OPVID4" out
+grep "$dev1" out |tee out1
+grep "$dev2" out |tee out2
+grep "$dev3" out |tee out3
+grep "$OPVID1" out1
+grep "$OPVID2" out2
+grep "$OPVID3" out3
+
+not pvs "$dev4"
+
+# dev1&2 have same serial, dev3&4 have same serial
+
+aux wipefs_a "${devs[@]}"
+
+echo "$SERIAL1" > "$SYS_DIR/dev/block/$MAJOR1:$MINOR1/device/serial"
+echo "$SERIAL1" > "$SYS_DIR/dev/block/$MAJOR2:$MINOR2/device/serial"
+echo "$SERIAL2" > "$SYS_DIR/dev/block/$MAJOR3:$MINOR3/device/serial"
+echo "$SERIAL2" > "$SYS_DIR/dev/block/$MAJOR4:$MINOR4/device/serial"
+
+rm "$DF"
+touch "$DF"
+vgcreate $vg1 "$dev1"
+vgcreate $vg2 "$dev2"
+vgcreate $vg3 "$dev3"
+vgcreate $vg4 "$dev4"
+cp "$DF" "$ORIG"
+OPVID1=$(echo $(pvs --noheading -o uuid "$dev1") )
+OPVID2=$(echo $(pvs --noheading -o uuid "$dev2") )
+OPVID3=$(echo $(pvs --noheading -o uuid "$dev3") )
+OPVID4=$(echo $(pvs --noheading -o uuid "$dev4") )
+PVID1=${OPVID1//-/}
+PVID2=${OPVID2//-/}
+PVID3=${OPVID3//-/}
+PVID4=${OPVID4//-/}
+
+grep "$PVID1" "$DF" |tee out
+grep "$SERIAL1" out
+grep "$dev1" out
+grep "$PVID2" "$DF" |tee out
+grep "$SERIAL1" out
+grep "$dev2" out
+grep "$PVID3" "$DF" |tee out
+grep "$SERIAL2" out
+grep "$dev3" out
+grep "$PVID4" "$DF" |tee out
+grep "$SERIAL2" out
+grep "$dev4" out
+
+pvs -o+uuid,deviceidtype,deviceid "${devs[@]}" |tee out
+grep "$dev1" out
+grep "$dev2" out
+grep "$dev3" out
+grep "$dev4" out
+grep "$OPVID1" out
+grep "$OPVID2" out
+grep "$OPVID3" out
+grep "$OPVID4" out
+grep $vg1 out
+grep $vg2 out
+grep $vg3 out
+grep $vg4 out
+grep sys_serial out
+grep "$SERIAL1" out
+grep "$SERIAL2" out
+
+pvs -o+uuid,deviceid "$dev1" |tee out
+grep "$OPVID1" out
+grep "$SERIAL1" out
+grep $vg1 out
+
+pvs -o+uuid,deviceid "$dev2" |tee out
+grep "$OPVID2" out
+grep "$SERIAL1" out
+grep $vg2 out
+
+pvs -o+uuid,deviceid "$dev3" |tee out
+grep "$OPVID3" out
+grep "$SERIAL2" out
+grep $vg3 out
+
+pvs -o+uuid,deviceid "$dev4" |tee out
+grep "$OPVID4" out
+grep "$SERIAL2" out
+grep $vg4 out
+
+# dev1&2 have serial1 and dev3&4 have serial2, swap devnames
+# edit DF to make devnames stale
+
+cp "$ORIG" orig
+sed -e "s|DEVNAME=$dev1|DEVNAME=tmpnm|" orig > tmp1
+sed -e "s|DEVNAME=$dev3|DEVNAME=$dev1|" tmp1 > tmp2
+sed -e "s|DEVNAME=tmpnm|DEVNAME=$dev3|" tmp2 > tmp3
+sed -e "s|DEVNAME=$dev2|DEVNAME=tmpnm|" tmp3 > tmp4
+sed -e "s|DEVNAME=$dev4|DEVNAME=$dev2|" tmp4 > tmp5
+sed -e "s|DEVNAME=tmpnm|DEVNAME=$dev4|" tmp5 > "$DF"
+cat "$DF"
+
+# pvs should report the correct info and fix the DF
+pvs -o+uuid,deviceid "${devs[@]}" |tee out
+grep "$dev1" out |tee out1
+grep "$dev2" out |tee out2
+grep "$dev3" out |tee out3
+grep "$dev4" out |tee out4
+grep "$OPVID1" out1
+grep "$OPVID2" out2
+grep "$OPVID3" out3
+grep "$OPVID4" out4
+grep "$SERIAL1" out1
+grep "$SERIAL1" out2
+grep "$SERIAL2" out3
+grep "$SERIAL2" out4
+
+grep "$PVID1" "$DF" |tee out
+grep "$SERIAL1" out
+grep "$dev1" out
+grep "$PVID2" "$DF" |tee out
+grep "$SERIAL1" out
+grep "$dev2" out
+grep "$PVID3" "$DF" |tee out
+grep "$SERIAL2" out
+grep "$dev3" out
+grep "$PVID4" "$DF" |tee out
+grep "$SERIAL2" out
+grep "$dev4" out
+
+pvs -o+uuid,deviceid "$dev1"|tee out1
+pvs -o+uuid,deviceid "$dev2"|tee out2
+pvs -o+uuid,deviceid "$dev3"|tee out3
+pvs -o+uuid,deviceid "$dev4"|tee out4
+grep "$OPVID1" out1
+grep "$SERIAL1" out1
+grep "$OPVID2" out2
+grep "$SERIAL1" out2
+grep "$OPVID3" out3
+grep "$SERIAL2" out3
+grep "$OPVID4" out4
+grep "$SERIAL2" out4
+
+
+# all devs have same serial, dev1&4 are pvs, dev2&3 are not pvs
+
+aux wipefs_a "${devs[@]}"
+
+echo "$SERIAL1" > "$SYS_DIR/dev/block/$MAJOR1:$MINOR1/device/serial"
+echo "$SERIAL1" > "$SYS_DIR/dev/block/$MAJOR2:$MINOR2/device/serial"
+echo "$SERIAL1" > "$SYS_DIR/dev/block/$MAJOR3:$MINOR3/device/serial"
+echo "$SERIAL1" > "$SYS_DIR/dev/block/$MAJOR4:$MINOR4/device/serial"
+
+rm "$DF"
+touch "$DF"
+vgcreate $vg1 "$dev1"
+vgcreate $vg4 "$dev4"
+cp "$DF" "$ORIG"
+OPVID1=$(echo $(pvs --noheading -o uuid "$dev1") )
+OPVID4=$(echo $(pvs --noheading -o uuid "$dev4") )
+PVID1=${OPVID1//-/}
+PVID4=${OPVID4//-/}
+
+grep "$PVID1" "$DF" |tee out
+grep "$SERIAL1" out
+grep "$dev1" out
+grep "$PVID4" "$DF" |tee out
+grep "$SERIAL1" out
+grep "$dev4" out
+
+pvs -o+uuid,deviceidtype,deviceid |tee out
+grep "$dev1" out
+grep "$dev4" out
+grep "$OPVID1" out
+grep "$OPVID4" out
+grep $vg1 out
+grep $vg4 out
+grep sys_serial out
+grep "$SERIAL1" out
+
+pvs -o+uuid,deviceid "$dev1" |tee out
+grep "$OPVID1" out
+grep "$SERIAL1" out
+grep $vg1 out
+
+not pvs -o+uuid,deviceid "$dev2"
+not pvs -o+uuid,deviceid "$dev3"
+
+pvs -o+uuid,deviceid "$dev4" |tee out
+grep "$OPVID4" out
+grep "$SERIAL1" out
+grep $vg4 out
+
+# edit DF to make devnames stale
+
+cp "$ORIG" orig
+sed -e "s|DEVNAME=$dev1|DEVNAME=$dev2|" orig > tmp1
+sed -e "s|DEVNAME=$dev4|DEVNAME=$dev3|" tmp1 > "$DF"
+cat "$DF"
+
+# pvs should report the correct info and fix the DF
+pvs -o+uuid,deviceid "${devs[@]}" > out || true
+cat out
+grep "$dev1" out |tee out1
+grep "$dev4" out |tee out4
+grep "$OPVID1" out1
+grep "$OPVID4" out4
+grep "$SERIAL1" out1
+grep "$SERIAL1" out4
+
+grep "$PVID1" "$DF" |tee out
+grep "$SERIAL1" out
+grep "$dev1" out
+grep "$PVID4" "$DF" |tee out
+grep "$SERIAL1" out
+grep "$dev4" out
+
+pvs -o+uuid,deviceid "$dev1"|tee out1
+pvs -o+uuid,deviceid "$dev4"|tee out4
+grep "$OPVID1" out1
+grep "$SERIAL1" out1
+grep "$OPVID4" out4
+grep "$SERIAL1" out4
+
+# one pv with serial, three other non-pvs with same serial
+
+aux wipefs_a "${devs[@]}"
+
+echo "$SERIAL1" > "$SYS_DIR/dev/block/$MAJOR1:$MINOR1/device/serial"
+echo "$SERIAL1" > "$SYS_DIR/dev/block/$MAJOR2:$MINOR2/device/serial"
+echo "$SERIAL1" > "$SYS_DIR/dev/block/$MAJOR3:$MINOR3/device/serial"
+echo "$SERIAL1" > "$SYS_DIR/dev/block/$MAJOR4:$MINOR4/device/serial"
+
+rm "$DF"
+touch "$DF"
+vgcreate $vg2 "$dev2"
+cp "$DF" "$ORIG"
+OPVID2=$(echo $(pvs --noheading -o uuid "$dev2") )
+PVID2=${OPVID2//-/}
+
+grep "$PVID2" "$DF" |tee out
+grep "$SERIAL1" out
+grep "$dev2" out
+
+pvs -o+uuid,deviceidtype,deviceid |tee out
+grep "$dev2" out
+grep sys_serial out
+grep "$SERIAL1" out
+not grep "$dev1" out
+not grep "$dev3" out
+not grep "$dev4" out
+
+# edit DF to make devname stale
+
+cp "$ORIG" orig
+sed -e "s|DEVNAME=$dev2|DEVNAME=$dev3|" orig > "$DF"
+cat "$DF"
+
+# pvs should report the correct info and fix the DF
+pvs -o+uuid,deviceid "${devs[@]}" > out || true
+cat out
+grep "$dev2" out
+grep "$OPVID2" out
+grep "$SERIAL1" out
+grep "$dev2" "$DF"
+
+# different serial numbers, stale pvid and devname in df,
+# lvm corrects pvid in df because serial number is unique
+
+aux wipefs_a "${devs[@]}"
+
+echo "$SERIAL1" > "$SYS_DIR/dev/block/$MAJOR1:$MINOR1/device/serial"
+echo "$SERIAL2" > "$SYS_DIR/dev/block/$MAJOR2:$MINOR2/device/serial"
+echo "$SERIAL3" > "$SYS_DIR/dev/block/$MAJOR3:$MINOR3/device/serial"
+echo "$SERIAL4" > "$SYS_DIR/dev/block/$MAJOR4:$MINOR4/device/serial"
+
+rm "$DF"
+touch "$DF"
+vgcreate $vg1 "$dev1"
+vgcreate $vg2 "$dev2"
+vgcreate $vg3 "$dev3"
+vgcreate $vg4 "$dev4"
+cp "$DF" "$ORIG"
+grep "$SERIAL1" "$DF"
+grep "$SERIAL2" "$DF"
+grep "$SERIAL3" "$DF"
+grep "$SERIAL4" "$DF"
+OPVID1=$(echo $(pvs --noheading -o uuid "$dev1") )
+OPVID2=$(echo $(pvs --noheading -o uuid "$dev2") )
+OPVID3=$(echo $(pvs --noheading -o uuid "$dev3") )
+OPVID4=$(echo $(pvs --noheading -o uuid "$dev4") )
+PVID1=${OPVID1//-/}
+PVID2=${OPVID2//-/}
+PVID3=${OPVID3//-/}
+PVID4=${OPVID4//-/}
+pvs -o+uuid,deviceid "${devs[@]}"
+
+cp "$ORIG" orig
+sed -e "s|PVID=$PVID1|PVID=bad14onBxSiv4dot0GRDPtrWqOlr1bad|" orig > tmp1
+sed -e "s|PVID=$PVID3|PVID=bad24onBxSiv4dot0GRDPtrWqOlr2bad|" tmp1 > tmp2
+sed -e "s|DEVNAME=$dev1|DEVNAME=.|" tmp2 > "$DF"
+cat "$DF"
+
+# pvs should report the correct info and fix the DF
+pvs -o+uuid,deviceid "${devs[@]}" |tee out
+grep "$dev1" out |tee out1
+grep "$dev2" out |tee out2
+grep "$dev3" out |tee out3
+grep "$dev4" out |tee out4
+grep "$OPVID1" out1
+grep "$OPVID2" out2
+grep "$OPVID3" out3
+grep "$OPVID4" out4
+grep $vg1 out1
+grep $vg2 out2
+grep $vg3 out3
+grep $vg4 out4
+grep "$SERIAL1" out1
+grep "$SERIAL2" out2
+grep "$SERIAL3" out3
+grep "$SERIAL4" out4
+
+grep "$PVID1" "$DF" |tee out
+grep "$SERIAL1" out
+grep "$dev1" out
+grep "$PVID2" "$DF" |tee out
+grep "$SERIAL2" out
+grep "$dev2" out
+grep "$PVID3" "$DF" |tee out
+grep "$SERIAL3" out
+grep "$dev3" out
+grep "$PVID4" "$DF" |tee out
+grep "$SERIAL4" out
+grep "$dev4" out
+
+# duplicate serial on two pvs, two pvs with devname type, all devnames stale
+
+aux wipefs_a "${devs[@]}"
+
+echo "$SERIAL1" > "$SYS_DIR/dev/block/$MAJOR1:$MINOR1/device/serial"
+echo "$SERIAL1" > "$SYS_DIR/dev/block/$MAJOR2:$MINOR2/device/serial"
+echo "" > "$SYS_DIR/dev/block/$MAJOR3:$MINOR3/device/serial"
+echo "" > "$SYS_DIR/dev/block/$MAJOR4:$MINOR4/device/serial"
+
+rm "$DF"
+touch "$DF"
+vgcreate $vg1 "$dev1"
+vgcreate $vg2 "$dev2"
+vgcreate $vg3 "$dev3"
+vgcreate $vg4 "$dev4"
+cp "$DF" "$ORIG"
+OPVID1=$(echo $(pvs --noheading -o uuid "$dev1") )
+OPVID2=$(echo $(pvs --noheading -o uuid "$dev2") )
+OPVID3=$(echo $(pvs --noheading -o uuid "$dev3") )
+OPVID4=$(echo $(pvs --noheading -o uuid "$dev4") )
+PVID1=${OPVID1//-/}
+PVID2=${OPVID2//-/}
+PVID3=${OPVID3//-/}
+PVID4=${OPVID4//-/}
+cat "$DF"
+
+pvs -o+uuid,deviceid "${devs[@]}"
+
+cp "$ORIG" orig
+sed -e "s|DEVNAME=$dev1|DEVNAME=tmpnm|" orig > tmp1
+sed -e "s|DEVNAME=$dev3|DEVNAME=$dev1|" tmp1 > tmp2
+sed -e "s|DEVNAME=tmpnm|DEVNAME=$dev3|" tmp2 > tmp3
+sed -e "s|DEVNAME=$dev2|DEVNAME=tmpnm|" tmp3 > tmp4
+sed -e "s|DEVNAME=$dev4|DEVNAME=$dev2|" tmp4 > tmp5
+sed -e "s|DEVNAME=tmpnm|DEVNAME=$dev4|" tmp5 > "$DF"
+cat "$DF"
+
+# pvs should report the correct info and fix the DF
+pvs -o+uuid,deviceid "${devs[@]}" |tee out
+grep "$dev1" out |tee out1
+grep "$dev2" out |tee out2
+grep "$dev3" out |tee out3
+grep "$dev4" out |tee out4
+grep "$OPVID1" out1
+grep "$OPVID2" out2
+grep "$OPVID3" out3
+grep "$OPVID4" out4
+grep $vg1 out1
+grep $vg2 out2
+grep $vg3 out3
+grep $vg4 out4
+grep "$SERIAL1" out1
+grep "$SERIAL1" out2
+
+cat "$DF"
+grep "$PVID1" "$DF" |tee out1
+grep "$PVID2" "$DF" |tee out2
+grep "$PVID3" "$DF" |tee out3
+grep "$PVID4" "$DF" |tee out4
+grep "$dev1" out1
+grep "$SERIAL1" out1
+grep "$dev2" out2
+grep "$SERIAL1" out2
+grep "$dev3" out3
+grep "$dev4" out4
+
+# two pvs with duplicate serial and stale devname, one pv with unique serial and stale pvid
+
+aux wipefs_a "${devs[@]}"
+
+echo "$SERIAL1" > "$SYS_DIR/dev/block/$MAJOR1:$MINOR1/device/serial"
+echo "$SERIAL1" > "$SYS_DIR/dev/block/$MAJOR2:$MINOR2/device/serial"
+echo "$SERIAL3" > "$SYS_DIR/dev/block/$MAJOR3:$MINOR3/device/serial"
+echo "$SERIAL1" > "$SYS_DIR/dev/block/$MAJOR4:$MINOR4/device/serial"
+
+rm "$DF"
+touch "$DF"
+vgcreate $vg1 "$dev1"
+vgcreate $vg2 "$dev2"
+vgcreate $vg3 "$dev3"
+cp "$DF" "$ORIG"
+OPVID1=$(echo $(pvs --noheading -o uuid "$dev1") )
+OPVID2=$(echo $(pvs --noheading -o uuid "$dev2") )
+OPVID3=$(echo $(pvs --noheading -o uuid "$dev3") )
+PVID1=${OPVID1//-/}
+PVID2=${OPVID2//-/}
+PVID3=${OPVID3//-/}
+cat "$DF"
+
+pvs -o+uuid,deviceid "${devs[@]}" || true
+
+cp "$ORIG" orig
+sed -e "s|DEVNAME=$dev1|DEVNAME=$dev4|" orig > tmp1
+sed -e "s|DEVNAME=$dev2|DEVNAME=$dev1|" tmp1 > tmp2
+sed -e "s|PVID=$dev3|PVID=bad14onBxSiv4dot0GRDPtrWqOlr1bad|" tmp2 > "$DF"
+cat "$DF"
+
+# pvs should report the correct info and fix the DF
+pvs -o+uuid,deviceid "${devs[@]}" > out || true
+cat out
+grep "$dev1" out |tee out1
+grep "$dev2" out |tee out2
+grep "$dev3" out |tee out3
+grep "$OPVID1" out1
+grep "$OPVID2" out2
+grep "$OPVID3" out3
+grep $vg1 out1
+grep $vg2 out2
+grep $vg3 out3
+grep "$SERIAL1" out1
+grep "$SERIAL1" out2
+grep "$SERIAL3" out3
+
+cat "$DF"
+grep "$PVID1" "$DF" |tee out1
+grep "$PVID2" "$DF" |tee out2
+grep "$PVID3" "$DF" |tee out3
+grep "$dev1" out1
+grep "$SERIAL1" out1
+grep "$dev2" out2
+grep "$SERIAL1" out2
+grep "$dev3" out3
+grep "$SERIAL3" out3
+
+# non-PV devices
+
+aux wipefs_a "${devs[@]}"
+
+echo "$SERIAL1" > "$SYS_DIR/dev/block/$MAJOR1:$MINOR1/device/serial"
+echo "$SERIAL2" > "$SYS_DIR/dev/block/$MAJOR2:$MINOR2/device/serial"
+echo "$SERIAL2" > "$SYS_DIR/dev/block/$MAJOR3:$MINOR3/device/serial"
+echo "$SERIAL4" > "$SYS_DIR/dev/block/$MAJOR4:$MINOR4/device/serial"
+
+rm "$DF"
+touch "$DF"
+vgcreate $vg4 "$dev4"
+lvmdevices --adddev "$dev1"
+lvmdevices --adddev "$dev2"
+lvmdevices --adddev "$dev3"
+cat "$DF"
+
+grep "$dev1" "$DF" |tee out1
+grep "$dev2" "$DF" |tee out2
+grep "$dev3" "$DF" |tee out3
+grep "$dev4" "$DF" |tee out4
+
+grep "$SERIAL1" out1
+grep "$SERIAL2" out2
+grep "$SERIAL2" out3
+grep "$SERIAL4" out4
+
+pvs "${devs[@]}" > out || true
+cat out
+grep "$dev4" out
+not grep "$dev1" out
+not grep "$dev2" out
+not grep "$dev3" out
+
+pvcreate "$dev1"
+pvs "${devs[@]}" > out || true
+cat out
+grep "$dev1" out
+grep "$dev4" out
+not grep "$dev2" out
+not grep "$dev3" out
+
+pvcreate "$dev2"
+pvs "${devs[@]}" > out || true
+cat out
+grep "$dev1" out
+grep "$dev4" out
+grep "$dev2" out
+not grep "$dev3" out
+
+pvcreate "$dev3"
+pvs "${devs[@]}" |tee out
+grep "$dev1" out
+grep "$dev4" out
+grep "$dev2" out
+grep "$dev3" out
+
+OPVID1=$(echo $(pvs --noheading -o uuid "$dev1") )
+OPVID2=$(echo $(pvs --noheading -o uuid "$dev2") )
+OPVID3=$(echo $(pvs --noheading -o uuid "$dev3") )
+OPVID4=$(echo $(pvs --noheading -o uuid "$dev4") )
+PVID1=${OPVID1//-/}
+PVID2=${OPVID2//-/}
+PVID3=${OPVID3//-/}
+PVID4=${OPVID4//-/}
+
+grep "$dev1" "$DF" |tee out1
+grep "$dev2" "$DF" |tee out2
+grep "$dev3" "$DF" |tee out3
+grep "$dev4" "$DF" |tee out4
+
+grep "$PVID1" out1
+grep "$PVID2" out2
+grep "$PVID3" out3
+grep "$PVID4" out4
+
+vgcreate $vg2 "$dev2" "$dev3"
+vgs | grep $vg2
+
+# 3 devs with duplicate serial, 2 pvs with stale devnames, 1 non-pv device
+
+aux wipefs_a "$dev1" "$dev2" "$dev3"
+
+echo "$SERIAL1" > "$SYS_DIR/dev/block/$MAJOR1:$MINOR1/device/serial"
+echo "$SERIAL1" > "$SYS_DIR/dev/block/$MAJOR2:$MINOR2/device/serial"
+echo "$SERIAL1" > "$SYS_DIR/dev/block/$MAJOR3:$MINOR3/device/serial"
+
+rm "$DF"
+touch "$DF"
+vgcreate $vg1 "$dev1" "$dev2"
+lvmdevices --adddev "$dev3"
+cat "$DF"
+cp "$DF" "$ORIG"
+
+OPVID1=$(echo $(pvs --noheading -o uuid "$dev1") )
+OPVID2=$(echo $(pvs --noheading -o uuid "$dev2") )
+PVID1=${OPVID1//-/}
+PVID2=${OPVID2//-/}
+
+pvs -o+uuid,deviceid "${devs[@]}" || true
+
+sed -e "s|DEVNAME=$dev1|DEVNAME=tmp|" "$ORIG" > tmp1
+sed -e "s|DEVNAME=$dev2|DEVNAME=$dev1|" tmp1 > tmp2
+sed -e "s|DEVNAME=tmp|DEVNAME=$dev2|" tmp2 > "$DF"
+cat "$DF"
+
+# pvs should report the correct info and fix the DF
+pvs -o+uuid,deviceid "${devs[@]}" > out || true
+cat out
+grep "$dev1" out |tee out1
+grep "$dev2" out |tee out2
+grep "$OPVID1" out1
+grep "$OPVID2" out2
+grep "$SERIAL1" out1
+grep "$SERIAL1" out2
diff --git a/test/shell/devicesfile-vpd-ids.sh b/test/shell/devicesfile-vpd-ids.sh
new file mode 100644
index 0000000..9a12f49
--- /dev/null
+++ b/test/shell/devicesfile-vpd-ids.sh
@@ -0,0 +1,436 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2020 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+test_description='device id wwid from vpd_pg83'
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+test "$DM_DEV_DIR" = "/dev" || skip "Only works with /dev access -> make check LVM_TEST_DEVDIR=/dev"
+
+aux lvmconf 'devices/use_devicesfile = 1'
+# requires trailing / to match dm
+aux lvmconf 'devices/device_id_sysfs_dir = "/test/sys/"'
+SYS_DIR="/test/sys"
+
+# These values match the values encoded in the binary blob
+# written to dev1_vpd_pg83
+DEV1_NAA=naa.600a098038303877413f4e7049592e6e
+DEV1_EUI=eui.3f4e7049592d6f0000a0973730387741
+DEV1_T10=t10.LVMTST_LUN_809wALVMTSTo
+# dev has a second naa wwid
+DEV1_NAA2=naa.600a098000000002ac18542400000dbd
+# dev has a third naa wwid in the scsi name field
+DEV1_NAA3=naa.553b13644430344b4e3f486d32647962
+
+create_base() {
+ mkdir -p $SYS_DIR/dev/block
+
+ echo -n "0083 009c 0201 0020 4c56 4d54 5354 2020 \
+ 204c 554e 2038 3039 7741 4c56 4d54 5354 \
+ 6f20 2020 2020 2020 0103 0010 600a 0980 \
+ 3830 3877 413f 4e70 4959 2e6e 0102 0010 \
+ 3f4e 7049 592d 6f00 00a0 9737 3038 7741 \
+ 0113 0010 600a 0980 0000 0002 ac18 5424 \
+ 0000 0dbd 0114 0004 0101 0005 0115 0004 \
+ 0000 03ec 0328 0028 6e61 612e 3535 3342 \
+ 3133 3634 3434 3330 3334 3442 3445 3346 \
+ 3438 3644 3332 3634 3739 3632 0000 0000" | xxd -r -p > $SYS_DIR/dev1_vpd_pg83
+}
+
+remove_base() {
+ rm $SYS_DIR/dev1_vpd_pg83
+ rmdir $SYS_DIR/dev/block
+ rmdir $SYS_DIR/dev
+ rmdir $SYS_DIR
+}
+
+setup_sysfs() {
+ mkdir -p $SYS_DIR/dev/block/$MAJOR1:$MINOR1/device
+ echo $1 > $SYS_DIR/dev/block/$MAJOR1:$MINOR1/device/wwid
+ cp $SYS_DIR/dev1_vpd_pg83 $SYS_DIR/dev/block/$MAJOR1:$MINOR1/device/vpd_pg83
+}
+
+cleanup_sysfs() {
+ rm -f $SYS_DIR/dev/block/$MAJOR1:$MINOR1/device/wwid
+ rm -f $SYS_DIR/dev/block/$MAJOR1:$MINOR1/device/vpd_pg83
+ rmdir $SYS_DIR/dev/block/$MAJOR1:$MINOR1/device || true
+ rmdir $SYS_DIR/dev/block/$MAJOR1:$MINOR1 || true
+}
+
+
+modprobe scsi_debug dev_size_mb=16 num_tgts=1
+sleep 2
+# Get scsi device name created by scsi_debug.
+# SD = sdh
+# DEV1 = /dev/sdh
+SD=$(grep -H scsi_debug /sys/block/sd*/device/model | cut -f4 -d /);
+echo $SD
+DEV1=/dev/$SD
+echo $DEV1
+
+DFDIR="$LVM_SYSTEM_DIR/devices"
+mkdir -p "$DFDIR" || true
+DF="$DFDIR/system.devices"
+DFTMP="$DFDIR/system.devices_tmp"
+touch $DF
+
+pvcreate "$DEV1"
+vgcreate $vg "$DEV1"
+MAJOR1=`pvs "$DEV1" --noheading -o major | tr -d - | awk '{print $1}'`
+MINOR1=`pvs "$DEV1" --noheading -o minor | tr -d - | awk '{print $1}'`
+PVID1=`pvs "$DEV1" --noheading -o uuid | tr -d - | awk '{print $1}'`
+
+create_base
+
+# No sys/wwid, lvm uses wwid from sys/vpd
+
+setup_sysfs $DEV1_NAA
+# no sys/wwid is reported
+rm $SYS_DIR/dev/block/$MAJOR1:$MINOR1/device/wwid
+rm $DF
+lvmdevices --adddev "$DEV1"
+cat $DF
+pvs "$DEV1"
+grep $DEV1_NAA $DF
+cleanup_sysfs
+
+# Kernel changes the type printed from sys/wwid from t10 to naa
+# after lvm has used sys_wwid with the t10 value.
+# set sys/wwid to t10 value
+# add dev to df, it uses t10 value
+# change sys/wwid to naa value
+# reporting pvs should still find the dev based on using vpd data
+# and find the t10 value there
+
+setup_sysfs $DEV1_T10
+rm $DF
+lvmdevices --adddev "$DEV1"
+cat $DF
+grep sys_wwid $DF
+grep $DEV1_T10 $DF
+pvs "$DEV1"
+# kernel changes what it reports from sys/wwid
+echo $DEV1_NAA > $SYS_DIR/dev/block/$MAJOR1:$MINOR1/device/wwid
+# lvm finds the original t10 id in vpd
+pvs "$DEV1"
+cleanup_sysfs
+
+# User chooses wwid type other than is printed from sys/wwid
+# set sys/wwid to t10|naa|eui value
+# lvmdevices --adddev using --deviceidtype different from sys/wwid
+# df entry uses the specified type
+# reporting pvs should show the pv
+
+setup_sysfs $DEV1_T10
+rm $DF
+lvmdevices --adddev "$DEV1" --deviceidtype wwid_naa
+cat $DF
+grep wwid_naa $DF
+grep $DEV1_NAA $DF
+pvs "$DEV1"
+lvmdevices --deldev "$DEV1"
+lvmdevices --addpvid "$PVID1" --deviceidtype wwid_naa
+cat $DF
+grep $DEV1_NAA $DF
+pvs "$DEV1"
+lvmdevices --deldev "$DEV1"
+lvmdevices --adddev "$DEV1" --deviceidtype wwid_eui
+cat $DF
+grep wwid_eui $DF
+grep $DEV1_EUI $DF
+pvs "$DEV1"
+cleanup_sysfs
+
+# Any of the vpd wwids can be used in the devices file
+# with type sys_wwid and the device will be matched to
+# it by finding that wwid in the vpd data.
+
+setup_sysfs $DEV1_NAA
+rm $DF
+lvmdevices --adddev "$DEV1"
+cat $DF
+rm $SYS_DIR/dev/block/$MAJOR1:$MINOR1/device/wwid
+pvs "$DEV1"
+cleanup_sysfs
+
+setup_sysfs $DEV1_NAA2
+rm $DF
+lvmdevices --adddev "$DEV1"
+cat $DF
+rm $SYS_DIR/dev/block/$MAJOR1:$MINOR1/device/wwid
+pvs "$DEV1"
+cleanup_sysfs
+
+setup_sysfs $DEV1_NAA3
+rm $DF
+lvmdevices --adddev "$DEV1"
+cat $DF
+rm $SYS_DIR/dev/block/$MAJOR1:$MINOR1/device/wwid
+pvs "$DEV1"
+cleanup_sysfs
+
+setup_sysfs $DEV1_EUI
+rm $DF
+lvmdevices --adddev "$DEV1"
+cat $DF
+rm $SYS_DIR/dev/block/$MAJOR1:$MINOR1/device/wwid
+pvs "$DEV1"
+cleanup_sysfs
+
+setup_sysfs $DEV1_T10
+rm $DF
+lvmdevices --adddev "$DEV1"
+cat $DF
+rm $SYS_DIR/dev/block/$MAJOR1:$MINOR1/device/wwid
+pvs "$DEV1"
+cleanup_sysfs
+
+# Test nvme wwid that starts with "nvme" instead of naa/eui/t10
+rm $DF
+aux wipefs_a "$DEV1"
+mkdir -p $SYS_DIR/dev/block/$MAJOR1:$MINOR1/
+echo "nvme.111111111111111111122222222222333333333333333-44444444444444444445555555555556666666666666666662-00000001" > $SYS_DIR/dev/block/$MAJOR1:$MINOR1/wwid
+lvmdevices --adddev "$DEV1"
+cat $DF
+vgcreate $vg "$DEV1"
+lvcreate -l1 -an $vg
+cat $DF
+pvs -o+deviceidtype,deviceid "$DEV1" |tee out
+grep sys_wwid out
+grep nvme.111 out
+grep sys_wwid $DF
+grep nvme.111 $DF
+lvmdevices --deldev "$DEV1"
+not lvmdevices --adddev "$DEV1" --deviceidtype wwid_eui
+lvmdevices --adddev "$DEV1" --deviceidtype sys_wwid
+lvmdevices | grep nvme.111
+lvremove -y $vg
+sleep 1
+lvs $vg
+vgremove $vg
+rm $SYS_DIR/dev/block/$MAJOR1:$MINOR1/wwid
+cleanup_sysfs
+
+# Test t10 wwid containing quote
+rm $DF
+aux wipefs_a "$DEV1"
+mkdir -p $SYS_DIR/dev/block/$MAJOR1:$MINOR1/device
+echo "t10.ATA_2.5\"_SATA_SSD_1112-A___111111111111" > $SYS_DIR/dev/block/$MAJOR1:$MINOR1/device/wwid
+lvmdevices --adddev "$DEV1"
+cat $DF
+vgcreate $vg "$DEV1"
+lvcreate -l1 -an $vg
+cat $DF
+# check wwid string in metadata output
+pvs -o+deviceidtype,deviceid "$DEV1" |tee out
+grep sys_wwid out
+# the quote is removed after the 5
+grep 2.5_SATA_SSD out
+# check wwid string in system.devices
+grep sys_wwid $DF
+# the quote is removed after the 5
+grep 2.5_SATA_SSD $DF
+lvremove -y $vg
+vgremove $vg
+rm $SYS_DIR/dev/block/$MAJOR1:$MINOR1/device/wwid
+cleanup_sysfs
+
+# Test t10 wwid with trailing space and line feed at the end
+rm $DF
+aux wipefs_a "$DEV1"
+mkdir -p $SYS_DIR/dev/block/$MAJOR1:$MINOR1/device
+echo -n "7431 302e 4154 4120 2020 2020 5642 4f58 \
+2048 4152 4444 4953 4b20 2020 2020 2020 \
+2020 2020 2020 2020 2020 2020 2020 2020 \
+2020 2020 5642 3963 3130 6433 3138 2d31 \
+3838 6439 6562 6320 0a" | xxd -r -p > $SYS_DIR/dev/block/$MAJOR1:$MINOR1/device/wwid
+cat $SYS_DIR/dev/block/$MAJOR1:$MINOR1/device/wwid
+lvmdevices --adddev "$DEV1"
+cat $DF
+vgcreate $vg "$DEV1"
+lvcreate -l1 -an $vg
+cat $DF
+# check wwid string in metadata output
+pvs -o+deviceidtype,deviceid "$DEV1" |tee out
+grep sys_wwid out
+# check wwid string in system.devices
+grep sys_wwid $DF
+lvremove -y $vg
+vgremove $vg
+rm $SYS_DIR/dev/block/$MAJOR1:$MINOR1/device/wwid
+cleanup_sysfs
+
+# Test t10 wwid with trailing space at the end that was created by 9.0/9.1
+rm $DF
+aux wipefs_a "$DEV1"
+mkdir -p $SYS_DIR/dev/block/$MAJOR1:$MINOR1/device
+echo -n "7431 302e 4154 4120 2020 2020 5642 4f58 \
+2048 4152 4444 4953 4b20 2020 2020 2020 \
+2020 2020 2020 2020 2020 2020 2020 2020 \
+2020 2020 5642 3963 3130 6433 3138 2d31 \
+3838 6439 6562 6320 0a" | xxd -r -p > $SYS_DIR/dev/block/$MAJOR1:$MINOR1/device/wwid
+cat $SYS_DIR/dev/block/$MAJOR1:$MINOR1/device/wwid
+lvmdevices --adddev "$DEV1"
+cat $DF
+vgcreate $vg "$DEV1"
+PVID1=`pvs "$DEV1" --noheading -o uuid | tr -d - | awk '{print $1}'`
+T10_WWID_RHEL91="t10.ATA_____VBOX_HARDDISK___________________________VB9c10d318-188d9ebc_"
+lvcreate -l1 -an $vg
+cat $DF
+# check wwid string in metadata output
+pvs -o+deviceidtype,deviceid "$DEV1" |tee out
+grep sys_wwid out
+# check wwid string in system.devices
+grep sys_wwid $DF
+# Replace IDNAME with the IDNAME that 9.0/9.1 created from this wwid
+cat $DF | grep -v IDNAME > $DFTMP
+cat $DFTMP
+echo "IDTYPE=sys_wwid IDNAME=t10.ATA_____VBOX_HARDDISK___________________________VB9c10d318-188d9ebc_ DEVNAME=${DEV1} PVID=${PVID1}" >> $DFTMP
+cp $DFTMP $DF
+cat $DF
+vgs
+pvs
+pvs -o+deviceidtype,deviceid "$DEV1"
+# Removing the trailing _ which should then work
+cat $DF | grep -v IDNAME > $DFTMP
+cat $DFTMP
+echo "IDTYPE=sys_wwid IDNAME=t10.ATA_____VBOX_HARDDISK___________________________VB9c10d318-188d9ebc DEVNAME=${DEV1} PVID=${PVID1}" >> $DFTMP
+cp $DFTMP $DF
+cat $DF
+vgs
+pvs
+pvs -o+deviceidtype,deviceid "$DEV1"
+lvremove -y $vg
+vgremove $vg
+rm $SYS_DIR/dev/block/$MAJOR1:$MINOR1/device/wwid
+cleanup_sysfs
+
+# test a t10 wwid that has actual trailing underscore which
+# is followed by a trailing space.
+rm $DF
+aux wipefs_a "$DEV1"
+mkdir -p $SYS_DIR/dev/block/$MAJOR1:$MINOR1/device
+echo -n "7431 302e 4154 4120 2020 2020 5642 4f58 \
+2048 4152 4444 4953 4b20 2020 2020 2020 \
+2020 2020 2020 2020 2020 2020 2020 2020 \
+2020 2020 5642 3963 3130 6433 3138 2d31 \
+3838 6439 6562 5f20 0a" | xxd -r -p > $SYS_DIR/dev/block/$MAJOR1:$MINOR1/device/wwid
+cat $SYS_DIR/dev/block/$MAJOR1:$MINOR1/device/wwid
+# The wwid has an actual underscore char (5f) followed by a space char (20)
+# 9.1 converts the trailing space to an underscore
+T10_WWID_RHEL91="t10.ATA_____VBOX_HARDDISK___________________________VB9c10d318-188d9eb__"
+# 9.2 ignores the trailing space
+T10_WWID_RHEL92="t10.ATA_____VBOX_HARDDISK___________________________VB9c10d318-188d9eb_"
+lvmdevices --adddev "$DEV1"
+cat $DF
+vgcreate $vg "$DEV1"
+PVID1=`pvs "$DEV1" --noheading -o uuid | tr -d - | awk '{print $1}'`
+lvcreate -l1 -an $vg
+cat $DF
+# check wwid string in metadata output
+pvs -o+deviceidtype,deviceid "$DEV1" |tee out
+grep sys_wwid out
+# check wwid string in system.devices
+grep sys_wwid $DF
+# Replace IDNAME with the IDNAME that 9.0/9.1 created from this wwid
+cat $DF | grep -v IDNAME > $DFTMP
+cat $DFTMP
+echo "IDTYPE=sys_wwid IDNAME=${T10_WWID_RHEL91} DEVNAME=${DEV1} PVID=${PVID1}" >> $DFTMP
+cp $DFTMP $DF
+cat $DF
+vgs
+pvs
+pvs -o+deviceidtype,deviceid "$DEV1"
+lvremove -y $vg
+vgremove $vg
+rm $SYS_DIR/dev/block/$MAJOR1:$MINOR1/device/wwid
+cleanup_sysfs
+
+#
+# Test trailing/leading/center spaces in sys_wwid and sys_serial device
+# ids, and that old system.devices files that have trailing/leading
+# underscores are understood.
+#
+
+rm $DF
+aux wipefs_a "$DEV1"
+mkdir -p $SYS_DIR/dev/block/$MAJOR1:$MINOR1/device
+echo -n " s123 456 " > $SYS_DIR/dev/block/$MAJOR1:$MINOR1/device/serial
+lvmdevices --adddev "$DEV1"
+cat $DF
+grep "IDNAME=s123__456 DEVNAME" $DF
+vgcreate $vg "$DEV1"
+PVID1=`pvs "$DEV1" --noheading -o uuid | tr -d - | awk '{print $1}'`
+cat $DF | grep -v IDNAME > $DFTMP
+cat $DFTMP
+echo "IDTYPE=sys_serial IDNAME=__s123__456__ DEVNAME=${DEV1} PVID=${PVID1}" >> $DFTMP
+cp $DFTMP $DF
+cat $DF
+vgs
+pvs -o+deviceidtype,deviceid "$DEV1"
+lvremove -y $vg
+vgremove $vg
+rm $SYS_DIR/dev/block/$MAJOR1:$MINOR1/device/serial
+cleanup_sysfs
+
+rm $DF
+aux wipefs_a "$DEV1"
+mkdir -p $SYS_DIR/dev/block/$MAJOR1:$MINOR1/device
+echo -n " t10.123 456 " > $SYS_DIR/dev/block/$MAJOR1:$MINOR1/device/wwid
+lvmdevices --adddev "$DEV1"
+cat $DF
+grep "IDNAME=t10.123_456 DEVNAME" $DF
+vgcreate $vg "$DEV1"
+PVID1=`pvs "$DEV1" --noheading -o uuid | tr -d - | awk '{print $1}'`
+cat $DF | grep -v IDNAME > $DFTMP
+cat $DFTMP
+echo "IDTYPE=sys_wwid IDNAME=__t10.123__456__ DEVNAME=${DEV1} PVID=${PVID1}" >> $DFTMP
+cp $DFTMP $DF
+cat $DF
+vgs
+pvs -o+deviceidtype,deviceid "$DEV1"
+lvremove -y $vg
+vgremove $vg
+rm $SYS_DIR/dev/block/$MAJOR1:$MINOR1/device/wwid
+cleanup_sysfs
+
+rm $DF
+aux wipefs_a "$DEV1"
+mkdir -p $SYS_DIR/dev/block/$MAJOR1:$MINOR1/device
+echo -n " naa.123 456 " > $SYS_DIR/dev/block/$MAJOR1:$MINOR1/device/wwid
+lvmdevices --adddev "$DEV1"
+cat $DF
+grep "IDNAME=naa.123__456 DEVNAME" $DF
+vgcreate $vg "$DEV1"
+PVID1=`pvs "$DEV1" --noheading -o uuid | tr -d - | awk '{print $1}'`
+cat $DF | grep -v IDNAME > $DFTMP
+cat $DFTMP
+echo "IDTYPE=sys_wwid IDNAME=__naa.123__456__ DEVNAME=${DEV1} PVID=${PVID1}" >> $DFTMP
+cp $DFTMP $DF
+cat $DF
+vgs
+pvs -o+deviceidtype,deviceid "$DEV1"
+lvremove -y $vg
+vgremove $vg
+rm $SYS_DIR/dev/block/$MAJOR1:$MINOR1/device/wwid
+cleanup_sysfs
+
+
+
+
+# TODO: lvmdevices --adddev <dev> --deviceidtype <type> --deviceid <val>
+# This would let the user specify the second naa wwid.
+
+remove_base
+rmmod scsi_debug || true
diff --git a/test/shell/discards-thin.sh b/test/shell/discards-thin.sh
index 84688b4..213f713 100644
--- a/test/shell/discards-thin.sh
+++ b/test/shell/discards-thin.sh
@@ -1,6 +1,6 @@
-#!/bin/sh
+#!/usr/bin/env bash
-# Copyright (C) 2012 Red Hat, Inc. All rights reserved.
+# Copyright (C) 2012-2013 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
@@ -8,43 +8,89 @@
#
# 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
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
#
# test support of thin discards
#
-. lib/test
+
+SKIP_WITH_LVMPOLLD=1
+SKIP_WITH_LVMLOCKD=1
+
+export LVM_TEST_THIN_REPAIR_CMD=${LVM_TEST_THIN_REPAIR_CMD-/bin/false}
+
+. lib/inittest
#
# Main
#
aux have_thin 1 1 0 || skip
-aux prepare_pvs 2 64
+aux prepare_vg 2 64
+get_devs
-vgcreate $vg -s 64K $(cat DEVICES)
+aux extend_filter_LVMTEST
# Create named pool only
lvcreate -l1 --discards ignore -T $vg/pool
check lv_field $vg/pool discards "ignore"
+check lv_field $vg/pool kernel_discards "ignore"
lvcreate -l1 --discards nopassdown -T $vg/pool1
check lv_field $vg/pool1 discards "nopassdown"
+check lv_field $vg/pool1 kernel_discards "nopassdown"
lvcreate -l1 --discards passdown -T $vg/pool2
check lv_field $vg/pool2 discards "passdown"
+check lv_field $vg/pool2 discards "passdown"
lvchange --discards nopassdown $vg/pool2
-# cannot convert active ignore -> passdown
+lvcreate -V1M -n origin -T $vg/pool
+lvcreate -s $vg/origin -n snap
+
+# Cannot convert active nopassdown -> ignore
+not lvchange --discards nopassdown $vg/pool
+
+# Cannot convert active ignore -> passdown
not lvchange --discards passdown $vg/pool
-# cannot convert active nopassdown -> ignore
+# Cannot convert active nopassdown -> ignore
not lvchange --discards ignore $vg/pool1
-# deactivate
+# Deactivate pool only
lvchange -an $vg/pool $vg/pool1
+
+# Cannot convert, since thin volumes are still active
+not lvchange --discards passdown $vg/pool
+
+# Deactive thin volumes
+lvchange -an $vg/origin $vg/snap
+
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
+
+# Create thin pool with discards set to "ignore".
+# If we create a thin volume which we use for a PV
+# which we use to create another thin pool on top
+# with discards set to "passdown", the discards value
+# in metadata is still "passdown", but because the
+# device below does not support it, the kernel value
+# of discards actually used will be "nopassdown".
+# This is why we have "-o discards" and "-o kernel_discards".
+vgcreate $SHARED -s 1m "${vg}_1" "${DEVICES[@]}"
+lvcreate -l 10 -T ${vg}_1/pool --discards ignore
+lvcreate -V 9m -T ${vg}_1/pool -n device_with_ignored_discards
+vgcreate $SHARED -s 1m ${vg}_2 "$DM_DEV_DIR/${vg}_1/device_with_ignored_discards"
+lvcreate -l 1 -T ${vg}_2/pool --discards passdown
+lvcreate -V 1 -T ${vg}_2/pool
+check lv_field ${vg}_1/pool discards "ignore"
+check lv_field ${vg}_1/pool kernel_discards "ignore"
+check lv_field ${vg}_2/pool discards "passdown"
+check lv_field ${vg}_2/pool kernel_discards "nopassdown"
+
+vgremove -ff ${vg}_2
+vgremove -ff ${vg}_1
diff --git a/test/shell/dmeventd-restart.sh b/test/shell/dmeventd-restart.sh
index fa9db46..0def8c1 100644
--- a/test/shell/dmeventd-restart.sh
+++ b/test/shell/dmeventd-restart.sh
@@ -1,4 +1,5 @@
-#!/bin/sh
+#!/usr/bin/env bash
+
# Copyright (C) 2008 Red Hat, Inc. All rights reserved.
#
# This copyrighted material is made available to anyone wishing to use,
@@ -7,45 +8,59 @@
#
# 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
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
-. lib/test
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
aux prepare_dmeventd
aux prepare_vg 5
-lvcreate -m 3 --ig -L 1 -n 4way $vg
+lvcreate -aey --type mirror -m 3 --nosync --ignoremonitoring -l1 -n 4way $vg
lvchange --monitor y $vg/4way
-lvcreate -m 2 --ig -L 1 -n 3way $vg
+lvcreate -aey --type mirror -m 2 --nosync --ignoremonitoring -l1 -n 3way $vg
lvchange --monitor y $vg/3way
+lvcreate -aey -l1 -n $lv1 $vg
+lvcreate -s -l1 -n $lv2 $vg/$lv1
+
dmeventd -R -f &
echo $! >LOCAL_DMEVENTD
sleep 2 # wait a bit, so we talk to the new dmeventd later
+check lv_field $vg/3way seg_monitor "monitored"
+check lv_field $vg/4way seg_monitor "monitored"
lvchange --monitor y --verbose $vg/3way 2>&1 | tee lvchange.out
-grep 'already monitored' lvchange.out
+# only non-cluster tests can check command result
+test -e LOCAL_CLVMD || grep 'already monitored' lvchange.out
lvchange --monitor y --verbose $vg/4way 2>&1 | tee lvchange.out
-grep 'already monitored' lvchange.out
+test -e LOCAL_CLVMD || grep 'already monitored' lvchange.out
# now try what happens if no dmeventd is running
-kill -9 $(cat LOCAL_DMEVENTD)
-rm LOCAL_DMEVENTD
+kill -9 "$(< LOCAL_DMEVENTD)"
+rm LOCAL_DMEVENTD debug.log*
dmeventd -R -f &
echo $! >LOCAL_DMEVENTD
# wait longer as tries to communicate with killed daemon
-sleep 7
+sleep 9
# 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\""
+# First lvs restarts 'dmeventd' (initiate a socket connection to a daemon)
+check lv_field $vg/3way seg_monitor "not monitored"
+pgrep -o dmeventd >LOCAL_DMEVENTD
+check lv_field $vg/4way seg_monitor "not monitored"
+
lvchange --monitor y --verbose $vg/3way 2>&1 | tee lvchange.out
-pgrep dmeventd >LOCAL_DMEVENTD
-not grep 'already monitored' lvchange.out
+test -e LOCAL_CLVMD || not grep 'already monitored' lvchange.out
+
+lvchange --monitor y --verbose $vg/$lv2 2>&1 | tee lvchange.out
+test -e LOCAL_CLVMD || not grep 'already monitored' lvchange.out
vgremove -ff $vg
diff --git a/test/shell/dmsecuretest.sh b/test/shell/dmsecuretest.sh
new file mode 100644
index 0000000..609fc7c
--- /dev/null
+++ b/test/shell/dmsecuretest.sh
@@ -0,0 +1,77 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2018 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+# Test secure table is not leaking data in user land
+
+SKIP_WITH_LVMPOLLD=1
+SKIP_WITH_LVMLOCKD=1
+
+# AES key matching rot13 string from dmsecuretest.c */
+SECURE="434e0cbab02ca68ffba9268222c3789d703fe62427b78b308518b3228f6a2122"
+
+. lib/inittest
+
+DMTEST="${PREFIX}-test-secure"
+
+# Test needs installed gdb package with gcore app
+which gcore || skip
+
+aux driver_at_least 4 6 || skip
+
+# ensure we can create devices (uses dmsetup, etc)
+aux prepare_devs 1
+
+# check both code versions - linked libdm and internal device_mapper version
+# there should not be any difference
+for i in securetest dmsecuretest ; do
+
+# 1st. try with empty table
+# 2nd. retry with already exiting DM node - exercize error path also wipes
+for j in empty existing ; do
+
+"$i" "$dev1" "$DMTEST" >cmdout 2>&1 &
+PID=$!
+sleep .5
+
+# crypt device should be loaded
+dmsetup status "$DMTEST"
+
+# generate core file for running&sleeping binary
+gcore "$PID" | tee out || skip
+
+# check we capture core while dmsecuretest was already sleeping
+grep "nanosleep" out || grep kernel_vsyscall out
+kill "$PID" || true
+wait
+
+cat cmdout
+
+# $SECURE string must NOT be present in core file
+not grep "$SECURE" "core.$PID" || {
+ ## cp "core.$PID" /dev/shm/core
+ rm -f "core.$PID"
+ should dmsetup remove "$DMTEST" # go around weird bugs
+ die "!!! Secure string $SECURE found present in core.$PID !!!"
+}
+rm -f "core.$PID"
+
+if test "$j" = empty ; then
+ not grep "Device or resource busy" cmdout
+else
+ # Device should be already present resulting into error message
+ grep "Device or resource busy" cmdout
+ dmsetup remove "$DMTEST"
+fi
+
+done
+
+done
diff --git a/test/shell/dmsetup-integrity-keys.sh b/test/shell/dmsetup-integrity-keys.sh
new file mode 100644
index 0000000..cd98ead
--- /dev/null
+++ b/test/shell/dmsetup-integrity-keys.sh
@@ -0,0 +1,58 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2017 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+# unrelated to lvm2 daemons
+SKIP_WITH_LVMLOCKD=1
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+INTERNAL_HASH_CRYPT="hmac(sha256)"
+INTERNAL_HASH_NOCRYPT=crc32
+JOURNAL_CRYPT="ctr(aes)"
+HEXKEY_32=0102030405060708090a0102030405060102030405060708090a010203040506
+HEXKEY2_32=0102030405060708090a010203040b060102030405060708090a010203040506
+HIDENKEY_32=0000000000000000000000000000000000000000000000000000000000000000
+
+aux target_at_least dm-integrity 1 0 0 || skip "missing dm-integrity target"
+aux target_at_least dm-zero 1 0 0 || skip "missing dm-zero target"
+
+function _teardown() {
+ aux teardown_devs_prefixed "$PREFIX"
+}
+
+trap '_teardown' EXIT
+
+dmsetup create "$PREFIX-zero" --table "0 10000 zero"
+dmsetup create "$PREFIX-integrity" --table "0 7856 integrity $DM_DEV_DIR/mapper/$PREFIX-zero 0 32 J 7 journal_sectors:88 interleave_sectors:32768 buffer_sectors:128 journal_watermark:50 commit_time:10000 internal_hash:$INTERNAL_HASH_NOCRYPT journal_crypt:$JOURNAL_CRYPT:$HEXKEY_32"
+
+str=$(dmsetup table "$PREFIX-integrity" | cut -d ' ' -f 15)
+test "$str" = "journal_crypt:$JOURNAL_CRYPT:$HIDENKEY_32"
+str=$(dmsetup table --showkeys "$PREFIX-integrity" | cut -d ' ' -f 15)
+test "$str" = "journal_crypt:$JOURNAL_CRYPT:$HEXKEY_32"
+str=$(dmsetup table "$PREFIX-integrity" | cut -d ' ' -f 14)
+test "$str" = "internal_hash:$INTERNAL_HASH_NOCRYPT"
+
+dmsetup remove "$PREFIX-integrity"
+dmsetup create "$PREFIX-integrity" --table "0 7856 integrity $DM_DEV_DIR/mapper/$PREFIX-zero 0 32 J 7 journal_sectors:88 interleave_sectors:32768 buffer_sectors:128 journal_watermark:50 commit_time:10000 internal_hash:$INTERNAL_HASH_CRYPT:$HEXKEY2_32 journal_crypt:$JOURNAL_CRYPT:$HEXKEY_32"
+
+str=$(dmsetup table "$PREFIX-integrity" | cut -d ' ' -f 15)
+test "$str" = "journal_crypt:$JOURNAL_CRYPT:$HIDENKEY_32"
+str=$(dmsetup table --showkeys "$PREFIX-integrity" | cut -d ' ' -f 15)
+test "$str" = "journal_crypt:$JOURNAL_CRYPT:$HEXKEY_32"
+str=$(dmsetup table "$PREFIX-integrity" | cut -d ' ' -f 14)
+test "$str" = "internal_hash:$INTERNAL_HASH_CRYPT:$HIDENKEY_32"
+str=$(dmsetup table --showkeys "$PREFIX-integrity" | cut -d ' ' -f 14)
+test "$str" = "internal_hash:$INTERNAL_HASH_CRYPT:$HEXKEY2_32"
+
+dmsetup remove "$PREFIX-integrity"
+dmsetup remove "$PREFIX-zero"
diff --git a/test/shell/dmsetup-keyring.sh b/test/shell/dmsetup-keyring.sh
new file mode 100644
index 0000000..3c0b867
--- /dev/null
+++ b/test/shell/dmsetup-keyring.sh
@@ -0,0 +1,75 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2017 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+# unrelated to lvm2 daemons
+SKIP_WITH_LVMLOCKD=1
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+CIPHER=aes-xts-plain64
+HEXKEY_32=0102030405060708090a0102030405060102030405060708090a010203040506
+HIDENKEY_32=0000000000000000000000000000000000000000000000000000000000000000
+KEY_NAME="$PREFIX:keydesc"
+
+function _teardown() {
+ keyctl unlink "%:$PREFIX-keyring"
+ aux teardown_devs_prefixed "$PREFIX"
+}
+
+aux target_at_least dm-zero 1 0 0 || skip "missing dm-zero target"
+aux target_at_least dm-crypt 1 15 0 || skip "dm-crypt doesn't support keys in kernel keyring service"
+which keyctl || skip "test requires keyctl utility"
+
+keyctl new_session || true # fails with 'su', works with 'su -'
+keyctl newring "$PREFIX-keyring" @s
+keyctl timeout "%:$PREFIX-keyring" 60
+
+trap '_teardown' EXIT
+
+keyctl add logon "$KEY_NAME" "${HEXKEY_32:0:32}" "%:$PREFIX-keyring"
+
+dmsetup create "$PREFIX-zero" --table "0 1 zero"
+# put key in kernel keyring for active table
+dmsetup create "$PREFIX-crypt" --table "0 1 crypt $CIPHER :32:logon:$KEY_NAME 0 $DM_DEV_DIR/mapper/$PREFIX-zero 0"
+# put hexbyte key in dm-crypt directly in inactive table
+dmsetup load "$PREFIX-crypt" --table "0 1 crypt $CIPHER $HEXKEY_32 0 $DM_DEV_DIR/mapper/$PREFIX-zero 0"
+
+# test dmsetup doesn't hide key descriptions...
+str=$(dmsetup table "$PREFIX-crypt" | cut -d ' ' -f 5)
+test "$str" = ":32:logon:$KEY_NAME"
+str=$(dmsetup table --showkeys "$PREFIX-crypt" | cut -d ' ' -f 5)
+test "$str" = ":32:logon:$KEY_NAME"
+
+# ...but it hides hexbyte representation of keys...
+str=$(dmsetup table --inactive "$PREFIX-crypt" | cut -d ' ' -f 5)
+test "$str" = "$HIDENKEY_32"
+#...unless --showkeys explictly requested
+str=$(dmsetup table --showkeys --inactive "$PREFIX-crypt" | cut -d ' ' -f 5)
+test "$str" = "$HEXKEY_32"
+
+# let's swap the tables
+dmsetup resume "$PREFIX-crypt"
+dmsetup load "$PREFIX-crypt" --table "0 1 crypt $CIPHER :32:logon:$KEY_NAME 0 $DM_DEV_DIR/mapper/$PREFIX-zero 0"
+
+str=$(dmsetup table --inactive "$PREFIX-crypt" | cut -d ' ' -f 5)
+test "$str" = ":32:logon:$KEY_NAME"
+str=$(dmsetup table --showkeys --inactive "$PREFIX-crypt" | cut -d ' ' -f 5)
+test "$str" = ":32:logon:$KEY_NAME"
+
+str=$(dmsetup table "$PREFIX-crypt" | cut -d ' ' -f 5)
+test "$str" = "$HIDENKEY_32"
+str=$(dmsetup table --showkeys "$PREFIX-crypt" | cut -d ' ' -f 5)
+test "$str" = "$HEXKEY_32"
+
+dmsetup remove "$PREFIX-crypt"
+dmsetup remove "$PREFIX-zero"
diff --git a/test/shell/dmstats-create.sh b/test/shell/dmstats-create.sh
new file mode 100644
index 0000000..03406ae
--- /dev/null
+++ b/test/shell/dmstats-create.sh
@@ -0,0 +1,30 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2016 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+SKIP_WITH_LVMPOLLD=1
+SKIP_WITH_LVMLOCKD=1
+
+. lib/inittest
+
+# Don't attempt to test stats with driver < 4.33.00
+aux driver_at_least 4 33 || skip
+
+# ensure we can create devices (uses dmsetup, etc)
+aux prepare_devs 1
+
+# basic dmstats create commands
+
+dmstats create "$dev1"
+dmstats create --start 0 --len 1 "$dev1"
+dmstats create --segments "$dev1"
+dmstats create --precise "$dev1"
+dmstats create --bounds 10ms,20ms,30ms "$dev1"
diff --git a/test/shell/dmstats-report.sh b/test/shell/dmstats-report.sh
new file mode 100644
index 0000000..bd72f1a
--- /dev/null
+++ b/test/shell/dmstats-report.sh
@@ -0,0 +1,30 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2016 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+SKIP_WITH_LVMPOLLD=1
+SKIP_WITH_LVMLOCKD=1
+
+. lib/inittest
+
+# Don't attempt to test stats with driver < 4.33.00
+aux driver_at_least 4 33 || skip
+
+# ensure we can create devices (uses dmsetup, etc)
+aux prepare_devs 1
+
+# prepare a stats region with a histogram
+dmstats create --bounds 10ms,20ms,30ms "$dev1"
+
+# basic dmstats report commands
+dmstats report
+dmstats report --count 1
+dmstats report --histogram
diff --git a/test/shell/dumpconfig.sh b/test/shell/dumpconfig.sh
index a16f753..abd4b62 100644
--- a/test/shell/dumpconfig.sh
+++ b/test/shell/dumpconfig.sh
@@ -1,4 +1,5 @@
-#!/bin/sh
+#!/usr/bin/env bash
+
# Copyright (C) 2011 Red Hat, Inc. All rights reserved.
#
# This copyrighted material is made available to anyone wishing to use,
@@ -7,13 +8,16 @@
#
# 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
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+
+SKIP_WITH_LVMPOLLD=1
-. lib/test
+. lib/inittest
flatten() {
cat > flatten.config
- for s in `egrep '^[a-z]+ {$' flatten.config | sed -e s,{$,,`; do
+ for s in $(grep -E '^[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
}
diff --git a/test/shell/duplicate-pvs-md0.sh b/test/shell/duplicate-pvs-md0.sh
new file mode 100644
index 0000000..ea800cf
--- /dev/null
+++ b/test/shell/duplicate-pvs-md0.sh
@@ -0,0 +1,308 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2012-2021 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+SKIP_WITH_LVMPOLLD=1
+SKIP_WITH_LVMLOCKD=1
+
+RUNDIR="/run"
+test -d "$RUNDIR" || RUNDIR="/var/run"
+PVS_ONLINE_DIR="$RUNDIR/lvm/pvs_online"
+VGS_ONLINE_DIR="$RUNDIR/lvm/vgs_online"
+HINTS="$RUNDIR/lvm/hints"
+
+_clear_online_files() {
+ # wait till udev is finished
+ aux udev_wait
+ rm -f "$PVS_ONLINE_DIR"/* "$VGS_ONLINE_DIR"/*
+}
+
+. lib/inittest
+
+MD_LEVEL=${MD_LEVEL-0}
+
+aux prepare_devs 4 10
+
+# Create an unused PV so that there is at least one PV in the hints
+# when the MD dev is stopped. If there are no PVs, the hints are
+# empty, and the code falls back to scanning all, and we do not end
+# up testing the code with hints actively used.
+pvcreate "$dev3"
+
+## Test variations:
+# PV on md raid1|raid0, md_component_checks auto|start, mddev start|stopped,
+# one raid dev disabled when mddev is stopped.
+
+# LVM will ask udev if a dev is an md component, but we don't
+# want to rely on that ability in this test so stops lvm from
+# asking udev if a dev is an md component.
+aux lvmconf "devices/obtain_device_list_from_udev = 0" \
+ "devices/md_component_detection = 1" \
+ "devices/md_component_checks = \"auto\""
+
+aux extend_filter_md "a|/dev/md|"
+
+# Run in 2 passes - 1st. with "auto" 2nd. with "start" component checks
+for pass in "auto" "start" ; do
+
+##########################################
+# PV on an md raidX device
+# md_component_checks: auto|start (not start)
+# mddev: started (not stopped)
+#
+aux mdadm_create --metadata=1.0 --level="$MD_LEVEL" --chunk=64 --raid-devices=2 "$dev1" "$dev2"
+mddev=$(< MD_DEV)
+lvmdevices --adddev $mddev || true
+
+pvcreate "$mddev"
+PVIDMD=$(get pv_field "$mddev" uuid | tr -d - )
+vgcreate $vg "$mddev"
+lvcreate -n $lv1 -l 2 -an $vg
+
+# pvs shows only the md dev as PV
+pvs "$mddev"
+not pvs "$dev1"
+not pvs "$dev2"
+pvs | tee out
+grep "$mddev" out
+not grep "$dev1" out
+not grep "$dev2" out
+# N.B. in this case hints are disabled for duplicate pvs seen by scan
+# it would be preferrable if this didn't happen as in auto mode, but it's ok.
+test "$pass" = "auto" && grep "$mddev" "$HINTS"
+not grep "$dev1" "$HINTS"
+not grep "$dev2" "$HINTS"
+
+# normal activation works
+lvchange -ay $vg/$lv1
+check active $vg $lv1
+vgchange -an $vg
+
+# pvscan activation all works
+_clear_online_files
+pvscan --cache -aay
+test -e "$RUNDIR/lvm/pvs_online/$PVIDMD"
+test -e "$RUNDIR/lvm/vgs_online/$vg"
+check active $vg $lv1
+vgchange -an $vg
+
+# pvscan activation from mddev works
+_clear_online_files
+pvscan --cache -aay "$mddev"
+test -f "$RUNDIR/lvm/pvs_online/$PVIDMD"
+test -f "$RUNDIR/lvm/vgs_online/$vg"
+check active $vg $lv1
+vgchange -an $vg
+
+# pvscan activation from md components does nothing
+_clear_online_files
+pvscan --cache -aay "$dev1"
+test ! -f "$RUNDIR/lvm/pvs_online/$PVIDMD"
+test ! -f "$RUNDIR/lvm/vgs_online/$vg"
+
+if [ "$pass" = "auto" ] ; then
+ pvscan --cache -aay "$dev2"
+ test ! -f "$RUNDIR/lvm/pvs_online/$PVIDMD"
+ test ! -f "$RUNDIR/lvm/vgs_online/$vg"
+fi
+# N.B. with raid0 the component because the PV/size difference
+# triggers and md component check, whereas with raid1 it doesn't.
+check inactive $vg $lv1
+
+vgchange -an $vg
+vgremove -f $vg
+lvmdevices --deldev $mddev || true
+aux cleanup_md_dev
+
+
+##########################################
+# PV on an md raidX device
+# md_component_checks: auto|start
+# mddev: stopped (not started)
+#
+
+aux mdadm_create --metadata=1.0 --level="$MD_LEVEL" --chunk=64 --raid-devices=2 "$dev1" "$dev2"
+mddev=$(< MD_DEV)
+lvmdevices --adddev $mddev || true
+
+pvcreate "$mddev"
+PVIDMD=$(get pv_field "$mddev" uuid | tr -d - )
+vgcreate $vg "$mddev"
+lvcreate -n $lv1 -l 2 -an $vg
+
+mdadm --stop "$mddev"
+cat /proc/mdstat
+
+# pvs does not show the PV
+not pvs "$mddev"
+not pvs "$dev1"
+not pvs "$dev2"
+pvs | tee out
+not grep "$mddev" out
+# N.B. it would be preferrable if dev1 did not appear in hints but it's ok
+# not grep "$dev1" $HINTS
+not grep "$dev1" out
+not grep "$dev2" out
+pvscan --cache
+not grep "$mddev" "$HINTS"
+not grep "$dev1" "$HINTS"
+not grep "$dev2" "$HINTS"
+
+# the vg is not seen, normal activation does nothing
+not lvchange -ay $vg/$lv1
+not lvs $vg
+
+# pvscan activation all does nothing
+_clear_online_files
+pvscan --cache -aay
+test ! -f "$RUNDIR/lvm/pvs_online/$PVIDMD"
+test ! -f "$RUNDIR/lvm/vgs_online/$vg"
+
+# pvscan activation from md components does nothing
+_clear_online_files
+pvscan --cache -aay "$dev1"
+test ! -f "$RUNDIR/lvm/pvs_online/$PVIDMD"
+test ! -f "$RUNDIR/lvm/vgs_online/$vg"
+pvscan --cache -aay "$dev2"
+test ! -f "$RUNDIR/lvm/pvs_online/$PVIDMD"
+test ! -f "$RUNDIR/lvm/vgs_online/$vg"
+
+#lvs -o active $vg |tee out || true
+#not grep "active" out
+
+aux wipefs_a "$dev1" "$dev2"
+
+##########################################
+# PV on an md raidX device
+# md_component_checks: auto|start
+# mddev: stopped (not started)
+# only one raid dev online
+#
+
+aux mdadm_create --metadata=1.0 --level="$MD_LEVEL" --chunk=64 --raid-devices=2 "$dev1" "$dev2"
+mddev=$(< MD_DEV)
+lvmdevices --adddev $mddev || true
+
+pvcreate "$mddev"
+PVIDMD=$(get pv_field "$mddev" uuid | tr -d - )
+vgcreate $vg "$mddev"
+lvcreate -n $lv1 -l 2 -an $vg
+
+mdadm --stop "$mddev"
+cat /proc/mdstat
+
+# disable one leg
+aux disable_dev "$dev2"
+
+# pvs does not show the PV
+not pvs "$mddev"
+not pvs "$dev1"
+not pvs "$dev2"
+pvs | tee out
+not grep "$mddev" out
+not grep "$dev1" out
+not grep "$dev2" out
+pvscan --cache
+not grep "$mddev" "$HINTS"
+# N.B. would be preferrable for this md component to not be in hints
+# grep "$dev1" $HINTS
+not grep "$dev1" "$HINTS"
+not grep "$dev2" "$HINTS"
+
+# the vg is not seen, normal activation does nothing
+not lvchange -ay $vg/$lv1
+not lvs $vg
+
+# pvscan activation all does nothing
+_clear_online_files
+pvscan --cache -aay
+test ! -f "$RUNDIR/lvm/pvs_online/$PVIDMD"
+test ! -f "$RUNDIR/lvm/vgs_online/$vg"
+
+# pvscan activation from md components does nothing
+_clear_online_files
+pvscan --cache -aay "$dev1"
+test ! -f "$RUNDIR/lvm/pvs_online/$PVIDMD"
+test ! -f "$RUNDIR/lvm/vgs_online/$vg"
+pvscan --cache -aay "$dev2"
+test ! -f "$RUNDIR/lvm/pvs_online/$PVIDMD"
+test ! -f "$RUNDIR/lvm/vgs_online/$vg"
+
+aux enable_dev "$dev2"
+lvmdevices --deldev $mddev || true
+aux cleanup_md_dev
+
+aux wipefs_a "$dev1" "$dev2"
+
+if [ "$MD_LEVEL" = "1" ] ; then
+##########################################
+# PV on an md raid1 device, auto+stopped
+# md_component_checks: auto|start
+# mddev: stopped (not started)
+# three raid images
+#
+aux mdadm_create --metadata=1.0 --level="$MD_LEVEL" --chunk=64 --raid-devices=3 "$dev1" "$dev2" "$dev4"
+mddev=$(< MD_DEV)
+lvmdevices --adddev $mddev || true
+
+pvcreate "$mddev"
+PVIDMD=$(get pv_field "$mddev" uuid | tr -d - )
+vgcreate $vg "$mddev"
+lvcreate -n $lv1 -l 2 -an $vg
+
+mdadm --stop "$mddev"
+cat /proc/mdstat
+
+# pvs does not show the PV
+not pvs "$mddev"
+not pvs "$dev1"
+not pvs "$dev2"
+not pvs "$dev4"
+pvs | tee out
+not grep "$mddev" out
+not grep "$dev1" out
+not grep "$dev2" out
+not grep "$dev4" out
+pvscan --cache
+not grep "$mddev" "$HINTS"
+not grep "$dev1" "$HINTS"
+not grep "$dev2" "$HINTS"
+not grep "$dev4" "$HINTS"
+
+# the vg is not seen, normal activation does nothing
+not lvchange -ay $vg/$lv1
+not lvs $vg
+
+# pvscan activation all does nothing
+_clear_online_files
+pvscan --cache -aay
+test ! -f "$RUNDIR/lvm/pvs_online/$PVIDMD"
+test ! -f "$RUNDIR/lvm/vgs_online/$vg"
+
+# pvscan activation from md components does nothing
+_clear_online_files
+pvscan --cache -aay "$dev1"
+test ! -f "$RUNDIR/lvm/pvs_online/$PVIDMD"
+test ! -f "$RUNDIR/lvm/vgs_online/$vg"
+pvscan --cache -aay "$dev2"
+test ! -f "$RUNDIR/lvm/pvs_online/$PVIDMD"
+test ! -f "$RUNDIR/lvm/vgs_online/$vg"
+pvscan --cache -aay "$dev4"
+test ! -f "$RUNDIR/lvm/pvs_online/$PVIDMD"
+test ! -f "$RUNDIR/lvm/vgs_online/$vg"
+
+aux wipefs_a "$dev1" "$dev2" "$dev4"
+fi # MD_LEVEL == 1
+
+# next loop with 'start'
+test "$pass" != "auto" || aux lvmconf "devices/md_component_checks = \"start\""
+
+done
diff --git a/test/shell/duplicate-pvs-md1.sh b/test/shell/duplicate-pvs-md1.sh
new file mode 100644
index 0000000..e896c10
--- /dev/null
+++ b/test/shell/duplicate-pvs-md1.sh
@@ -0,0 +1,21 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2012-2021 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+# . different PV/VG's that happen to have the same PVID
+# . a single PV/VG cloned to another device
+# . dm wrapper around a PV
+# . a single PV/VG cloned plus a dm wrapper (two separate dups of a PV)
+
+
+# Reuse same test just use raid level 1
+export MD_LEVEL=1
+. ./shell/duplicate-pvs-md0.sh
diff --git a/test/shell/duplicate-pvs-multipath.sh b/test/shell/duplicate-pvs-multipath.sh
new file mode 100644
index 0000000..bc98d2d
--- /dev/null
+++ b/test/shell/duplicate-pvs-multipath.sh
@@ -0,0 +1,71 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2021 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+test_description='duplicate pv detection of mpath components using wwid'
+
+SKIP_WITH_LVMPOLLD=1
+SKIP_WITH_LVMLOCKD=1
+
+. lib/inittest
+
+# FIXME: skip until mpath/scsi_debug cleanup works after a failure
+skip
+
+modprobe --dry-run scsi_debug || skip
+multipath -l || skip
+multipath -l | grep scsi_debug && skip
+
+# FIXME: setting multipath_component_detection=0 now also disables
+# the wwid-based mpath component detection, so this test will need
+# to find another way to disable only the filter-mpath code (using
+# sysfs and multipath/wwids) while keeping the code enabled that
+# eliminates duplicates based on their matching wwids which this
+# tries to test.
+
+# Prevent wwids from being used for filtering.
+aux lvmconf 'devices/multipath_wwids_file = "/dev/null"'
+# Need to use /dev/mapper/mpath
+aux lvmconf 'devices/dir = "/dev"'
+aux lvmconf 'devices/scan = "/dev"'
+# Could set filter to $MP and the component /dev/sd devs
+aux lvmconf "devices/filter = [ \"a|.*|\" ]"
+aux lvmconf "devices/global_filter = [ \"a|.*|\" ]"
+
+modprobe scsi_debug dev_size_mb=100 num_tgts=1 vpd_use_hostno=0 add_host=4 delay=20 max_luns=2 no_lun_0=1
+sleep 2
+
+multipath -r
+sleep 2
+
+MPB=$(multipath -l | grep scsi_debug | cut -f1 -d ' ')
+echo $MPB
+MP=/dev/mapper/$MPB
+echo $MP
+
+pvcreate $MP
+vgcreate $vg1 $MP
+lvcreate -l1 $vg1
+vgchange -an $vg1
+
+pvs |tee out
+grep $MP out
+for i in $(grep -H scsi_debug /sys/block/sd*/device/model | cut -f4 -d /); do
+ not grep /dev/$i out;
+done
+
+vgchange -an $vg1
+vgremove -y $vg1
+
+sleep 2
+multipath -f $MP
+sleep 1
+rmmod scsi_debug
diff --git a/test/shell/duplicate-vgid.sh b/test/shell/duplicate-vgid.sh
new file mode 100644
index 0000000..12163c2
--- /dev/null
+++ b/test/shell/duplicate-vgid.sh
@@ -0,0 +1,52 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2008-2013 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.
+
+SKIP_WITH_LVMLOCKD=1
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+aux prepare_devs 2
+
+vgcreate $vg1 "$dev1"
+vgchange --setautoactivation n $vg1
+UUID1=$(vgs --noheading -o vg_uuid $vg1 | xargs)
+lvcreate -l1 -an -n $lv1 $vg1
+dd if="$dev1" of="$dev2" bs=1M count=1
+aux disable_dev "$dev1"
+vgrename $vg1 $vg2
+pvchange -u "$dev2"
+aux enable_dev "$dev1"
+
+vgs -o+uuid |tee out
+grep $vg1 out | tee out1
+grep $UUID1 out1
+grep $vg2 out | tee out2
+grep $UUID1 out2
+
+vgs $vg1
+vgs $vg2
+lvs $vg1/$lv1
+lvs $vg2/$lv1
+
+lvremove $vg1/$lv1
+lvremove $vg2/$lv1
+
+lvcreate -l1 -an -n $lv2 $vg1
+lvcreate -l1 -an -n $lv3 $vg2
+
+vgchange -u $vg2
+
+vgs -o uuid $vg1 |tee out
+grep $UUID1 out
+
+vgs -o uuid $vg2 |tee out
+not grep $UUID1 out
+
+vgremove -ff $vg1
+vgremove -ff $vg2
diff --git a/test/shell/duplicate-vgnames.sh b/test/shell/duplicate-vgnames.sh
new file mode 100644
index 0000000..b3f2c43
--- /dev/null
+++ b/test/shell/duplicate-vgnames.sh
@@ -0,0 +1,624 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2008-2013 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.
+
+SKIP_WITH_LVMLOCKD=1
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+aux prepare_devs 7
+
+# test setups:
+# # local vgs named foo # foreign vg named foo
+# a. 0 1
+# b. 0 2
+# c. 1 1
+# d. 1 2
+# e. 2 0
+# f. 2 1
+# g. 2 2
+# h. 3 3
+#
+# commands to run for each test setup:
+#
+# vgs
+# all cases show all local
+#
+# vgs --foreign
+# all cases show all local and foreign
+#
+# vgs foo
+# a. not found
+# b. not found
+# c. show 1 local
+# d. show 1 local
+# e-g. dup error
+#
+# vgs --foreign foo
+# a. show 1 foreign
+# b. dup error
+# c. show 1 local
+# d. show 1 local
+# e-g. dup error
+#
+# vgchange -ay
+# a. none
+# b. none
+# c. activate 1 local
+# d. activate 1 local
+# e-g. activate 2 local
+# (if both local vgs have lvs with same name the second will fail to activate)
+#
+# vgchange -ay foo
+# a. none
+# b. none
+# c. activate 1 local
+# d. activate 1 local
+# e-g. dup error
+#
+# lvcreate foo
+# a. none
+# b. none
+# c. create 1 local
+# d. create 1 local
+# e-g. dup error
+#
+# vgremove foo
+# a. none
+# b. none
+# c. remove 1 local
+# d. remove 1 local
+# e-g. dup error
+# (in a couple cases test that vgremove -S vg_uuid=N works for local vg when local dups exist)
+
+
+# a. 0 local, 1 foreign
+# setup
+vgcreate $vg1 "$dev1"
+lvcreate -n $lv1 -l1 -an $vg1
+UUID1=$(vgs --noheading -o vg_uuid $vg1 | xargs)
+vgchange -y --systemid "other" $vg1
+
+vgs -o+uuid |tee out
+not grep $vg1 out
+vgs --foreign -o+uuid |tee out
+grep $vg1 out
+grep $UUID1 out
+
+not vgs -o+uuid $vg1 |tee out
+not grep $vg1 out
+vgs --foreign -o+uuid $vg1 |tee out
+grep $vg1 out
+
+vgchange -ay
+lvs --foreign -o vguuid,active |tee out
+not grep active out
+vgchange -an
+
+not vgchange -ay $vg1
+lvs --foreign -o vguuid,active |tee out
+not grep active out
+vgchange -an
+
+not lvcreate -l1 -an -n $lv2 $vg1
+lvs --foreign -o vguuid,name |tee out
+grep $UUID1 out | not grep $lv2
+
+not vgremove $vg1
+vgs --foreign -o+uuid |tee out
+grep $UUID1 out
+vgremove -y -S vg_uuid=$UUID1
+vgs --foreign -o+uuid |tee out
+grep $UUID1 out
+
+aux wipefs_a "$dev1" "$dev2"
+
+# b. 0 local, 2 foreign
+# setup
+vgcreate $vg1 "$dev1"
+lvcreate -n $lv1 -l1 -an $vg1
+UUID1=$(vgs --noheading -o vg_uuid $vg1 | xargs)
+vgchange -y --systemid "other" $vg1
+aux disable_dev "$dev1"
+vgcreate $vg1 "$dev2"
+lvcreate -n $lv1 -l1 -an $vg1
+UUID2=$(vgs --noheading -o vg_uuid $vg1 | xargs)
+vgchange -y --systemid "other2" $vg1
+aux enable_dev "$dev1"
+
+vgs -o+uuid |tee out
+not grep $vg1 out
+vgs --foreign -o+uuid |tee out
+grep $vg1 out
+grep $UUID1 out
+grep $UUID2 out
+
+not vgs -o+uuid $vg1 |tee out
+not grep $vg1 out
+not vgs --foreign -o+uuid $vg1 |tee out
+not grep $vg1 out
+
+vgchange -ay
+lvs --foreign -o vguuid,active |tee out
+not grep active out
+vgchange -an
+
+not vgchange -ay $vg1
+lvs --foreign -o vguuid,active |tee out
+not grep active out
+vgchange -an
+
+not lvcreate -l1 -an -n $lv2 $vg1
+lvs --foreign -o vguuid,name |tee out
+grep $UUID1 out | not grep $lv2
+grep $UUID2 out | not grep $lv2
+
+not vgremove $vg1
+vgs --foreign -o+uuid |tee out
+grep $UUID1 out
+
+aux wipefs_a "$dev1" "$dev2" "$dev3"
+
+# c. 1 local, 1 foreign
+# setup
+vgcreate $vg1 "$dev1"
+lvcreate -n $lv1 -l1 -an $vg1
+UUID1=$(vgs --noheading -o vg_uuid $vg1 | xargs)
+aux disable_dev "$dev1"
+vgcreate $vg1 "$dev2"
+lvcreate -n $lv1 -l1 -an $vg1
+UUID2=$(vgs --noheading -o vg_uuid $vg1 | xargs)
+vgchange -y --systemid "other" $vg1
+aux enable_dev "$dev1"
+
+vgs -o+uuid |tee out
+cat out
+grep $vg1 out
+grep $UUID1 out
+not grep $UUID2 out
+vgs --foreign -o+uuid |tee out
+grep $vg1 out
+grep $UUID1 out
+grep $UUID2 out
+
+vgs -o+uuid $vg1 |tee out
+grep $vg1 out
+grep $UUID1 out
+not grep $UUID2 out
+vgs --foreign -o+uuid $vg1 |tee out
+grep $vg1 out
+grep $UUID1 out
+not grep $UUID2 out
+
+vgchange -ay
+lvs --foreign -o vguuid,active |tee out
+grep $UUID1 out | grep active
+grep $UUID2 out | not grep active
+vgchange -an
+
+vgchange -ay $vg1
+lvs --foreign -o vguuid,active |tee out
+grep $UUID1 out | grep active
+grep $UUID2 out | not grep active
+vgchange -an
+
+lvcreate -l1 -an -n $lv2 $vg1
+lvs --foreign -o vguuid,name |tee out
+grep $UUID1 out | grep $lv2
+grep $UUID2 out | not grep $lv2
+
+vgremove -y $vg1
+vgs -o+uuid |tee out
+not grep $UUID1 out
+vgs --foreign -o+uuid |tee out
+grep $UUID2 out
+
+aux wipefs_a "$dev1" "$dev2" "$dev3"
+
+# d. 1 local, 2 foreign
+# setup
+vgcreate $vg1 "$dev1"
+lvcreate -n $lv1 -l1 -an $vg1
+UUID1=$(vgs --noheading -o vg_uuid $vg1 | xargs)
+aux disable_dev "$dev1"
+vgcreate $vg1 "$dev2"
+lvcreate -n $lv1 -l1 -an $vg1
+UUID2=$(vgs --noheading -o vg_uuid $vg1 | xargs)
+vgchange -y --systemid "other" $vg1
+aux disable_dev "$dev2"
+vgcreate $vg1 "$dev3"
+lvcreate -n $lv1 -l1 -an $vg1
+UUID3=$(vgs --noheading -o vg_uuid $vg1 | xargs)
+vgchange -y --systemid "other2" $vg1
+aux enable_dev "$dev1" "$dev2"
+
+vgs -o+uuid |tee out
+grep $vg1 out
+grep $UUID1 out
+not grep $UUID2 out
+not grep $UUID3 out
+vgs --foreign -o+uuid |tee out
+grep $vg1 out
+grep $UUID1 out
+grep $UUID2 out
+grep $UUID3 out
+
+vgs -o+uuid $vg1 |tee out
+grep $vg1 out
+grep $UUID1 out
+not grep $UUID2 out
+not grep $UUID3 out
+vgs --foreign -o+uuid $vg1 |tee out
+grep $vg1 out
+grep $UUID1 out
+not grep $UUID2 out
+not grep $UUID3 out
+
+vgchange -ay
+lvs --foreign -o vguuid,active |tee out
+grep $UUID1 out | grep active
+grep $UUID2 out | not grep active
+grep $UUID3 out | not grep active
+vgchange -an
+
+vgchange -ay $vg1
+lvs --foreign -o vguuid,active |tee out
+grep $UUID1 out | grep active
+grep $UUID2 out | not grep active
+grep $UUID3 out | not grep active
+vgchange -an
+
+lvcreate -l1 -an -n $lv2 $vg1
+lvs --foreign -o vguuid,name |tee out
+grep $UUID1 out | grep $lv2
+grep $UUID2 out | not grep $lv2
+grep $UUID3 out | not grep $lv2
+
+vgremove -y $vg1
+vgs -o+uuid |tee out
+not grep $UUID1 out
+vgs --foreign -o+uuid |tee out
+grep $UUID2 out
+grep $UUID3 out
+
+aux wipefs_a "$dev1" "$dev2" "$dev3" "$dev4"
+
+# e. 2 local, 0 foreign
+# setup
+vgcreate $vg1 "$dev1"
+lvcreate -n $lv1 -l1 -an $vg1
+UUID1=$(vgs --noheading -o vg_uuid $vg1 | xargs)
+aux disable_dev "$dev1"
+vgcreate $vg1 "$dev2"
+# diff lvname to prevent clash in vgchange -ay
+lvcreate -n ${lv1}_b -l1 -an $vg1
+UUID2=$(vgs --noheading -o vg_uuid $vg1 | xargs)
+aux enable_dev "$dev1"
+
+vgs -o+uuid |tee out
+grep $vg1 out
+grep $UUID1 out
+grep $UUID2 out
+vgs --foreign -o+uuid |tee out
+grep $vg1 out
+grep $UUID1 out
+grep $UUID2 out
+
+not vgs -o+uuid $vg1 |tee out
+not grep $vg1 out
+not vgs --foreign -o+uuid $vg1 |tee out
+not grep $vg1 out
+
+vgchange -ay
+lvs --foreign -o vguuid,active |tee out
+grep $UUID1 out | grep active
+grep $UUID2 out | grep active
+vgchange -an
+
+not vgchange -ay $vg1
+lvs --foreign -o vguuid,active |tee out
+grep $UUID1 out | not grep active
+grep $UUID2 out | not grep active
+vgchange -an
+
+not lvcreate -l1 -an -n $lv2 $vg1
+lvs --foreign -o vguuid,name |tee out
+grep $UUID1 out | not grep $lv2
+grep $UUID2 out | not grep $lv2
+
+not vgremove $vg1
+vgs -o+uuid |tee out
+grep $vg1 out
+grep $UUID1 out
+grep $UUID2 out
+vgremove -y -S vg_uuid=$UUID1
+vgs -o+uuid |tee out
+not grep $UUID1 out
+grep $UUID2 out
+vgremove -y -S vg_uuid=$UUID2
+vgs -o+uuid |tee out
+not grep $UUID1 out
+not grep $UUID2 out
+
+aux wipefs_a "$dev1" "$dev2" "$dev3"
+
+# f. 2 local, 1 foreign
+# setup
+vgcreate $vg1 "$dev1"
+lvcreate -n $lv1 -l1 -an $vg1
+UUID1=$(vgs --noheading -o vg_uuid $vg1 | xargs)
+aux disable_dev "$dev1"
+vgcreate $vg1 "$dev2"
+# diff lvname to prevent clash in vgchange -ay
+lvcreate -n ${lv1}_b -l1 -an $vg1
+UUID2=$(vgs --noheading -o vg_uuid $vg1 | xargs)
+aux disable_dev "$dev2"
+vgcreate $vg1 "$dev3"
+lvcreate -n $lv1 -l1 -an $vg1
+UUID3=$(vgs --noheading -o vg_uuid $vg1 | xargs)
+vgchange -y --systemid "other" $vg1
+aux enable_dev "$dev1" "$dev2"
+
+vgs -o+uuid |tee out
+grep $vg1 out
+grep $UUID1 out
+grep $UUID2 out
+not group $UUID3 out
+vgs --foreign -o+uuid |tee out
+grep $vg1 out
+grep $UUID1 out
+grep $UUID2 out
+grep $UUID3 out
+
+not vgs -o+uuid $vg1 |tee out
+not grep $vg1 out
+not vgs --foreign -o+uuid $vg1 |tee out
+not grep $vg1 out
+
+vgchange -ay
+lvs --foreign -o vguuid,active |tee out
+grep $UUID1 out | grep active
+grep $UUID2 out | grep active
+grep $UUID3 out | not grep active
+vgchange -an
+
+not vgchange -ay $vg1
+lvs --foreign -o vguuid,active |tee out
+grep $UUID1 out | not grep active
+grep $UUID2 out | not grep active
+grep $UUID3 out | not grep active
+vgchange -an
+
+not lvcreate -l1 -an -n $lv2 $vg1
+lvs --foreign -o vguuid,name |tee out
+grep $UUID1 out | not grep $lv2
+grep $UUID2 out | not grep $lv2
+grep $UUID3 out | not grep $lv2
+
+not vgremove $vg1
+vgs --foreign -o+uuid |tee out
+grep $vg1 out
+grep $UUID1 out
+grep $UUID2 out
+grep $UUID3 out
+vgremove -y -S vg_uuid=$UUID1
+vgs --foreign -o+uuid |tee out
+not grep $UUID1 out
+grep $UUID2 out
+grep $UUID3 out
+vgremove -y -S vg_uuid=$UUID2
+vgs --foreign -o+uuid |tee out
+not grep $UUID1 out
+not grep $UUID2 out
+grep $UUID3 out
+
+aux wipefs_a "$dev1" "$dev2" "$dev3" "$dev4"
+
+# g. 2 local, 2 foreign
+# setup
+vgcreate $vg1 "$dev1"
+lvcreate -n $lv1 -l1 -an $vg1
+UUID1=$(vgs --noheading -o vg_uuid $vg1 | xargs)
+aux disable_dev "$dev1"
+vgcreate $vg1 "$dev2"
+# diff lvname to prevent clash in vgchange -ay
+lvcreate -n ${lv1}_b -l1 -an $vg1
+UUID2=$(vgs --noheading -o vg_uuid $vg1 | xargs)
+aux disable_dev "$dev2"
+vgcreate $vg1 "$dev3"
+lvcreate -n $lv1 -l1 -an $vg1
+UUID3=$(vgs --noheading -o vg_uuid $vg1 | xargs)
+vgchange -y --systemid "other" $vg1
+aux disable_dev "$dev3"
+vgcreate $vg1 "$dev4"
+lvcreate -n $lv1 -l1 -an $vg1
+UUID4=$(vgs --noheading -o vg_uuid $vg1 | xargs)
+vgchange -y --systemid "other2" $vg1
+aux enable_dev "$dev1" "$dev2" "$dev3"
+
+vgs -o+uuid |tee out
+grep $vg1 out
+grep $UUID1 out
+grep $UUID2 out
+not group $UUID3 out
+not group $UUID4 out
+vgs --foreign -o+uuid |tee out
+grep $vg1 out
+grep $UUID1 out
+grep $UUID2 out
+grep $UUID3 out
+grep $UUID4 out
+
+not vgs -o+uuid $vg1 |tee out
+not grep $vg1 out
+not vgs --foreign -o+uuid $vg1 |tee out
+not grep $vg1 out
+
+vgchange -ay
+lvs --foreign -o vguuid,active |tee out
+grep $UUID1 out | grep active
+grep $UUID2 out | grep active
+grep $UUID3 out | not grep active
+grep $UUID4 out | not grep active
+vgchange -an
+
+not vgchange -ay $vg1
+lvs --foreign -o vguuid,active |tee out
+grep $UUID1 out | not grep active
+grep $UUID2 out | not grep active
+grep $UUID3 out | not grep active
+grep $UUID4 out | not grep active
+vgchange -an
+
+not lvcreate -l1 -an -n $lv2 $vg1
+lvs --foreign -o vguuid,name |tee out
+grep $UUID1 out | not grep $lv2
+grep $UUID2 out | not grep $lv2
+grep $UUID3 out | not grep $lv2
+grep $UUID4 out | not grep $lv2
+
+not vgremove $vg1
+vgs --foreign -o+uuid |tee out
+grep $vg1 out
+grep $UUID1 out
+grep $UUID2 out
+grep $UUID3 out
+grep $UUID4 out
+
+aux wipefs_a "$dev1" "$dev2" "$dev3" "$dev4" "$dev5"
+
+# h. 3 local, 3 foreign
+# setup
+vgcreate $vg1 "$dev1"
+lvcreate -n $lv1 -l1 -an $vg1
+UUID1=$(vgs --noheading -o vg_uuid $vg1 | xargs)
+aux disable_dev "$dev1"
+vgcreate $vg1 "$dev2"
+# diff lvname to prevent clash in vgchange -ay
+lvcreate -n ${lv1}_b -l1 -an $vg1
+UUID2=$(vgs --noheading -o vg_uuid $vg1 | xargs)
+aux disable_dev "$dev2"
+vgcreate $vg1 "$dev3"
+# diff lvname to prevent clash in vgchange -ay
+lvcreate -n ${lv1}_bb -l1 -an $vg1
+UUID3=$(vgs --noheading -o vg_uuid $vg1 | xargs)
+aux disable_dev "$dev3"
+vgcreate $vg1 "$dev4"
+lvcreate -n $lv1 -l1 -an $vg1
+UUID4=$(vgs --noheading -o vg_uuid $vg1 | xargs)
+vgchange -y --systemid "other" $vg1
+aux disable_dev "$dev4"
+vgcreate $vg1 "$dev5"
+lvcreate -n $lv1 -l1 -an $vg1
+UUID5=$(vgs --noheading -o vg_uuid $vg1 | xargs)
+vgchange -y --systemid "other2" $vg1
+aux disable_dev "$dev5"
+vgcreate $vg1 "$dev6"
+lvcreate -n $lv1 -l1 -an $vg1
+UUID6=$(vgs --noheading -o vg_uuid $vg1 | xargs)
+vgchange -y --systemid "other3" $vg1
+aux enable_dev "$dev1" "$dev2" "$dev3" "$dev4" "$dev5"
+
+vgs -o+uuid |tee out
+grep $vg1 out
+grep $UUID1 out
+grep $UUID2 out
+grep $UUID3 out
+not group $UUID4 out
+not group $UUID5 out
+not group $UUID6 out
+vgs --foreign -o+uuid |tee out
+grep $vg1 out
+grep $UUID1 out
+grep $UUID2 out
+grep $UUID3 out
+grep $UUID4 out
+grep $UUID5 out
+grep $UUID6 out
+
+not vgs -o+uuid $vg1 |tee out
+not grep $vg1 out
+not vgs --foreign -o+uuid $vg1 |tee out
+not grep $vg1 out
+
+vgchange -ay
+lvs --foreign -o vguuid,active |tee out
+grep $UUID1 out | grep active
+grep $UUID2 out | grep active
+grep $UUID3 out | grep active
+grep $UUID4 out | not grep active
+grep $UUID5 out | not grep active
+grep $UUID6 out | not grep active
+vgchange -an
+
+not vgchange -ay $vg1
+lvs --foreign -o vguuid,active |tee out
+grep $UUID1 out | not grep active
+grep $UUID2 out | not grep active
+grep $UUID3 out | not grep active
+grep $UUID4 out | not grep active
+grep $UUID5 out | not grep active
+grep $UUID6 out | not grep active
+vgchange -an
+
+not lvcreate -l1 -an -n $lv2 $vg1
+lvs --foreign -o vguuid,name |tee out
+grep $UUID1 out | not grep $lv2
+grep $UUID2 out | not grep $lv2
+grep $UUID3 out | not grep $lv2
+grep $UUID4 out | not grep $lv2
+grep $UUID5 out | not grep $lv2
+grep $UUID6 out | not grep $lv2
+
+not vgremove $vg1
+vgs --foreign -o+uuid |tee out
+grep $vg1 out
+grep $UUID1 out
+grep $UUID2 out
+grep $UUID3 out
+grep $UUID4 out
+grep $UUID5 out
+grep $UUID6 out
+
+aux wipefs_a "$dev1" "$dev2" "$dev3" "$dev4" "$dev5" "$dev6"
+
+# vgreduce test with 1 local and 1 foreign vg.
+# setup
+vgcreate $vg1 "$dev1" "$dev7"
+lvcreate -n $lv1 -l1 -an $vg1 "$dev1"
+UUID1=$(vgs --noheading -o vg_uuid $vg1 | xargs)
+PV1UUID=$(pvs --noheading -o uuid "$dev1")
+PV7UUID=$(pvs --noheading -o uuid "$dev7")
+aux disable_dev "$dev1" "$dev7"
+vgcreate $vg1 "$dev2"
+PV2UUID=$(pvs --noheading -o uuid "$dev2")
+lvcreate -n $lv1 -l1 -an $vg1
+UUID2=$(vgs --noheading -o vg_uuid $vg1 | xargs)
+vgchange -y --systemid "other" $vg1
+aux enable_dev "$dev1" "$dev7"
+
+vgs --foreign -o+uuid |tee out
+grep $vg1 out
+grep $UUID1 out
+grep $UUID2 out
+pvs --foreign -o+uuid |tee out
+grep $PV1UUID out
+grep $PV7UUID out
+grep $PV2UUID out
+
+vgreduce $vg1 "$dev7"
+
+pvs --foreign -o+uuid |tee out
+grep $PV1UUID out
+grep $PV7UUID out
+grep $PV2UUID out
+
+grep $PV7UUID out >out2
+not grep $vg1 out2
+
+vgremove -ff $vg1
diff --git a/test/shell/duplicate-vgrename.sh b/test/shell/duplicate-vgrename.sh
new file mode 100644
index 0000000..2d6f169
--- /dev/null
+++ b/test/shell/duplicate-vgrename.sh
@@ -0,0 +1,304 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2008-2013 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.
+
+SKIP_WITH_LVMLOCKD=1
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+aux prepare_devs 4
+
+# a. 0 local, 1 foreign
+# setup
+vgcreate $vg1 "$dev1"
+lvcreate -n $lv1 -l1 -ky -an $vg1
+UUID1=$(vgs --noheading -o vg_uuid $vg1 | xargs)
+vgchange -y --systemid "other" $vg1
+
+not vgrename $vg1 $vg2
+vgs --foreign -o+uuid |tee out
+grep $UUID1 out
+not vgrename $UUID1 $vg2
+vgs --foreign -o+uuid |tee out
+grep $UUID1 out
+
+lvs --foreign
+
+aux wipefs_a "$dev1"
+
+# b. 0 local, 2 foreign
+# setup
+vgcreate $vg1 "$dev1"
+lvcreate -n $lv1 -l1 -ky -an $vg1
+UUID1=$(vgs --noheading -o vg_uuid $vg1 | xargs)
+vgchange -y --systemid "other" $vg1
+aux disable_dev "$dev1"
+vgcreate $vg1 "$dev2"
+lvcreate -n $lv1 -l1 -ky -an $vg1
+UUID2=$(vgs --noheading -o vg_uuid $vg1 | xargs)
+vgchange -y --systemid "other2" $vg1
+aux enable_dev "$dev1"
+
+not vgrename $vg1 $vg2
+vgs --foreign -o+uuid |tee out
+lvs --foreign
+grep $vg1 out
+not grep $vg2 out
+grep $UUID1 out
+grep $UUID2 out
+not vgrename $UUID1 $vg2
+vgs --foreign -o+uuid |tee out
+lvs --foreign
+grep $vg1 out
+not grep $vg2 out
+grep $UUID1 out
+grep $UUID2 out
+
+lvs --foreign
+
+aux wipefs_a "$dev1" "$dev2"
+
+# c. 1 local, 1 foreign
+# setup
+vgcreate $vg1 "$dev1"
+lvcreate -n $lv1 -l1 -ky -an $vg1
+UUID1=$(vgs --noheading -o vg_uuid $vg1 | xargs)
+aux disable_dev "$dev1"
+vgcreate $vg1 "$dev2"
+lvcreate -n $lv1 -l1 -ky -an $vg1
+UUID2=$(vgs --noheading -o vg_uuid $vg1 | xargs)
+vgchange -y --systemid "other" $vg1
+aux enable_dev "$dev1"
+
+vgrename $vg1 $vg2
+vgs --foreign -o+uuid |tee out
+lvs --foreign
+grep $vg1 out
+grep $vg2 out
+grep $UUID1 out
+grep $UUID2 out
+not vgrename $vg2 $vg1
+vgs --foreign -o+uuid |tee out
+lvs --foreign
+grep $vg1 out
+grep $vg2 out
+grep $UUID1 out
+grep $UUID2 out
+
+lvs --foreign
+
+aux wipefs_a "$dev1" "$dev2"
+
+# d. 1 local, 2 foreign
+# setup
+vgcreate $vg1 "$dev1"
+lvcreate -n $lv1 -l1 -ky -an $vg1
+UUID1=$(vgs --noheading -o vg_uuid $vg1 | xargs)
+aux disable_dev "$dev1"
+vgcreate $vg1 "$dev2"
+lvcreate -n $lv1 -l1 -ky -an $vg1
+UUID2=$(vgs --noheading -o vg_uuid $vg1 | xargs)
+vgchange -y --systemid "other" $vg1
+aux disable_dev "$dev2"
+vgcreate $vg1 "$dev3"
+lvcreate -n $lv1 -l1 -ky -an $vg1
+UUID3=$(vgs --noheading -o vg_uuid $vg1 | xargs)
+vgchange -y --systemid "other2" $vg1
+aux enable_dev "$dev1" "$dev2"
+
+vgrename $vg1 $vg2
+vgs --foreign -o+uuid |tee out
+lvs --foreign
+grep $vg1 out
+grep $vg2 out
+grep $UUID1 out
+grep $UUID2 out
+grep $UUID3 out
+not vgrename $vg2 $vg1
+vgs --foreign -o+uuid |tee out
+lvs --foreign
+grep $vg1 out
+grep $vg2 out
+grep $UUID1 out
+grep $UUID2 out
+grep $UUID3 out
+
+lvs --foreign
+
+aux wipefs_a "$dev1" "$dev2" "$dev3"
+
+# e. 2 local, 0 foreign
+# setup
+vgcreate $vg1 "$dev1"
+lvcreate -n $lv1 -l1 -ky -an $vg1
+UUID1=$(vgs --noheading -o vg_uuid $vg1 | xargs)
+aux disable_dev "$dev1"
+vgcreate $vg1 "$dev2"
+lvcreate -n ${lv1}_b -l1 -ky -an $vg1
+UUID2=$(vgs --noheading -o vg_uuid $vg1 | xargs)
+aux enable_dev "$dev1"
+
+not vgrename $vg1 $vg2
+vgs -o+uuid |tee out
+lvs --foreign
+grep $vg1 out
+not grep $vg2 out
+grep $UUID1 out
+grep $UUID2 out
+vgrename $UUID1 $vg2
+vgs -o+uuid |tee out
+lvs --foreign
+grep $vg1 out
+grep $vg2 out
+grep $UUID1 out
+grep $UUID2 out
+not vgrename $UUID2 $vg2
+vgs -o+uuid |tee out
+lvs --foreign
+grep $vg1 out
+grep $vg2 out
+grep $UUID1 out
+grep $UUID2 out
+
+lvs --foreign
+
+aux wipefs_a "$dev1" "$dev2"
+
+# f. 2 local, 1 foreign
+# setup
+vgcreate $vg1 "$dev1"
+lvcreate -n $lv1 -l1 -ky -an $vg1
+UUID1=$(vgs --noheading -o vg_uuid $vg1 | xargs)
+aux disable_dev "$dev1"
+vgcreate $vg1 "$dev2"
+lvcreate -n ${lv1}_b -l1 -ky -an $vg1
+UUID2=$(vgs --noheading -o vg_uuid $vg1 | xargs)
+aux disable_dev "$dev2"
+vgcreate $vg1 "$dev3"
+lvcreate -n $lv1 -l1 -ky -an $vg1
+UUID3=$(vgs --noheading -o vg_uuid $vg1 | xargs)
+vgchange -y --systemid "other" $vg1
+aux enable_dev "$dev1" "$dev2"
+lvs --foreign
+
+not vgrename $vg1 $vg2
+vgs --foreign -o+uuid |tee out
+lvs --foreign
+grep $vg1 out
+not grep $vg2 out
+grep $UUID1 out
+grep $UUID2 out
+grep $UUID3 out
+vgrename $UUID1 $vg2
+vgs --foreign -o+uuid |tee out
+lvs --foreign
+grep $vg1 out
+grep $vg2 out
+grep $UUID1 out
+grep $UUID2 out
+grep $UUID3 out
+vgrename $vg1 $vg3
+vgs --foreign -o+uuid |tee out
+lvs --foreign
+grep $vg1 out
+grep $vg2 out
+grep $vg3 out
+grep $UUID1 out
+grep $UUID2 out
+grep $UUID3 out
+not vgrename $vg2 $vg1
+vgs --foreign -o+uuid |tee out
+lvs --foreign
+grep $vg1 out
+grep $vg2 out
+grep $vg3 out
+grep $UUID1 out
+grep $UUID2 out
+grep $UUID3 out
+not vgrename $vg2 $vg3
+vgs --foreign -o+uuid |tee out
+lvs --foreign
+grep $vg1 out
+grep $vg2 out
+grep $vg3 out
+grep $UUID1 out
+grep $UUID2 out
+grep $UUID3 out
+
+lvs --foreign
+
+aux wipefs_a "$dev1" "$dev2" "$dev3"
+
+# g. 3 local, 0 foreign
+# setup
+vgcreate $vg1 "$dev1"
+lvcreate -n $lv1 -l1 -ky -an $vg1
+UUID1=$(vgs --noheading -o vg_uuid $vg1 | xargs)
+aux disable_dev "$dev1"
+vgcreate $vg1 "$dev2"
+lvcreate -n ${lv1}_b -l1 -ky -an $vg1
+UUID2=$(vgs --noheading -o vg_uuid $vg1 | xargs)
+aux disable_dev "$dev2"
+vgcreate $vg1 "$dev3"
+lvcreate -n ${lv1}_c -l1 -ky -an $vg1
+UUID3=$(vgs --noheading -o vg_uuid $vg1 | xargs)
+aux enable_dev "$dev1" "$dev2"
+
+not vgrename $vg1 $vg2
+vgs -o+uuid |tee out
+lvs --foreign
+grep $vg1 out
+not grep $vg2 out
+grep $UUID1 out
+grep $UUID2 out
+grep $UUID3 out
+vgrename $UUID1 $vg2
+vgs -o+uuid |tee out
+lvs --foreign
+grep $vg1 out
+grep $vg2 out
+grep $UUID1 out
+grep $UUID2 out
+grep $UUID3 out
+not vgrename $vg1 $vg2
+vgs -o+uuid |tee out
+lvs --foreign
+grep $vg1 out
+grep $vg2 out
+grep $UUID1 out
+grep $UUID2 out
+grep $UUID3 out
+not vgrename $vg1 $vg3
+vgs -o+uuid |tee out
+lvs --foreign
+grep $vg1 out
+grep $vg2 out
+not grep $vg3 out
+grep $UUID1 out
+grep $UUID2 out
+grep $UUID3 out
+not vgrename $UUID2 $vg2
+vgs -o+uuid |tee out
+lvs --foreign
+grep $vg1 out
+grep $vg2 out
+not grep $vg3 out
+grep $UUID1 out
+grep $UUID2 out
+grep $UUID3 out
+vgrename $UUID2 $vg3
+vgs -o+uuid |tee out
+lvs --foreign
+grep $vg1 out
+grep $vg2 out
+grep $vg3 out
+grep $UUID1 out
+grep $UUID2 out
+grep $UUID3 out
+
+lvs --foreign
diff --git a/test/shell/error-usage.sh b/test/shell/error-usage.sh
new file mode 100644
index 0000000..bc9f30a
--- /dev/null
+++ b/test/shell/error-usage.sh
@@ -0,0 +1,47 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2014 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+# Basic usage of zero target
+
+
+SKIP_WITH_LVMLOCKD=1
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+aux prepare_vg 1
+
+lvcreate --type error -L1 -n $lv1 $vg
+lvextend -L+1 $vg/$lv1
+
+# has to match
+
+check lv_field $vg/$lv1 lv_modules "error"
+check lv_field $vg/$lv1 segtype "error"
+check lv_field $vg/$lv1 seg_count "1"
+check lv_field $vg/$lv1 seg_size_pe "4" # 4 * 512 => 2M
+
+# FIXME should we print info we are ignoring stripping?
+lvextend -L+1 -I64 -i2 $vg/$lv1
+
+# We support mixing error with zero & linear targets
+lvextend -L+1 --type zero $vg/$lv1
+lvextend -L+1 --type linear $vg/$lv1
+lvextend -L+1 --type striped $vg/$lv1
+lvextend -L+1 --type error $vg/$lv1
+
+# 4 segments: error 3m, zero 1m, linear 2m, error 1m
+lvs -o+segtype,seg_size $vg
+check lv_field $vg/$lv1 seg_count "4"
+check lv_field $vg/$lv1 size "7.00m"
+
+vgremove -ff $vg
diff --git a/test/shell/exported.sh b/test/shell/exported.sh
new file mode 100644
index 0000000..18a8646
--- /dev/null
+++ b/test/shell/exported.sh
@@ -0,0 +1,209 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2008-2013,2018 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+# Check what is and is not permitted on an exported VG/PV
+
+aux prepare_devs 3
+get_devs
+
+vgcreate $vg1 "$dev1"
+vgcreate $vg2 "$dev2"
+
+lvcreate -l1 -n $lv1 -an $vg1
+lvcreate -l1 -n $lv2 -an $vg2
+
+vgchange --addtag aa $vg1
+lvchange --addtag bb $vg1/$lv1
+
+# vgexport only when no lvs are active
+lvchange -ay $vg1/$lv1
+not vgexport $vg1
+lvchange -an $vg1/$lv1
+
+vgexport $vg1
+
+lvm fullreport |tee out
+grep $vg1 out
+
+lvm fullreport $vg1 |tee out
+grep $vg1 out
+
+not lvchange -ay $vg1
+not lvchange -ay $vg1/$lv1
+not lvchange --addtag bar $vg1/$lv1
+not lvchange --monitor y $vg1/$lv1
+
+not lvconvert --type mirror $vg1/$lv1
+
+not lvcreate -l1 $vg1
+
+not lvdisplay $vg1
+
+lvdisplay 2>&1|tee out
+not grep $vg1 out
+
+not lvextend -l+1 $vg1/$lv1
+
+lvmdiskscan 2>&1|tee foo
+grep "$dev1" foo
+
+not lvreduce -l-1 $vg1/$lv1
+
+not lvremove $vg1
+not lvremove $vg1/$lv1
+
+not lvrename $vg1 $lv1 $lv2
+
+not lvresize --size 1M $vg1/$lv1
+
+not lvs $vg1
+
+lvs 2>&1|tee out
+not grep $vg1 out
+
+lvscan 2>&1|tee out
+not grep $vg1 out
+
+not pvchange --addtag cc "$dev1"
+pvs -o+tags "$dev1" 2>&1|tee out
+grep "$dev1" out
+not grep cc out
+
+pvs -osize "$dev1" > before
+not pvresize --setphysicalvolumesize 100M "$dev1"
+pvs -osize "$dev1" > after
+diff before after
+
+pvck "$dev1"
+pvck --dump headers "$dev1" > out
+grep "label_header at 512" out
+
+not pvcreate "$dev1"
+
+pvdisplay "$dev1" 2>&1|tee out
+grep "$dev1" out
+
+not pvmove "$dev1"
+
+not pvremove "$dev1"
+
+pvs "$dev1" 2>&1|tee out
+grep "$dev1" out
+
+pvscan 2>&1|tee out
+grep "$dev1" out
+
+pvscan --cache 2>&1|tee out
+grep "$dev1" out
+
+vgcfgbackup $vg1
+
+vgcfgrestore $vg1
+
+not vgchange -ay $vg1
+not vgchange --addtag asdf $vg1
+not vgchange --monitor y $vg1
+
+not vgck $vg1
+
+not vgcreate $vg1 "$dev3"
+
+vgdisplay $vg1 2>&1|tee out
+grep $vg1 out
+
+not vgexport $vg1
+
+vgexport $vg2
+not lvcreate -l1 -n $lv3 -an $vg2
+vgimport $vg2
+lvcreate -l1 -n $lv3 -an $vg2
+lvremove $vg2/$lv3
+
+not vgextend $vg1 "$dev3"
+
+not vgmerge $vg1 $vg2
+
+not vgmknodes $vg1
+
+not vgreduce --removemissing $vg1
+
+not vgremove $vg1
+
+vgrename $vg1 $vg3
+vgrename $vg3 $vg1
+
+vgs $vg1 2>&1|tee out
+grep $vg1 out
+
+vgscan 2>&1|tee out
+grep $vg1 out
+
+# pvscan --cache tracks online state of exported PVs,
+# but autoactivation should not activate LVs.
+pvscan --cache -aay "$dev1"
+vgimport $vg1
+check inactive $vg1 $lv1
+vgexport $vg1
+
+# using a tag does not give access to exported vg
+lvchange -ay @foo
+vgimport $vg1
+check inactive $vg1 $lv1
+vgexport $vg1
+
+# using select does not give access to exported vg
+lvchange -ay --select lvname=$lv1
+vgimport $vg1
+check inactive $vg1 $lv1
+vgexport $vg1
+
+# tag or select do not work with vgremove on exported vg
+vgremove @foo
+vgs $vg1
+vgremove --select vgname=$vg1
+vgs $vg1
+
+# exported vg is skipped without error when not named
+vgchange -ay
+vgimport $vg1
+check inactive $vg1 $lv1
+vgexport $vg1
+
+# exported vg is skipped without error when not named
+vgchange --addtag newtag
+vgs -o tags $vg1 > out
+not grep newtag out
+vgchange --deltag aa
+vgs -o tags $vg1 > out
+grep aa out
+
+# exported vg is skipped without error when not named
+vgchange --monitor y
+vgchange --monitor n
+
+vgimport $vg1
+vgextend $vg1 "$dev3"
+vgexport $vg1
+
+not vgreduce $vg1 "$dev3"
+
+not vgsplit $vg1 "$vg3" "$dev3"
+
+# For vgimportclone see vgimportclone.sh
+
+vgimport $vg1
+vgremove -ff $vg1
+vgremove -ff $vg2
diff --git a/test/shell/fsadm-crypt-fsresize.sh b/test/shell/fsadm-crypt-fsresize.sh
new file mode 100644
index 0000000..da56886
--- /dev/null
+++ b/test/shell/fsadm-crypt-fsresize.sh
@@ -0,0 +1,625 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2008-2017 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+test_description='Exercise fsadm filesystem resize on crypt devices'
+
+SKIP_WITH_LVMPOLLD=1
+
+# FIXME: cannot use brd (ramdisk) - lsblk is NOT listing it
+# so lsblk usage should be replaced
+export LVM_TEST_PREFER_BRD=0
+
+. lib/inittest
+
+aux prepare_vg 1 1100
+
+# Tests require a libblkid version that shows FSLASTBLOCK
+which mkfs.ext4 || skip
+
+lvcreate -n $lv1 -L 100 $vg
+mkfs.ext4 "$DM_DEV_DIR/$vg/$lv1"
+blkid -p "$DM_DEV_DIR/$vg/$lv1" | grep FSLASTBLOCK || skip
+lvchange -an $vg
+lvremove $vg/$lv1
+
+# set to "skip" to avoid testing given fs and test warning result
+# i.e. check_reiserfs=skip
+check_ext2=
+check_ext3=
+check_xfs=
+check_reiserfs=
+check_cryptsetup=
+DROP_SYMLINK=
+
+CRYPT_NAME="$PREFIX-tcrypt"
+CRYPT_DEV="$DM_DEV_DIR/mapper/$CRYPT_NAME"
+
+CRYPT_NAME2="$PREFIX-tcrypt2"
+CRYPT_DEV2="$DM_DEV_DIR/mapper/$CRYPT_NAME2"
+
+CRYPT_NAME_PLAIN="$PREFIX-tcryptp"
+CRYPT_DEV_PLAIN="$DM_DEV_DIR/mapper/$CRYPT_NAME_PLAIN"
+
+FORMAT_PARAMS="-i1"
+PWD1="93R4P4pIqAH8"
+PWD2="mymJeD8ivEhE"
+PWD3="ocMakf3fAcQO"
+SKIP_DETACHED=
+
+if which cryptsetup ; then
+ # use older format luks1 - otherwise the test would need to pass password everywhere...
+ case $(cryptsetup --version) in
+ "cryptsetup 2"*) FORMAT_PARAMS="$FORMAT_PARAMS --type luks1" ;;
+ esac
+else
+ check_cryptsetup=${check_cryptsetup:-cryptsetup}
+fi
+
+which mkfs.ext2 || check_ext2=${check_ext2:-mkfs.ext2}
+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 || {
+ which xfs_repair || check_xfs=${check_xfs:-xfs_repair}
+}
+grep xfs /proc/filesystems || check_xfs=${check_xfs:-no_xfs}
+
+which mkfs.reiserfs || check_reiserfs=${check_reiserfs:-mkfs.reiserfs}
+which reiserfsck || check_reiserfs=${check_reiserfs:-reiserfsck}
+modprobe reiserfs || true
+grep reiserfs /proc/filesystems || check_reiserfs=${check_reiserfs:-no_reiserfs}
+
+vg_lv=$vg/$lv1
+vg_lv2=$vg/${lv1}bar
+vg_lv3=$vg/${lv1}plain
+dev_vg_lv="$DM_DEV_DIR/$vg_lv"
+dev_vg_lv2="$DM_DEV_DIR/$vg_lv2"
+dev_vg_lv3="$DM_DEV_DIR/$vg_lv3"
+mount_dir="mnt"
+
+test ! -d "$mount_dir" && mkdir "$mount_dir"
+
+crypt_close() {
+ aux udev_wait
+ cryptsetup remove "$1"
+ if [ "$?" -eq 0 ] && [ -n "$DROP_SYMLINK" ]; then
+ rm -f "$DM_DEV_DIR/mapper/$1"
+ fi
+}
+
+cleanup_mounted_and_teardown()
+{
+ umount "$mount_dir" || true
+ crypt_close $CRYPT_NAME > /dev/null 2>&1 || true
+ crypt_close $CRYPT_NAME2 > /dev/null 2>&1 || true
+ crypt_close $CRYPT_NAME_PLAIN > /dev/null 2>&1 || true
+ aux teardown
+}
+
+fscheck_ext3()
+{
+ fsck.ext3 -p -F -f "$1"
+}
+
+fscheck_xfs()
+{
+ if which xfs_repair ; then
+ xfs_repair -n "$1"
+ else
+ xfs_check "$1"
+ fi
+}
+
+fscheck_reiserfs()
+{
+ reiserfsck --check -p -f "$1" </dev/null
+}
+
+check_missing()
+{
+ local t
+ eval "t=\$check_$1"
+ test -z "$t" && return 0
+ test "$t" = skip && return 1
+ echo "WARNING: fsadm test skipped $1 tests, $t tool is missing."
+ # trick to get test listed with warning
+ # should false;
+ return 1
+}
+
+get_crypt_kname() {
+ lsblk -r -n -o KNAME,NAME | grep "$1" | cut -d ' ' -f 1
+}
+
+
+# $1 device
+# $2 pass
+crypt_format() {
+ echo "$2" | cryptsetup luksFormat $FORMAT_PARAMS "$1"
+}
+
+
+# $1 device
+# $2 pass
+# $3 name
+crypt_open() {
+ local kname=
+ echo "$2" | cryptsetup luksOpen "$1" "$3"
+ test -L "$DM_DEV_DIR/mapper/$3" || {
+ kname=$(get_crypt_kname $3)
+ ln -s "/dev/$kname" "$DM_DEV_DIR/mapper/$3"
+ DROP_SYMLINK=1
+ }
+}
+
+# $1 data device
+# $2 pass
+# $3 name
+# $4 header
+crypt_open_detached() {
+ local kname=
+ echo "$2" | cryptsetup luksOpen --header "$4" "$1" "$3" || return $?
+ test -L "$DM_DEV_DIR/mapper/$3" || {
+ kname=$(get_crypt_kname $3)
+ ln -s "/dev/$kname" "$DM_DEV_DIR/mapper/$3"
+ DROP_SYMLINK=1
+ }
+}
+
+# $1 device
+# $2 pass
+# $3 name
+crypt_open_plain() {
+ local kname=
+ echo "$2" | cryptsetup create "$3" "$1"
+ test -L "$DM_DEV_DIR/mapper/$3" || {
+ kname=$(get_crypt_kname $3)
+ ln -s "/dev/$kname" "$DM_DEV_DIR/mapper/$3"
+ DROP_SYMLINK=1
+ }
+}
+
+# $1 device
+# $2 type
+create_crypt_device()
+{
+ crypt_format "$dev_vg_lv" $PWD1
+ crypt_open "$dev_vg_lv" $PWD1 "$CRYPT_NAME"
+
+ crypt_format "$dev_vg_lv2" $PWD2
+
+ if crypt_open_detached "$dev_vg_lv3" "$PWD2" "$PREFIX-test" "$dev_vg_lv2"; then
+ crypt_close "$PREFIX-test"
+ else
+ SKIP_DETACHED=1
+ fi
+}
+
+which lsblk > /dev/null || skip
+check_missing cryptsetup || skip
+
+vgchange -s 128k
+lvcreate -n $lv1 -L25M $vg
+lvcreate -n ${lv1}bar -L335M $vg
+lvcreate -n ${lv1}plain -L335M $vg
+create_crypt_device
+trap 'cleanup_mounted_and_teardown' EXIT
+
+
+# $1 LVM backend (vg/lv name)
+# $2 LVM backend device (/dev/vg/lv)
+# $3 active dm-crypt device (/dev/mapper/some_name )
+test_ext2_resize() {
+ mkfs.ext2 -b4096 -j "$3"
+
+ fsadm --lvresize resize $1 30M
+ # Fails - not enough space for 4M fs
+ not fsadm -y --lvresize resize "$2" 4M
+ lvresize -L+10M --fs resize $1
+ lvreduce -L10M --fs resize $1
+
+ fscheck_ext3 "$3"
+ mount "$3" "$mount_dir"
+ not fsadm -y --lvresize resize $1 4M
+ echo n | not lvresize -L4M --fs resize -n $1
+ lvresize -L+20M --fs resize -n $1
+ umount "$mount_dir"
+ fscheck_ext3 "$3"
+}
+
+test_ext2_small_shrink() {
+ mkfs.ext2 "$3"
+
+ lvresize -L-1 --fs resize $1
+ lvresize -L-1 --fs resize $1
+
+ fscheck_ext3 "$3"
+}
+
+test_ext3_resize() {
+ mkfs.ext3 -b4096 -j "$3"
+
+ fsadm --lvresize resize $1 30M
+ # Fails - not enough space for 4M fs
+ not fsadm -y --lvresize resize "$2" 4M
+ lvresize -L+10M --fs resize $1
+ lvreduce -L10M --fs resize $1
+
+ fscheck_ext3 "$3"
+ mount "$3" "$mount_dir"
+ lvresize -L+10M --fs resize $1
+
+ not fsadm -y --lvresize resize $1 4M
+ echo n | not lvresize -L4M --fs resize -n $1
+ lvresize -L+20M --fs resize -n $1
+ lvresize -L-10M --fs resize -y $1
+ umount "$mount_dir"
+}
+
+test_ext3_small_shrink() {
+ mkfs.ext3 "$3"
+
+ lvresize -L-1 --fs resize $1
+ lvresize -L-1 --fs resize $1
+
+ fscheck_ext3 "$3"
+}
+
+test_xfs_resize() {
+ mkfs.xfs -f "$3"
+
+ fsadm --lvresize resize $1 330M
+ # Fails - not enough space for 4M fs
+ lvresize -L+10M -y --fs resize $1
+ not lvreduce -L10M --fs resize $1
+
+ fscheck_xfs "$3"
+ mount "$3" "$mount_dir"
+ lvresize -L+10M -y --fs resize -n $1
+ umount "$mount_dir"
+ fscheck_xfs "$3"
+}
+
+test_xfs_small_shrink() {
+ mkfs.xfs -f "$3"
+
+ not lvresize -L-1 --fs resize $1
+ fscheck_xfs "$3"
+}
+
+test_reiserfs_resize() {
+ mkfs.reiserfs -s 513 -f "$3"
+
+ fsadm -y --lvresize resize $1 30M
+ # resize fs does not support resiserfs and requires resize_fsadm
+ not lvresize -L+10M --fs resize $1
+ lvresize -L+10M --fs resize_fsadm $1
+ fsadm --lvresize -y resize $1 10M
+
+ fscheck_reiserfs "$3"
+ mount "$3" "$mount_dir"
+
+ fsadm -y --lvresize resize $1 30M
+ umount "$mount_dir"
+ fscheck_reiserfs "$3"
+}
+
+test_reiserfs_small_shrink() {
+ mkfs.reiserfs -s 513 -f "$3"
+
+ not lvresize -y -L-1 --fs resize $1
+ lvresize -y -L-1 --fs resize_fsadm $1
+ lvresize -y -L-1 --fs resize_fsadm $1
+
+ fscheck_reiserfs "$3"
+}
+
+# $1 LVM backend (vg/lv name)
+# $2 LVM backend device (/dev/vg/lv)
+# $3 active dm-crypt device (/dev/mapper/some_name )
+# $4 active dm-crypt name ( some_name )
+test_ext2_inactive() {
+ crypt_open "$2" $PWD2 "$4"
+ mkfs.ext2 -b4096 -j "$3"
+ crypt_close "$4"
+
+ not fsadm --lvresize resize $1 30M
+ not lvresize -L+10M --fs resize $1
+ not lvreduce -L10M --fs resize $1
+
+ crypt_open "$2" $PWD2 "$4"
+ fscheck_ext3 "$3"
+ crypt_close "$4"
+}
+
+test_ext3_inactive() {
+ crypt_open "$2" $PWD2 "$4"
+ mkfs.ext3 -b4096 -j "$3"
+ crypt_close "$4"
+
+ not fsadm --lvresize resize $1 30M
+ not lvresize -L+10M --fs resize $1
+ not lvreduce -L10M --fs resize $1
+
+ crypt_open "$2" $PWD2 "$4"
+ fscheck_ext3 "$3"
+ crypt_close "$4"
+}
+
+test_xfs_inactive() {
+ crypt_open "$2" $PWD2 "$4"
+ mkfs.xfs -f "$3"
+ crypt_close "$4"
+
+ not fsadm --lvresize resize $1 30M
+ not lvresize -L+10M --fs resize $1
+ not lvreduce -L10M --fs resize $1
+
+ crypt_open "$2" $PWD2 "$4"
+ fscheck_xfs "$3"
+ crypt_close "$4"
+}
+
+test_reiserfs_inactive() {
+ crypt_open "$2" $PWD2 "$4"
+ mkfs.reiserfs -s 513 -f "$3"
+ crypt_close "$4"
+
+ not fsadm --lvresize resize $1 30M
+ not lvresize -L+10M --fs resize $1
+ not lvreduce -L10M --fs resize $1
+
+ crypt_open "$2" $PWD2 "$4"
+ fscheck_reiserfs "$3"
+ crypt_close "$4"
+}
+
+# $1 LVM backend (vg/lv name)
+# $2 LVM backend device (/dev/vg/lv)
+# $3 active dm-crypt device (/dev/mapper/some_name )
+# $4 active dm-crypt name ( some_name )
+test_ext2_plain() {
+ mkfs.ext2 -b4096 -j "$3"
+
+ not fsadm --lvresize resize $1 30M
+ not lvresize -L+10M --fs resize $1
+ not lvreduce -L10M --fs resize $1
+ fscheck_ext3 "$3"
+
+ fsadm --cryptresize resize $3 30M
+ fsadm --cryptresize resize $3 35M
+ fscheck_ext3 "$3"
+
+ mount "$3" "$mount_dir"
+ not fsadm -y --cryptresize resize $3 4M
+ umount "$mount_dir"
+ fscheck_ext3 "$3"
+
+ crypt_close "$4"
+ not fsadm --lvresize resize $1 30M
+ not lvresize -L+10M --fs resize $1
+ not lvreduce -L10M --fs resize $1
+ crypt_open_plain "$2" $PWD3 "$4"
+ fscheck_ext3 "$3"
+}
+
+test_ext3_plain() {
+ mkfs.ext3 -b4096 -j "$3"
+
+ not fsadm --lvresize resize $1 30M
+ not lvresize -L+10M --fs resize $1
+ not lvreduce -L10M --fs resize $1
+ fscheck_ext3 "$3"
+
+ fsadm --cryptresize resize $3 30M
+ fsadm --cryptresize resize $3 35M
+ fscheck_ext3 "$3"
+
+ mount "$3" "$mount_dir"
+ not fsadm -y --cryptresize resize $3 4M
+ umount "$mount_dir"
+ fscheck_ext3 "$3"
+
+ crypt_close "$4"
+ not fsadm --lvresize resize $1 30M
+ not lvresize -L+10M --fs resize $1
+ not lvreduce -L10M --fs resize $1
+ crypt_open_plain "$2" $PWD3 "$4"
+ fscheck_ext3 "$3"
+}
+
+test_xfs_plain() {
+ mkfs.xfs -f "$3"
+
+ not fsadm --lvresize resize $1 30M
+ not lvresize -L+10M --fs resize $1
+ not lvreduce -L10M --fs resize $1
+ fscheck_xfs "$3"
+
+ lvresize -f -L+10M $1
+ fsadm --cryptresize resize $3 345M
+ # no shrink support in xfs
+ not fsadm --cryptresize resize $3 35M
+ fscheck_xfs "$3"
+
+ crypt_close "$4"
+ not fsadm --lvresize resize $1 30M
+ not lvresize -L+10M --fs resize $1
+ not lvreduce -L10M --fs resize $1
+ crypt_open_plain "$2" $PWD3 "$4"
+ fscheck_xfs "$3"
+
+ lvresize -f -L320M $1
+}
+
+test_reiserfs_plain() {
+ mkfs.reiserfs -s 513 -f "$3"
+
+ not fsadm --lvresize resize $1 30M
+ not lvresize -L+10M --fs resize $1
+ not lvreduce -L-10M --fs resize $1
+ fscheck_reiserfs "$3"
+
+ fsadm -y --cryptresize resize $3 30M
+ fsadm -y --cryptresize resize $3 35M
+ fscheck_reiserfs "$3"
+
+ crypt_close "$4"
+ not fsadm --lvresize resize $1 30M
+ not lvresize -L+10M --fs resize $1
+ not lvreduce -L10M --fs resize $1
+ crypt_open_plain "$2" $PWD3 "$4"
+ fscheck_reiserfs "$3"
+}
+
+# $1 LVM header backend (vg/lv name)
+# $2 LVM hedaer backend device (/dev/vg/lv)
+# $3 active dm-crypt device (/dev/mapper/some_name )
+# $4 active dm-crypt name ( some_name )a
+test_ext2_detached() {
+ mkfs.ext2 -b4096 -j "$3"
+
+ not fsadm --lvresize resize $1 30M
+ not lvresize -L+10M --fs resize $1
+ not lvreduce -L10M --fs resize $1
+ fscheck_ext3 "$3"
+}
+
+test_ext3_detached() {
+ mkfs.ext3 -b4096 -j "$3"
+
+ not fsadm --lvresize resize $1 30M
+ not lvresize -L+10M --fs resize $1
+ not lvreduce -L10M --fs resize $1
+ fscheck_ext3 "$3"
+}
+
+test_xfs_detached() {
+ mkfs.xfs -f "$3"
+
+ not fsadm --lvresize resize $1 30M
+ not lvresize -L+10M --fs resize $1
+ not lvreduce -L10M --fs resize $1
+
+ fscheck_xfs "$3"
+}
+
+test_reiserfs_detached() {
+ mkfs.reiserfs -s 513 -f "$3"
+
+ not fsadm --lvresize resize $1 30M
+ not lvresize -L+10M --fs resize $1
+ not lvreduce -L10M --fs resize $1
+
+ fscheck_reiserfs "$3"
+}
+
+if check_missing ext2; then
+ test_ext2_resize "$vg_lv" "$dev_vg_lv" "$CRYPT_DEV"
+ lvresize --fs ignore -y -L25M $vg_lv
+ cryptsetup resize $CRYPT_NAME
+
+ test_ext2_inactive "$vg_lv2" "$dev_vg_lv2" "$CRYPT_DEV2" "$CRYPT_NAME2"
+
+ crypt_open_plain "$dev_vg_lv3" $PWD3 "$CRYPT_NAME_PLAIN"
+ test_ext2_plain "$vg_lv3" "$dev_vg_lv3" "$CRYPT_DEV_PLAIN" "$CRYPT_NAME_PLAIN"
+ crypt_close "$CRYPT_NAME_PLAIN"
+
+ lvresize --fs ignore -y -L100M $vg_lv
+ cryptsetup resize $CRYPT_NAME
+ test_ext2_small_shrink "$vg_lv" "$dev_vg_lv" "$CRYPT_DEV"
+ lvresize --fs ignore -y -L25M $vg_lv
+ cryptsetup resize $CRYPT_NAME
+
+ if [ -z "$SKIP_DETACHED" ]; then
+ crypt_open_detached "$dev_vg_lv3" $PWD2 "$CRYPT_NAME2" "$dev_vg_lv2"
+ test_ext2_detached "$vg_lv2" "$dev_vg_lv2" "$CRYPT_DEV2" "$CRYPT_NAME2"
+ crypt_close "$CRYPT_NAME2"
+ fi
+fi
+
+if check_missing ext3; then
+ test_ext3_resize "$vg_lv" "$dev_vg_lv" "$CRYPT_DEV"
+ lvresize --fs ignore -y -L25M $vg_lv
+ cryptsetup resize $CRYPT_NAME
+
+ test_ext3_inactive "$vg_lv2" "$dev_vg_lv2" "$CRYPT_DEV2" "$CRYPT_NAME2"
+
+ crypt_open_plain "$dev_vg_lv3" $PWD3 "$CRYPT_NAME_PLAIN"
+ test_ext3_plain "$vg_lv3" "$dev_vg_lv3" "$CRYPT_DEV_PLAIN" "$CRYPT_NAME_PLAIN"
+ crypt_close "$CRYPT_NAME_PLAIN"
+
+ lvresize --fs ignore -y -L100M $vg_lv
+ cryptsetup resize $CRYPT_NAME
+ test_ext3_small_shrink "$vg_lv" "$dev_vg_lv" "$CRYPT_DEV"
+ lvresize --fs ignore -y -L25M $vg_lv
+ cryptsetup resize $CRYPT_NAME
+
+ if [ -z "$SKIP_DETACHED" ]; then
+ crypt_open_detached "$dev_vg_lv3" $PWD2 "$CRYPT_NAME2" "$dev_vg_lv2"
+ test_ext3_detached "$vg_lv2" "$dev_vg_lv2" "$CRYPT_DEV2" "$CRYPT_NAME2"
+ crypt_close "$CRYPT_NAME2"
+ fi
+fi
+
+if check_missing xfs; then
+ lvresize --fs ignore -y -L325M $vg_lv
+ cryptsetup resize $CRYPT_NAME
+
+ test_xfs_resize "$vg_lv" "$dev_vg_lv" "$CRYPT_DEV"
+
+ test_xfs_inactive "$vg_lv2" "$dev_vg_lv2" "$CRYPT_DEV2" "$CRYPT_NAME2"
+
+ crypt_open_plain "$dev_vg_lv3" $PWD3 "$CRYPT_NAME_PLAIN"
+ test_xfs_plain "$vg_lv3" "$dev_vg_lv3" "$CRYPT_DEV_PLAIN" "$CRYPT_NAME_PLAIN"
+ crypt_close "$CRYPT_NAME_PLAIN"
+
+ lvresize --fs ignore -y -L310M $vg_lv
+ cryptsetup resize $CRYPT_NAME
+ test_xfs_small_shrink "$vg_lv" "$dev_vg_lv" "$CRYPT_DEV"
+ lvresize --fs ignore -y -L325M $vg_lv
+ cryptsetup resize $CRYPT_NAME
+
+ if [ -z "$SKIP_DETACHED" ]; then
+ crypt_open_detached "$dev_vg_lv3" $PWD2 "$CRYPT_NAME2" "$dev_vg_lv2"
+ test_xfs_detached "$vg_lv2" "$dev_vg_lv2" "$CRYPT_DEV2" "$CRYPT_NAME2"
+ crypt_close "$CRYPT_NAME2"
+ fi
+fi
+
+if check_missing reiserfs; then
+ test_reiserfs_resize "$vg_lv" "$dev_vg_lv" "$CRYPT_DEV"
+ lvresize --fs ignore -y -L25M $vg_lv
+ cryptsetup resize $CRYPT_NAME
+
+ test_reiserfs_inactive "$vg_lv2" "$dev_vg_lv2" "$CRYPT_DEV2" "$CRYPT_NAME2"
+
+ crypt_open_plain "$dev_vg_lv3" $PWD3 "$CRYPT_NAME_PLAIN"
+ test_reiserfs_plain "$vg_lv3" "$dev_vg_lv3" "$CRYPT_DEV_PLAIN" "$CRYPT_NAME_PLAIN"
+ crypt_close "$CRYPT_NAME_PLAIN"
+
+ lvresize --fs ignore -y -L100M $vg_lv
+ cryptsetup resize $CRYPT_NAME
+ test_reiserfs_small_shrink "$vg_lv" "$dev_vg_lv" "$CRYPT_DEV"
+ lvresize --fs ignore -y -L25M $vg_lv
+ cryptsetup resize $CRYPT_NAME
+
+ if [ -z "$SKIP_DETACHED" ]; then
+ crypt_open_detached "$dev_vg_lv3" $PWD2 "$CRYPT_NAME2" "$dev_vg_lv2"
+ test_reiserfs_detached "$vg_lv2" "$dev_vg_lv2" "$CRYPT_DEV2" "$CRYPT_NAME2"
+ crypt_close "$CRYPT_NAME2"
+ fi
+fi
+
+crypt_close "$CRYPT_NAME"
+
+vgremove -ff $vg
diff --git a/test/shell/fsadm-crypt.sh b/test/shell/fsadm-crypt.sh
new file mode 100644
index 0000000..4415cea
--- /dev/null
+++ b/test/shell/fsadm-crypt.sh
@@ -0,0 +1,614 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2008-2017 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+test_description='Exercise fsadm filesystem resize on crypt devices'
+
+SKIP_WITH_LVMPOLLD=1
+
+# FIXME: cannot use brd (ramdisk) - lsblk is NOT listing it
+# so lsblk usage should be replaced
+export LVM_TEST_PREFER_BRD=0
+
+. lib/inittest
+
+aux prepare_vg 1 1300
+
+# set to "skip" to avoid testing given fs and test warning result
+# i.e. check_reiserfs=skip
+check_ext2=
+check_ext3=
+check_xfs=
+check_reiserfs=
+check_cryptsetup=
+DROP_SYMLINK=
+
+CRYPT_NAME="$PREFIX-tcrypt"
+CRYPT_DEV="$DM_DEV_DIR/mapper/$CRYPT_NAME"
+
+CRYPT_NAME2="$PREFIX-tcrypt2"
+CRYPT_DEV2="$DM_DEV_DIR/mapper/$CRYPT_NAME2"
+
+CRYPT_NAME_PLAIN="$PREFIX-tcryptp"
+CRYPT_DEV_PLAIN="$DM_DEV_DIR/mapper/$CRYPT_NAME_PLAIN"
+
+FORMAT_PARAMS="-i1"
+PWD1="93R4P4pIqAH8"
+PWD2="mymJeD8ivEhE"
+PWD3="ocMakf3fAcQO"
+SKIP_DETACHED=
+
+if which cryptsetup ; then
+ # use older format luks1 - otherwise the test would need to pass password everywhere...
+ case $(cryptsetup --version) in
+ "cryptsetup 2"*) FORMAT_PARAMS="$FORMAT_PARAMS --type luks1" ;;
+ esac
+else
+ check_cryptsetup=${check_cryptsetup:-cryptsetup}
+fi
+
+which mkfs.ext2 || check_ext2=${check_ext2:-mkfs.ext2}
+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 || {
+ which xfs_repair || check_xfs=${check_xfs:-xfs_repair}
+}
+grep xfs /proc/filesystems || check_xfs=${check_xfs:-no_xfs}
+
+which mkfs.reiserfs || check_reiserfs=${check_reiserfs:-mkfs.reiserfs}
+which reiserfsck || check_reiserfs=${check_reiserfs:-reiserfsck}
+modprobe reiserfs || true
+grep reiserfs /proc/filesystems || check_reiserfs=${check_reiserfs:-no_reiserfs}
+
+vg_lv=$vg/$lv1
+vg_lv2=$vg/${lv1}bar
+vg_lv3=$vg/${lv1}plain
+dev_vg_lv="$DM_DEV_DIR/$vg_lv"
+dev_vg_lv2="$DM_DEV_DIR/$vg_lv2"
+dev_vg_lv3="$DM_DEV_DIR/$vg_lv3"
+mount_dir="mnt"
+
+test ! -d "$mount_dir" && mkdir "$mount_dir"
+
+crypt_close() {
+ aux udev_wait
+ cryptsetup remove "$1"
+ if [ "$?" -eq 0 ] && [ -n "$DROP_SYMLINK" ]; then
+ rm -f "$DM_DEV_DIR/mapper/$1"
+ fi
+}
+
+cleanup_mounted_and_teardown()
+{
+ umount "$mount_dir" || true
+ crypt_close $CRYPT_NAME > /dev/null 2>&1 || true
+ crypt_close $CRYPT_NAME2 > /dev/null 2>&1 || true
+ crypt_close $CRYPT_NAME_PLAIN > /dev/null 2>&1 || true
+ aux teardown
+}
+
+fscheck_ext3()
+{
+ fsck.ext3 -p -F -f "$1"
+}
+
+fscheck_xfs()
+{
+ if which xfs_repair ; then
+ xfs_repair -n "$1"
+ else
+ xfs_check "$1"
+ fi
+}
+
+fscheck_reiserfs()
+{
+ reiserfsck --check -p -f "$1" </dev/null
+}
+
+check_missing()
+{
+ local t
+ eval "t=\$check_$1"
+ test -z "$t" && return 0
+ test "$t" = skip && return 1
+ echo "WARNING: fsadm test skipped $1 tests, $t tool is missing."
+ # trick to get test listed with warning
+ # should false;
+ return 1
+}
+
+get_crypt_kname() {
+ lsblk -r -n -o KNAME,NAME | grep "$1" | cut -d ' ' -f 1
+}
+
+
+# $1 device
+# $2 pass
+crypt_format() {
+ echo "$2" | cryptsetup luksFormat $FORMAT_PARAMS "$1"
+}
+
+
+# $1 device
+# $2 pass
+# $3 name
+crypt_open() {
+ local kname=
+ echo "$2" | cryptsetup luksOpen "$1" "$3"
+ test -L "$DM_DEV_DIR/mapper/$3" || {
+ kname=$(get_crypt_kname $3)
+ ln -s "/dev/$kname" "$DM_DEV_DIR/mapper/$3"
+ DROP_SYMLINK=1
+ }
+}
+
+# $1 data device
+# $2 pass
+# $3 name
+# $4 header
+crypt_open_detached() {
+ local kname=
+ echo "$2" | cryptsetup luksOpen --header "$4" "$1" "$3" || return $?
+ test -L "$DM_DEV_DIR/mapper/$3" || {
+ kname=$(get_crypt_kname $3)
+ ln -s "/dev/$kname" "$DM_DEV_DIR/mapper/$3"
+ DROP_SYMLINK=1
+ }
+}
+
+# $1 device
+# $2 pass
+# $3 name
+crypt_open_plain() {
+ local kname=
+ echo "$2" | cryptsetup create "$3" "$1"
+ test -L "$DM_DEV_DIR/mapper/$3" || {
+ kname=$(get_crypt_kname $3)
+ ln -s "/dev/$kname" "$DM_DEV_DIR/mapper/$3"
+ DROP_SYMLINK=1
+ }
+}
+
+# $1 device
+# $2 type
+create_crypt_device()
+{
+ crypt_format "$dev_vg_lv" $PWD1
+ crypt_open "$dev_vg_lv" $PWD1 "$CRYPT_NAME"
+
+ crypt_format "$dev_vg_lv2" $PWD2
+
+ if crypt_open_detached "$dev_vg_lv3" "$PWD2" "$PREFIX-test" "$dev_vg_lv2"; then
+ crypt_close "$PREFIX-test"
+ else
+ SKIP_DETACHED=1
+ fi
+}
+
+which lsblk > /dev/null || skip
+check_missing cryptsetup || skip
+
+vgchange -s 128k
+lvcreate -n $lv1 -L25M $vg
+lvcreate -n ${lv1}bar -L335M $vg
+lvcreate -n ${lv1}plain -L335M $vg
+create_crypt_device
+trap 'cleanup_mounted_and_teardown' EXIT
+
+
+# $1 LVM backend (vg/lv name)
+# $2 LVM backend device (/dev/vg/lv)
+# $3 active dm-crypt device (/dev/mapper/some_name )
+test_ext2_resize() {
+ mkfs.ext2 -b4096 -j "$3"
+
+ fsadm --lvresize resize $1 30M
+ # Fails - not enough space for 4M fs
+ not fsadm -y --lvresize resize "$2" 4M
+ lvresize -L+10M --fs resize_fsadm $1
+ lvreduce -L10M --fs resize_fsadm $1
+
+ fscheck_ext3 "$3"
+ mount "$3" "$mount_dir"
+ not fsadm -y --lvresize resize $1 4M
+ echo n | not lvresize -L4M --fs resize_fsadm -n $1
+ lvresize -L+20M --fs resize_fsadm -n $1
+ umount "$mount_dir"
+ fscheck_ext3 "$3"
+}
+
+test_ext2_small_shrink() {
+ mkfs.ext2 "$3"
+
+ lvresize -L-1 --fs resize_fsadm $1
+ lvresize -L-1 --fs resize_fsadm $1
+
+ fscheck_ext3 "$3"
+}
+
+test_ext3_resize() {
+ mkfs.ext3 -b4096 -j "$3"
+
+ fsadm --lvresize resize $1 30M
+ # Fails - not enough space for 4M fs
+ not fsadm -y --lvresize resize "$2" 4M
+ lvresize -L+10M --fs resize_fsadm $1
+ lvreduce -L10M --fs resize_fsadm $1
+
+ fscheck_ext3 "$3"
+ mount "$3" "$mount_dir"
+ lvresize -L+10M --fs resize_fsadm $1
+
+ not fsadm -y --lvresize resize $1 4M
+ echo n | not lvresize -L4M --fs resize_fsadm -n $1
+ lvresize -L+20M --fs resize_fsadm -n $1
+ lvresize -L-10M --fs resize_fsadm -y $1
+ umount "$mount_dir"
+}
+
+test_ext3_small_shrink() {
+ mkfs.ext3 "$3"
+
+ lvresize -L-1 --fs resize_fsadm $1
+ lvresize -L-1 --fs resize_fsadm $1
+
+ fscheck_ext3 "$3"
+}
+
+test_xfs_resize() {
+ mkfs.xfs -f "$3"
+
+ fsadm --lvresize resize $1 330M
+ # Fails - not enough space for 4M fs
+ lvresize -L+10M --fs resize_fsadm $1
+ not lvreduce -L10M --fs resize_fsadm $1
+
+ fscheck_xfs "$3"
+ mount "$3" "$mount_dir"
+ lvresize -L+10M --fs resize_fsadm -n $1
+ umount "$mount_dir"
+ fscheck_xfs "$3"
+}
+
+test_xfs_small_shrink() {
+ mkfs.xfs -f "$3"
+
+ not lvresize -L-1 --fs resize_fsadm $1
+ fscheck_xfs "$3"
+}
+
+test_reiserfs_resize() {
+ mkfs.reiserfs -s 513 -f "$3"
+
+ fsadm --lvresize resize $1 30M
+ lvresize -L+10M --fs resize_fsadm $1
+ fsadm --lvresize -y resize $1 10M
+
+ fscheck_reiserfs "$3"
+ mount "$3" "$mount_dir"
+
+ fsadm -y --lvresize resize $1 30M
+ umount "$mount_dir"
+ fscheck_reiserfs "$3"
+}
+
+test_reiserfs_small_shrink() {
+ mkfs.reiserfs -s 513 -f "$3"
+
+ lvresize -y -L-1 --fs resize_fsadm $1
+ lvresize -y -L-1 --fs resize_fsadm $1
+
+ fscheck_reiserfs "$3"
+}
+
+# $1 LVM backend (vg/lv name)
+# $2 LVM backend device (/dev/vg/lv)
+# $3 active dm-crypt device (/dev/mapper/some_name )
+# $4 active dm-crypt name ( some_name )
+test_ext2_inactive() {
+ crypt_open "$2" $PWD2 "$4"
+ mkfs.ext2 -b4096 -j "$3"
+ crypt_close "$4"
+
+ not fsadm --lvresize resize $1 30M
+ not lvresize -L+10M --fs resize_fsadm $1
+ not lvreduce -L10M --fs resize_fsadm $1
+
+ crypt_open "$2" $PWD2 "$4"
+ fscheck_ext3 "$3"
+ crypt_close "$4"
+}
+
+test_ext3_inactive() {
+ crypt_open "$2" $PWD2 "$4"
+ mkfs.ext3 -b4096 -j "$3"
+ crypt_close "$4"
+
+ not fsadm --lvresize resize $1 30M
+ not lvresize -L+10M --fs resize_fsadm $1
+ not lvreduce -L10M --fs resize_fsadm $1
+
+ crypt_open "$2" $PWD2 "$4"
+ fscheck_ext3 "$3"
+ crypt_close "$4"
+}
+
+test_xfs_inactive() {
+ crypt_open "$2" $PWD2 "$4"
+ mkfs.xfs -f "$3"
+ crypt_close "$4"
+
+ not fsadm --lvresize resize $1 30M
+ not lvresize -L+10M --fs resize_fsadm $1
+ not lvreduce -L10M --fs resize_fsadm $1
+
+ crypt_open "$2" $PWD2 "$4"
+ fscheck_xfs "$3"
+ crypt_close "$4"
+}
+
+test_reiserfs_inactive() {
+ crypt_open "$2" $PWD2 "$4"
+ mkfs.reiserfs -s 513 -f "$3"
+ crypt_close "$4"
+
+ not fsadm --lvresize resize $1 30M
+ not lvresize -L+10M --fs resize_fsadm $1
+ not lvreduce -L10M --fs resize_fsadm $1
+
+ crypt_open "$2" $PWD2 "$4"
+ fscheck_reiserfs "$3"
+ crypt_close "$4"
+}
+
+# $1 LVM backend (vg/lv name)
+# $2 LVM backend device (/dev/vg/lv)
+# $3 active dm-crypt device (/dev/mapper/some_name )
+# $4 active dm-crypt name ( some_name )
+test_ext2_plain() {
+ mkfs.ext2 -b4096 -j "$3"
+
+ not fsadm --lvresize resize $1 30M
+ not lvresize -L+10M --fs resize_fsadm $1
+ not lvreduce -L10M --fs resize_fsadm $1
+ fscheck_ext3 "$3"
+
+ fsadm --cryptresize resize $3 30M
+ fsadm --cryptresize resize $3 35M
+ fscheck_ext3 "$3"
+
+ mount "$3" "$mount_dir"
+ not fsadm -y --cryptresize resize $3 4M
+ umount "$mount_dir"
+ fscheck_ext3 "$3"
+
+ crypt_close "$4"
+ not fsadm --lvresize resize $1 30M
+ not lvresize -L+10M --fs resize_fsadm $1
+ not lvreduce -L10M --fs resize_fsadm $1
+ crypt_open_plain "$2" $PWD3 "$4"
+ fscheck_ext3 "$3"
+}
+
+test_ext3_plain() {
+ mkfs.ext3 -b4096 -j "$3"
+
+ not fsadm --lvresize resize $1 30M
+ not lvresize -L+10M --fs resize_fsadm $1
+ not lvreduce -L10M --fs resize_fsadm $1
+ fscheck_ext3 "$3"
+
+ fsadm --cryptresize resize $3 30M
+ fsadm --cryptresize resize $3 35M
+ fscheck_ext3 "$3"
+
+ mount "$3" "$mount_dir"
+ not fsadm -y --cryptresize resize $3 4M
+ umount "$mount_dir"
+ fscheck_ext3 "$3"
+
+ crypt_close "$4"
+ not fsadm --lvresize resize $1 30M
+ not lvresize -L+10M --fs resize_fsadm $1
+ not lvreduce -L10M --fs resize_fsadm $1
+ crypt_open_plain "$2" $PWD3 "$4"
+ fscheck_ext3 "$3"
+}
+
+test_xfs_plain() {
+ mkfs.xfs -f "$3"
+
+ not fsadm --lvresize resize $1 30M
+ not lvresize -L+10M --fs resize_fsadm $1
+ not lvreduce -L10M --fs resize_fsadm $1
+ fscheck_xfs "$3"
+
+ lvresize -f -L+10M $1
+ fsadm --cryptresize resize $3 345M
+ # no shrink support in xfs
+ not fsadm --cryptresize resize $3 35M
+ fscheck_xfs "$3"
+
+ crypt_close "$4"
+ not fsadm --lvresize resize $1 30M
+ not lvresize -L+10M --fs resize_fsadm $1
+ not lvreduce -L10M --fs resize_fsadm $1
+ crypt_open_plain "$2" $PWD3 "$4"
+ fscheck_xfs "$3"
+
+ lvresize -f -L320M $1
+}
+
+test_reiserfs_plain() {
+ mkfs.reiserfs -s 513 -f "$3"
+
+ not fsadm --lvresize resize $1 30M
+ not lvresize -L+10M --fs resize_fsadm $1
+ not lvreduce -L-10M --fs resize_fsadm $1
+ fscheck_reiserfs "$3"
+
+ fsadm -y --cryptresize resize $3 30M
+ fsadm -y --cryptresize resize $3 35M
+ fscheck_reiserfs "$3"
+
+ crypt_close "$4"
+ not fsadm --lvresize resize $1 30M
+ not lvresize -L+10M --fs resize_fsadm $1
+ not lvreduce -L10M --fs resize_fsadm $1
+ crypt_open_plain "$2" $PWD3 "$4"
+ fscheck_reiserfs "$3"
+}
+
+# $1 LVM header backend (vg/lv name)
+# $2 LVM hedaer backend device (/dev/vg/lv)
+# $3 active dm-crypt device (/dev/mapper/some_name )
+# $4 active dm-crypt name ( some_name )a
+test_ext2_detached() {
+ mkfs.ext2 -b4096 -j "$3"
+
+ not fsadm --lvresize resize $1 30M
+ not lvresize -L+10M --fs resize_fsadm $1
+ not lvreduce -L10M --fs resize_fsadm $1
+ fscheck_ext3 "$3"
+}
+
+test_ext3_detached() {
+ mkfs.ext3 -b4096 -j "$3"
+
+ not fsadm --lvresize resize $1 30M
+ not lvresize -L+10M --fs resize_fsadm $1
+ not lvreduce -L10M --fs resize_fsadm $1
+ fscheck_ext3 "$3"
+}
+
+test_xfs_detached() {
+ mkfs.xfs -f "$3"
+
+ not fsadm --lvresize resize $1 30M
+ not lvresize -L+10M --fs resize_fsadm $1
+ not lvreduce -L10M --fs resize_fsadm $1
+
+ fscheck_xfs "$3"
+}
+
+test_reiserfs_detached() {
+ mkfs.reiserfs -s 513 -f "$3"
+
+ not fsadm --lvresize resize $1 30M
+ not lvresize -L+10M --fs resize_fsadm $1
+ not lvreduce -L10M --fs resize_fsadm $1
+
+ fscheck_reiserfs "$3"
+}
+
+if check_missing ext2; then
+ test_ext2_resize "$vg_lv" "$dev_vg_lv" "$CRYPT_DEV"
+ lvresize --fs ignore -y -L25M $vg_lv
+ cryptsetup resize $CRYPT_NAME
+
+ test_ext2_inactive "$vg_lv2" "$dev_vg_lv2" "$CRYPT_DEV2" "$CRYPT_NAME2"
+
+ crypt_open_plain "$dev_vg_lv3" $PWD3 "$CRYPT_NAME_PLAIN"
+ test_ext2_plain "$vg_lv3" "$dev_vg_lv3" "$CRYPT_DEV_PLAIN" "$CRYPT_NAME_PLAIN"
+ crypt_close "$CRYPT_NAME_PLAIN"
+
+ lvresize --fs ignore -y -L100M $vg_lv
+ cryptsetup resize $CRYPT_NAME
+ test_ext2_small_shrink "$vg_lv" "$dev_vg_lv" "$CRYPT_DEV"
+ lvresize --fs ignore -y -L25M $vg_lv
+ cryptsetup resize $CRYPT_NAME
+
+ if [ -z "$SKIP_DETACHED" ]; then
+ crypt_open_detached "$dev_vg_lv3" $PWD2 "$CRYPT_NAME2" "$dev_vg_lv2"
+ test_ext2_detached "$vg_lv2" "$dev_vg_lv2" "$CRYPT_DEV2" "$CRYPT_NAME2"
+ crypt_close "$CRYPT_NAME2"
+ fi
+fi
+
+if check_missing ext3; then
+ test_ext3_resize "$vg_lv" "$dev_vg_lv" "$CRYPT_DEV"
+ lvresize --fs ignore -y -L25M $vg_lv
+ cryptsetup resize $CRYPT_NAME
+
+ test_ext3_inactive "$vg_lv2" "$dev_vg_lv2" "$CRYPT_DEV2" "$CRYPT_NAME2"
+
+ crypt_open_plain "$dev_vg_lv3" $PWD3 "$CRYPT_NAME_PLAIN"
+ test_ext3_plain "$vg_lv3" "$dev_vg_lv3" "$CRYPT_DEV_PLAIN" "$CRYPT_NAME_PLAIN"
+ crypt_close "$CRYPT_NAME_PLAIN"
+
+ lvresize --fs ignore -y -L100M $vg_lv
+ cryptsetup resize $CRYPT_NAME
+ test_ext3_small_shrink "$vg_lv" "$dev_vg_lv" "$CRYPT_DEV"
+ lvresize --fs ignore -y -L25M $vg_lv
+ cryptsetup resize $CRYPT_NAME
+
+ if [ -z "$SKIP_DETACHED" ]; then
+ crypt_open_detached "$dev_vg_lv3" $PWD2 "$CRYPT_NAME2" "$dev_vg_lv2"
+ test_ext3_detached "$vg_lv2" "$dev_vg_lv2" "$CRYPT_DEV2" "$CRYPT_NAME2"
+ crypt_close "$CRYPT_NAME2"
+ fi
+fi
+
+if check_missing xfs; then
+ lvresize -f -L310M $vg_lv
+ cryptsetup resize $CRYPT_NAME
+ test_xfs_resize "$vg_lv" "$dev_vg_lv" "$CRYPT_DEV"
+ lvresize --fs ignore -y -L325M $vg_lv
+ cryptsetup resize $CRYPT_NAME
+
+ test_xfs_inactive "$vg_lv2" "$dev_vg_lv2" "$CRYPT_DEV2" "$CRYPT_NAME2"
+
+ crypt_open_plain "$dev_vg_lv3" $PWD3 "$CRYPT_NAME_PLAIN"
+ test_xfs_plain "$vg_lv3" "$dev_vg_lv3" "$CRYPT_DEV_PLAIN" "$CRYPT_NAME_PLAIN"
+ crypt_close "$CRYPT_NAME_PLAIN"
+
+ lvresize --fs ignore -y -L310M $vg_lv
+ cryptsetup resize $CRYPT_NAME
+ test_xfs_small_shrink "$vg_lv" "$dev_vg_lv" "$CRYPT_DEV"
+ lvresize --fs ignore -y -L25M $vg_lv
+ cryptsetup resize $CRYPT_NAME
+
+ if [ -z "$SKIP_DETACHED" ]; then
+ crypt_open_detached "$dev_vg_lv3" $PWD2 "$CRYPT_NAME2" "$dev_vg_lv2"
+ test_xfs_detached "$vg_lv2" "$dev_vg_lv2" "$CRYPT_DEV2" "$CRYPT_NAME2"
+ crypt_close "$CRYPT_NAME2"
+ fi
+fi
+
+if check_missing reiserfs; then
+ test_reiserfs_resize "$vg_lv" "$dev_vg_lv" "$CRYPT_DEV"
+ lvresize --fs ignore -y -L25M $vg_lv
+ cryptsetup resize $CRYPT_NAME
+
+ test_reiserfs_inactive "$vg_lv2" "$dev_vg_lv2" "$CRYPT_DEV2" "$CRYPT_NAME2"
+
+ crypt_open_plain "$dev_vg_lv3" $PWD3 "$CRYPT_NAME_PLAIN"
+ test_reiserfs_plain "$vg_lv3" "$dev_vg_lv3" "$CRYPT_DEV_PLAIN" "$CRYPT_NAME_PLAIN"
+ crypt_close "$CRYPT_NAME_PLAIN"
+
+ lvresize --fs ignore -y -L100M $vg_lv
+ cryptsetup resize $CRYPT_NAME
+ test_reiserfs_small_shrink "$vg_lv" "$dev_vg_lv" "$CRYPT_DEV"
+ lvresize --fs ignore -y -L25M $vg_lv
+ cryptsetup resize $CRYPT_NAME
+
+ if [ -z "$SKIP_DETACHED" ]; then
+ crypt_open_detached "$dev_vg_lv3" $PWD2 "$CRYPT_NAME2" "$dev_vg_lv2"
+ test_reiserfs_detached "$vg_lv2" "$dev_vg_lv2" "$CRYPT_DEV2" "$CRYPT_NAME2"
+ crypt_close "$CRYPT_NAME2"
+ fi
+fi
+
+crypt_close "$CRYPT_NAME"
+
+vgremove -ff $vg
diff --git a/test/shell/fsadm-renamed.sh b/test/shell/fsadm-renamed.sh
new file mode 100644
index 0000000..698b143
--- /dev/null
+++ b/test/shell/fsadm-renamed.sh
@@ -0,0 +1,138 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2017 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 operation on renamed device'
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+aux prepare_vg 1 700
+
+vg_lv=$vg/$lv1
+vg_lv_ren=${vg_lv}_renamed
+
+dev_vg_lv="$DM_DEV_DIR/$vg_lv"
+dev_vg_lv_ren="$DM_DEV_DIR/$vg_lv_ren"
+
+mount_dir="mnt"
+mount_space_dir="mnt space dir"
+mount_dolar_dir="mnt \$SPACE dir"
+
+test ! -d "$mount_dir" && mkdir "$mount_dir"
+test ! -d "$mount_space_dir" && mkdir "$mount_space_dir"
+test ! -d "$mount_dolar_dir" && mkdir "$mount_dolar_dir"
+
+cleanup_mounted_and_teardown()
+{
+ umount "$mount_dir" || true
+ umount "$mount_space_dir" || true
+ umount "$mount_dolar_dir" || true
+ aux teardown
+}
+
+check_mounted()
+{
+ mount | tee out
+ grep $vg out || {
+ # older versions of systemd sometimes umount volume by mistake
+ # skip further test when this case happens
+ systemctl --version | grep "systemd 222" && \
+ skip "System is running old racy systemd version."
+ }
+}
+
+# Test for block sizes != 1024 (rhbz #480022)
+trap 'cleanup_mounted_and_teardown' EXIT
+
+# Iterate over supported filesystems
+for i in mkfs.ext3 mkfs.xfs mkfs.reiserfs
+do
+
+if not which "$i" ; then
+ echo "Skipping tests for missing $i"
+ continue
+fi
+
+lvcreate -n $lv1 -L300M $vg
+
+case "$i" in
+*ext3) MKFS_ARGS="-b1024 -j" ;;
+*xfs) MKFS_ARGS="-l internal,size=64m -f" ;;
+*reiserfs) MKFS_ARGS="-s 513 -f" ;;
+esac
+
+echo "$i"
+"$i" $MKFS_ARGS "$dev_vg_lv"
+
+# Adding couple udev wait ops as some older systemd
+# might get confused and was 'randomly/racy' umounting
+# devices just mounted.
+#
+# See for explanation:
+# https://github.com/systemd/systemd/commit/628c89cc68ab96fce2de7ebba5933725d147aecc
+# https://github.com/systemd/systemd/pull/2017
+aux udev_wait
+
+# mount /dev/test/lv1 on /mnt
+mount "$dev_vg_lv" "$mount_dir"
+
+aux udev_wait
+
+# rename lv1 to lv1_renamed, now /dev/test/lv1_renamed is mounted on /mnt,
+# but "df" and "mount" commands will still show /dev/test/lv1 mounted on /mnt.
+lvrename $vg_lv $vg_lv_ren
+
+check_mounted
+
+# fails on renamed LV
+# lvextend -r test/lv1_renamed succeeds in extending the LV (as lv1_renamed),
+# but xfs_growfs /dev/test/lv1_renamed fails because it doesn't recognize
+# that device is mounted, because the old lv name reported as being mounted.
+fail lvresize -y -L+10M -r $vg_lv_ren
+
+# fails on unknown mountpoint (FIXME: umount)
+not umount "$dev_vg_lv"
+
+# create a new LV with the previous name of the renamed lv
+lvcreate -L300 -n $lv1 $vg
+"$i" $MKFS_ARGS "$dev_vg_lv"
+
+aux udev_wait
+
+# mount the new lv on a dir with a similar name as the other
+# now df will show
+# /dev/mapper/test-lv1 ... /mnt
+# /dev/mapper/test-lv1 ... /mnt $SPACE dir
+mount "$dev_vg_lv" "$mount_dolar_dir"
+
+check_mounted
+
+# try to resize the LV that was renamed: lvextend -r test/lv1_renamed
+# this succeeds in extending the LV (lv1_renamed), but xfs_growfs fails
+# for the same reason as above, i.e. mount doesn't show the lv1_renamed
+# device is mounted anywhere.
+not lvresize -L+10M -r $vg_lv_ren
+
+umount "$mount_dir"
+
+lvresize -y -L+10M -r $vg_lv
+
+aux udev_wait
+
+umount "$mount_dolar_dir"
+
+lvremove -ff $vg
+
+done
+
+vgremove -ff $vg
diff --git a/test/shell/fsadm.sh b/test/shell/fsadm.sh
index 4e624db..7f155d7 100644
--- a/test/shell/fsadm.sh
+++ b/test/shell/fsadm.sh
@@ -1,5 +1,6 @@
-#!/bin/sh
-# Copyright (C) 2008-2012 Red Hat, Inc. All rights reserved.
+#!/usr/bin/env bash
+
+# Copyright (C) 2008-2014 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
@@ -7,26 +8,36 @@
#
# 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
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
test_description='Exercise fsadm filesystem resize'
-. lib/test
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
-aux prepare_vg 1 100
+aux prepare_vg 1 400
# set to "skip" to avoid testing given fs and test warning result
# i.e. check_reiserfs=skip
+check_ext2=
check_ext3=
check_xfs=
check_reiserfs=
+which mkfs.ext2 || check_ext2=${check_ext2:-mkfs.ext2}
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 xfs_check || {
+ which xfs_repair || check_xfs=${check_xfs:-xfs_repair}
+}
+grep xfs /proc/filesystems || check_xfs=${check_xfs:-no_xfs}
+
which mkfs.reiserfs || check_reiserfs=${check_reiserfs:-mkfs.reiserfs}
which reiserfsck || check_reiserfs=${check_reiserfs:-reiserfsck}
+modprobe reiserfs || true
+grep reiserfs /proc/filesystems || check_reiserfs=${check_reiserfs:-no_reiserfs}
vg_lv=$vg/$lv1
vg_lv2=$vg/${lv1}bar
@@ -34,27 +45,30 @@ 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
+ umount "$mount_dir" 2>/dev/null || true
+ umount "$mount_space_dir" 2>/dev/null || true
aux teardown
}
fscheck_ext3()
{
- fsck.ext3 -p -F -f "$dev_vg_lv"
+ # fsck with result code '1' is success
+ fsck.ext3 -p -F -f "$dev_vg_lv" || test "$?" -eq 1
}
fscheck_xfs()
{
- xfs_check "$dev_vg_lv"
+ if which xfs_repair ; then
+ xfs_repair -n "$dev_vg_lv"
+ else
+ xfs_check "$dev_vg_lv"
+ fi
}
fscheck_reiserfs()
@@ -64,11 +78,13 @@ fscheck_reiserfs()
check_missing()
{
- eval local t=$\check_$1
+ local t
+ eval "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"
+ echo "WARNING: fsadm test skipped $1 tests, $t tool is missing."
+ # trick to get test listed with warning
+ # should false;
return 1
}
@@ -77,24 +93,62 @@ lvcreate -n $lv1 -L20M $vg
lvcreate -n ${lv1}bar -L10M $vg
trap 'cleanup_mounted_and_teardown' EXIT
+# prints help
+fsadm
+
+# check needs arg
+not fsadm check
+
+# check needs arg
+not fsadm resize "$dev_vg_lv" 30M |& tee out
+grep "Cannot get FSTYPE" out
+
if check_missing ext2; then
mkfs.ext2 -b4096 -j "$dev_vg_lv"
+ # Check 'check' works
+ fsadm check $vg_lv
+ # Check 'resize' without size parameter works
+ fsadm resize $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
+ lvresize -L+10M --fs resize_fsadm $vg_lv
+ lvreduce -L10M --fs resize_fsadm $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
+ echo n | not lvresize -L4M --fs resize_fsadm -n $vg_lv
+ lvresize -L+20M --fs resize_fsadm -n $vg_lv
umount "$mount_dir"
fscheck_ext3
- lvresize -f -L20M $vg_lv
+ lvresize --fs ignore -y -L20M $vg_lv
+
+ if which debugfs ; then
+ mkfs.ext2 -b4096 -j "$dev_vg_lv"
+ mount "$dev_vg_lv" "$mount_dir"
+ touch "$mount_dir/file"
+ umount "$mount_dir"
+ # generate a 'repariable' corruption
+ # so fsck returns code 1 (fs repaired)
+ debugfs -R "clri file" -w "$dev_vg_lv"
+
+ fsadm -v -f check "$dev_vg_lv"
+
+ # corrupting again
+ mount "$dev_vg_lv" "$mount_dir"
+ touch "$mount_dir/file"
+ umount "$mount_dir"
+ debugfs -R "clri file" -w "$dev_vg_lv"
+
+ mount "$dev_vg_lv" "$mount_dir"
+ fsadm -v -y --lvresize resize $vg_lv 10M
+ lvresize -L+10M -y --fs resize_fsadm -n $vg_lv
+ umount "$mount_dir" 2>/dev/null || true
+ fscheck_ext3
+ fi
fi
if check_missing ext3; then
@@ -104,47 +158,49 @@ if check_missing ext3; then
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
+ lvresize -L+10M --fs resize_fsadm $vg_lv
+ lvreduce -L10M --fs resize_fsadm $vg_lv
fscheck_ext3
mount "$dev_vg_lv" "$mount_dir"
- lvresize -L+10M -r $vg_lv
+ lvresize -L+10M --fs resize_fsadm $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
+ lvresize -L+20M --fs resize_fsadm -n $vg_lv
+ lvresize -L-10M --fs resize_fsadm -y $vg_lv
umount "$mount_dir"
umount "$mount_space_dir"
fscheck_ext3
- lvresize -f -L20M $vg_lv
+ lvresize --fs ignore -y -L20M $vg_lv
fi
if check_missing xfs; then
- mkfs.xfs -l internal,size=1000b -f "$dev_vg_lv"
+ lvresize -L 300M $vg_lv
+ mkfs.xfs -l internal -f "$dev_vg_lv"
- fsadm --lvresize resize $vg_lv 30M
+ fsadm --lvresize resize $vg_lv 320M
# Fails - not enough space for 4M fs
- lvresize -L+10M -r $vg_lv
- not lvreduce -L10M -r $vg_lv
+ lvresize -L+10M --fs resize_fsadm $vg_lv
+ not lvreduce -L10M --fs resize_fsadm $vg_lv
fscheck_xfs
mount "$dev_vg_lv" "$mount_dir"
- lvresize -L+10M -r -n $vg_lv
+ lvresize -L+10M --fs resize_fsadm -n $vg_lv
umount "$mount_dir"
fscheck_xfs
- lvresize -f -L20M $vg_lv
+ lvresize --fs ignore -y -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
+ lvresize -L+10M --fs resize_fsadm $vg_lv
fsadm --lvresize -y resize $vg_lv 10M
fscheck_reiserfs
@@ -154,7 +210,7 @@ if check_missing reiserfs; then
umount "$mount_dir"
fscheck_reiserfs
- lvresize -f -L20M $vg_lv
+ lvresize --fs ignore -y -L20M $vg_lv
fi
vgremove -ff $vg
diff --git a/test/shell/hints.sh b/test/shell/hints.sh
new file mode 100644
index 0000000..e25c7e1
--- /dev/null
+++ b/test/shell/hints.sh
@@ -0,0 +1,480 @@
+#!/usr/bin/env 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+SKIP_WITH_LVMPOLLD=1
+
+# hints are currently disabled with lvmlockd
+SKIP_WITH_LVMLOCKD=1
+
+. lib/inittest
+
+# Since this test is currenly using 'system's' hints,
+# it cannot be running, while lvmdbusd operates in the system.
+# FIXME: sometimes test suite itself 'leaks' lvmdbusd process.
+pgrep lvmdbusd && skip "Can't run this test, while lvmdbusd is running"
+
+RUNDIR="/run"
+test -d "$RUNDIR" || RUNDIR="/var/run"
+HINTS="$RUNDIR/lvm/hints"
+NOHINTS="$RUNDIR/lvm/nohints"
+NEWHINTS="$RUNDIR/lvm/newhints"
+PREV="$RUNDIR/lvm/prev-hints"
+
+# TODO:
+# Test commands that ignore hints
+# Test flock
+
+
+aux lvmconf 'devices/scan_lvs = 0'
+
+aux prepare_devs 6
+
+# no PVs yet so hints should have no devs
+pvs
+not grep scan: $HINTS
+
+#
+# test --nohints option
+#
+
+pvcreate "$dev1"
+pvcreate "$dev2"
+# pvs --nohints does not create hints
+pvs --nohints |tee out
+grep "$dev1" out
+grep "$dev2" out
+not grep "$dev1" $HINTS
+not grep "$dev2" $HINTS
+# pvs creates hints
+pvs
+grep "$dev1" $HINTS
+grep "$dev2" $HINTS
+
+# save hints with dev1 and dev2 before dev3 is created
+cp $HINTS $PREV
+# pvcreate --nohints invalidates hints
+pvcreate --nohints "$dev3"
+ls $NEWHINTS
+# pvs --nohints does not update hints
+pvs --nohints |tee out
+grep "$dev1" out
+grep "$dev2" out
+grep "$dev3" out
+not grep "$dev3" $HINTS
+# restore old hint file without dev3
+cp $PREV $HINTS
+# pvs --nohints does not update hints
+pvs --nohints |tee out
+grep "$dev1" out
+grep "$dev2" out
+grep "$dev3" out
+grep "$dev1" $HINTS
+grep "$dev2" $HINTS
+not grep "$dev3" $HINTS
+# pvs updates hints
+pvs |tee out
+grep "$dev1" out
+grep "$dev2" out
+grep "$dev3" out
+grep "$dev1" $HINTS
+grep "$dev2" $HINTS
+grep "$dev3" $HINTS
+
+aux wipefs_a "$dev1" "$dev2" "$dev3"
+
+#
+# vg1 uses dev1,dev2
+#
+# Test basics that PVs are in hints, not non-PV devs,
+# and that only PVs are scanned when using hints.
+#
+
+rm $HINTS
+
+vgcreate $vg1 "$dev1" "$dev2"
+lvcreate -n $lv1 -l 4 $vg1
+
+# test that only the two PVs are in hints
+pvs
+grep -v -E "$dev1|$dev2" $HINTS > tmptest
+not grep scan: tmptest
+
+# test that 'pvs' submits only three reads, one for each PV in hints
+# for initial scan, and one more in vg_read rescan check
+
+if which strace; then
+strace -e io_submit pvs 2>&1|tee tmptest
+test "$(grep -c io_submit tmptest)" -eq 3
+
+# test that 'pvs -a' submits seven reads, one for each device,
+# and one more in vg_read rescan check
+strace -e io_submit pvs -a 2>&1|tee tmptest
+test "$(grep -c io_submit tmptest)" -eq 7
+fi
+
+#
+# vg2 uses dev3,dev4
+#
+# Test common commands that cause hints to be refreshed:
+# pvcreate/vgcreate/vgextend/vgreduce/vgremove/pvremove
+#
+
+not pvs "$dev3"
+not grep "$dev3" $HINTS
+cp $HINTS $PREV
+pvcreate "$dev3"
+grep "# Created empty" $HINTS
+cat $NEWHINTS
+# next cmd recreates hints
+pvs "$dev3"
+grep "$dev3" $HINTS
+not diff $HINTS $PREV
+not cat $NEWHINTS
+
+not vgs $vg2
+cp $HINTS $PREV
+vgcreate $vg2 "$dev3"
+grep "# Created empty" $HINTS
+cat $NEWHINTS
+# next cmd recreates hints
+vgs $vg2
+grep $vg2 $HINTS
+not diff $HINTS $PREV
+not cat $NEWHINTS
+
+cp $HINTS $PREV
+vgextend $vg2 "$dev4"
+grep "# Created empty" $HINTS
+cat $NEWHINTS
+# next cmd recreates hints
+vgs $vg2
+grep "$dev4" $HINTS
+not diff $HINTS $PREV
+not cat $NEWHINTS
+
+cp $HINTS $PREV
+vgreduce $vg2 "$dev4"
+grep "# Created empty" $HINTS
+cat $NEWHINTS
+# next cmd recreates hints
+vgs $vg2
+grep "$dev4" $HINTS
+not diff $HINTS $PREV
+not cat $NEWHINTS
+
+cp $HINTS $PREV
+vgremove $vg2
+grep "# Created empty" $HINTS
+cat $NEWHINTS
+# next cmd recreates hints
+not vgs $vg2
+not grep $vg2 $HINTS
+not diff $HINTS $PREV
+not cat $NEWHINTS
+
+cp $HINTS $PREV
+pvremove "$dev3" "$dev4"
+grep "# Created empty" $HINTS
+cat $NEWHINTS
+# next cmd recreates hints
+not pvs "$dev3"
+not pvs "$dev4"
+not grep "$dev3" $HINTS
+not grep "$dev4" $HINTS
+not diff $HINTS $PREV
+not cat $NEWHINTS
+
+#
+# Test that adding a new device and removing a device
+# causes hints to be recreated.
+#
+# with a devices file the appearance of a new device on
+# the system does not disturb lvm, so this test doesn't
+# apply
+#
+
+if ! lvmdevices; then
+
+not pvs "$dev5"
+
+# create a new temp device that will cause hint hash to change
+DEVNAME=${PREFIX}pv99
+echo "0 $(blockdev --getsize "$dev5") linear $dev5 0" | dmsetup create $DEVNAME
+dmsetup status $DEVNAME
+
+cp $HINTS $PREV
+# pvs ignores current hints because of different dev hash and refreshes new hints
+pvs
+# devs listed in hints before and after are the same
+grep scan: $PREV > scan1
+grep scan: $HINTS > scan2
+diff scan1 scan2
+# hash listed before and after are different
+cat $PREV
+cat $HINTS
+grep devs_hash $PREV > devs_hash1
+grep devs_hash $HINTS > devs_hash2
+not diff devs_hash1 devs_hash2
+
+# hints are stable/unchanging
+cp $HINTS $PREV
+pvs
+diff $HINTS $PREV
+
+# remove the temp device which will cause hint hash to change again
+dmsetup remove $DEVNAME
+
+cp $HINTS $PREV
+# pvs ignores current hints because of different dev hash and refreshes new hints
+pvs
+# devs listed in hints before and after are the same
+grep scan: $PREV > scan1
+grep scan: $HINTS > scan2
+diff scan1 scan2
+# hash listed before and after are different
+grep devs_hash $PREV > devs_hash1
+grep devs_hash $HINTS > devs_hash2
+not diff devs_hash1 devs_hash2
+
+# end of new device test for non-devicesfile case
+fi
+
+#
+# Test that hints don't change from a bunch of commands
+# that use hints and shouldn't change it.
+#
+
+# first create some more metadata using vg2
+pvcreate "$dev3" "$dev4"
+vgcreate $vg2 "$dev3"
+lvcreate -n $lv1 -l1 $vg2
+lvcreate -n $lv2 -l1 $vg2
+
+cp $HINTS $PREV
+lvm fullreport
+lvchange -ay $vg1
+lvchange -an $vg1
+lvcreate -l1 -n $lv2 $vg1
+lvcreate -l1 -an -n $lv3 $vg1
+lvchange -an $vg1
+lvremove $vg1/$lv3
+lvresize --fs ignore -l+1 $vg1/$lv2
+lvresize --fs ignore -l-1 $vg1/$lv2
+lvdisplay
+pvdisplay
+vgdisplay
+lvs
+pvs
+vgs
+vgchange -ay $vg2
+vgchange -an $vg2
+vgck $vg2
+lvrename $vg1 $lv2 $lv3
+# no change in hints after all that
+diff $HINTS $PREV
+
+#
+# Test that changing the filter will cause hint refresh
+#
+
+rm $HINTS $PREV
+vgs
+cp $HINTS $PREV
+# this changes the filter to exclude dev5 which is not a PV
+aux hide_dev "$dev5"
+# next cmd sees different filter, ignores hints, creates new hints
+pvs
+not diff $HINTS $PREV
+# run cmds using new filter
+pvs
+cp $HINTS $PREV
+vgs
+# hints are stable once refreshed
+diff $HINTS $PREV
+# this changes the filter to include dev5
+aux unhide_dev "$dev5"
+# next cmd sees different filter, ignores hints, creates new hints
+pvs
+not diff $HINTS $PREV
+# hints are stable
+cp $HINTS $PREV
+vgs
+diff $HINTS $PREV
+
+#
+# Test that changing scan_lvs will cause hint refresh
+#
+
+rm $HINTS $PREV
+vgs
+cp $HINTS $PREV
+# change lvm.conf
+aux lvmconf 'devices/scan_lvs = 1'
+# next cmd sees new setting, ignores hints, creates new hints
+pvs
+not diff $HINTS $PREV
+# run cmds using new filter
+pvs
+cp $HINTS $PREV
+vgs
+# hints are stable once refreshed
+diff $HINTS $PREV
+# change lvm.conf back
+aux lvmconf 'devices/scan_lvs = 0'
+# next cmd sees different scan_lvs, ignores hints, creates new hints
+pvs
+not diff $HINTS $PREV
+# hints are stable once refreshed
+cp $HINTS $PREV
+pvs
+diff $HINTS $PREV
+
+#
+# Test pvscan --cache to force hints refresh
+#
+
+# pvs (no change), pvscan (hints are new), pvs (no change)
+rm $HINTS $PREV
+pvs
+cp $HINTS $PREV
+# this next pvscan recreates the hints file
+pvscan --cache
+# the only diff will be "Created by pvscan ..." vs "Created by pvs ..."
+not diff $HINTS $PREV
+cp $HINTS $PREV
+pvs
+diff $HINTS $PREV
+grep 'Created by pvscan' $HINTS
+# dev4 is a PV not used by a VG, dev5 is not a PV
+# using dd to copy skirts hint tracking so dev5 won't be seen
+# (unless the dd triggers udev which triggers pvscan --cache $dev5,
+# but I've not seen that happen in tests so far.)
+dd if="$dev4" of="$dev5" bs=1M
+# this pvs won't see dev5
+pvs > foo
+cat foo
+grep "$dev4" foo
+not grep "$dev5" foo
+# no hints have changed after dd and pvs since dd cannot be detected
+diff $HINTS $PREV
+# force hints refresh, will see duplicate now
+pvscan --cache
+not diff $HINTS $PREV
+cat $HINTS
+pvs -a > foo
+# after force refresh, both devs (dups) appear in output
+cat foo
+grep "$dev4" foo
+grep "$dev5" foo
+# clear PV from dev5
+dd if=/dev/zero of="$dev5" bs=1M count=1
+# this pvs won't use hints because of duplicate PVs,
+# and will create new hints
+cp $HINTS $PREV
+pvs > foo
+not diff $HINTS $PREV
+grep "$dev4" foo
+not grep "$dev5" foo
+grep "$dev4" $HINTS
+not grep "$dev5" $HINTS
+
+#
+# Test pvscan --cache <dev> forces refresh
+#
+
+rm $HINTS $PREV
+pvs
+cp $HINTS $PREV
+# this next pvscan creates newhints to trigger a refresh
+pvscan --cache "$dev4"
+cat $NEWHINTS
+# this next pvs creates new hints
+pvs
+# the only diff will be "Created by..."
+not diff $HINTS $PREV
+
+
+#
+# Test pvck --repair forces refresh
+#
+
+rm $HINTS $PREV
+pvs
+cp $HINTS $PREV
+pvck --repairtype label_header -y "$dev3"
+cat $NEWHINTS
+grep 'Created empty by pvck' $HINTS
+# this next pvs creates new hints
+pvs
+# the only diff will be "Created by..."
+not diff $HINTS $PREV
+
+
+#
+# Test incorrect dev-to-pvid info in hints is detected
+# dev4 is a PV not in a VG
+#
+
+pvs
+cp $HINTS tmp-old
+# this pvchange will invalidate current hints
+pvchange -u "$dev4"
+grep "# Created empty" $HINTS
+cat $NEWHINTS
+# this next pvs will create new hints with the new uuid
+pvs
+grep "$dev4" $HINTS > tmp-newuuid
+cp $HINTS tmp-new
+not diff tmp-old tmp-new
+# hints are stable
+pvs
+diff $HINTS tmp-new
+# replace the current hints with the old hints with the old uuid
+cp tmp-old $HINTS
+# this next pvs will see wrong dev-to-pvid mapping and invalidate hints
+pvs
+cat $HINTS
+cat $NEWHINTS
+# this next pvs will create new hints with the new uuid
+pvs
+cat $HINTS
+grep -f tmp-newuuid $HINTS
+rm tmp-old tmp-new tmp-newuuid
+
+
+#
+# Test incorrent pvid-to-vgname info in hints is detected
+#
+
+# this vgcreate invalidates current hints
+vgcreate $vg3 "$dev4"
+# this pvs creates new hints
+pvs
+cp $HINTS tmp-old
+# this vgrename will invalidate current hints
+vgrename $vg3 $vg4
+# this pvs will create new hints with the new vg name
+pvs
+cp $HINTS tmp-new
+not diff tmp-old tmp-new
+# replace the current hints with the old hints with the old vg name
+cp tmp-old $HINTS
+# this pvs will see wrong pvid-to-vgname mapping and invalidate hints
+pvs
+cat $NEWHINTS
+# this pvs will create new hints with the new vg name
+pvs
+grep $vg4 $HINTS
+
+vgremove -y $vg4
+vgremove -y $vg2
+vgremove -y $vg1
diff --git a/test/shell/idm_fabric_failure.sh b/test/shell/idm_fabric_failure.sh
new file mode 100644
index 0000000..edca86b
--- /dev/null
+++ b/test/shell/idm_fabric_failure.sh
@@ -0,0 +1,58 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2020 Seagate, 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 v2.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+[ -z "$LVM_TEST_FAILURE" ] && skip
+
+aux prepare_devs 3
+aux extend_filter_LVMTEST
+
+vgcreate $SHARED $vg "$dev1" "$dev2" "$dev3"
+
+# Create new logic volume
+lvcreate -a ey --zero n -l 50%FREE -n $lv1 $vg
+
+DRIVE1=$(dmsetup deps -o devname "$dev1" | awk '{gsub(/[()]/,""); print $4;}' | sed 's/[0-9]*$//')
+DRIVE2=$(dmsetup deps -o devname "$dev2" | awk '{gsub(/[()]/,""); print $4;}' | sed 's/[0-9]*$//')
+DRIVE3=$(dmsetup deps -o devname "$dev3" | awk '{gsub(/[()]/,""); print $4;}' | sed 's/[0-9]*$//')
+
+HOST1=$(readlink "/sys/block/$DRIVE1" | awk -F'/' '{print $6}')
+HOST2=$(readlink "/sys/block/$DRIVE2" | awk -F'/' '{print $6}')
+HOST3=$(readlink "/sys/block/$DRIVE3" | awk -F'/' '{print $6}')
+
+# Emulate fabric failure
+echo 1 > "/sys/block/$DRIVE1/device/delete"
+[ -f "/sys/block/$DRIVE2/device/delete" ] && echo 1 > "/sys/block/$DRIVE2/device/delete"
+[ -f "/sys/block/$DRIVE3/device/delete" ] && echo 1 > "/sys/block/$DRIVE3/device/delete"
+
+# Wait for 10s and will not lead to timeout
+sleep 10
+
+# Rescan drives so can probe the deleted drives and join back them
+echo "- - -" > "/sys/class/scsi_host/${HOST1}/scan"
+echo "- - -" > "/sys/class/scsi_host/${HOST2}/scan"
+echo "- - -" > "/sys/class/scsi_host/${HOST3}/scan"
+
+not check grep_lvmlockd_dump "S lvm_$vg kill_vg"
+
+# The previous device-mapper are removed, but LVM still can directly
+# access VGs from the specified physical drives. So enable drives
+# for these drives.
+aux extend_filter_LVMTEST "a|/dev/$DRIVE1*|" "a|/dev/$DRIVE2*|" "a|/dev/$DRIVE3*|"
+aux lvmconf "devices/allow_changes_with_duplicate_pvs = 1"
+
+lvcreate -a n --zero n -l 10 -n $lv2 $vg
+
+vgremove -ff $vg
diff --git a/test/shell/idm_fabric_failure_half_brain.sh b/test/shell/idm_fabric_failure_half_brain.sh
new file mode 100644
index 0000000..e649646
--- /dev/null
+++ b/test/shell/idm_fabric_failure_half_brain.sh
@@ -0,0 +1,78 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2020 Seagate, 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 v2.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+[ -z "$LVM_TEST_LOCK_TYPE_IDM" ] && skip
+[ -z "$LVM_TEST_FAILURE" ] && skip
+
+aux prepare_devs 2
+aux extend_filter_LVMTEST
+
+DRIVE1=$(dmsetup deps -o devname "$dev1" | awk '{gsub(/[()]/,""); print $4;}' | sed 's/[0-9]*$//')
+DRIVE2=$(dmsetup deps -o devname "$dev2" | awk '{gsub(/[()]/,""); print $4;}' | sed 's/[0-9]*$//')
+
+[ "$(basename -- $DRIVE1)" = "$(basename -- $DRIVE2)" ] && die "Need to pass two different drives!?"
+
+# The previous device-mapper are removed, but LVM still can directly
+# access VGs from the specified physical drives. So enable drives
+# for these drives.
+aux extend_filter_LVMTEST "a|/dev/$DRIVE1*|" "a|/dev/$DRIVE2*|"
+aux lvmconf "devices/allow_changes_with_duplicate_pvs = 1"
+
+vgcreate $SHARED $vg "$dev1" "$dev2"
+
+# Create new logic volume
+lvcreate -a ey --zero n -l 100%FREE -n $lv1 $vg
+
+drive_list=($DRIVE1)
+
+# Find all drives with the same WWN and delete them from system,
+# so that we can emulate the same drive with multiple paths are
+# disconnected with system.
+drive_wwn=$(udevadm info /dev/${DRIVE1} | awk -F= '/E: ID_WWN=/ {print $2}')
+for dev in /dev/*; do
+ if [ -b "$dev" ] && [[ ! "$dev" =~ [0-9] ]]; then
+ wwn=$(udevadm info "${dev}" | awk -F= '/E: ID_WWN=/ {print $2}')
+ if [ "$wwn" = "$drive_wwn" ]; then
+ base_name="$(basename -- ${dev})"
+ drive_list+=("$base_name")
+ host_list+=( $(readlink "/sys/block/$base_name" | awk -F'/' '{print $6}') )
+ fi
+ fi
+done
+
+for d in "${drive_list[@]}"; do
+ [ -f "/sys/block/$d/device/delete" ] && echo 1 > "/sys/block/$d/device/delete"
+done
+
+# Fail to create new logic volume
+not lvcreate -a n --zero n -l 1 -n $lv2 $vg
+
+# Wait for lock time out caused by drive failure
+sleep 70
+
+not check grep_lvmlockd_dump "S lvm_$vg kill_vg"
+
+# Rescan drives so can probe the deleted drives and join back them
+for h in "${host_list[@]}"; do
+ [ -f "/sys/class/scsi_host/${h}/scan" ] && echo "- - -" > "/sys/class/scsi_host/${h}/scan"
+done
+
+# After the drive is reconnected, $vg should be visible again.
+vgchange --lock-start
+lvremove -f $vg/$lv1
+lvcreate -a ey --zero n -l 1 -n $lv2 $vg
+vgremove -ff $vg
diff --git a/test/shell/idm_fabric_failure_timeout.sh b/test/shell/idm_fabric_failure_timeout.sh
new file mode 100644
index 0000000..2924d81
--- /dev/null
+++ b/test/shell/idm_fabric_failure_timeout.sh
@@ -0,0 +1,74 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2020 Seagate, 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 v2.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+[ -z "$LVM_TEST_LOCK_TYPE_IDM" ] && skip
+[ -z "$LVM_TEST_FAILURE" ] && skip
+
+aux prepare_devs 1
+aux extend_filter_LVMTEST
+
+DRIVE1=$(dmsetup deps -o devname "$dev1" | awk '{gsub(/[()]/,""); print $4;}' | sed 's/[0-9]*$//')
+
+# The previous device-mapper are removed, but LVM still can directly
+# access VGs from the specified physical drives. So enable drives
+# for these drives.
+aux extend_filter_LVMTEST "a|/dev/$DRIVE1*|"
+aux lvmconf "devices/allow_changes_with_duplicate_pvs = 1"
+
+vgcreate $SHARED $vg "$dev1"
+
+# Create new logic volume
+lvcreate -a ey --zero n -l 1 -n $lv1 $vg
+
+drive_list=( "$DRIVE1" )
+
+# Find all drives with the same WWN and delete them from system,
+# so that we can emulate the same drive with multiple paths are
+# disconnected with system.
+drive_wwn=$(udevadm info /dev/${DRIVE1} | awk -F= '/E: ID_WWN=/ {print $2}')
+for dev in /dev/*; do
+ if [ -b "$dev" ] && [[ ! "$dev" =~ [0-9] ]]; then
+ wwn=$(udevadm info "${dev}" | awk -F= '/E: ID_WWN=/ {print $2}')
+ if [ "$wwn" = "$drive_wwn" ]; then
+ base_name="$(basename -- ${dev})"
+ drive_list+=("$base_name")
+ host_list+=( $(readlink "/sys/block/$base_name" | awk -F'/' '{print $6}') )
+ fi
+ fi
+done
+
+for d in "${drive_list[@]}"; do
+ [ -f "/sys/block/$d/device/delete" ] && echo 1 > "/sys/block/$d/device/delete"
+done
+
+# Fail to create new logic volume
+not lvcreate -a n --zero n -l 1 -n $lv2 $vg
+
+# Wait for lock time out caused by drive failure
+sleep 70
+
+check grep_lvmlockd_dump "S lvm_$vg kill_vg"
+lvmlockctl --drop $vg
+
+# Rescan drives so can probe the deleted drives and join back them
+for h in "${host_list[@]}"; do
+ [ -f "/sys/class/scsi_host/${h}/scan" ] && echo "- - -" > "/sys/class/scsi_host/${h}/scan"
+done
+
+# After the drive is reconnected, $vg should be visible again.
+vgchange --lock-start
+vgremove -ff $vg
diff --git a/test/shell/idm_ilm_failure.sh b/test/shell/idm_ilm_failure.sh
new file mode 100644
index 0000000..6b8e591
--- /dev/null
+++ b/test/shell/idm_ilm_failure.sh
@@ -0,0 +1,80 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2020 Seagate, 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+[ -z "$LVM_TEST_LOCK_TYPE_IDM" ] && skip
+[ -z "$LVM_TEST_FAILURE" ] && skip
+
+aux prepare_devs 3
+aux extend_filter_LVMTEST
+
+DRIVE1=$(dmsetup deps -o devname "$dev1" | awk '{gsub(/[()]/,""); print $4;}' | sed 's/[0-9]*$//')
+DRIVE2=$(dmsetup deps -o devname "$dev2" | awk '{gsub(/[()]/,""); print $4;}' | sed 's/[0-9]*$//')
+DRIVE3=$(dmsetup deps -o devname "$dev3" | awk '{gsub(/[()]/,""); print $4;}' | sed 's/[0-9]*$//')
+
+if [ "$DRIVE1" = "$DRIVE2" ] || [ "$DRIVE1" = "$DRIVE3" ] || [ "$DRIVE2" = "$DRIVE3" ]; then
+ die "Need to pass three different drives!?"
+fi
+
+# The previous device-mapper are removed, but LVM still can directly
+# access VGs from the specified physical drives. So enable drives
+# for these drives.
+aux extend_filter_LVMTEST "a|/dev/$DRIVE1*|" "a|/dev/$DRIVE2*|" "a|/dev/$DRIVE3*|"
+aux lvmconf "devices/allow_changes_with_duplicate_pvs = 1"
+
+vgcreate $SHARED $vg "$dev1" "$dev2" "$dev3"
+
+# Create new logic volume and deactivate it
+lvcreate -a y --zero n -l 1 -n $lv1 $vg
+
+# Inject failure 40% so cannot send partially request to drives
+idm_inject_failure 40
+
+# Wait for 40s, but the lock will not be time out
+sleep 40
+
+# Inject failure with 0% so can access drives
+idm_inject_failure 0
+
+# Deactivate logic volume due to locking failure
+lvchange $vg/$lv1 -a n
+
+# Inject failure 100% so cannot send request to drives
+idm_inject_failure 100
+
+# Wait for 70s but should have no any alive locks
+sleep 70
+
+# Inject failure with 0% so can access drives
+idm_inject_failure 0
+
+# Activate logic volume
+lvchange $vg/$lv1 -a y
+
+# Inject failure so cannot send request to drives
+idm_inject_failure 100
+
+# Wait for 70s but will not time out
+sleep 70
+
+# Inject failure with 0% so can access drives
+idm_inject_failure 0
+
+check grep_lvmlockd_dump "S lvm_$vg kill_vg"
+lvmlockctl --drop $vg
+
+vgchange --lock-start
+vgremove -f $vg
diff --git a/test/shell/inconsistent-metadata.sh b/test/shell/inconsistent-metadata.sh
index 9f4ffd2..e5ccf0c 100644
--- a/test/shell/inconsistent-metadata.sh
+++ b/test/shell/inconsistent-metadata.sh
@@ -1,4 +1,5 @@
-#!/bin/sh
+#!/usr/bin/env bash
+
# Copyright (C) 2008 Red Hat, Inc. All rights reserved.
#
# This copyrighted material is made available to anyone wishing to use,
@@ -7,74 +8,64 @@
#
# 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
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
-. lib/test
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
aux prepare_vg 3 12
+get_devs
-lvcreate -m 1 -l 1 -n mirror $vg
+lvcreate -aye --type mirror -m 1 -l 1 -n mirror $vg
lvcreate -l 1 -n resized $vg
lvchange -a n $vg/mirror
-aux backup_dev $(cat DEVICES)
+aux backup_dev "${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
+makeold() {
+ # reset metadata on all devs to starting condition
+ aux restore_dev "${DEVICES[@]}"
+ not check lv_field $vg/resized lv_size "8.00m"
+ # change the metadata on all devs
lvresize -L 8192K $vg/resized
+ # reset metadata on just dev1 to the previous version
aux restore_dev "$dev1"
}
-check() {
- lvs -o lv_name,lv_size --units k $vg | tee lvs.out
- grep resized lvs.out | grep 8192
-}
+# create old metadata
+makeold
+
+# reports old metadata
+vgs $vg 2>&1 | tee cmd.out
+grep "ignoring metadata" cmd.out
+check lv_field $vg/resized lv_size "8.00m"
+
+# corrects old metadata
+lvcreate -l1 -an $vg
+
+# no old report
+vgs $vg 2>&1 | tee cmd.out
+not grep "ignoring metadata" cmd.out
+check lv_field $vg/resized lv_size "8.00m"
+
+
+echo Check auto-repair of failed vgextend
+echo - metadata written to original pv but not new pv
-# 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)
+pvremove -ff "${DEVICES[@]}"
+pvcreate "${DEVICES[@]}"
+
aux backup_dev "$dev2"
-vgcreate $vg "$dev1"
+vgcreate $SHARED $vg "$dev1"
vgextend $vg "$dev2"
aux restore_dev "$dev2"
+
+vgs -o+vg_mda_count $vg
+pvs -o+vg_mda_count
+
should check compare_fields vgs $vg vg_mda_count pvs "$dev2" vg_mda_count
+
+vgremove -ff $vg
diff --git a/test/shell/integrity-blocksize-2.sh b/test/shell/integrity-blocksize-2.sh
new file mode 100644
index 0000000..14c3bb1
--- /dev/null
+++ b/test/shell/integrity-blocksize-2.sh
@@ -0,0 +1,98 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2018 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+aux have_integrity 1 5 0 || skip
+# Avoid 4K ramdisk devices on older kernels
+aux kernel_at_least 5 10 || export LVM_TEST_PREFER_BRD=0
+
+mnt="mnt"
+mkdir -p $mnt
+
+# prepare_devs uses ramdisk backing which has 512 LBS and 4K PBS
+# This should cause mkfs.xfs to use 4K sector size,
+# and integrity to use 4K block size
+aux prepare_devs 2 64
+
+vgcreate $vg "$dev1" "$dev2"
+blockdev --getss "$dev1"
+blockdev --getpbsz "$dev1"
+blockdev --getss "$dev2"
+blockdev --getpbsz "$dev2"
+
+# add integrity while LV is inactive
+lvcreate --type raid1 -m1 -n $lv1 -l 8 $vg
+lvchange -an $vg/$lv1
+lvchange -ay $vg/$lv1
+mkfs.ext4 "$DM_DEV_DIR/$vg/$lv1"
+mount "$DM_DEV_DIR/$vg/$lv1" $mnt
+echo "hello world" > $mnt/hello
+umount $mnt
+lvchange -an $vg
+lvconvert --raidintegrity y $vg/$lv1
+lvchange -ay $vg
+aux wait_recalc $vg/${lv1}_rimage_0
+aux wait_recalc $vg/${lv1}_rimage_1
+lvs -a -o+devices $vg
+mount "$DM_DEV_DIR/$vg/$lv1" $mnt
+cat $mnt/hello
+umount $mnt
+lvchange -an $vg/$lv1
+lvremove $vg/$lv1
+
+# add integrity while LV is active, fs unmounted
+# lvconvert will use ribs 512 to avoid increasing LBS from 512 to 4k on active LV
+lvcreate --type raid1 -m1 -n $lv1 -l 8 $vg
+lvchange -an $vg/$lv1
+lvchange -ay $vg/$lv1
+mkfs.ext4 "$DM_DEV_DIR/$vg/$lv1"
+mount "$DM_DEV_DIR/$vg/$lv1" $mnt
+echo "hello world" > $mnt/hello
+umount $mnt
+lvchange -an $vg
+lvchange -ay $vg
+lvconvert --raidintegrity y $vg/$lv1
+aux wait_recalc $vg/${lv1}_rimage_0
+aux wait_recalc $vg/${lv1}_rimage_1
+lvs -a -o+devices $vg
+mount "$DM_DEV_DIR/$vg/$lv1" $mnt
+cat $mnt/hello | grep "hello world"
+umount $mnt
+lvchange -an $vg/$lv1
+lvremove $vg/$lv1
+
+# add integrity while LV is active, fs mounted
+# lvconvert will use ribs 512 to avoid increasing LBS from 512 to 4k on active LV
+lvcreate --type raid1 -m1 -n $lv1 -l 8 $vg
+lvchange -an $vg/$lv1
+lvchange -ay $vg/$lv1
+mkfs.ext4 "$DM_DEV_DIR/$vg/$lv1"
+mount "$DM_DEV_DIR/$vg/$lv1" $mnt
+echo "hello world" > $mnt/hello
+lvconvert --raidintegrity y $vg/$lv1
+aux wait_recalc $vg/${lv1}_rimage_0
+aux wait_recalc $vg/${lv1}_rimage_1
+lvs -a -o+devices $vg
+cat $mnt/hello | grep "hello world"
+umount $mnt
+lvchange -an $vg/$lv1
+lvchange -ay $vg/$lv1
+mount "$DM_DEV_DIR/$vg/$lv1" $mnt
+cat $mnt/hello | grep "hello world"
+umount $mnt
+lvchange -an $vg/$lv1
+lvremove $vg/$lv1
+
+vgremove -ff $vg
diff --git a/test/shell/integrity-blocksize-3.sh b/test/shell/integrity-blocksize-3.sh
new file mode 100644
index 0000000..f86d7f7
--- /dev/null
+++ b/test/shell/integrity-blocksize-3.sh
@@ -0,0 +1,252 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2018 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+aux have_integrity 1 5 0 || skip
+
+mnt="mnt"
+mkdir -p $mnt
+
+# scsi_debug devices with 512 LBS 512 PBS
+aux prepare_scsi_debug_dev 256
+check sysfs "$(< SCSI_DEBUG_DEV)" queue/logical_block_size "512"
+check sysfs "$(< SCSI_DEBUG_DEV)" queue/physical_block_size "512"
+aux prepare_devs 2 64
+
+vgcreate $vg "$dev1" "$dev2"
+blockdev --getss "$dev1"
+blockdev --getpbsz "$dev1"
+blockdev --getss "$dev2"
+blockdev --getpbsz "$dev2"
+
+# add integrity while LV is inactive
+lvcreate --type raid1 -m1 -n $lv1 -l 8 $vg
+lvchange -an $vg/$lv1
+lvchange -ay $vg/$lv1
+mkfs.ext4 "$DM_DEV_DIR/$vg/$lv1"
+mount "$DM_DEV_DIR/$vg/$lv1" $mnt
+echo "hello world" > $mnt/hello
+umount $mnt
+lvchange -an $vg
+lvconvert --raidintegrity y $vg/$lv1
+lvchange -ay $vg
+aux wait_recalc $vg/${lv1}_rimage_0
+aux wait_recalc $vg/${lv1}_rimage_1
+lvs -a -o+devices $vg
+mount "$DM_DEV_DIR/$vg/$lv1" $mnt
+cat $mnt/hello
+umount $mnt
+lvchange -an $vg/$lv1
+lvremove $vg/$lv1
+
+# add integrity while LV is active, fs unmounted
+lvcreate --type raid1 -m1 -n $lv1 -l 8 $vg
+lvchange -an $vg/$lv1
+lvchange -ay $vg/$lv1
+mkfs.ext4 "$DM_DEV_DIR/$vg/$lv1"
+mount "$DM_DEV_DIR/$vg/$lv1" $mnt
+echo "hello world" > $mnt/hello
+umount $mnt
+lvchange -an $vg
+lvchange -ay $vg
+lvconvert --raidintegrity y $vg/$lv1
+aux wait_recalc $vg/${lv1}_rimage_0
+aux wait_recalc $vg/${lv1}_rimage_1
+lvs -a -o+devices $vg
+mount "$DM_DEV_DIR/$vg/$lv1" $mnt
+cat $mnt/hello | grep "hello world"
+umount $mnt
+lvchange -an $vg/$lv1
+lvremove $vg/$lv1
+
+# add integrity while LV is active, fs mounted
+lvcreate --type raid1 -m1 -n $lv1 -l 8 $vg
+lvchange -an $vg/$lv1
+lvchange -ay $vg/$lv1
+mkfs.ext4 "$DM_DEV_DIR/$vg/$lv1"
+mount "$DM_DEV_DIR/$vg/$lv1" $mnt
+echo "hello world" > $mnt/hello
+lvconvert --raidintegrity y $vg/$lv1
+aux wait_recalc $vg/${lv1}_rimage_0
+aux wait_recalc $vg/${lv1}_rimage_1
+lvs -a -o+devices $vg
+cat $mnt/hello | grep "hello world"
+umount $mnt
+lvchange -an $vg/$lv1
+lvchange -ay $vg/$lv1
+mount "$DM_DEV_DIR/$vg/$lv1" $mnt
+cat $mnt/hello | grep "hello world"
+umount $mnt
+lvchange -an $vg/$lv1
+lvremove $vg/$lv1
+
+vgremove -ff $vg
+aux cleanup_scsi_debug_dev
+sleep 1
+
+# scsi_debug devices with 4K LBS and 4K PBS
+aux prepare_scsi_debug_dev 256 sector_size=4096
+check sysfs "$(< SCSI_DEBUG_DEV)" queue/logical_block_size "4096"
+check sysfs "$(< SCSI_DEBUG_DEV)" queue/physical_block_size "4096"
+aux prepare_devs 2 64
+
+vgcreate $vg "$dev1" "$dev2"
+blockdev --getss "$dev1"
+blockdev --getpbsz "$dev1"
+blockdev --getss "$dev2"
+blockdev --getpbsz "$dev2"
+
+# add integrity while LV is inactive
+lvcreate --type raid1 -m1 -n $lv1 -l 8 $vg
+lvchange -an $vg/$lv1
+lvchange -ay $vg/$lv1
+mkfs.ext4 "$DM_DEV_DIR/$vg/$lv1"
+mount "$DM_DEV_DIR/$vg/$lv1" $mnt
+echo "hello world" > $mnt/hello
+umount $mnt
+lvchange -an $vg
+lvconvert --raidintegrity y $vg/$lv1
+lvchange -ay $vg
+aux wait_recalc $vg/${lv1}_rimage_0
+aux wait_recalc $vg/${lv1}_rimage_1
+lvs -a -o+devices $vg
+mount "$DM_DEV_DIR/$vg/$lv1" $mnt
+cat $mnt/hello
+umount $mnt
+lvchange -an $vg/$lv1
+lvremove $vg/$lv1
+
+# add integrity while LV is active, fs unmounted
+lvcreate --type raid1 -m1 -n $lv1 -l 8 $vg
+lvchange -an $vg/$lv1
+lvchange -ay $vg/$lv1
+mkfs.ext4 "$DM_DEV_DIR/$vg/$lv1"
+mount "$DM_DEV_DIR/$vg/$lv1" $mnt
+echo "hello world" > $mnt/hello
+umount $mnt
+lvchange -an $vg
+lvchange -ay $vg
+lvconvert --raidintegrity y $vg/$lv1
+aux wait_recalc $vg/${lv1}_rimage_0
+aux wait_recalc $vg/${lv1}_rimage_1
+lvs -a -o+devices $vg
+mount "$DM_DEV_DIR/$vg/$lv1" $mnt
+cat $mnt/hello | grep "hello world"
+umount $mnt
+lvchange -an $vg/$lv1
+lvremove $vg/$lv1
+
+# add integrity while LV is active, fs mounted
+lvcreate --type raid1 -m1 -n $lv1 -l 8 $vg
+lvchange -an $vg/$lv1
+lvchange -ay $vg/$lv1
+mkfs.ext4 "$DM_DEV_DIR/$vg/$lv1"
+mount "$DM_DEV_DIR/$vg/$lv1" $mnt
+echo "hello world" > $mnt/hello
+lvconvert --raidintegrity y $vg/$lv1
+aux wait_recalc $vg/${lv1}_rimage_0
+aux wait_recalc $vg/${lv1}_rimage_1
+lvs -a -o+devices $vg
+cat $mnt/hello | grep "hello world"
+umount $mnt
+lvchange -an $vg/$lv1
+lvchange -ay $vg/$lv1
+mount "$DM_DEV_DIR/$vg/$lv1" $mnt
+cat $mnt/hello | grep "hello world"
+umount $mnt
+lvchange -an $vg/$lv1
+lvremove $vg/$lv1
+
+vgremove -ff $vg
+aux cleanup_scsi_debug_dev
+sleep 1
+
+# scsi_debug devices with 512 LBS and 4K PBS
+aux prepare_scsi_debug_dev 256 sector_size=512 physblk_exp=3
+check sysfs "$(< SCSI_DEBUG_DEV)" queue/logical_block_size "512"
+check sysfs "$(< SCSI_DEBUG_DEV)" queue/physical_block_size "4096"
+aux prepare_devs 2 64
+
+vgcreate $vg "$dev1" "$dev2"
+blockdev --getss "$dev1"
+blockdev --getpbsz "$dev1"
+blockdev --getss "$dev2"
+blockdev --getpbsz "$dev2"
+
+# add integrity while LV is inactive
+lvcreate --type raid1 -m1 -n $lv1 -l 8 $vg
+lvchange -an $vg/$lv1
+lvchange -ay $vg/$lv1
+mkfs.ext4 "$DM_DEV_DIR/$vg/$lv1"
+mount "$DM_DEV_DIR/$vg/$lv1" $mnt
+echo "hello world" > $mnt/hello
+umount $mnt
+lvchange -an $vg
+lvconvert --raidintegrity y $vg/$lv1
+lvchange -ay $vg
+aux wait_recalc $vg/${lv1}_rimage_0
+aux wait_recalc $vg/${lv1}_rimage_1
+lvs -a -o+devices $vg
+mount "$DM_DEV_DIR/$vg/$lv1" $mnt
+cat $mnt/hello
+umount $mnt
+lvchange -an $vg/$lv1
+lvremove $vg/$lv1
+
+# add integrity while LV is active, fs unmounted
+# lvconvert will use ribs 512 to avoid increasing LBS from 512 to 4k on active LV
+lvcreate --type raid1 -m1 -n $lv1 -l 8 $vg
+lvchange -an $vg/$lv1
+lvchange -ay $vg/$lv1
+mkfs.ext4 "$DM_DEV_DIR/$vg/$lv1"
+mount "$DM_DEV_DIR/$vg/$lv1" $mnt
+echo "hello world" > $mnt/hello
+umount $mnt
+lvchange -an $vg
+lvchange -ay $vg
+lvconvert --raidintegrity y $vg/$lv1
+aux wait_recalc $vg/${lv1}_rimage_0
+aux wait_recalc $vg/${lv1}_rimage_1
+lvs -a -o+devices $vg
+mount "$DM_DEV_DIR/$vg/$lv1" $mnt
+cat $mnt/hello | grep "hello world"
+umount $mnt
+lvchange -an $vg/$lv1
+lvremove $vg/$lv1
+
+# add integrity while LV is active, fs mounted
+# lvconvert will use ribs 512 to avoid increasing LBS from 512 to 4k on active LV
+lvcreate --type raid1 -m1 -n $lv1 -l 8 $vg
+lvchange -an $vg/$lv1
+lvchange -ay $vg/$lv1
+mkfs.ext4 "$DM_DEV_DIR/$vg/$lv1"
+mount "$DM_DEV_DIR/$vg/$lv1" $mnt
+echo "hello world" > $mnt/hello
+lvconvert --raidintegrity y $vg/$lv1
+aux wait_recalc $vg/${lv1}_rimage_0
+aux wait_recalc $vg/${lv1}_rimage_1
+lvs -a -o+devices $vg
+cat $mnt/hello | grep "hello world"
+umount $mnt
+lvchange -an $vg/$lv1
+lvchange -ay $vg/$lv1
+mount "$DM_DEV_DIR/$vg/$lv1" $mnt
+cat $mnt/hello | grep "hello world"
+umount $mnt
+lvchange -an $vg/$lv1
+lvremove $vg/$lv1
+
+vgremove -ff $vg
+aux cleanup_scsi_debug_dev
diff --git a/test/shell/integrity-blocksize.sh b/test/shell/integrity-blocksize.sh
new file mode 100644
index 0000000..e5d2620
--- /dev/null
+++ b/test/shell/integrity-blocksize.sh
@@ -0,0 +1,298 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2018 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+aux have_integrity 1 5 0 || skip
+
+losetup -h | grep sector-size || skip
+
+
+cleanup_mounted_and_teardown()
+{
+ umount "$mnt" || true
+ vgremove -ff $vg1 $vg2 || true
+
+ test -n "${LOOP1-}" && { losetup -d "$LOOP1" || true ; }
+ test -n "${LOOP2-}" && { losetup -d "$LOOP2" || true ; }
+ test -n "${LOOP3-}" && { losetup -d "$LOOP3" || true ; }
+ test -n "${LOOP4-}" && { losetup -d "$LOOP4" || true ; }
+
+ rm -f loop[abcd]
+ aux teardown
+}
+
+mnt="mnt"
+mkdir -p $mnt
+
+# Tests with fs block sizes require a libblkid version that shows BLOCK_SIZE
+aux prepare_devs 1
+vgcreate $vg "$dev1"
+lvcreate -n $lv1 -l8 $vg
+mkfs.ext4 "$DM_DEV_DIR/$vg/$lv1"
+blkid -p "$DM_DEV_DIR/$vg/$lv1" | grep BLOCK_SIZE || skip
+lvchange -an $vg
+vgremove -ff $vg
+
+trap 'cleanup_mounted_and_teardown' EXIT
+
+# Currently (5.9-rc5 hits 'blkdev_issue_discard()' kernel WARNING)
+#truncate -s 64M loopa
+#truncate -s 64M loopb
+#truncate -s 64M loopc
+#truncate -s 64M loopd
+
+dd if=/dev/zero of=loopa bs=1M count=64 conv=fdatasync
+dd if=/dev/zero of=loopb bs=1M count=64 conv=fdatasync
+dd if=/dev/zero of=loopc bs=1M count=64 conv=fdatasync
+dd if=/dev/zero of=loopd bs=1M count=64 conv=fdatasync
+
+LOOP1=$(losetup -f loopa --show) || skip "Cannot find free loop device"
+LOOP2=$(losetup -f loopb --show) || skip "Cannot find free loop device"
+LOOP3=$(losetup -f loopc --sector-size 4096 --show) || skip "Loop cannot handle --sector-size 4096"
+LOOP4=$(losetup -f loopd --sector-size 4096 --show) || skip "Loop cannot handle --sector-size 4096"
+
+echo "$LOOP1"
+echo "$LOOP2"
+echo "$LOOP3"
+echo "$LOOP4"
+
+aux extend_filter "a|$LOOP1|" "a|$LOOP2|" "a|$LOOP3|" "a|$LOOP4|"
+aux extend_devices "$LOOP1" "$LOOP2" "$LOOP3" "$LOOP4"
+
+aux lvmconf 'devices/scan = "/dev"'
+
+vgcreate $vg1 "$LOOP1" "$LOOP2"
+vgcreate $vg2 "$LOOP3" "$LOOP4"
+
+# LOOP1/LOOP2 have LBS 512 and PBS 512
+# LOOP3/LOOP4 have LBS 4K and PBS 4K
+
+blockdev --getss "$LOOP1"
+blockdev --getpbsz "$LOOP1"
+blockdev --getss "$LOOP2"
+blockdev --getpbsz "$LOOP2"
+blockdev --getss "$LOOP3"
+blockdev --getpbsz "$LOOP3"
+blockdev --getss "$LOOP4"
+blockdev --getpbsz "$LOOP4"
+
+# lvcreate on dev512, result 512
+lvcreate --type raid1 -m1 --raidintegrity y -l 8 -n $lv1 $vg1
+pvck --dump metadata "$LOOP1" | grep 'block_size = 512'
+lvremove -y $vg1/$lv1
+
+# lvcreate on dev4k, result 4k
+lvcreate --type raid1 -m1 --raidintegrity y -l 8 -n $lv1 $vg2
+pvck --dump metadata "$LOOP3" | grep 'block_size = 4096'
+lvremove -y $vg2/$lv1
+
+# lvcreate --bs 512 on dev4k, result fail
+not lvcreate --type raid1 -m1 --raidintegrity y --raidintegrityblocksize 512 -l 8 -n $lv1 $vg2
+
+# lvcreate --bs 4096 on dev512, result 4k
+lvcreate --type raid1 -m1 --raidintegrity y --raidintegrityblocksize 4096 -l 8 -n $lv1 $vg1
+lvs -o raidintegrityblocksize $vg1/$lv1 | grep 4096
+pvck --dump metadata "$LOOP1" | grep 'block_size = 4096'
+lvremove -y $vg1/$lv1
+
+# Test an unknown fs block size by simply not creating a fs on the lv.
+
+# lvconvert on dev512, fsunknown, result 512
+lvcreate --type raid1 -m1 -l 8 -n $lv1 $vg1
+# clear any residual fs so that libblkid cannot find an fs block size
+aux wipefs_a "$DM_DEV_DIR/$vg1/$lv1"
+lvconvert --raidintegrity y $vg1/$lv1
+pvck --dump metadata "$LOOP1" | grep 'block_size = 512'
+lvremove -y $vg1/$lv1
+
+# lvconvert on dev4k, fsunknown, result 4k
+lvcreate --type raid1 -m1 -l 8 -n $lv1 $vg2
+# clear any residual fs so that libblkid cannot find an fs block size
+aux wipefs_a "$DM_DEV_DIR//$vg2/$lv1"
+lvconvert --raidintegrity y $vg2/$lv1
+pvck --dump metadata $LOOP3 | grep 'block_size = 4096'
+lvremove -y $vg2/$lv1
+
+# lvconvert --bs 4k on dev512, fsunknown, result fail
+lvcreate --type raid1 -m1 -l 8 -n $lv1 $vg1
+# clear any residual fs so that libblkid cannot find an fs block size
+aux wipefs_a "$DM_DEV_DIR//$vg1/$lv1"
+not lvconvert --raidintegrity y --raidintegrityblocksize 4096 $vg1/$lv1
+lvremove -y $vg1/$lv1
+
+# lvconvert --bs 512 on dev4k, fsunknown, result fail
+lvcreate --type raid1 -m1 -l 8 -n $lv1 $vg2
+# clear any residual fs so that libblkid cannot find an fs block size
+aux wipefs_a "$DM_DEV_DIR//$vg2/$lv1"
+not lvconvert --raidintegrity y --raidintegrityblocksize 512 $vg2/$lv1
+lvremove -y $vg2/$lv1
+
+# lvconvert on dev512, ext4 1024, result 1024
+lvcreate --type raid1 -m1 -l 8 -n $lv1 $vg1
+aux wipefs_a "$DM_DEV_DIR//$vg1/$lv1"
+mkfs.ext4 "$DM_DEV_DIR/$vg1/$lv1"
+blkid -p "$DM_DEV_DIR/$vg1/$lv1" | tee out
+grep BLOCK_SIZE=\"1024\" out
+lvconvert --raidintegrity y $vg1/$lv1
+blkid -p "$DM_DEV_DIR/$vg1/$lv1" | grep BLOCK_SIZE=\"1024\"
+mount "$DM_DEV_DIR/$vg1/$lv1" $mnt
+umount $mnt
+pvck --dump metadata "$LOOP1" | grep 'block_size = 512'
+lvremove -y $vg1/$lv1
+
+# lvconvert on dev4k, ext4 4096, result 4096
+lvcreate --type raid1 -m1 -l 8 -n $lv1 $vg2
+aux wipefs_a "$DM_DEV_DIR/$vg2/$lv1"
+mkfs.ext4 "$DM_DEV_DIR/$vg2/$lv1"
+blkid -p "$DM_DEV_DIR/$vg2/$lv1" | grep BLOCK_SIZE=\"4096\"
+lvconvert --raidintegrity y $vg2/$lv1
+blkid -p "$DM_DEV_DIR/$vg2/$lv1" | grep BLOCK_SIZE=\"4096\"
+mount "$DM_DEV_DIR/$vg2/$lv1" $mnt
+umount $mnt
+pvck --dump metadata $LOOP3 | grep 'block_size = 4096'
+lvremove -y $vg2/$lv1
+
+# lvconvert on dev512, ext4 1024, result 1024 (LV active when adding)
+lvcreate --type raid1 -m1 -l 8 -n $lv1 $vg1
+aux wipefs_a "$DM_DEV_DIR//$vg1/$lv1"
+mkfs.ext4 -b 1024 "$DM_DEV_DIR/$vg1/$lv1"
+blkid -p "$DM_DEV_DIR/$vg1/$lv1" | grep BLOCK_SIZE=\"1024\"
+lvconvert --raidintegrity y $vg1/$lv1
+blkid -p "$DM_DEV_DIR/$vg1/$lv1" | grep BLOCK_SIZE=\"1024\"
+mount "$DM_DEV_DIR/$vg1/$lv1" $mnt
+umount $mnt
+pvck --dump metadata "$LOOP1" | grep 'block_size = 512'
+lvremove -y $vg1/$lv1
+
+# lvconvert on dev512, ext4 1024, result 1024 (LV inactive when adding)
+lvcreate --type raid1 -m1 -l 8 -n $lv1 $vg1
+aux wipefs_a "$DM_DEV_DIR//$vg1/$lv1"
+mkfs.ext4 -b 1024 "$DM_DEV_DIR/$vg1/$lv1"
+blkid -p "$DM_DEV_DIR/$vg1/$lv1" | grep BLOCK_SIZE=\"1024\"
+lvchange -an $vg1/$lv1
+lvconvert --raidintegrity y $vg1/$lv1
+lvchange -ay $vg1/$lv1
+blkid -p "$DM_DEV_DIR/$vg1/$lv1" | grep BLOCK_SIZE=\"1024\"
+mount "$DM_DEV_DIR/$vg1/$lv1" $mnt
+umount $mnt
+pvck --dump metadata "$LOOP1" | grep 'block_size = 1024'
+lvremove -y $vg1/$lv1
+
+# lvconvert on dev4k, ext4 4096, result 4096
+lvcreate --type raid1 -m1 -l 8 -n $lv1 $vg2
+aux wipefs_a "$DM_DEV_DIR//$vg2/$lv1"
+mkfs.ext4 "$DM_DEV_DIR/$vg2/$lv1"
+blkid -p "$DM_DEV_DIR/$vg2/$lv1" | grep BLOCK_SIZE=\"4096\"
+lvconvert --raidintegrity y $vg2/$lv1
+blkid -p "$DM_DEV_DIR/$vg2/$lv1" | grep BLOCK_SIZE=\"4096\"
+mount "$DM_DEV_DIR/$vg2/$lv1" $mnt
+umount $mnt
+pvck --dump metadata "$LOOP3" | grep 'block_size = 4096'
+lvremove -y $vg2/$lv1
+
+# lvconvert --bs 512 on dev512, ext4 4096, result 512
+lvcreate --type raid1 -m1 -l 8 -n $lv1 $vg1
+aux wipefs_a "$DM_DEV_DIR//$vg1/$lv1"
+mkfs.ext4 -b 4096 "$DM_DEV_DIR/$vg1/$lv1"
+blkid -p "$DM_DEV_DIR/$vg1/$lv1" | grep BLOCK_SIZE=\"4096\"
+lvconvert --raidintegrity y --raidintegrityblocksize 512 $vg1/$lv1
+lvs -o raidintegrityblocksize $vg1/$lv1 | grep 512
+blkid -p "$DM_DEV_DIR/$vg1/$lv1" | grep BLOCK_SIZE=\"4096\"
+mount "$DM_DEV_DIR/$vg1/$lv1" $mnt
+umount $mnt
+pvck --dump metadata "$LOOP1" | grep 'block_size = 512'
+lvremove -y $vg1/$lv1
+
+# lvconvert --bs 1024 on dev512, ext4 4096, result 1024
+lvcreate --type raid1 -m1 -l 8 -n $lv1 $vg1
+aux wipefs_a "$DM_DEV_DIR//$vg1/$lv1"
+mkfs.ext4 -b 4096 "$DM_DEV_DIR/$vg1/$lv1"
+blkid -p "$DM_DEV_DIR/$vg1/$lv1" | grep BLOCK_SIZE=\"4096\"
+lvchange -an $vg1/$lv1
+# lv needs to be inactive to increase LBS from 512
+lvconvert --raidintegrity y --raidintegrityblocksize 1024 $vg1/$lv1
+lvs -o raidintegrityblocksize $vg1/$lv1 | grep 1024
+lvchange -ay $vg1/$lv1
+blkid -p "$DM_DEV_DIR/$vg1/$lv1" | grep BLOCK_SIZE=\"4096\"
+mount "$DM_DEV_DIR/$vg1/$lv1" $mnt
+umount $mnt
+pvck --dump metadata "$LOOP1" | grep 'block_size = 1024'
+lvremove -y $vg1/$lv1
+
+# lvconvert --bs 512 on dev512, ext4 1024, result 512
+lvcreate --type raid1 -m1 -l 8 -n $lv1 $vg1
+aux wipefs_a "$DM_DEV_DIR//$vg1/$lv1"
+mkfs.ext4 -b 1024 "$DM_DEV_DIR/$vg1/$lv1"
+blkid -p "$DM_DEV_DIR/$vg1/$lv1" | grep BLOCK_SIZE=\"1024\"
+lvconvert --raidintegrity y --raidintegrityblocksize 512 $vg1/$lv1
+blkid -p "$DM_DEV_DIR/$vg1/$lv1" | grep BLOCK_SIZE=\"1024\"
+mount "$DM_DEV_DIR/$vg1/$lv1" $mnt
+umount $mnt
+pvck --dump metadata "$LOOP1" | grep 'block_size = 512'
+lvremove -y $vg1/$lv1
+
+# lvconvert --bs 512 on dev4k, ext4 4096, result fail
+lvcreate --type raid1 -m1 -l 8 -n $lv1 $vg2
+aux wipefs_a "$DM_DEV_DIR//$vg2/$lv1"
+mkfs.ext4 "$DM_DEV_DIR/$vg2/$lv1"
+not lvconvert --raidintegrity y --raidintegrityblocksize 512 $vg2/$lv1
+lvremove -y $vg2/$lv1
+
+# TODO: need to use scsi_debug to create devs with LBS 512 PBS 4k
+# TODO: lvconvert, fsunknown, LBS 512, PBS 4k: result 512
+# TODO: lvconvert --bs 512, fsunknown, LBS 512, PBS 4k: result 512
+# TODO: lvconvert --bs 4k, fsunknown, LBS 512, PBS 4k: result 4k
+
+# lvconvert on dev512, ext4 1024, result 1024, (detect fs with LV inactive)
+lvcreate --type raid1 -m1 -l 8 -n $lv1 $vg1
+aux wipefs_a "$DM_DEV_DIR//$vg1/$lv1"
+mkfs.ext4 "$DM_DEV_DIR/$vg1/$lv1"
+mount "$DM_DEV_DIR/$vg1/$lv1" $mnt
+echo "test" > $mnt/test
+umount $mnt
+blkid -p "$DM_DEV_DIR/$vg1/$lv1" | grep BLOCK_SIZE=\"1024\"
+lvchange -an $vg1/$lv1
+lvconvert --raidintegrity y $vg1/$lv1
+lvchange -ay $vg1/$lv1
+mount "$DM_DEV_DIR/$vg1/$lv1" $mnt
+cat $mnt/test
+umount $mnt
+blkid -p "$DM_DEV_DIR/$vg1/$lv1" | grep BLOCK_SIZE=\"1024\"
+pvck --dump metadata "$LOOP1" | tee out
+grep 'block_size = 1024' out
+lvchange -an $vg1/$lv1
+lvremove -y $vg1/$lv1
+
+# lvconvert on dev4k, ext4 4096, result 4096 (detect fs with LV inactive)
+lvcreate --type raid1 -m1 -l 8 -n $lv1 $vg2
+aux wipefs_a "$DM_DEV_DIR//$vg2/$lv1"
+mkfs.ext4 "$DM_DEV_DIR/$vg2/$lv1"
+mount "$DM_DEV_DIR/$vg2/$lv1" $mnt
+echo "test" > $mnt/test
+umount $mnt
+blkid -p "$DM_DEV_DIR/$vg2/$lv1" | grep BLOCK_SIZE=\"4096\"
+lvchange -an $vg2/$lv1
+lvconvert --raidintegrity y $vg2/$lv1
+lvchange -ay $vg2/$lv1
+mount "$DM_DEV_DIR/$vg2/$lv1" $mnt
+cat $mnt/test
+umount $mnt
+blkid -p "$DM_DEV_DIR/$vg2/$lv1" | grep BLOCK_SIZE=\"4096\"
+pvck --dump metadata "$LOOP3" | tee out
+grep 'block_size = 4096' out
+lvchange -an $vg2/$lv1
+lvremove -y $vg2/$lv1
+
+# remove of $vg1, $vg2 and loops in cleanup_mounted_and_teardown()
diff --git a/test/shell/integrity-caching.sh b/test/shell/integrity-caching.sh
new file mode 100644
index 0000000..72fb4af
--- /dev/null
+++ b/test/shell/integrity-caching.sh
@@ -0,0 +1,527 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2018 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+which mkfs.ext4 || skip
+which resize2fs || skip
+aux have_integrity 1 5 0 || skip
+# Avoid 4K ramdisk devices on older kernels
+aux kernel_at_least 5 10 || export LVM_TEST_PREFER_BRD=0
+
+mnt="mnt"
+mkdir -p $mnt
+
+aux prepare_devs 9 80
+
+# Use awk instead of anoyingly long log out from printf
+#printf "%0.sA" {1..16384} >> fileA
+awk 'BEGIN { while (z++ < 16384) printf "A" }' > fileA
+awk 'BEGIN { while (z++ < 4096) printf "B" ; while (z++ < 16384) printf "b" }' > fileB
+awk 'BEGIN { while (z++ < 16384) printf "C" }' > fileC
+
+# generate random data
+dd if=/dev/urandom of=randA bs=512K count=2
+dd if=/dev/urandom of=randB bs=512K count=3
+dd if=/dev/urandom of=randC bs=512K count=4
+
+_prepare_vg() {
+ # zero devs so we are sure to find the correct file data
+ # on the underlying devs when corrupting it
+ aux clear_devs "$dev1" "$dev2" "$dev3" "$dev4" "$dev5"
+ vgcreate $SHARED $vg "$dev1" "$dev2" "$dev3" "$dev4" "$dev5" "$dev6"
+ pvs
+}
+
+_test_fs_with_read_repair() {
+ mkfs.ext4 -b 4096 "$DM_DEV_DIR/$vg/$lv1"
+
+ mount "$DM_DEV_DIR/$vg/$lv1" $mnt
+
+ cp randA $mnt
+ cp randB $mnt
+ cp randC $mnt
+ cp fileA $mnt
+ cp fileB $mnt
+ cp fileC $mnt
+
+ # The files written above are in the writecache so reading
+ # them back later will come from the writecache and not from the
+ # corrupted dev. Write a bunch of new data to the fs to clear
+ # the original files from the writecache, so when they are read
+ # back the data will hopefully come from the underlying disk and
+ # trigger reading the corrupted data.
+ mkdir $mnt/new1
+ cat randA > $mnt/new1/randA
+ cat randB > $mnt/new1/randB
+ cat randC > $mnt/new1/randC
+ sync
+ du -h $mnt/new1
+ cp -r $mnt/new1 $mnt/new2 || true
+ cp -r $mnt/new1 $mnt/new3 || true
+ cp -r $mnt/new1 $mnt/new4 || true
+ sync
+ du -h $mnt
+ df -h
+ # hopefully fileA is no longer in the writecache.
+
+ umount $mnt
+ lvchange -an $vg/$lv1
+ for dev in "$@"; do
+ aux corrupt_dev "$dev" BBBBBBBBBBBBBBBBB BBBBBBBBCBBBBBBBB
+ done
+
+ lvchange -ay $vg/$lv1
+ mount "$DM_DEV_DIR/$vg/$lv1" $mnt
+
+ cmp -b $mnt/fileA fileA
+ cmp -b $mnt/fileB fileB
+ cmp -b $mnt/fileC fileC
+ umount $mnt
+}
+
+_add_new_data_to_mnt() {
+ mkfs.ext4 -b 4096 "$DM_DEV_DIR/$vg/$lv1"
+
+ mount "$DM_DEV_DIR/$vg/$lv1" $mnt
+
+ # add original data
+ cp randA $mnt
+ cp randB $mnt
+ cp randC $mnt
+ mkdir $mnt/1
+ cp fileA $mnt/1
+ cp fileB $mnt/1
+ cp fileC $mnt/1
+ mkdir $mnt/2
+ cp fileA $mnt/2
+ cp fileB $mnt/2
+ cp fileC $mnt/2
+}
+
+_add_more_data_to_mnt() {
+ mkdir $mnt/more
+ cp fileA $mnt/more
+ cp fileB $mnt/more
+ cp fileC $mnt/more
+ cp randA $mnt/more
+ cp randB $mnt/more
+ cp randC $mnt/more
+}
+
+_verify_data_on_mnt() {
+ cmp -b randA $mnt/randA
+ cmp -b randB $mnt/randB
+ cmp -b randC $mnt/randC
+ cmp -b fileA $mnt/1/fileA
+ cmp -b fileB $mnt/1/fileB
+ cmp -b fileC $mnt/1/fileC
+ cmp -b fileA $mnt/2/fileA
+ cmp -b fileB $mnt/2/fileB
+ cmp -b fileC $mnt/2/fileC
+}
+
+_verify_data_on_lv() {
+ lvchange -ay $vg/$lv1
+ mount "$DM_DEV_DIR/$vg/$lv1" $mnt
+ _verify_data_on_mnt
+ rm $mnt/randA
+ rm $mnt/randB
+ rm $mnt/randC
+ rm -rf $mnt/1
+ rm -rf $mnt/2
+ umount $mnt
+ lvchange -an $vg/$lv1
+}
+
+# lv1 is a raid+integrity LV
+# three variations of caching on lv1:
+#
+# 1. lvcreate --type cache-pool -n fast -l 4 $vg $dev6
+# lvconvert --type cache --cachepool fast $vg/$lv1
+#
+# 2. lvcreate --type linear -n fast -l 4 $vg $dev6
+# lvconvert --type cache --cachvol fast $vg/$lv1
+#
+# 3. lvcreate --type linear -n fast -l 4 $vg $dev6
+# lvconvert --type writecache --cachvol fast $vg/$lv1
+
+do_test() {
+
+# --cachepool | --cachevol
+local create_type=$1
+
+# cache | writecache
+local convert_type=$2
+
+# --type cache-pool | --type linear
+local convert_option=$3
+
+# corig | wcorig
+local suffix=$4
+
+_prepare_vg
+lvcreate --type raid1 -m1 --raidintegrity y -n $lv1 -l 8 $vg "$dev1" "$dev2"
+lvcreate --type $create_type -n fast -l 4 -an $vg "$dev6"
+lvconvert -y --type $convert_type $convert_option fast $vg/$lv1
+lvs -a -o name,size,segtype,devices,sync_percent $vg
+aux wait_recalc $vg/${lv1}_${suffix}_rimage_0
+aux wait_recalc $vg/${lv1}_${suffix}_rimage_1
+aux wait_recalc $vg/${lv1}_${suffix}
+_test_fs_with_read_repair "$dev1"
+lvs -o integritymismatches $vg/${lv1}_${suffix}_rimage_0 |tee mismatch
+not grep ' 0 ' mismatch
+lvs -o integritymismatches $vg/${lv1}_${suffix} |tee mismatch
+not grep ' 0 ' mismatch
+lvchange -an $vg/$lv1
+lvconvert --raidintegrity n $vg/${lv1}_${suffix}
+lvs -a -o name,size,segtype,devices,sync_percent $vg
+lvremove $vg/$lv1
+vgremove -ff $vg
+
+_prepare_vg
+lvcreate --type raid1 -m2 --raidintegrity y -n $lv1 -l 8 $vg "$dev1" "$dev2" "$dev3"
+lvcreate --type $create_type -n fast -l 4 -an $vg "$dev6"
+lvconvert -y --type $convert_type $convert_option fast $vg/$lv1
+lvs -a -o name,size,segtype,devices,sync_percent $vg
+aux wait_recalc $vg/${lv1}_${suffix}_rimage_0
+aux wait_recalc $vg/${lv1}_${suffix}_rimage_1
+aux wait_recalc $vg/${lv1}_${suffix}_rimage_2
+aux wait_recalc $vg/${lv1}_${suffix}
+_test_fs_with_read_repair "$dev1" "$dev2"
+lvs -o integritymismatches $vg/${lv1}_${suffix}_rimage_0 |tee mismatch
+not grep ' 0 ' mismatch
+lvs -o integritymismatches $vg/${lv1}_${suffix} |tee mismatch
+not grep ' 0 ' mismatch
+lvchange -an $vg/$lv1
+lvconvert --raidintegrity n $vg/${lv1}_${suffix}
+lvconvert --splitcache $vg/$lv1
+lvremove $vg/$lv1
+vgremove -ff $vg
+
+_prepare_vg
+lvcreate --type raid5 --raidintegrity y -n $lv1 -I4 -l 8 $vg "$dev1" "$dev2" "$dev3"
+lvcreate --type $create_type -n fast -l 4 -an $vg "$dev6"
+lvconvert -y --type $convert_type $convert_option fast $vg/$lv1
+lvs -a -o name,size,segtype,devices,sync_percent $vg
+aux wait_recalc $vg/${lv1}_${suffix}_rimage_0
+aux wait_recalc $vg/${lv1}_${suffix}_rimage_1
+aux wait_recalc $vg/${lv1}_${suffix}_rimage_2
+aux wait_recalc $vg/${lv1}_${suffix}
+_test_fs_with_read_repair "$dev1" "$dev2" "$dev3"
+lvs -o integritymismatches $vg/${lv1}_${suffix}_rimage_0
+lvs -o integritymismatches $vg/${lv1}_${suffix}_rimage_1
+lvs -o integritymismatches $vg/${lv1}_${suffix}_rimage_2
+lvs -o integritymismatches $vg/${lv1}_${suffix} |tee mismatch
+not grep ' 0 ' mismatch
+lvconvert --splitcache $vg/$lv1
+lvchange -an $vg/$lv1
+lvconvert --raidintegrity n $vg/$lv1
+lvremove $vg/$lv1
+vgremove -ff $vg
+
+# Test removing integrity from an active LV
+
+_prepare_vg
+lvcreate --type raid1 -m1 --raidintegrity y -n $lv1 -l 8 $vg
+lvcreate --type $create_type -n fast -l 4 -an $vg "$dev6"
+lvconvert -y --type $convert_type $convert_option fast $vg/$lv1
+lvs -a -o name,size,segtype,devices,sync_percent $vg
+aux wait_recalc $vg/${lv1}_${suffix}_rimage_0
+aux wait_recalc $vg/${lv1}_${suffix}_rimage_1
+aux wait_recalc $vg/${lv1}_${suffix}
+_add_new_data_to_mnt
+lvconvert --raidintegrity n $vg/${lv1}_${suffix}
+_add_more_data_to_mnt
+lvconvert --splitcache $vg/$lv1
+_verify_data_on_mnt
+umount $mnt
+lvchange -an $vg/$lv1
+_verify_data_on_lv
+lvremove $vg/$lv1
+vgremove -ff $vg
+
+# Test adding integrity to an active LV
+
+_prepare_vg
+lvcreate --type raid1 -m1 -n $lv1 -l 8 $vg
+aux wait_recalc $vg/$lv1
+lvcreate --type $create_type -n fast -l 4 -an $vg "$dev6"
+lvconvert -y --type $convert_type $convert_option fast $vg/$lv1
+lvs -a -o name,size,segtype,devices,sync_percent $vg
+_add_new_data_to_mnt
+# Can only be enabled while raid is top level lv (for now.)
+not lvconvert --raidintegrity y $vg/${lv1}_${suffix}
+#aux wait_recalc $vg/${lv1}_${suffix}_rimage_0
+#aux wait_recalc $vg/${lv1}_${suffix}_rimage_1
+_add_more_data_to_mnt
+_verify_data_on_mnt
+umount $mnt
+lvchange -an $vg/$lv1
+_verify_data_on_lv
+lvremove $vg/$lv1
+vgremove -ff $vg
+
+# Test lvextend while inactive
+
+_prepare_vg
+lvcreate --type raid1 -m1 --raidintegrity y -n $lv1 -l 8 $vg "$dev1" "$dev2"
+aux wait_recalc $vg/${lv1}_rimage_0
+aux wait_recalc $vg/${lv1}_rimage_1
+aux wait_recalc $vg/$lv1
+lvcreate --type $create_type -n fast -l 4 -an $vg "$dev6"
+lvconvert -y --type $convert_type $convert_option fast $vg/$lv1
+lvs -a -o name,size,segtype,devices,sync_percent $vg
+_add_new_data_to_mnt
+umount $mnt
+lvchange -an $vg/$lv1
+# use two new devs for raid extend to ensure redundancy
+vgextend $vg "$dev7" "$dev8"
+lvs -a -o name,segtype,devices $vg
+lvextend -l 16 $vg/$lv1 "$dev7" "$dev8"
+lvs -a -o name,segtype,devices $vg
+lvchange -ay $vg/$lv1
+mount "$DM_DEV_DIR/$vg/$lv1" $mnt
+resize2fs "$DM_DEV_DIR/$vg/$lv1"
+aux wait_recalc $vg/${lv1}_${suffix}_rimage_0
+aux wait_recalc $vg/${lv1}_${suffix}_rimage_1
+_add_more_data_to_mnt
+_verify_data_on_mnt
+umount $mnt
+lvchange -an $vg/$lv1
+_verify_data_on_lv
+lvremove $vg/$lv1
+vgremove -ff $vg
+
+# Test lvextend while active
+
+_prepare_vg
+lvcreate --type raid1 -m1 --raidintegrity y -n $lv1 -l 8 $vg "$dev1" "$dev2"
+aux wait_recalc $vg/${lv1}_rimage_0
+aux wait_recalc $vg/${lv1}_rimage_1
+aux wait_recalc $vg/$lv1
+lvcreate --type $create_type -n fast -l 4 -an $vg "$dev6"
+lvconvert -y --type $convert_type $convert_option fast $vg/$lv1
+# use two new devs for raid extend to ensure redundancy
+vgextend $vg "$dev7" "$dev8"
+lvs -a -o name,size,segtype,devices,sync_percent $vg
+_add_new_data_to_mnt
+lvextend -l 16 $vg/$lv1 "$dev7" "$dev8"
+lvs -a -o name,size,segtype,devices,sync_percent $vg
+resize2fs "$DM_DEV_DIR/$vg/$lv1"
+aux wait_recalc $vg/${lv1}_${suffix}_rimage_0
+aux wait_recalc $vg/${lv1}_${suffix}_rimage_1
+_add_more_data_to_mnt
+_verify_data_on_mnt
+umount $mnt
+lvchange -an $vg/$lv1
+_verify_data_on_lv
+lvremove $vg/$lv1
+vgremove -ff $vg
+
+_prepare_vg
+lvcreate --type raid5 --raidintegrity y -n $lv1 -I4 -l 8 $vg "$dev1" "$dev2" "$dev3"
+aux wait_recalc $vg/${lv1}_rimage_0
+aux wait_recalc $vg/${lv1}_rimage_1
+aux wait_recalc $vg/${lv1}_rimage_2
+aux wait_recalc $vg/$lv1
+lvcreate --type $create_type -n fast -l 4 -an $vg "$dev6"
+lvconvert -y --type $convert_type $convert_option fast $vg/$lv1
+vgextend $vg "$dev7" "$dev8" "$dev9"
+lvs -a -o name,size,segtype,devices,sync_percent $vg
+_add_new_data_to_mnt
+lvextend -l 16 $vg/$lv1 "$dev7" "$dev8" "$dev9"
+lvs -a -o name,size,segtype,devices,sync_percent $vg
+resize2fs "$DM_DEV_DIR/$vg/$lv1"
+aux wait_recalc $vg/${lv1}_${suffix}_rimage_0
+aux wait_recalc $vg/${lv1}_${suffix}_rimage_1
+_add_more_data_to_mnt
+_verify_data_on_mnt
+umount $mnt
+lvchange -an $vg/$lv1
+_verify_data_on_lv
+lvremove $vg/$lv1
+vgremove -ff $vg
+
+# Test adding image to raid1
+
+_prepare_vg
+lvcreate --type raid1 -m1 --raidintegrity y -n $lv1 -l 8 $vg
+aux wait_recalc $vg/${lv1}_rimage_0
+aux wait_recalc $vg/${lv1}_rimage_1
+aux wait_recalc $vg/$lv1
+lvcreate --type $create_type -n fast -l 4 -an $vg "$dev6"
+lvconvert -y --type $convert_type $convert_option fast $vg/$lv1
+lvs -a -o name,size,segtype,devices,sync_percent $vg
+_add_new_data_to_mnt
+# currently only allowed while raid is top level lv
+not lvconvert -y -m+1 $vg/${lv1}_${suffix}
+#aux wait_recalc $vg/${lv1}_${suffix}_rimage_0
+#aux wait_recalc $vg/${lv1}_${suffix}_rimage_1
+#aux wait_recalc $vg/${lv1}_${suffix}_rimage_2
+_add_more_data_to_mnt
+_verify_data_on_mnt
+umount $mnt
+lvchange -an $vg/$lv1
+_verify_data_on_lv
+lvremove $vg/$lv1
+vgremove -ff $vg
+
+# Test removing image from raid1
+
+_prepare_vg
+lvcreate --type raid1 -m2 --raidintegrity y -n $lv1 -l 8 $vg
+aux wait_recalc $vg/${lv1}_rimage_0
+aux wait_recalc $vg/${lv1}_rimage_1
+aux wait_recalc $vg/${lv1}_rimage_2
+aux wait_recalc $vg/$lv1
+lvcreate --type $create_type -n fast -l 4 -an $vg "$dev6"
+lvconvert -y --type $convert_type $convert_option fast $vg/$lv1
+lvs -a -o name,size,segtype,devices,sync_percent $vg
+_add_new_data_to_mnt
+lvconvert -y -m-1 $vg/${lv1}_${suffix}
+lvs -a -o name,size,segtype,devices,sync_percent $vg
+_add_more_data_to_mnt
+_verify_data_on_mnt
+umount $mnt
+lvchange -an $vg/$lv1
+_verify_data_on_lv
+lvremove $vg/$lv1
+vgremove -ff $vg
+
+# Test disallowed operations on raid+integrity
+
+_prepare_vg
+lvcreate --type raid1 -m1 --raidintegrity y -n $lv1 -l 8 $vg "$dev1" "$dev2"
+aux wait_recalc $vg/${lv1}_rimage_0
+aux wait_recalc $vg/${lv1}_rimage_1
+aux wait_recalc $vg/$lv1
+lvcreate --type $create_type -n fast -l 4 -an $vg "$dev6"
+lvconvert -y --type $convert_type $convert_option fast $vg/$lv1
+lvs -a -o name,size,segtype,devices,sync_percent $vg
+_add_new_data_to_mnt
+not lvconvert -y -m-1 $vg/$lv1
+not lvconvert -y -m-1 $vg/${lv1}_${suffix}
+not lvconvert --splitmirrors 1 -n tmp -y $vg/$lv1
+not lvconvert --splitmirrors 1 -n tmp -y $vg/${lv1}_${suffix}
+not lvconvert --splitmirrors 1 --trackchanges -y $vg/$lv1
+not lvconvert --splitmirrors 1 --trackchanges -y $vg/${lv1}_${suffix}
+not lvchange --syncaction repair $vg/$lv1
+not lvchange --syncaction repair $vg/${lv1}_${suffix}
+not lvreduce -L4M $vg/$lv1
+not lvreduce -L4M $vg/${lv1}_${suffix}
+not lvcreate -s -n snap -L4M $vg/${lv1}_${suffix}
+# plan to enable snap on top level raid+integrity, so then
+# snap+writecache+raid+integrity should be allowed.
+not lvcreate -s -n snap -L4M $vg/$lv1
+lvs -a -o name,size,segtype,devices
+not pvmove -n $vg/$lv1 "$dev1"
+not pvmove -n $vg/${lv1}_${suffix} "$dev1"
+not pvmove "$dev1"
+_verify_data_on_mnt
+umount $mnt
+lvchange -an $vg/$lv1
+_verify_data_on_lv
+lvremove $vg/$lv1
+vgremove -ff $vg
+
+# Repeat many of the tests above using bitmap mode
+
+_prepare_vg
+lvcreate --type raid1 -m1 --raidintegrity y --raidintegritymode bitmap -n $lv1 -l 8 $vg "$dev1" "$dev2"
+lvcreate --type $create_type -n fast -l 4 -an $vg "$dev6"
+lvconvert -y --type $convert_type $convert_option fast $vg/$lv1
+lvs -a -o name,size,segtype,devices,sync_percent $vg
+aux wait_recalc $vg/${lv1}_${suffix}_rimage_0
+aux wait_recalc $vg/${lv1}_${suffix}_rimage_1
+aux wait_recalc $vg/${lv1}_${suffix}
+_test_fs_with_read_repair "$dev1"
+lvs -o integritymismatches $vg/${lv1}_${suffix}_rimage_0 |tee mismatch
+not grep ' 0 ' mismatch
+lvs -o integritymismatches $vg/${lv1}_${suffix} |tee mismatch
+not grep ' 0 ' mismatch
+lvchange -an $vg/$lv1
+lvconvert --raidintegrity n $vg/${lv1}_${suffix}
+lvremove $vg/$lv1
+vgremove -ff $vg
+
+_prepare_vg
+lvcreate --type raid6 --raidintegrity y --raidintegritymode bitmap -n $lv1 -I4 -l 8 $vg "$dev1" "$dev2" "$dev3" "$dev4" "$dev5"
+lvcreate --type $create_type -n fast -l 4 -an $vg "$dev6"
+lvconvert -y --type $convert_type $convert_option fast $vg/$lv1
+lvs -a -o name,size,segtype,devices,sync_percent $vg
+aux wait_recalc $vg/${lv1}_${suffix}_rimage_0
+aux wait_recalc $vg/${lv1}_${suffix}_rimage_1
+aux wait_recalc $vg/${lv1}_${suffix}_rimage_2
+aux wait_recalc $vg/${lv1}_${suffix}_rimage_3
+aux wait_recalc $vg/${lv1}_${suffix}_rimage_4
+aux wait_recalc $vg/${lv1}_${suffix}
+_test_fs_with_read_repair "$dev1" "$dev2" "$dev3" "$dev4" "$dev5"
+lvs -o integritymismatches $vg/${lv1}_${suffix}_rimage_0
+lvs -o integritymismatches $vg/${lv1}_${suffix}_rimage_1
+lvs -o integritymismatches $vg/${lv1}_${suffix}_rimage_2
+lvs -o integritymismatches $vg/${lv1}_${suffix}_rimage_3
+lvs -o integritymismatches $vg/${lv1}_${suffix}_rimage_4
+lvs -o integritymismatches $vg/${lv1}_${suffix} |tee mismatch
+not grep ' 0 ' mismatch
+lvchange -an $vg/$lv1
+lvconvert --raidintegrity n $vg/${lv1}_${suffix}
+lvremove $vg/$lv1
+vgremove -ff $vg
+
+# remove from active lv
+_prepare_vg
+lvcreate --type raid1 -m1 --raidintegrity y --raidintegritymode bitmap -n $lv1 -l 8 $vg "$dev1" "$dev2"
+aux wait_recalc $vg/${lv1}_rimage_0
+aux wait_recalc $vg/${lv1}_rimage_1
+aux wait_recalc $vg/$lv1
+lvcreate --type $create_type -n fast -l 4 -an $vg "$dev6"
+lvconvert -y --type $convert_type $convert_option fast $vg/$lv1
+lvs -a -o name,size,segtype,devices,sync_percent $vg
+_add_new_data_to_mnt
+lvconvert --raidintegrity n $vg/${lv1}_${suffix}
+_add_more_data_to_mnt
+_verify_data_on_mnt
+umount $mnt
+lvchange -an $vg/$lv1
+_verify_data_on_lv
+lvremove $vg/$lv1
+vgremove -ff $vg
+
+# add to active lv
+_prepare_vg
+lvcreate --type raid1 -m1 -n $lv1 -l 8 $vg
+_add_new_data_to_mnt
+lvconvert --raidintegrity y --raidintegritymode bitmap $vg/$lv1
+lvcreate --type $create_type -n fast -l 4 -an $vg "$dev6"
+lvconvert -y --type $convert_type $convert_option fast $vg/$lv1
+lvs -a -o name,size,segtype,devices,sync_percent $vg
+aux wait_recalc $vg/${lv1}_${suffix}_rimage_0
+aux wait_recalc $vg/${lv1}_${suffix}_rimage_1
+aux wait_recalc $vg/${lv1}_${suffix}
+_add_more_data_to_mnt
+_verify_data_on_mnt
+umount $mnt
+lvchange -an $vg/$lv1
+_verify_data_on_lv
+lvremove $vg/$lv1
+vgremove -ff $vg
+}
+
+do_test cache-pool cache --cachepool corig
+do_test linear cache --cachevol corig
+do_test linear writecache --cachevol wcorig
+
+# TODO: add do_test() variant that skips adding the cache to lv1.
+# This would be equivalent to integrity.sh which could be dropped.
diff --git a/test/shell/integrity-dmeventd.sh b/test/shell/integrity-dmeventd.sh
new file mode 100644
index 0000000..f3bc122
--- /dev/null
+++ b/test/shell/integrity-dmeventd.sh
@@ -0,0 +1,263 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2018 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+which mkfs.ext4 || skip
+aux have_integrity 1 5 0 || skip
+# Avoid 4K ramdisk devices on older kernels
+aux kernel_at_least 5 10 || export LVM_TEST_PREFER_BRD=0
+
+mnt="mnt"
+mkdir -p $mnt
+
+aux prepare_devs 6 64
+
+# Use awk instead of anoyingly long log out from printf
+#printf "%0.sA" {1..16384} >> fileA
+awk 'BEGIN { while (z++ < 16384) printf "A" }' > fileA
+awk 'BEGIN { while (z++ < 16384) printf "B" }' > fileB
+awk 'BEGIN { while (z++ < 16384) printf "C" }' > fileC
+
+# generate random data
+dd if=/dev/urandom of=randA bs=512K count=2
+dd if=/dev/urandom of=randB bs=512K count=3
+dd if=/dev/urandom of=randC bs=512K count=4
+
+_prepare_vg() {
+ vgcreate $SHARED $vg "$dev1" "$dev2" "$dev3" "$dev4"
+ pvs
+}
+
+_add_new_data_to_mnt() {
+ mkfs.ext4 "$DM_DEV_DIR/$vg/$lv1"
+
+ mount "$DM_DEV_DIR/$vg/$lv1" $mnt
+
+ # add original data
+ cp randA $mnt
+ cp randB $mnt
+ cp randC $mnt
+ mkdir $mnt/1
+ cp fileA $mnt/1
+ cp fileB $mnt/1
+ cp fileC $mnt/1
+ mkdir $mnt/2
+ cp fileA $mnt/2
+ cp fileB $mnt/2
+ cp fileC $mnt/2
+}
+
+_add_more_data_to_mnt() {
+ mkdir $mnt/more
+ cp fileA $mnt/more
+ cp fileB $mnt/more
+ cp fileC $mnt/more
+ cp randA $mnt/more
+ cp randB $mnt/more
+ cp randC $mnt/more
+}
+
+_verify_data_on_mnt() {
+ diff randA $mnt/randA
+ diff randB $mnt/randB
+ diff randC $mnt/randC
+ diff fileA $mnt/1/fileA
+ diff fileB $mnt/1/fileB
+ diff fileC $mnt/1/fileC
+ diff fileA $mnt/2/fileA
+ diff fileB $mnt/2/fileB
+ diff fileC $mnt/2/fileC
+}
+
+_verify_data_on_lv() {
+ lvchange -ay $vg/$lv1
+ mount "$DM_DEV_DIR/$vg/$lv1" $mnt
+ _verify_data_on_mnt
+ rm $mnt/randA
+ rm $mnt/randB
+ rm $mnt/randC
+ rm -rf $mnt/1
+ rm -rf $mnt/2
+ umount $mnt
+ lvchange -an $vg/$lv1
+}
+
+aux lvmconf \
+ 'activation/raid_fault_policy = "allocate"'
+
+aux prepare_dmeventd
+
+# raid1, one device fails, dmeventd calls repair
+
+vgcreate $SHARED $vg "$dev1" "$dev2" "$dev3" "$dev4"
+lvcreate --type raid1 -m 2 --raidintegrity y --ignoremonitoring -l 8 -n $lv1 $vg "$dev1" "$dev2" "$dev3"
+lvchange --monitor y $vg/$lv1
+lvs -a -o+devices $vg
+aux wait_recalc $vg/${lv1}_rimage_0
+aux wait_recalc $vg/${lv1}_rimage_1
+aux wait_recalc $vg/${lv1}_rimage_2
+aux wait_for_sync $vg $lv1
+_add_new_data_to_mnt
+
+aux disable_dev "$dev2"
+
+# wait for dmeventd to call lvconvert --repair which should
+# replace dev2 with dev4
+sync
+sleep 5
+
+lvs -a -o+devices $vg | tee out
+not grep "$dev2" out
+grep "$dev4" out
+
+_add_more_data_to_mnt
+_verify_data_on_mnt
+
+aux enable_dev "$dev2"
+
+lvs -a -o+devices $vg | tee out
+not grep "$dev2" out
+grep "$dev4" out
+grep "$dev1" out
+grep "$dev3" out
+
+umount $mnt
+lvchange -an $vg/$lv1
+_verify_data_on_lv
+lvremove $vg/$lv1
+vgremove -ff $vg
+
+# raid1, two devices fail, dmeventd calls repair
+
+vgcreate $SHARED $vg "$dev1" "$dev2" "$dev3" "$dev4" "$dev5"
+lvcreate --type raid1 -m 2 --raidintegrity y --ignoremonitoring -l 8 -n $lv1 $vg "$dev1" "$dev2" "$dev3"
+lvchange --monitor y $vg/$lv1
+lvs -a -o+devices $vg
+aux wait_recalc $vg/${lv1}_rimage_0
+aux wait_recalc $vg/${lv1}_rimage_1
+aux wait_recalc $vg/${lv1}_rimage_2
+aux wait_for_sync $vg $lv1
+_add_new_data_to_mnt
+
+aux disable_dev "$dev1" "$dev2"
+
+# wait for dmeventd to call lvconvert --repair which should
+# replace dev1 and dev2 with dev4 and dev5
+sync
+sleep 5
+
+lvs -a -o+devices $vg | tee out
+not grep "$dev1" out
+not grep "$dev2" out
+grep "$dev4" out
+grep "$dev5" out
+grep "$dev3" out
+
+_add_more_data_to_mnt
+_verify_data_on_mnt
+
+aux enable_dev "$dev1" "$dev2"
+
+lvs -a -o+devices $vg | tee out
+not grep "$dev1" out
+not grep "$dev2" out
+grep "$dev4" out
+grep "$dev5" out
+grep "$dev3" out
+
+umount $mnt
+lvchange -an $vg/$lv1
+_verify_data_on_lv
+lvremove $vg/$lv1
+vgremove -ff $vg
+
+# raid6, one device fails, dmeventd calls repair
+
+vgcreate $SHARED $vg "$dev1" "$dev2" "$dev3" "$dev4" "$dev5" "$dev6"
+lvcreate --type raid6 --raidintegrity y --ignoremonitoring -l 8 -n $lv1 $vg "$dev1" "$dev2" "$dev3" "$dev4" "$dev5"
+lvchange --monitor y $vg/$lv1
+lvs -a -o+devices $vg
+aux wait_recalc $vg/${lv1}_rimage_0
+aux wait_recalc $vg/${lv1}_rimage_1
+aux wait_recalc $vg/${lv1}_rimage_2
+aux wait_recalc $vg/${lv1}_rimage_3
+aux wait_recalc $vg/${lv1}_rimage_4
+aux wait_for_sync $vg $lv1
+_add_new_data_to_mnt
+
+aux disable_dev "$dev2"
+
+# wait for dmeventd to call lvconvert --repair which should
+# replace dev2 with dev6
+sync
+sleep 5
+
+lvs -a -o+devices $vg | tee out
+not grep "$dev2" out
+grep "$dev6" out
+
+_add_more_data_to_mnt
+_verify_data_on_mnt
+
+aux enable_dev "$dev2"
+
+lvs -a -o+devices $vg | tee out
+not grep "$dev2" out
+grep "$dev6" out
+
+umount $mnt
+lvchange -an $vg/$lv1
+_verify_data_on_lv
+lvremove $vg/$lv1
+vgremove -ff $vg
+
+# raid10, one device fails, dmeventd calls repair
+
+vgcreate $SHARED $vg "$dev1" "$dev2" "$dev3" "$dev4" "$dev5"
+lvcreate --type raid10 --raidintegrity y --ignoremonitoring -l 8 -n $lv1 $vg "$dev1" "$dev2" "$dev3" "$dev4"
+lvchange --monitor y $vg/$lv1
+lvs -a -o+devices $vg
+aux wait_recalc $vg/${lv1}_rimage_0
+aux wait_recalc $vg/${lv1}_rimage_1
+aux wait_recalc $vg/${lv1}_rimage_2
+aux wait_recalc $vg/${lv1}_rimage_3
+aux wait_for_sync $vg $lv1
+_add_new_data_to_mnt
+
+aux disable_dev "$dev1"
+
+# wait for dmeventd to call lvconvert --repair which should
+# replace dev1 with dev5
+sync
+sleep 5
+
+lvs -a -o+devices $vg | tee out
+not grep "$dev1" out
+grep "$dev5" out
+
+_add_more_data_to_mnt
+_verify_data_on_mnt
+
+aux enable_dev "$dev1"
+
+lvs -a -o+devices $vg | tee out
+not grep "$dev1" out
+grep "$dev5" out
+
+umount $mnt
+lvchange -an $vg/$lv1
+_verify_data_on_lv
+lvremove $vg/$lv1
+vgremove -ff $vg
diff --git a/test/shell/integrity-large.sh b/test/shell/integrity-large.sh
new file mode 100644
index 0000000..37823ab
--- /dev/null
+++ b/test/shell/integrity-large.sh
@@ -0,0 +1,177 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2018 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+# Test writecache usage
+
+SKIP_WITH_LVMPOLLD=1
+SKIP_WITH_LOW_SPACE=1100
+
+. lib/inittest
+
+aux have_integrity 1 5 0 || skip
+which mkfs.xfs || skip
+
+mnt="mnt"
+mkdir -p $mnt
+
+# raid1 LV needs to be extended to 512MB to test imeta being exended
+aux prepare_devs 4 632
+
+# this test may consume lot of disk space - so make sure cleaning works
+# also in failure case
+cleanup_mounted_and_teardown()
+{
+ umount "$mnt" 2>/dev/null || true
+ # Comment out this 'vgremove' when there is any need to analyze
+ # content of the failed test dir, otherwise all is deleted.
+ vgremove -ff $vg || true
+ aux teardown
+}
+
+trap 'cleanup_mounted_and_teardown' EXIT
+
+# Use awk instead of anoyingly long log out from printf
+#printf "%0.sA" {1..16384} >> fileA
+awk 'BEGIN { while (z++ < 16384) printf "A" }' > fileA
+awk 'BEGIN { while (z++ < 16384) printf "B" }' > fileB
+awk 'BEGIN { while (z++ < 16384) printf "C" }' > fileC
+
+# generate random data
+dd if=/dev/urandom of=randA bs=512K count=2
+dd if=/dev/urandom of=randB bs=512K count=3
+dd if=/dev/urandom of=randC bs=512K count=4
+
+_prepare_vg() {
+ vgcreate $SHARED $vg "$dev1" "$dev2"
+ pvs
+}
+
+_add_data_to_lv() {
+ mkfs.xfs -f "$DM_DEV_DIR/$vg/$lv1"
+
+ mount "$DM_DEV_DIR/$vg/$lv1" $mnt
+
+ # add original data
+ cp randA $mnt
+ cp randB $mnt
+ cp randC $mnt
+ mkdir $mnt/1
+ cp fileA $mnt/1
+ cp fileB $mnt/1
+ cp fileC $mnt/1
+ mkdir $mnt/2
+ cp fileA $mnt/2
+ cp fileB $mnt/2
+ cp fileC $mnt/2
+
+ umount $mnt
+}
+
+_verify_data_on_lv() {
+ mount "$DM_DEV_DIR/$vg/$lv1" $mnt
+
+ diff randA $mnt/randA
+ diff randB $mnt/randB
+ diff randC $mnt/randC
+ diff fileA $mnt/1/fileA
+ diff fileB $mnt/1/fileB
+ diff fileC $mnt/1/fileC
+ diff fileA $mnt/2/fileA
+ diff fileB $mnt/2/fileB
+ diff fileC $mnt/2/fileC
+
+ umount $mnt
+}
+
+# lvextend to 512MB is needed for the imeta LV to
+# be extended from 4MB to 8MB.
+
+_prepare_vg
+lvcreate --type raid1 -m1 -n $lv1 -L 300 $vg
+lvchange -an $vg/$lv1
+lvchange -ay $vg/$lv1
+_add_data_to_lv
+# lv needs to be inactive when adding integrity to increase LBS from 512 and get a ribs of 4k
+lvchange -an $vg/$lv1
+lvconvert --raidintegrity y $vg/$lv1
+lvchange -ay $vg/$lv1
+aux wait_recalc $vg/${lv1}_rimage_0
+aux wait_recalc $vg/${lv1}_rimage_1
+lvs -a -o+devices $vg
+_verify_data_on_lv
+lvchange -an $vg/$lv1
+lvextend -L 512M $vg/$lv1
+lvs -a -o+devices $vg
+lvchange -ay $vg/$lv1
+_verify_data_on_lv
+aux wait_recalc $vg/${lv1}_rimage_0
+aux wait_recalc $vg/${lv1}_rimage_1
+lvs -a -o+devices $vg
+check lv_field $vg/${lv1}_rimage_0_imeta size "12.00m"
+check lv_field $vg/${lv1}_rimage_1_imeta size "12.00m"
+
+# provide space to extend the images onto new devs
+vgextend $vg "$dev3" "$dev4"
+
+# extending the images is possible using dev3,dev4
+# but extending imeta on the existing dev1,dev2 fails
+not lvextend -L +512M $vg/$lv1
+
+# removing integrity will permit extending the images
+# using dev3,dev4 since imeta limitation is gone
+lvconvert --raidintegrity n $vg/$lv1
+lvextend -L +512M $vg/$lv1
+lvs -a -o+devices $vg
+
+# adding integrity again will allocate new 12MB imeta LVs
+# on dev3,dev4
+lvconvert --raidintegrity y $vg/$lv1
+aux wait_recalc $vg/${lv1}_rimage_0
+aux wait_recalc $vg/${lv1}_rimage_1
+lvs -a -o+devices $vg
+check lv_field $vg/${lv1}_rimage_0_imeta size "20.00m"
+check lv_field $vg/${lv1}_rimage_1_imeta size "20.00m"
+
+lvchange -an $vg/$lv1
+lvremove $vg/$lv1
+
+# As the test doesn't wait for full resync
+# delay legs so not all data need to be written.
+aux delay_dev "$dev1" 1000 0 "$(( $(get first_extent_sector "$dev1") + 16000 )):1200000"
+aux delay_dev "$dev2" 0 10 "$(( $(get first_extent_sector "$dev2") + 16000 )):1200000"
+
+
+# this succeeds because dev1,dev2 can hold rmeta+rimage
+lvcreate --type raid1 -n $lv1 -L 592M -an $vg "$dev1" "$dev2"
+lvs -a -o+devices $vg
+lvremove $vg/$lv1
+
+# this fails because dev1,dev2 can hold rmeta+rimage, but not imeta
+# and we require imeta to be on same devs as rmeta/rimeta
+not lvcreate --type raid1 --raidintegrity y -n $lv1 -L 624M -an $vg "$dev1" "$dev2"
+lvs -a -o+devices $vg
+
+# this can allocate from more devs so there's enough space for imeta to
+# be allocated in the vg, but lvcreate fails because rmeta+rimage are
+# allocated from dev1,dev2, we restrict imeta to being allocated on the
+# same devs as rmeta/rimage, and dev1,dev2 can't fit imeta.
+not lvcreate --type raid1 --raidintegrity y -n $lv1 -L 624M -an $vg
+lvs -a -o+devices $vg
+
+# counterintuitively, increasing the size will allow lvcreate to succeed
+# because rmeta+rimage are pushed to being allocated on dev1,dev2,dev3,dev4
+# which means imeta is now free to be allocated from dev3,dev4 which have
+# plenty of space
+lvcreate --type raid1 --raidintegrity y -n $lv1 -L 640M -an $vg
+lvs -a -o+devices $vg
+
+vgremove -ff $vg
diff --git a/test/shell/integrity-misc.sh b/test/shell/integrity-misc.sh
new file mode 100644
index 0000000..3ab0c2b
--- /dev/null
+++ b/test/shell/integrity-misc.sh
@@ -0,0 +1,216 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2018 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+which mkfs.ext4 || skip
+aux have_integrity 1 5 0 || skip
+# Avoid 4K ramdisk devices on older kernels
+aux kernel_at_least 5 10 || export LVM_TEST_PREFER_BRD=0
+
+mnt="mnt"
+mkdir -p $mnt
+
+aux prepare_devs 5 64
+
+# Use awk instead of anoyingly long log out from printf
+#printf "%0.sA" {1..16384} >> fileA
+awk 'BEGIN { while (z++ < 16384) printf "A" }' > fileA
+awk 'BEGIN { while (z++ < 16384) printf "B" }' > fileB
+awk 'BEGIN { while (z++ < 16384) printf "C" }' > fileC
+
+# generate random data
+dd if=/dev/urandom of=randA bs=512K count=2
+dd if=/dev/urandom of=randB bs=512K count=3
+dd if=/dev/urandom of=randC bs=512K count=4
+
+_prepare_vg() {
+ vgcreate $SHARED $vg "$dev1" "$dev2" "$dev3" "$dev4" "$dev5"
+ pvs
+}
+
+_add_new_data_to_mnt() {
+ mkfs.ext4 "$DM_DEV_DIR/$vg/$lv1"
+
+ mount "$DM_DEV_DIR/$vg/$lv1" $mnt
+
+ # add original data
+ cp randA $mnt
+ cp randB $mnt
+ cp randC $mnt
+ mkdir $mnt/1
+ cp fileA $mnt/1
+ cp fileB $mnt/1
+ cp fileC $mnt/1
+ mkdir $mnt/2
+ cp fileA $mnt/2
+ cp fileB $mnt/2
+ cp fileC $mnt/2
+}
+
+_add_more_data_to_mnt() {
+ mkdir $mnt/more
+ cp fileA $mnt/more
+ cp fileB $mnt/more
+ cp fileC $mnt/more
+ cp randA $mnt/more
+ cp randB $mnt/more
+ cp randC $mnt/more
+}
+
+_verify_data_on_mnt() {
+ diff randA $mnt/randA
+ diff randB $mnt/randB
+ diff randC $mnt/randC
+ diff fileA $mnt/1/fileA
+ diff fileB $mnt/1/fileB
+ diff fileC $mnt/1/fileC
+ diff fileA $mnt/2/fileA
+ diff fileB $mnt/2/fileB
+ diff fileC $mnt/2/fileC
+}
+
+_verify_data_on_lv() {
+ lvchange -ay $vg/$lv1
+ mount "$DM_DEV_DIR/$vg/$lv1" $mnt
+ _verify_data_on_mnt
+ rm $mnt/randA
+ rm $mnt/randB
+ rm $mnt/randC
+ rm -rf $mnt/1
+ rm -rf $mnt/2
+ umount $mnt
+ lvchange -an $vg/$lv1
+}
+
+# lvrename
+_prepare_vg
+lvcreate --type raid1 -m1 --raidintegrity y -n $lv1 -l 8 $vg
+aux wait_recalc $vg/${lv1}_rimage_0
+aux wait_recalc $vg/${lv1}_rimage_1
+aux wait_recalc $vg/$lv1
+_add_new_data_to_mnt
+umount $mnt
+lvrename $vg/$lv1 $vg/$lv2
+mount "$DM_DEV_DIR/$vg/$lv2" $mnt
+_verify_data_on_mnt
+umount $mnt
+lvchange -an $vg/$lv2
+lvremove $vg/$lv2
+vgremove -ff $vg
+
+# lvconvert --replace
+# an existing dev is replaced with another dev
+# lv must be active
+_prepare_vg
+lvcreate --type raid1 -m1 --raidintegrity y -n $lv1 -l 8 $vg "$dev1" "$dev2"
+aux wait_recalc $vg/${lv1}_rimage_0
+aux wait_recalc $vg/${lv1}_rimage_1
+aux wait_recalc $vg/$lv1
+lvs -o raidintegritymode $vg/$lv1 | grep journal
+_add_new_data_to_mnt
+lvconvert --replace "$dev1" $vg/$lv1 "$dev3"
+lvs -a -o+devices $vg > out
+cat out
+grep "$dev2" out
+grep "$dev3" out
+not grep "$dev1" out
+_add_more_data_to_mnt
+_verify_data_on_mnt
+umount $mnt
+lvchange -an $vg/$lv1
+_verify_data_on_lv
+lvremove $vg/$lv1
+vgremove -ff $vg
+
+# lvconvert --replace
+# same as prev but with bitmap mode
+_prepare_vg
+lvcreate --type raid1 -m1 --raidintegrity y --raidintegritymode bitmap -n $lv1 -l 8 $vg "$dev1" "$dev2"
+aux wait_recalc $vg/${lv1}_rimage_0
+aux wait_recalc $vg/${lv1}_rimage_1
+aux wait_recalc $vg/$lv1
+lvs -o raidintegritymode $vg/$lv1 | grep bitmap
+_add_new_data_to_mnt
+lvconvert --replace "$dev1" $vg/$lv1 "$dev3"
+lvs -a -o+devices $vg > out
+cat out
+grep "$dev2" out
+grep "$dev3" out
+not grep "$dev1" out
+_add_more_data_to_mnt
+_verify_data_on_mnt
+umount $mnt
+lvchange -an $vg/$lv1
+_verify_data_on_lv
+lvremove $vg/$lv1
+vgremove -ff $vg
+
+# lvconvert --repair
+# while lv is active a device goes missing (with rimage,rmeta,imeta,orig).
+# lvconvert --repair should replace the missing dev with another,
+# (like lvconvert --replace does for a dev that's not missing).
+_prepare_vg
+lvcreate --type raid1 -m1 --raidintegrity y -n $lv1 -l 8 $vg "$dev1" "$dev2"
+aux wait_recalc $vg/${lv1}_rimage_0
+aux wait_recalc $vg/${lv1}_rimage_1
+aux wait_recalc $vg/$lv1
+_add_new_data_to_mnt
+aux disable_dev "$dev2"
+lvs -a -o+devices $vg > out
+cat out
+grep unknown out
+lvconvert -vvvv -y --repair $vg/$lv1
+lvs -a -o+devices $vg > out
+cat out
+not grep "$dev2" out
+not grep unknown out
+_add_more_data_to_mnt
+_verify_data_on_mnt
+umount $mnt
+lvchange -an $vg/$lv1
+lvremove $vg/$lv1
+aux enable_dev "$dev2"
+vgremove -ff $vg
+
+# lvchange activationmode
+# a device is missing (with rimage,rmeta,imeta,iorig), the lv
+# is already inactive, and it cannot be activated, with
+# activationmode degraded or partial, or in any way,
+# until integrity is removed.
+
+_prepare_vg
+lvcreate --type raid1 -m1 --raidintegrity y -n $lv1 -l 8 $vg "$dev1" "$dev2"
+aux wait_recalc $vg/${lv1}_rimage_0
+aux wait_recalc $vg/${lv1}_rimage_1
+aux wait_recalc $vg/$lv1
+_add_new_data_to_mnt
+umount $mnt
+lvchange -an $vg/$lv1
+aux disable_dev "$dev2"
+lvs -a -o+devices $vg
+not lvchange -ay $vg/$lv1
+not lvchange -ay --activationmode degraded $vg/$lv1
+not lvchange -ay --activationmode partial $vg/$lv1
+lvconvert --raidintegrity n $vg/$lv1
+lvchange -ay --activationmode degraded $vg/$lv1
+mount "$DM_DEV_DIR/$vg/$lv1" $mnt
+_add_more_data_to_mnt
+_verify_data_on_mnt
+umount $mnt
+lvchange -an $vg/$lv1
+lvremove $vg/$lv1
+aux enable_dev "$dev2"
+vgremove -ff $vg
+
diff --git a/test/shell/integrity-syncaction.sh b/test/shell/integrity-syncaction.sh
new file mode 100644
index 0000000..4bd4acc
--- /dev/null
+++ b/test/shell/integrity-syncaction.sh
@@ -0,0 +1,159 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2018 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+which mkfs.ext4 || skip
+aux have_integrity 1 5 0 || skip
+# Avoid 4K ramdisk devices on older kernels
+aux kernel_at_least 5 10 || export LVM_TEST_PREFER_BRD=0
+
+mnt="mnt"
+mkdir -p $mnt
+
+aux prepare_devs 3 40
+
+# Use awk instead of anoyingly long log out from printf
+#printf "%0.sA" {1..16384} >> fileA
+awk 'BEGIN { while (z++ < 16384) printf "A" }' > fileA
+awk 'BEGIN { while (z++ < 4096) printf "B" ; while (z++ < 16384) printf "b" }' > fileB
+awk 'BEGIN { while (z++ < 16384) printf "C" }' > fileC
+
+_prepare_vg() {
+ # zero devs so we are sure to find the correct file data
+ # on the underlying devs when corrupting it
+ aux clear_devs "$dev1" "$dev2" "$dev3"
+ vgcreate $SHARED $vg "$dev1" "$dev2" "$dev3"
+ pvs
+}
+
+_test1() {
+ mkfs.ext4 "$DM_DEV_DIR/$vg/$lv1"
+
+ mount "$DM_DEV_DIR/$vg/$lv1" $mnt
+
+ cp fileA $mnt
+ cp fileB $mnt
+ cp fileC $mnt
+
+ umount $mnt
+ lvchange -an $vg/$lv1
+
+ # Corrupting raid1 is simple - 1 leg needs to be modifed
+ # For raid5 corrupted block can be places on any of its leg.
+ for i in "$@" ; do
+ aux corrupt_dev "$i" BBBBBBBBBBBBBBBBB BBBBBBBBCBBBBBBBB |& tee out
+ grep -q "copied" out && break # leg found and corrupted
+ done
+
+ lvchange -ay $vg/$lv1
+
+ # so without synchecking the array - integrity doesn't know yet about failure
+ check lv_field $vg/${lv1}_rimage_0 integritymismatches "0"
+ check lv_field $vg/${lv1}_rimage_1 integritymismatches "0"
+ [ $# -gt 2 ] && check lv_field $vg/${lv1}_rimage_2 integritymismatches "0"
+
+ lvchange --syncaction check $vg/$lv1
+
+ aux wait_recalc $vg/$lv1
+
+ # after synaction check - integrity should recognize faulty devices
+ baddev=0
+ for i in 0 1 2 ; do
+ [ "$i" -gt 1 ] && [ $# -lt 3 ] && continue # only raid5 has rimage_2
+ [ "$(get lv_field $vg/${lv1}_rimage_${i} integritymismatches)" = "0" ] || baddev=$(( baddev + 1 ))
+ done
+ [ "$baddev" -eq 1 ] || die "Unexpected number of integritymismatched devices ($baddev)!"
+
+ mount "$DM_DEV_DIR/$vg/$lv1" $mnt
+ cmp -b $mnt/fileA fileA
+ cmp -b $mnt/fileB fileB
+ cmp -b $mnt/fileC fileC
+ umount $mnt
+}
+
+_test2() {
+ mkfs.ext4 "$DM_DEV_DIR/$vg/$lv1"
+
+ mount "$DM_DEV_DIR/$vg/$lv1" $mnt
+
+ cp fileA $mnt
+ cp fileB $mnt
+ cp fileC $mnt
+
+ umount $mnt
+ lvchange -an $vg/$lv1
+
+ # corrupt fileB and fileC on dev1
+ aux corrupt_dev "$dev1" BBBBBBBBBBBBBBBBB BBBBBBBBCBBBBBBBB
+ aux corrupt_dev "$dev1" CCCCCCCCCCCCCCCCC DDDDDDDDDDDDDDDDD
+
+ # corrupt fileA on dev2
+ aux corrupt_dev "$dev2" AAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAEAA
+
+ lvchange -ay $vg/$lv1
+
+ check lv_field $vg/${lv1}_rimage_0 integritymismatches "0"
+ check lv_field $vg/${lv1}_rimage_1 integritymismatches "0"
+
+ lvchange --syncaction check $vg/$lv1
+
+ aux wait_recalc $vg/$lv1
+
+ not check lv_field $vg/${lv1}_rimage_0 integritymismatches "0"
+ not check lv_field $vg/${lv1}_rimage_1 integritymismatches "0"
+
+ mount "$DM_DEV_DIR/$vg/$lv1" $mnt
+ cmp -b $mnt/fileA fileA
+ cmp -b $mnt/fileB fileB
+ cmp -b $mnt/fileC fileC
+ umount $mnt
+}
+
+_prepare_vg
+lvcreate --type raid1 -m1 --raidintegrity y -n $lv1 -l 6 $vg "$dev1" "$dev2"
+aux wait_recalc $vg/${lv1}_rimage_0
+aux wait_recalc $vg/${lv1}_rimage_1
+aux wait_recalc $vg/$lv1
+_test1 "$dev1"
+not check $vg/$lv1 integritymismatches "0"
+lvchange -an $vg/$lv1
+lvconvert --raidintegrity n $vg/$lv1
+lvremove $vg/$lv1
+vgremove -ff $vg
+
+_prepare_vg
+lvcreate --type raid1 -m1 --raidintegrity y -n $lv1 -l 6 $vg "$dev1" "$dev2"
+aux wait_recalc $vg/${lv1}_rimage_0
+aux wait_recalc $vg/${lv1}_rimage_1
+aux wait_recalc $vg/$lv1
+_test2
+not check $vg/$lv1 integritymismatches "0"
+lvchange -an $vg/$lv1
+lvconvert --raidintegrity n $vg/$lv1
+lvremove $vg/$lv1
+vgremove -ff $vg
+
+_prepare_vg
+lvcreate --type raid5 --raidintegrity y -n $lv1 -I 4K -l 6 $vg "$dev1" "$dev2" "$dev3"
+aux wait_recalc $vg/${lv1}_rimage_0
+aux wait_recalc $vg/${lv1}_rimage_1
+aux wait_recalc $vg/${lv1}_rimage_2
+aux wait_recalc $vg/$lv1
+_test1 "$dev1" "$dev2" "$dev3"
+not check $vg/$lv1 integritymismatches "0"
+lvchange -an $vg/$lv1
+lvconvert --raidintegrity n $vg/$lv1
+lvremove $vg/$lv1
+vgremove -ff $vg
diff --git a/test/shell/integrity.sh b/test/shell/integrity.sh
new file mode 100644
index 0000000..61229c8
--- /dev/null
+++ b/test/shell/integrity.sh
@@ -0,0 +1,771 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2018 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+which mkfs.ext4 || skip
+which resize2fs || skip
+aux have_integrity 1 5 0 || skip
+# Avoid 4K ramdisk devices on older kernels
+aux kernel_at_least 5 10 || export LVM_TEST_PREFER_BRD=0
+
+mnt="mnt"
+mkdir -p $mnt
+
+aux prepare_devs 5 64
+
+# Use awk instead of anoyingly long log out from printf
+#printf "%0.sA" {1..16384} >> fileA
+awk 'BEGIN { while (z++ < 16384) printf "A" }' > fileA
+awk 'BEGIN { while (z++ < 4096) printf "B" ; while (z++ < 16384) printf "b" }' > fileB
+awk 'BEGIN { while (z++ < 16384) printf "C" }' > fileC
+
+# generate random data
+dd if=/dev/urandom of=randA bs=512K count=2
+dd if=/dev/urandom of=randB bs=512K count=3
+dd if=/dev/urandom of=randC bs=512K count=4
+
+_prepare_vg() {
+ # zero devs so we are sure to find the correct file data
+ # on the underlying devs when corrupting it
+ aux clear_devs "$dev1" "$dev2" "$dev3" "$dev4" "$dev5"
+ vgcreate $SHARED $vg "$dev1" "$dev2" "$dev3" "$dev4" "$dev5"
+ pvs
+}
+
+_test_fs_with_read_repair() {
+ mkfs.ext4 -b 4096 "$DM_DEV_DIR/$vg/$lv1"
+
+ mount "$DM_DEV_DIR/$vg/$lv1" $mnt
+
+ cp randA $mnt
+ cp randB $mnt
+ cp randC $mnt
+ cp fileA $mnt
+ cp fileB $mnt
+ cp fileC $mnt
+
+ umount $mnt
+ lvchange -an $vg/$lv1
+
+ for dev in "$@"; do
+ aux corrupt_dev "$dev" BBBBBBBBBBBBBBBBB BBBBBBBBCBBBBBBBB
+ done
+
+ lvchange -ay $vg/$lv1
+
+ mount "$DM_DEV_DIR/$vg/$lv1" $mnt
+ cmp -b $mnt/fileA fileA
+ cmp -b $mnt/fileB fileB
+ cmp -b $mnt/fileC fileC
+ umount $mnt
+}
+
+_add_new_data_to_mnt() {
+ mkfs.ext4 -b 4096 "$DM_DEV_DIR/$vg/$lv1"
+
+ mount "$DM_DEV_DIR/$vg/$lv1" $mnt
+
+ # add original data
+ cp randA $mnt
+ cp randB $mnt
+ cp randC $mnt
+ mkdir $mnt/1
+ cp fileA $mnt/1
+ cp fileB $mnt/1
+ cp fileC $mnt/1
+ mkdir $mnt/2
+ cp fileA $mnt/2
+ cp fileB $mnt/2
+ cp fileC $mnt/2
+}
+
+_add_more_data_to_mnt() {
+ mkdir $mnt/more
+ cp fileA $mnt/more
+ cp fileB $mnt/more
+ cp fileC $mnt/more
+ cp randA $mnt/more
+ cp randB $mnt/more
+ cp randC $mnt/more
+}
+
+_verify_data_on_mnt() {
+ cmp -b randA $mnt/randA
+ cmp -b randB $mnt/randB
+ cmp -b randC $mnt/randC
+ cmp -b fileA $mnt/1/fileA
+ cmp -b fileB $mnt/1/fileB
+ cmp -b fileC $mnt/1/fileC
+ cmp -b fileA $mnt/2/fileA
+ cmp -b fileB $mnt/2/fileB
+ cmp -b fileC $mnt/2/fileC
+}
+
+_verify_data_on_lv() {
+ lvchange -ay $vg/$lv1
+ mount "$DM_DEV_DIR/$vg/$lv1" $mnt
+ _verify_data_on_mnt
+ rm $mnt/randA
+ rm $mnt/randB
+ rm $mnt/randC
+ rm -rf $mnt/1
+ rm -rf $mnt/2
+ umount $mnt
+ lvchange -an $vg/$lv1
+}
+
+# Test corrupting data on an image and verifying that
+# it is detected by integrity and corrected by raid.
+
+_prepare_vg
+lvcreate --type raid1 -m1 --raidintegrity y -n $lv1 -l 8 $vg "$dev1" "$dev2"
+lvs -a -o name,segtype,devices,sync_percent $vg
+aux wait_recalc $vg/${lv1}_rimage_0
+aux wait_recalc $vg/${lv1}_rimage_1
+aux wait_recalc $vg/$lv1
+_test_fs_with_read_repair "$dev1"
+lvs -o integritymismatches $vg/${lv1}_rimage_0 |tee mismatch
+not grep 0 mismatch
+lvs -o integritymismatches $vg/$lv1 |tee mismatch
+not grep 0 mismatch
+lvchange -an $vg/$lv1
+lvconvert --raidintegrity n $vg/$lv1
+lvremove $vg/$lv1
+vgremove -ff $vg
+
+_prepare_vg
+lvcreate --type raid1 -m2 --raidintegrity y -n $lv1 -l 8 $vg "$dev1" "$dev2" "$dev3"
+lvs -a -o name,segtype,devices,sync_percent $vg
+aux wait_recalc $vg/${lv1}_rimage_0
+aux wait_recalc $vg/${lv1}_rimage_1
+aux wait_recalc $vg/${lv1}_rimage_2
+aux wait_recalc $vg/$lv1
+_test_fs_with_read_repair "$dev1" "$dev2"
+lvs -o integritymismatches $vg/${lv1}_rimage_0 |tee mismatch
+not grep 0 mismatch
+lvs -o integritymismatches $vg/$lv1 |tee mismatch
+not grep 0 mismatch
+lvchange -an $vg/$lv1
+lvconvert --raidintegrity n $vg/$lv1
+lvremove $vg/$lv1
+vgremove -ff $vg
+
+_prepare_vg
+lvcreate --type raid4 --raidintegrity y -n $lv1 -I 4K -l 8 $vg "$dev1" "$dev2" "$dev3"
+lvs -a -o name,segtype,devices,sync_percent $vg
+aux wait_recalc $vg/${lv1}_rimage_0
+aux wait_recalc $vg/${lv1}_rimage_1
+aux wait_recalc $vg/${lv1}_rimage_2
+aux wait_recalc $vg/$lv1
+_test_fs_with_read_repair "$dev1" "$dev2" "$dev3"
+lvs -o integritymismatches $vg/${lv1}_rimage_0
+lvs -o integritymismatches $vg/${lv1}_rimage_1
+lvs -o integritymismatches $vg/${lv1}_rimage_2
+lvs -o integritymismatches $vg/$lv1 |tee mismatch
+not grep 0 mismatch
+lvchange -an $vg/$lv1
+lvconvert --raidintegrity n $vg/$lv1
+lvremove $vg/$lv1
+vgremove -ff $vg
+
+_prepare_vg
+lvcreate --type raid5 --raidintegrity y -n $lv1 -I 4K -l 8 $vg "$dev1" "$dev2" "$dev3"
+lvs -a -o name,segtype,devices,sync_percent $vg
+aux wait_recalc $vg/${lv1}_rimage_0
+aux wait_recalc $vg/${lv1}_rimage_1
+aux wait_recalc $vg/${lv1}_rimage_2
+aux wait_recalc $vg/$lv1
+_test_fs_with_read_repair "$dev1" "$dev2" "$dev3"
+lvs -o integritymismatches $vg/${lv1}_rimage_0
+lvs -o integritymismatches $vg/${lv1}_rimage_1
+lvs -o integritymismatches $vg/${lv1}_rimage_2
+lvs -o integritymismatches $vg/$lv1 |tee mismatch
+not grep 0 mismatch
+lvchange -an $vg/$lv1
+lvconvert --raidintegrity n $vg/$lv1
+lvremove $vg/$lv1
+vgremove -ff $vg
+
+_prepare_vg
+lvcreate --type raid6 --raidintegrity y -n $lv1 -I 4K -l 8 $vg "$dev1" "$dev2" "$dev3" "$dev4" "$dev5"
+lvs -a -o name,segtype,devices,sync_percent $vg
+aux wait_recalc $vg/${lv1}_rimage_0
+aux wait_recalc $vg/${lv1}_rimage_1
+aux wait_recalc $vg/${lv1}_rimage_2
+aux wait_recalc $vg/${lv1}_rimage_3
+aux wait_recalc $vg/${lv1}_rimage_4
+aux wait_recalc $vg/$lv1
+_test_fs_with_read_repair "$dev1" "$dev2" "$dev3" "$dev4" "$dev5"
+lvs -o integritymismatches $vg/${lv1}_rimage_0
+lvs -o integritymismatches $vg/${lv1}_rimage_1
+lvs -o integritymismatches $vg/${lv1}_rimage_2
+lvs -o integritymismatches $vg/${lv1}_rimage_3
+lvs -o integritymismatches $vg/${lv1}_rimage_4
+lvs -o integritymismatches $vg/$lv1 |tee mismatch
+not grep 0 mismatch
+lvchange -an $vg/$lv1
+lvconvert --raidintegrity n $vg/$lv1
+lvremove $vg/$lv1
+vgremove -ff $vg
+
+_prepare_vg
+lvcreate --type raid10 --raidintegrity y -n $lv1 -l 8 $vg "$dev1" "$dev2" "$dev3" "$dev4"
+lvs -a -o name,segtype,devices,sync_percent $vg
+aux wait_recalc $vg/${lv1}_rimage_0
+aux wait_recalc $vg/${lv1}_rimage_1
+aux wait_recalc $vg/${lv1}_rimage_2
+aux wait_recalc $vg/${lv1}_rimage_3
+aux wait_recalc $vg/$lv1
+_test_fs_with_read_repair "$dev1" "$dev3"
+lvs -o integritymismatches $vg/${lv1}_rimage_0
+lvs -o integritymismatches $vg/${lv1}_rimage_1
+lvs -o integritymismatches $vg/${lv1}_rimage_2
+lvs -o integritymismatches $vg/${lv1}_rimage_3
+lvs -o integritymismatches $vg/$lv1 |tee mismatch
+not grep 0 mismatch
+lvchange -an $vg/$lv1
+lvconvert --raidintegrity n $vg/$lv1
+lvremove $vg/$lv1
+vgremove -ff $vg
+
+# Test removing integrity from an active LV
+
+_prepare_vg
+lvcreate --type raid1 -m1 --raidintegrity y -n $lv1 -l 8 $vg
+lvs -a -o name,segtype,devices,sync_percent $vg
+aux wait_recalc $vg/${lv1}_rimage_0
+aux wait_recalc $vg/${lv1}_rimage_1
+aux wait_recalc $vg/$lv1
+_add_new_data_to_mnt
+lvconvert --raidintegrity n $vg/$lv1
+_add_more_data_to_mnt
+_verify_data_on_mnt
+umount $mnt
+lvchange -an $vg/$lv1
+_verify_data_on_lv
+lvremove $vg/$lv1
+vgremove -ff $vg
+
+_prepare_vg
+lvcreate --type raid4 --raidintegrity y -n $lv1 -l 8 $vg
+lvs -a -o name,segtype,devices,sync_percent $vg
+aux wait_recalc $vg/${lv1}_rimage_0
+aux wait_recalc $vg/${lv1}_rimage_1
+aux wait_recalc $vg/${lv1}_rimage_2
+aux wait_recalc $vg/$lv1
+_add_new_data_to_mnt
+lvconvert --raidintegrity n $vg/$lv1
+_add_more_data_to_mnt
+_verify_data_on_mnt
+umount $mnt
+lvchange -an $vg/$lv1
+_verify_data_on_lv
+lvremove $vg/$lv1
+vgremove -ff $vg
+
+_prepare_vg
+lvcreate --type raid5 --raidintegrity y -n $lv1 -l 8 $vg
+lvs -a -o name,segtype,devices,sync_percent $vg
+aux wait_recalc $vg/${lv1}_rimage_0
+aux wait_recalc $vg/${lv1}_rimage_1
+aux wait_recalc $vg/${lv1}_rimage_2
+aux wait_recalc $vg/$lv1
+_add_new_data_to_mnt
+lvconvert --raidintegrity n $vg/$lv1
+_add_more_data_to_mnt
+_verify_data_on_mnt
+umount $mnt
+lvchange -an $vg/$lv1
+_verify_data_on_lv
+lvremove $vg/$lv1
+vgremove -ff $vg
+
+_prepare_vg
+lvcreate --type raid6 --raidintegrity y -n $lv1 -l 8 $vg
+lvs -a -o name,segtype,devices,sync_percent $vg
+aux wait_recalc $vg/${lv1}_rimage_0
+aux wait_recalc $vg/${lv1}_rimage_1
+aux wait_recalc $vg/${lv1}_rimage_2
+aux wait_recalc $vg/${lv1}_rimage_3
+aux wait_recalc $vg/${lv1}_rimage_4
+aux wait_recalc $vg/$lv1
+_add_new_data_to_mnt
+lvconvert --raidintegrity n $vg/$lv1
+_add_more_data_to_mnt
+_verify_data_on_mnt
+umount $mnt
+lvchange -an $vg/$lv1
+_verify_data_on_lv
+lvremove $vg/$lv1
+vgremove -ff $vg
+
+_prepare_vg
+lvcreate --type raid10 --raidintegrity y -n $lv1 -l 8 $vg
+lvs -a -o name,segtype,devices,sync_percent $vg
+aux wait_recalc $vg/${lv1}_rimage_0
+aux wait_recalc $vg/${lv1}_rimage_1
+aux wait_recalc $vg/$lv1
+_add_new_data_to_mnt
+lvconvert --raidintegrity n $vg/$lv1
+_add_more_data_to_mnt
+_verify_data_on_mnt
+umount $mnt
+lvchange -an $vg/$lv1
+_verify_data_on_lv
+lvremove $vg/$lv1
+vgremove -ff $vg
+
+# Test adding integrity to an active LV
+
+_prepare_vg
+lvcreate --type raid1 -m1 -n $lv1 -l 8 $vg
+lvs -a -o name,segtype,devices,sync_percent $vg
+aux wait_recalc $vg/$lv1
+_add_new_data_to_mnt
+lvconvert --raidintegrity y $vg/$lv1
+aux wait_recalc $vg/${lv1}_rimage_0
+aux wait_recalc $vg/${lv1}_rimage_1
+_add_more_data_to_mnt
+_verify_data_on_mnt
+umount $mnt
+lvchange -an $vg/$lv1
+_verify_data_on_lv
+lvremove $vg/$lv1
+vgremove -ff $vg
+
+_prepare_vg
+lvcreate --type raid4 -n $lv1 -l 8 $vg
+lvs -a -o name,segtype,devices,sync_percent $vg
+aux wait_recalc $vg/$lv1
+_add_new_data_to_mnt
+lvconvert --raidintegrity y $vg/$lv1
+aux wait_recalc $vg/${lv1}_rimage_0
+aux wait_recalc $vg/${lv1}_rimage_1
+_add_more_data_to_mnt
+_verify_data_on_mnt
+umount $mnt
+lvchange -an $vg/$lv1
+_verify_data_on_lv
+lvremove $vg/$lv1
+vgremove -ff $vg
+
+_prepare_vg
+lvcreate --type raid5 -n $lv1 -l 8 $vg
+lvs -a -o name,segtype,devices,sync_percent $vg
+aux wait_recalc $vg/$lv1
+_add_new_data_to_mnt
+lvconvert --raidintegrity y $vg/$lv1
+aux wait_recalc $vg/${lv1}_rimage_0
+aux wait_recalc $vg/${lv1}_rimage_1
+_add_more_data_to_mnt
+_verify_data_on_mnt
+umount $mnt
+lvchange -an $vg/$lv1
+_verify_data_on_lv
+lvremove $vg/$lv1
+vgremove -ff $vg
+
+_prepare_vg
+lvcreate --type raid6 -n $lv1 -l 8 $vg
+lvs -a -o name,segtype,devices,sync_percent $vg
+aux wait_recalc $vg/$lv1
+_add_new_data_to_mnt
+lvconvert --raidintegrity y $vg/$lv1
+aux wait_recalc $vg/${lv1}_rimage_0
+aux wait_recalc $vg/${lv1}_rimage_1
+_add_more_data_to_mnt
+_verify_data_on_mnt
+umount $mnt
+lvchange -an $vg/$lv1
+_verify_data_on_lv
+lvremove $vg/$lv1
+vgremove -ff $vg
+
+_prepare_vg
+lvcreate --type raid10 -n $lv1 -l 8 $vg
+lvs -a -o name,segtype,devices,sync_percent $vg
+aux wait_recalc $vg/$lv1
+_add_new_data_to_mnt
+lvconvert --raidintegrity y $vg/$lv1
+aux wait_recalc $vg/${lv1}_rimage_0
+aux wait_recalc $vg/${lv1}_rimage_1
+_add_more_data_to_mnt
+_verify_data_on_mnt
+umount $mnt
+lvchange -an $vg/$lv1
+_verify_data_on_lv
+lvremove $vg/$lv1
+vgremove -ff $vg
+
+# Test lvextend while inactive
+
+_prepare_vg
+lvcreate --type raid1 -m1 --raidintegrity y -n $lv1 -l 8 $vg
+lvs -a -o name,segtype,devices,sync_percent $vg
+aux wait_recalc $vg/${lv1}_rimage_0
+aux wait_recalc $vg/${lv1}_rimage_1
+aux wait_recalc $vg/$lv1
+_add_new_data_to_mnt
+umount $mnt
+lvchange -an $vg/$lv1
+lvextend -l 16 $vg/$lv1
+lvchange -ay $vg/$lv1
+mount "$DM_DEV_DIR/$vg/$lv1" $mnt
+resize2fs "$DM_DEV_DIR/$vg/$lv1"
+aux wait_recalc $vg/${lv1}_rimage_0
+aux wait_recalc $vg/${lv1}_rimage_1
+lvs -a -o name,segtype,devices,sync_percent $vg
+_add_more_data_to_mnt
+_verify_data_on_mnt
+umount $mnt
+lvchange -an $vg/$lv1
+_verify_data_on_lv
+lvremove $vg/$lv1
+vgremove -ff $vg
+
+_prepare_vg
+lvcreate --type raid6 --raidintegrity y -n $lv1 -l 8 $vg
+lvs -a -o name,segtype,sync_percent,devices $vg
+aux wait_recalc $vg/${lv1}_rimage_0
+aux wait_recalc $vg/${lv1}_rimage_1
+aux wait_recalc $vg/${lv1}_rimage_2
+aux wait_recalc $vg/${lv1}_rimage_3
+aux wait_recalc $vg/${lv1}_rimage_4
+aux wait_recalc $vg/$lv1
+_add_new_data_to_mnt
+umount $mnt
+lvchange -an $vg/$lv1
+lvextend -l 16 $vg/$lv1
+lvchange -ay $vg/$lv1
+mount "$DM_DEV_DIR/$vg/$lv1" $mnt
+resize2fs "$DM_DEV_DIR/$vg/$lv1"
+aux wait_recalc $vg/${lv1}_rimage_0
+aux wait_recalc $vg/${lv1}_rimage_1
+lvs -a -o name,segtype,devices,sync_percent $vg
+_add_more_data_to_mnt
+_verify_data_on_mnt
+umount $mnt
+lvchange -an $vg/$lv1
+_verify_data_on_lv
+lvremove $vg/$lv1
+vgremove -ff $vg
+
+# Test lvextend while active
+
+_prepare_vg
+lvcreate --type raid1 -m1 --raidintegrity y -n $lv1 -l 8 $vg
+lvs -a -o name,segtype,devices,sync_percent $vg
+aux wait_recalc $vg/${lv1}_rimage_0
+aux wait_recalc $vg/${lv1}_rimage_1
+aux wait_recalc $vg/$lv1
+lvs -a -o+devices $vg
+_add_new_data_to_mnt
+lvextend -l 16 $vg/$lv1
+resize2fs "$DM_DEV_DIR/$vg/$lv1"
+aux wait_recalc $vg/${lv1}_rimage_0
+aux wait_recalc $vg/${lv1}_rimage_1
+lvs -a -o+devices $vg
+_add_more_data_to_mnt
+_verify_data_on_mnt
+umount $mnt
+lvchange -an $vg/$lv1
+_verify_data_on_lv
+lvremove $vg/$lv1
+vgremove -ff $vg
+
+_prepare_vg
+lvcreate --type raid5 --raidintegrity y -n $lv1 -l 8 $vg
+lvs -a -o name,segtype,devices,sync_percent $vg
+aux wait_recalc $vg/${lv1}_rimage_0
+aux wait_recalc $vg/${lv1}_rimage_1
+aux wait_recalc $vg/${lv1}_rimage_2
+aux wait_recalc $vg/$lv1
+lvs -a -o+devices $vg
+_add_new_data_to_mnt
+lvextend -l 16 $vg/$lv1
+resize2fs "$DM_DEV_DIR/$vg/$lv1"
+aux wait_recalc $vg/${lv1}_rimage_0
+aux wait_recalc $vg/${lv1}_rimage_1
+lvs -a -o+devices $vg
+_add_more_data_to_mnt
+_verify_data_on_mnt
+umount $mnt
+lvchange -an $vg/$lv1
+_verify_data_on_lv
+lvremove $vg/$lv1
+vgremove -ff $vg
+
+_prepare_vg
+lvcreate --type raid10 --raidintegrity y -n $lv1 -l 8 $vg
+lvs -a -o name,segtype,devices,sync_percent $vg
+aux wait_recalc $vg/${lv1}_rimage_0
+aux wait_recalc $vg/${lv1}_rimage_1
+aux wait_recalc $vg/$lv1
+lvs -a -o+devices $vg
+_add_new_data_to_mnt
+lvextend -l 16 $vg/$lv1
+resize2fs "$DM_DEV_DIR/$vg/$lv1"
+aux wait_recalc $vg/${lv1}_rimage_0
+aux wait_recalc $vg/${lv1}_rimage_1
+lvs -a -o+devices $vg
+_add_more_data_to_mnt
+_verify_data_on_mnt
+umount $mnt
+lvchange -an $vg/$lv1
+_verify_data_on_lv
+lvremove $vg/$lv1
+vgremove -ff $vg
+
+# Test adding image to raid1
+
+_prepare_vg
+lvcreate --type raid1 -m1 --raidintegrity y -n $lv1 -l 8 $vg
+lvs -a -o name,segtype,devices,sync_percent $vg
+aux wait_recalc $vg/${lv1}_rimage_0
+aux wait_recalc $vg/${lv1}_rimage_1
+aux wait_recalc $vg/$lv1
+lvs -a -o+devices $vg
+_add_new_data_to_mnt
+lvconvert -y -m+1 $vg/$lv1
+aux wait_recalc $vg/${lv1}_rimage_0
+aux wait_recalc $vg/${lv1}_rimage_1
+aux wait_recalc $vg/${lv1}_rimage_2
+lvs -a -o+devices $vg
+_add_more_data_to_mnt
+_verify_data_on_mnt
+umount $mnt
+lvchange -an $vg/$lv1
+_verify_data_on_lv
+lvremove $vg/$lv1
+vgremove -ff $vg
+
+# Test removing image from raid1
+
+_prepare_vg
+lvcreate --type raid1 -m2 --raidintegrity y -n $lv1 -l 8 $vg
+lvs -a -o name,segtype,devices,sync_percent $vg
+aux wait_recalc $vg/${lv1}_rimage_0
+aux wait_recalc $vg/${lv1}_rimage_1
+aux wait_recalc $vg/${lv1}_rimage_2
+aux wait_recalc $vg/$lv1
+_add_new_data_to_mnt
+lvconvert -y -m-1 $vg/$lv1
+lvs -a -o+devices $vg
+_add_more_data_to_mnt
+_verify_data_on_mnt
+umount $mnt
+lvchange -an $vg/$lv1
+_verify_data_on_lv
+lvremove $vg/$lv1
+vgremove -ff $vg
+
+# Test disallowed operations on raid+integrity
+
+_prepare_vg
+lvcreate --type raid1 -m1 --raidintegrity y -n $lv1 -l 8 $vg
+lvs -a -o name,segtype,devices,sync_percent $vg
+aux wait_recalc $vg/${lv1}_rimage_0
+aux wait_recalc $vg/${lv1}_rimage_1
+aux wait_recalc $vg/$lv1
+_add_new_data_to_mnt
+not lvconvert -y -m-1 $vg/$lv1
+not lvconvert --splitmirrors 1 -n tmp -y $vg/$lv1
+not lvconvert --splitmirrors 1 --trackchanges -y $vg/$lv1
+not lvchange --syncaction repair $vg/$lv1
+not lvreduce -L4M $vg/$lv1
+not pvmove -n $vg/$lv1 "$dev1"
+not pvmove "$dev1"
+_verify_data_on_mnt
+umount $mnt
+lvchange -an $vg/$lv1
+_verify_data_on_lv
+lvremove $vg/$lv1
+vgremove -ff $vg
+
+# Repeat many of the tests above using bitmap mode
+
+_prepare_vg
+lvcreate --type raid1 -m1 --raidintegrity y --raidintegritymode bitmap -n $lv1 -l 8 $vg "$dev1" "$dev2"
+lvs -a -o name,segtype,devices,sync_percent $vg
+aux wait_recalc $vg/${lv1}_rimage_0
+aux wait_recalc $vg/${lv1}_rimage_1
+aux wait_recalc $vg/$lv1
+_test_fs_with_read_repair "$dev1"
+lvs -o integritymismatches $vg/${lv1}_rimage_0 |tee mismatch
+not grep 0 mismatch
+lvs -o integritymismatches $vg/$lv1 |tee mismatch
+not grep 0 mismatch
+lvchange -an $vg/$lv1
+lvconvert --raidintegrity n $vg/$lv1
+lvremove $vg/$lv1
+vgremove -ff $vg
+
+_prepare_vg
+lvcreate --type raid6 --raidintegrity y --raidintegritymode bitmap -n $lv1 -I 4K -l 8 $vg "$dev1" "$dev2" "$dev3" "$dev4" "$dev5"
+lvs -a -o name,segtype,devices,sync_percent $vg
+aux wait_recalc $vg/${lv1}_rimage_0
+aux wait_recalc $vg/${lv1}_rimage_1
+aux wait_recalc $vg/${lv1}_rimage_2
+aux wait_recalc $vg/${lv1}_rimage_3
+aux wait_recalc $vg/${lv1}_rimage_4
+aux wait_recalc $vg/$lv1
+_test_fs_with_read_repair "$dev1" "$dev2" "$dev3" "$dev4" "$dev5"
+lvs -o integritymismatches $vg/${lv1}_rimage_0
+lvs -o integritymismatches $vg/${lv1}_rimage_1
+lvs -o integritymismatches $vg/${lv1}_rimage_2
+lvs -o integritymismatches $vg/${lv1}_rimage_3
+lvs -o integritymismatches $vg/${lv1}_rimage_4
+lvs -o integritymismatches $vg/$lv1 |tee mismatch
+not grep 0 mismatch
+lvchange -an $vg/$lv1
+lvconvert --raidintegrity n $vg/$lv1
+lvremove $vg/$lv1
+vgremove -ff $vg
+
+# remove from active lv
+_prepare_vg
+lvcreate --type raid1 -m1 --raidintegrity y --raidintegritymode bitmap -n $lv1 -l 8 $vg "$dev1" "$dev2"
+lvs -a -o name,segtype,devices,sync_percent $vg
+aux wait_recalc $vg/${lv1}_rimage_0
+aux wait_recalc $vg/${lv1}_rimage_1
+_add_new_data_to_mnt
+lvconvert --raidintegrity n $vg/$lv1
+_add_more_data_to_mnt
+_verify_data_on_mnt
+umount $mnt
+lvchange -an $vg/$lv1
+_verify_data_on_lv
+lvremove $vg/$lv1
+vgremove -ff $vg
+
+# add to active lv
+_prepare_vg
+lvcreate --type raid1 -m1 -n $lv1 -l 8 $vg
+_add_new_data_to_mnt
+lvconvert --raidintegrity y --raidintegritymode bitmap $vg/$lv1
+aux wait_recalc $vg/${lv1}_rimage_0
+aux wait_recalc $vg/${lv1}_rimage_1
+_add_more_data_to_mnt
+_verify_data_on_mnt
+umount $mnt
+lvchange -an $vg/$lv1
+_verify_data_on_lv
+lvremove $vg/$lv1
+vgremove -ff $vg
+
+# lvextend active
+_prepare_vg
+lvcreate --type raid1 --raidintegrity y --raidintegritymode bitmap -m1 -n $lv1 -l 8 $vg
+lvs -a -o name,segtype,devices,sync_percent $vg
+aux wait_recalc $vg/${lv1}_rimage_0
+aux wait_recalc $vg/${lv1}_rimage_1
+_add_new_data_to_mnt
+lvextend -l 16 $vg/$lv1
+aux wait_recalc $vg/${lv1}_rimage_0
+aux wait_recalc $vg/${lv1}_rimage_1
+resize2fs "$DM_DEV_DIR/$vg/$lv1"
+_add_more_data_to_mnt
+_verify_data_on_mnt
+umount $mnt
+lvchange -an $vg/$lv1
+_verify_data_on_lv
+lvremove $vg/$lv1
+vgremove -ff $vg
+
+# add image to raid1
+_prepare_vg
+lvcreate --type raid1 -m1 --raidintegrity y --raidintegritymode bitmap -n $lv1 -l 8 $vg
+lvs -a -o name,segtype,devices,sync_percent $vg
+aux wait_recalc $vg/${lv1}_rimage_0
+aux wait_recalc $vg/${lv1}_rimage_1
+_add_new_data_to_mnt
+lvconvert -y -m+1 $vg/$lv1
+aux wait_recalc $vg/${lv1}_rimage_0
+aux wait_recalc $vg/${lv1}_rimage_1
+aux wait_recalc $vg/${lv1}_rimage_2
+_add_more_data_to_mnt
+_verify_data_on_mnt
+umount $mnt
+lvchange -an $vg/$lv1
+_verify_data_on_lv
+lvremove $vg/$lv1
+vgremove -ff $vg
+
+# Test that raid+integrity cannot be a sublv
+# part1: cannot add integrity to a raid LV that is already a sublv
+
+_prepare_vg
+
+lvcreate --type raid1 -m1 -n $lv1 -l 8 $vg
+lvconvert -y --type thin-pool $vg/$lv1
+not lvconvert --raidintegrity y $vg/$lv1
+not lvconvert --raidintegrity y $vg/${lv1}_tdata
+not lvconvert --raidintegrity y $vg/${lv1}_tmeta
+lvremove -y $vg/$lv1
+
+lvcreate --type raid1 -m1 -n $lv1 -l 8 $vg
+lvconvert -y --type cache-pool $vg/$lv1
+not lvconvert --raidintegrity y $vg/$lv1
+not lvconvert --raidintegrity y $vg/${lv1}_cdata
+not lvconvert --raidintegrity y $vg/${lv1}_cmeta
+lvremove -y $vg/$lv1
+
+lvcreate --type raid1 -m1 -n $lv1 -l 8 $vg
+lvcreate --type cache-pool -n cpool -l 8 $vg
+lvconvert -y --type cache --cachepool cpool $vg/$lv1
+not lvconvert --raidintegrity y $vg/$lv1
+not lvconvert --raidintegrity y $vg/${lv1}_corig
+lvremove -y $vg/$lv1
+
+lvcreate --type raid1 -m1 -n $lv1 -l 8 $vg
+lvcreate --type raid1 -m1 -n cvol -l 8 $vg
+lvconvert -y --type cache --cachevol cvol $vg/$lv1
+not lvconvert --raidintegrity y $vg/$lv1
+not lvconvert --raidintegrity y $vg/${lv1}_corig
+not lvconvert --raidintegrity y $vg/cvol
+lvremove -y $vg/$lv1
+
+lvcreate --type raid1 -m1 -n $lv1 -l 8 $vg
+lvcreate -n cvol -l 8 $vg
+lvchange -an $vg
+lvconvert -y --type writecache --cachevol cvol $vg/$lv1
+not lvconvert --raidintegrity y $vg/$lv1
+not lvconvert --raidintegrity y $vg/${lv1}_wcorig
+lvremove -y $vg/$lv1
+
+# Test that raid+integrity cannot be a sublv
+# part2: cannot convert an existing raid+integrity LV into a sublv
+
+lvcreate --type raid1 -m1 -n $lv1 -l 8 $vg
+lvconvert -y --type thin-pool $vg/$lv1
+not lvconvert --raidintegrity y $vg/${lv1}_tdata
+lvremove -y $vg/$lv1
+
+lvcreate --type raid1 -m1 -n $lv1 -l 8 $vg
+lvcreate --type raid1 -m1 -n $lv2 -l 8 $vg
+lvconvert -y --type cache --cachevol $lv2 $vg/$lv1
+not lvconvert --raidintegrity y $vg/${lv1}_corig
+not lvconvert --raidintegrity y $vg/${lv2}_cvol
+lvremove -y $vg/$lv1
+
+lvcreate --type raid1 -m1 -n $lv1 -l 8 $vg
+lvcreate --type raid1 -m1 -n $lv2 -l 8 $vg
+lvconvert -y --type cache --cachepool $lv2 $vg/$lv1
+not lvconvert --raidintegrity y $vg/${lv1}_corig
+not lvconvert --raidintegrity y $vg/${lv2}_cpool_cdata
+not lvconvert --raidintegrity y $vg/${lv2}_cpool_cmeta
+lvremove -y $vg/$lv1
+
+vgremove -ff $vg
diff --git a/test/shell/large-physical-sector-size.sh b/test/shell/large-physical-sector-size.sh
new file mode 100644
index 0000000..b603418
--- /dev/null
+++ b/test/shell/large-physical-sector-size.sh
@@ -0,0 +1,43 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2019 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+LOGICAL_BLOCK_SIZE=4096
+
+# PHYSICAL_BLOCK_SIZE is set with physblk_exp which
+# shifts the logical block size value.
+
+# 4096 << 9 = 2MB physical block size
+PHYSICAL_BLOCK_SHIFT=9
+
+aux prepare_scsi_debug_dev 256 sector_size=$LOGICAL_BLOCK_SIZE physblk_exp=$PHYSICAL_BLOCK_SHIFT || skip
+
+check sysfs "$(< SCSI_DEBUG_DEV)" queue/logical_block_size "$LOGICAL_BLOCK_SIZE"
+
+aux prepare_pvs 1 256
+
+get_devs
+
+vgcreate $SHARED $vg "$dev1"
+
+for i in $(seq 1 40); do lvcreate -an -l1 $vg; done;
+
+lvs $vg
+
+lvremove -y $vg
+
+vgremove $vg
+
+aux cleanup_scsi_debug_dev
diff --git a/test/shell/listings.sh b/test/shell/listings.sh
index b6e4dfa..0c614d0 100644
--- a/test/shell/listings.sh
+++ b/test/shell/listings.sh
@@ -1,5 +1,6 @@
-#!/bin/sh
-# Copyright (C) 2008 Red Hat, Inc. All rights reserved.
+#!/usr/bin/env bash
+
+# Copyright (C) 2008-2014 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
@@ -7,35 +8,46 @@
#
# 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
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
#
# tests functionality of lvs, pvs, vgs, *display tools
#
-. lib/test
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
aux prepare_devs 5
+get_devs
+
+# Check there is no PV
+pvscan | tee out
+grep "No matching" out
-pvcreate "$dev1"
+pvcreate --uuid BADBEE-BAAD-BAAD-BAAD-BAAD-BAAD-BADBEE --norestorefile "$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
+pvs --noheadings "${DEVICES[@]}"
+test "$(pvs --noheadings "${DEVICES[@]}" | wc -l)" -eq 5
+pvdisplay
#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
+test "$(pvs --noheadings -o seg_all,pv_all,lv_all,vg_all "${DEVICES[@]}" | wc -l)" -eq 5
-vgcreate -c n $vg $(cat DEVICES)
+vgcreate $SHARED $vg "${DEVICES[@]}"
+
+check pv_field "$dev1" pv_uuid BADBEE-BAAD-BAAD-BAAD-BAAD-BAAD-BADBEE
#COMM pvs and vgs report mda_count, mda_free (bz202886, bz247444)
-pvs -o +pv_mda_count,pv_mda_free $(cat DEVICES)
+pvs -o +pv_mda_count,pv_mda_free "${DEVICES[@]}"
for I in "$dev2" "$dev3" "$dev5"; do
- check pv_field $I pv_mda_count 0
- check pv_field $I pv_mda_free 0
+ 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
@@ -45,25 +57,166 @@ pvdisplay "$dev2"|grep "VG Name.*$vg"
check pv_field "$dev2" vg_name $vg
#COMM lvs displays snapshots (bz171215)
-lvcreate -l4 -n $lv1 $vg
+lvcreate -aey -l4 -n $lv1 $vg
lvcreate -l4 -s -n $lv2 $vg/$lv1
-test $(lvs --noheadings $vg | wc -l) -eq 2
+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."
+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."
+lvcreate -aey -l2 --type mirror -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."
+
+# Check we parse /dev/mapper/vg-lv
+lvdisplay "$DM_DEV_DIR/mapper/$vg-$lv3"
+# Check we parse /dev/vg/lv
+lvdisplay "$DM_DEV_DIR/$vg/$lv3"
+
+lvcreate -l2 -s $vg/$lv3
+lvcreate -l1 -s -n inval $vg/$lv3
+lvcreate -l4 -I4 -i2 -n stripe $vg
+# Invalidate snapshot
+not dd if=/dev/zero of="$DM_DEV_DIR/$vg/inval" bs=4K
+invalid lvscan "$dev1"
+lvdisplay --maps
+lvscan --all
#COMM vgs with options from pvs still treats arguments as VGs (bz193543)
vgs -o pv_name,vg_name $vg
# would complain if not
+vgs -o all $vg
#COMM pvdisplay --maps feature (bz149814)
-pvdisplay $(cat DEVICES) >out
-pvdisplay --maps $(cat DEVICES) >out2
+pvdisplay "${DEVICES[@]}" >out
+pvdisplay --maps "${DEVICES[@]}" >out2
not diff out out2
+
+aux disable_dev "$dev1"
+pvs -o +pv_uuid | grep BADBEE-BAAD-BAAD-BAAD-BAAD-BAAD-BADBEE
+aux enable_dev "$dev1"
+
+pvscan --uuid
+pvscan -e
+pvscan -s
+pvscan --novolumegroup
+vgscan --mknodes
+vgmknodes --refresh
+lvscan
+lvmdiskscan
+
+invalid pvscan "$dev1"
+invalid pvscan -aay
+invalid pvscan --major 254
+invalid pvscan --minor 0
+invalid pvscan --novolumegroup -e
+invalid vgscan $vg
+invalid lvscan $vg
+
+if aux have_readline; then
+cat <<EOF | lvm
+vgdisplay --units k $vg
+vgdisplay -c $vg
+vgdisplay -C $vg
+vgdisplay -s $vg
+vgdisplay -v $vg
+lvdisplay -c $vg
+lvdisplay -C $vg
+lvdisplay -m $vg
+lvdisplay --units g $vg
+EOF
+else
+pvdisplay -c "$dev1"
+pvdisplay -s "$dev1"
+vgdisplay --units k $vg
+vgdisplay -c $vg
+vgdisplay -C $vg
+vgdisplay -s $vg
+vgdisplay -v $vg
+lvdisplay -c $vg
+lvdisplay -C $vg
+lvdisplay -m $vg
+lvdisplay --units g $vg
+fi
+
+pvdisplay -c "$dev1"
+pvdisplay -s "$dev1"
+
+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
+
+invalid lvdisplay -C -m $vg
+invalid lvdisplay -c -m $vg
+invalid lvdisplay --aligned $vg
+invalid lvdisplay --noheadings $vg
+invalid lvdisplay --options lv_name $vg
+invalid lvdisplay --separator : $vg
+invalid lvdisplay --sort size $vg
+invalid lvdisplay --unbuffered $vg
+
+invalid vgdisplay -C -A
+invalid vgdisplay -C -c
+invalid vgdisplay -C -s
+invalid vgdisplay -c -s
+invalid vgdisplay --aligned
+invalid vgdisplay --noheadings
+invalid vgdisplay --options
+invalid vgdisplay --separator :
+invalid vgdisplay --sort size
+invalid vgdisplay --unbuffered
+invalid vgdisplay -A $vg1
+
+invalid pvdisplay -C -A
+invalid pvdisplay -C -c
+invalid pvdisplay -C -m
+invalid pvdisplay -C -s
+invalid pvdisplay -c -m
+invalid pvdisplay -c -s
+invalid pvdisplay --aligned
+invalid pvdisplay --all
+invalid pvdisplay --noheadings
+invalid pvdisplay --options
+invalid pvdisplay --separator :
+invalid pvdisplay --sort size
+invalid pvdisplay --unbuffered
+invalid pvdisplay -A $vg1
+
+# Check exported VG listing
+vgchange -an $vg
+vgexport -a
+pvscan
+pvdisplay --noheadings -C -o attr,name | tee out
+not grep -v "ax-" out
+vgimport -a
+pvdisplay --noheadings -C -o attr,name | tee out
+grep -v "ax-" out
+
+vgremove -ff $vg
+
+#test vgdisplay -A to select only active VGs
+# all LVs active - VG considered active
+pvcreate "$dev1" "$dev2" "$dev3"
+
+vgcreate $SHARED $vg1 "$dev1"
+lvcreate -l1 $vg1
+lvcreate -l1 $vg1
+
+# at least one LV active - VG considered active
+vgcreate $SHARED $vg2 "$dev2"
+lvcreate -l1 $vg2
+lvcreate -l1 -an -Zn $vg2
+
+# no LVs active - VG considered inactive
+vgcreate $SHARED $vg3 "$dev3"
+lvcreate -l1 -an -Zn $vg3
+lvcreate -l1 -an -Zn $vg3
+
+vgdisplay -s -A | grep $vg1
+vgdisplay -s -A | grep $vg2
+vgdisplay -s -A | not grep $vg3
+
+vgremove -f $vg1 $vg2 $vg3
diff --git a/test/shell/lock-blocking.sh b/test/shell/lock-blocking.sh
index 480a73b..9defaf2 100644
--- a/test/shell/lock-blocking.sh
+++ b/test/shell/lock-blocking.sh
@@ -1,4 +1,5 @@
-#!/bin/sh
+#!/usr/bin/env bash
+
# Copyright (C) 2008 Red Hat, Inc. All rights reserved.
#
# This copyrighted material is made available to anyone wishing to use,
@@ -7,35 +8,42 @@
#
# 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
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
test_description='test some blocking / non-blocking multi-vg operations'
-. lib/test
+SKIP_WITH_CLVMD=1
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+# Make sure the placement of locking dir is known
+aux lvmconf "global/locking_dir = \"$TESTDIR/var/lock/lvm\""
aux prepare_devs 3
-test -e LOCAL_CLVMD && skip
pvcreate "$dev1" "$dev2"
-vgcreate $vg "$dev1" "$dev2"
+vgcreate $SHARED $vg "$dev1" "$dev2"
-# if wait_for_locks set, vgremove should wait for orphan lock
+# if wait_for_locks set, vgremove should wait for global 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
+flock -w 5 "$TESTDIR/var/lock/lvm/P_global" sleep 10 &
+while ! test -f "$TESTDIR/var/lock/lvm/P_global" ; 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
+test ! -f "$TESTDIR/var/lock/lvm/P_global"
# 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" &
+vgcreate $SHARED $vg "$dev1" "$dev2"
+flock -w 5 "$TESTDIR/var/lock/lvm/P_global" sleep 10 &
-while ! test -f $TESTDIR/var/lock/lvm/P_orphans ; do sleep .1 ; done
-flock_pid=`jobs -p`
+while ! test -f "$TESTDIR/var/lock/lvm/P_global" ; 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
+test -f "$TESTDIR/var/lock/lvm/P_global" # still running
+kill "$flock_pid"
+
+vgremove -ff $vg
diff --git a/test/shell/lock-parallel.sh b/test/shell/lock-parallel.sh
new file mode 100644
index 0000000..5526b62
--- /dev/null
+++ b/test/shell/lock-parallel.sh
@@ -0,0 +1,50 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2014-2015 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+# Test parallel use of lvm commands and check locks aren't dropped
+# RHBZ: https://bugzilla.redhat.com/show_bug.cgi?id=1049296
+
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+which mkfs.ext3 || skip
+which fsck || skip
+
+aux prepare_vg
+
+lvcreate -L10 -n $lv1 $vg
+lvcreate -l1 -n $lv2 $vg
+mkfs.ext3 "$DM_DEV_DIR/$vg/$lv1"
+
+# Slowdown PV for resized LV
+aux delay_dev "$dev1" 50 50 "$(get first_extent_sector "$dev1"):"
+
+lvresize -L-5 -r $vg/$lv1 &
+
+# Let's wait till resize starts
+for i in $(seq 1 300); do
+ pgrep fsck && break
+ sleep .1
+done
+
+lvremove -f $vg/$lv2
+
+wait
+
+aux enable_dev "$dev1"
+
+# Check removed $lv2 does not reappear
+not check lv_exists $vg $lv2
+
+vgremove -ff $vg
diff --git a/test/shell/losetup-partscan.sh b/test/shell/losetup-partscan.sh
new file mode 100644
index 0000000..6705689
--- /dev/null
+++ b/test/shell/losetup-partscan.sh
@@ -0,0 +1,68 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2016 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+# Check how lvm2 handles partitions over losetup -P devices
+
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+which sfdisk || skip
+
+aux prepare_loop 1000 -P || skip
+
+test -f LOOP
+LOOP=$(< LOOP)
+
+echo "1 2" | sfdisk "$LOOP"
+
+# wait for links
+aux udev_wait
+
+# losetup -P should provide partition
+ls -la "${LOOP}"*
+test -e "${LOOP}p1"
+
+aux lvmconf 'devices/scan = "/dev"'
+
+aux extend_filter "a|$LOOP|"
+aux extend_devices "$LOOP"
+
+# creation should fail for 'partitioned' loop device
+not pvcreate -y "$LOOP"
+not vgcreate $SHARED ${PREFIX}vg "$LOOP"
+
+aux teardown_devs
+
+aux prepare_loop 1000 || skip
+
+test -f LOOP
+LOOP=$(< LOOP)
+
+
+echo "1 2" | sfdisk "$LOOP"
+
+# wait for links
+aux udev_wait
+
+# no partitione should be actually there
+ls -la "${LOOP}"*
+test ! -e "${LOOP}p1"
+
+aux extend_filter "a|$LOOP|"
+aux extend_devices "$LOOP"
+
+# creation should pass for 'non-partitioned' loop device
+pvcreate -y "$LOOP"
+
+vgcreate $SHARED ${PREFIX}vg "$LOOP"
diff --git a/test/shell/lv-ancestry.sh b/test/shell/lv-ancestry.sh
new file mode 100644
index 0000000..b786d2e
--- /dev/null
+++ b/test/shell/lv-ancestry.sh
@@ -0,0 +1,230 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2016 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+SKIP_WITH_LVMPOLLD=1
+
+
+. lib/inittest
+
+aux have_thin 1 0 0 || skip
+aux prepare_pvs 1 16
+get_devs
+
+aux lvmconf "metadata/record_lvs_history=1"
+
+vgcreate $SHARED -s 64K "$vg" "${DEVICES[@]}"
+
+lvcreate -l100%FREE -T ${vg}/pool
+
+# Thin snap chain with 2 branches starting at lv3.
+#
+# lv1 --> lv2 --> lv3 --> lv4 --> lv5
+# \
+# --> lv6 --> lv7
+
+lvcreate -V1 -T ${vg}/pool -n lv1
+lvcreate -s ${vg}/lv1 -n lv2
+lvcreate -s ${vg}/lv2 -n lv3
+lvcreate -s ${vg}/lv3 -n lv4
+lvcreate -s ${vg}/lv4 -n lv5
+lvcreate -s ${vg}/lv3 -n lv6
+lvcreate -s ${vg}/lv6 -n lv7
+
+check lvh_field ${vg}/lv1 full_ancestors ""
+check lvh_field ${vg}/lv1 full_descendants "lv2,lv3,lv4,lv5,lv6,lv7"
+
+check lvh_field ${vg}/lv2 full_ancestors "lv1"
+check lvh_field ${vg}/lv2 full_descendants "lv3,lv4,lv5,lv6,lv7"
+
+check lvh_field ${vg}/lv3 full_ancestors "lv2,lv1"
+check lvh_field ${vg}/lv3 full_descendants "lv4,lv5,lv6,lv7"
+
+check lvh_field ${vg}/lv4 full_ancestors "lv3,lv2,lv1"
+check lvh_field ${vg}/lv4 full_descendants "lv5"
+
+check lvh_field ${vg}/lv5 full_ancestors "lv4,lv3,lv2,lv1"
+check lvh_field ${vg}/lv5 full_descendants ""
+
+check lvh_field ${vg}/lv6 full_ancestors "lv3,lv2,lv1"
+check lvh_field ${vg}/lv6 full_descendants "lv7"
+
+check lvh_field ${vg}/lv7 full_ancestors "lv6,lv3,lv2,lv1"
+check lvh_field ${vg}/lv7 full_descendants ""
+
+
+# lv1 --> lv2 --> lv3 --> -lv4 --> lv5
+# \
+# --> lv6 --> lv7
+lvremove -ff ${vg}/lv4
+
+check lvh_field ${vg}/lv1 full_ancestors ""
+check lvh_field ${vg}/lv1 full_descendants "lv2,lv3,lv6,lv7,-lv4,lv5"
+
+check lvh_field ${vg}/lv2 full_ancestors "lv1"
+check lvh_field ${vg}/lv2 full_descendants "lv3,lv6,lv7,-lv4,lv5"
+
+check lvh_field ${vg}/lv3 full_ancestors "lv2,lv1"
+check lvh_field ${vg}/lv3 full_descendants "lv6,lv7,-lv4,lv5"
+
+check lvh_field ${vg}/-lv4 full_ancestors "lv3,lv2,lv1"
+check lvh_field ${vg}/-lv4 full_descendants "lv5"
+
+check lvh_field ${vg}/lv5 full_ancestors "-lv4,lv3,lv2,lv1"
+check lvh_field ${vg}/lv5 full_descendants ""
+
+check lvh_field ${vg}/lv6 full_ancestors "lv3,lv2,lv1"
+check lvh_field ${vg}/lv6 full_descendants "lv7"
+
+check lvh_field ${vg}/lv7 full_ancestors "lv6,lv3,lv2,lv1"
+check lvh_field ${vg}/lv7 full_descendants ""
+
+
+# lv1 --> lv2 --> -lv3 --> -lv4 --> lv5
+# \
+# --> lv6 --> lv7
+lvremove -ff ${vg}/lv3
+
+check lvh_field ${vg}/lv1 full_ancestors ""
+check lvh_field ${vg}/lv1 full_descendants "lv2,-lv3,-lv4,lv5,lv6,lv7"
+
+check lvh_field ${vg}/lv2 full_ancestors "lv1"
+check lvh_field ${vg}/lv2 full_descendants "-lv3,-lv4,lv5,lv6,lv7"
+
+check lvh_field ${vg}/-lv3 full_ancestors "lv2,lv1"
+check lvh_field ${vg}/-lv3 full_descendants "-lv4,lv5,lv6,lv7"
+
+check lvh_field ${vg}/-lv4 full_ancestors "-lv3,lv2,lv1"
+check lvh_field ${vg}/-lv4 full_descendants "lv5"
+
+check lvh_field ${vg}/lv5 full_ancestors "-lv4,-lv3,lv2,lv1"
+check lvh_field ${vg}/lv5 full_descendants ""
+
+check lvh_field ${vg}/lv6 full_ancestors "-lv3,lv2,lv1"
+check lvh_field ${vg}/lv6 full_descendants "lv7"
+
+check lvh_field ${vg}/lv7 full_ancestors "lv6,-lv3,lv2,lv1"
+check lvh_field ${vg}/lv7 full_descendants ""
+
+# lv1 --> -lv2 --> -lv3 --> -lv4 --> lv5
+# \
+# --> lv6 --> lv7
+lvremove -ff $vg/lv2
+
+check lvh_field ${vg}/lv1 full_ancestors ""
+check lvh_field ${vg}/lv1 full_descendants "-lv2,-lv3,-lv4,lv5,lv6,lv7"
+
+check lvh_field ${vg}/-lv2 full_ancestors "lv1"
+check lvh_field ${vg}/-lv2 full_descendants "-lv3,-lv4,lv5,lv6,lv7"
+
+check lvh_field ${vg}/-lv3 full_ancestors "-lv2,lv1"
+check lvh_field ${vg}/-lv3 full_descendants "-lv4,lv5,lv6,lv7"
+
+check lvh_field ${vg}/-lv4 full_ancestors "-lv3,-lv2,lv1"
+check lvh_field ${vg}/-lv4 full_descendants "lv5"
+
+check lvh_field ${vg}/lv5 full_ancestors "-lv4,-lv3,-lv2,lv1"
+check lvh_field ${vg}/lv5 full_descendants ""
+
+check lvh_field ${vg}/lv6 full_ancestors "-lv3,-lv2,lv1"
+check lvh_field ${vg}/lv6 full_descendants "lv7"
+
+check lvh_field ${vg}/lv7 full_ancestors "lv6,-lv3,-lv2,lv1"
+check lvh_field ${vg}/lv7 full_descendants ""
+
+# lv1 --> -lv2 --> -lv3 --> -lv4 --> lv5
+# \
+# --> -lv6 --> lv7
+lvremove -ff ${vg}/lv6
+
+check lvh_field ${vg}/lv1 full_ancestors ""
+check lvh_field ${vg}/lv1 full_descendants "-lv2,-lv3,-lv4,lv5,-lv6,lv7"
+
+check lvh_field ${vg}/-lv2 full_ancestors "lv1"
+check lvh_field ${vg}/-lv2 full_descendants "-lv3,-lv4,lv5,-lv6,lv7"
+
+check lvh_field ${vg}/-lv3 full_ancestors "-lv2,lv1"
+check lvh_field ${vg}/-lv3 full_descendants "-lv4,lv5,-lv6,lv7"
+
+check lvh_field ${vg}/-lv4 full_ancestors "-lv3,-lv2,lv1"
+check lvh_field ${vg}/-lv4 full_descendants "lv5"
+
+check lvh_field ${vg}/lv5 full_ancestors "-lv4,-lv3,-lv2,lv1"
+check lvh_field ${vg}/lv5 full_descendants ""
+
+check lvh_field ${vg}/-lv6 full_ancestors "-lv3,-lv2,lv1"
+check lvh_field ${vg}/-lv6 full_descendants "lv7"
+
+check lvh_field ${vg}/lv7 full_ancestors "-lv6,-lv3,-lv2,lv1"
+check lvh_field ${vg}/lv7 full_descendants ""
+
+# lv1 --> -lv2 -----------> -lv4 --> lv5
+# \
+# --> -lv6 --> lv7
+lvremove -ff ${vg}/-lv3
+
+check lvh_field ${vg}/lv1 full_ancestors ""
+check lvh_field ${vg}/lv1 full_descendants "-lv2,-lv4,lv5,-lv6,lv7"
+
+check lvh_field ${vg}/-lv2 full_ancestors "lv1"
+check lvh_field ${vg}/-lv2 full_descendants "-lv4,lv5,-lv6,lv7"
+
+check lvh_field ${vg}/-lv4 full_ancestors "-lv2,lv1"
+check lvh_field ${vg}/-lv4 full_descendants "lv5"
+
+check lvh_field ${vg}/lv5 full_ancestors "-lv4,-lv2,lv1"
+check lvh_field ${vg}/lv5 full_descendants ""
+
+check lvh_field ${vg}/-lv6 full_ancestors "-lv2,lv1"
+check lvh_field ${vg}/-lv6 full_descendants "lv7"
+
+check lvh_field ${vg}/lv7 full_ancestors "-lv6,-lv2,lv1"
+check lvh_field ${vg}/lv7 full_descendants ""
+
+# -lv2 -----------> -lv4 --> lv5
+# \
+# --> -lv6 --> lv7
+
+lvremove --nohistory -ff ${vg}/lv1
+
+check lvh_field ${vg}/-lv2 full_ancestors ""
+check lvh_field ${vg}/-lv2 full_descendants "-lv4,lv5,-lv6,lv7"
+
+check lvh_field ${vg}/-lv4 full_ancestors "-lv2"
+check lvh_field ${vg}/-lv4 full_descendants "lv5"
+
+check lvh_field ${vg}/lv5 full_ancestors "-lv4,-lv2"
+check lvh_field ${vg}/lv5 full_descendants ""
+
+check lvh_field ${vg}/-lv6 full_ancestors "-lv2"
+check lvh_field ${vg}/-lv6 full_descendants "lv7"
+
+check lvh_field ${vg}/lv7 full_ancestors "-lv6,-lv2"
+check lvh_field ${vg}/lv7 full_descendants ""
+
+# -lv2 -----------> -lv4 --> lv5
+#
+# lv7
+lvremove --nohistory -ff ${vg}/-lv6
+
+check lvh_field ${vg}/-lv2 full_ancestors ""
+check lvh_field ${vg}/-lv2 full_descendants "-lv4,lv5"
+
+check lvh_field ${vg}/-lv4 full_ancestors "-lv2"
+check lvh_field ${vg}/-lv4 full_descendants "lv5"
+
+check lvh_field ${vg}/lv5 full_ancestors "-lv4,-lv2"
+check lvh_field ${vg}/lv5 full_descendants ""
+
+check lvh_field ${vg}/lv7 full_ancestors ""
+check lvh_field ${vg}/lv7 full_descendants ""
+
+vgremove -ff $vg
diff --git a/test/shell/lvchange-cache-mode.sh b/test/shell/lvchange-cache-mode.sh
new file mode 100644
index 0000000..a50dfd4
--- /dev/null
+++ b/test/shell/lvchange-cache-mode.sh
@@ -0,0 +1,90 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2016 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+# Exercise changing of caching mode on both cache pool and cached LV.
+
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+aux have_cache 1 5 0 || skip
+
+aux prepare_vg 2
+
+lvcreate --type cache-pool -L18 -n cpool $vg "$dev1"
+lvcreate -H -L14 -n $lv1 --cachemode writeback --cachesettings migration_threshold=204800 --cachepool $vg/cpool $vg "$dev2"
+
+#cat "$DM_DEV_DIR/$vg/$lv1" >/dev/null
+#aux delay_dev "$dev2" 300 1000 $(get first_extent_sector "$dev2"):
+
+#dmsetup status $vg-$lv1
+#dmsetup table $vg-$lv1
+
+for i in $(seq 1 10) ; do
+echo 3 >/proc/sys/vm/drop_caches
+dd if=/dev/zero of="$DM_DEV_DIR/$vg/$lv1" bs=64K count=20 oflag=direct || true
+echo 3 >/proc/sys/vm/drop_caches
+dd if="$DM_DEV_DIR/$vg/$lv1" of=/dev/null bs=64K count=20 oflag=direct || true
+done
+
+lvs -o+cache_dirty_blocks,cache_read_hits,cache_read_misses,cache_write_hits,cache_write_misses $vg/$lv1
+
+
+#
+# Drop later, code loading dm tables directly without lvm
+# RHBZ 1337588
+#
+#dmsetup table
+#echo "STATUS before cleaner"
+#dmsetup status
+#dmsetup load --table "0 28672 cache 253:4 253:3 253:5 128 1 writethrough cleaner 0" $vg-$lv1
+#dmsetup resume $vg-$lv1
+#sleep 1
+#dmsetup table
+#echo "STATUS after cleaner 1sec"
+#dmsetup status --noflush
+#dmsetup suspend --noflush $vg-$lv1
+#dmsetup resume $vg-$lv1
+
+#dmsetup load --table "0 28672 cache 253:4 253:3 253:5 128 1 passthrough smq 2 migration_threshold 204800" $vg-$lv1
+#dmsetup status $vg-$lv1
+#dmsetup load --table "0 28672 cache 253:4 253:3 253:5 128 1 writethrough smq 2 migration_threshold 204800" $vg-$lv1
+#dmsetup resume $vg-$lv1
+#dmsetup status $vg-$lv1
+#dmsetup table $vg-$lv1
+#dmsetup ls --tree
+#exit
+
+check lv_field $vg/$lv1 cache_mode "writeback"
+lvchange --cachemode passthrough $vg/$lv1
+check lv_field $vg/$lv1 cache_mode "passthrough"
+lvchange --cachemode writethrough $vg/$lv1
+check lv_field $vg/$lv1 cache_mode "writethrough"
+lvchange --cachemode writeback $vg/$lv1
+check lv_field $vg/$lv1 cache_mode "writeback"
+
+lvconvert --splitcache $vg/$lv1
+
+lvs -a $vg
+
+check lv_field $vg/cpool cache_mode "writeback"
+lvchange --cachemode passthrough $vg/cpool
+check lv_field $vg/cpool cache_mode "passthrough"
+lvchange --cachemode writethrough $vg/cpool
+check lv_field $vg/cpool cache_mode "writethrough"
+lvchange --cachemode writeback $vg/cpool
+check lv_field $vg/cpool cache_mode "writeback"
+
+lvs -a $vg
+
+vgremove -f $vg
diff --git a/test/shell/lvchange-cache-old.sh b/test/shell/lvchange-cache-old.sh
new file mode 100644
index 0000000..992249c
--- /dev/null
+++ b/test/shell/lvchange-cache-old.sh
@@ -0,0 +1,43 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2015 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+# Exercise usage of older metadata which are missing some new settings
+
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+aux have_cache 1 3 0 || skip
+
+# FIXME: parallel cache metadata allocator is crashing when used value 8000!
+aux prepare_vg 5 80
+
+
+lvcreate -l 10 --type cache-pool $vg/cpool
+lvcreate -l 20 -H -n $lv1 --cachepool $vg/cpool $vg
+
+vgcfgbackup -f backup $vg
+
+# check metadata without cache policy
+lvchange -an $vg
+grep -v "policy =" backup >backup_1
+vgcfgrestore -f backup_1 $vg
+lvchange -ay $vg
+
+# check metadata without cache mode
+lvchange -an $vg
+grep -v "cache_mode =" backup >backup_2
+vgcfgrestore -f backup_2 $vg
+lvchange -ay $vg
+
+vgremove -ff $vg
diff --git a/test/shell/lvchange-cache-syncaction-raid.sh b/test/shell/lvchange-cache-syncaction-raid.sh
new file mode 100644
index 0000000..bd4500d
--- /dev/null
+++ b/test/shell/lvchange-cache-syncaction-raid.sh
@@ -0,0 +1,44 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2016 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+# test activation race for raid's --syncaction check
+
+
+SKIP_WITH_LVMPOLLD=1
+
+
+# Current support for syncaction in cluster is broken
+# might get fixed one day though
+# meanwhile skipped
+SKIP_WITH_CLVMD=1
+
+. lib/inittest
+
+aux have_cache 1 5 0 || skip
+
+# Proper mismatch count 1.5.2+ upstream, 1.3.5 < x < 1.4.0 in RHEL6
+aux have_raid 1 3 5 &&
+ ! aux have_raid 1 4 0 ||
+ aux have_raid 1 5 2 || skip
+aux prepare_vg 3
+
+
+# Bug 1169495 - RFE: allow raid scrubbing on cache origin raid volumes
+# lvcreate RAID1 origin, lvcreate cache-pool, and lvconvert to cache
+# then test that the origin can be scrubbed.
+lvcreate --type raid1 -m 1 --nosync -l 2 -n $lv1 $vg
+lvcreate --type cache-pool -l 1 -n ${lv1}_cachepool $vg
+lvconvert --cache -Zy --cachepool $vg/${lv1}_cachepool $vg/$lv1
+lvchange --syncaction check $vg/${lv1}_corig
+# Check may go too quickly to verify with check of syncaction
+
+vgremove -ff $vg
diff --git a/test/shell/lvchange-cache.sh b/test/shell/lvchange-cache.sh
new file mode 100644
index 0000000..93c8c3b
--- /dev/null
+++ b/test/shell/lvchange-cache.sh
@@ -0,0 +1,97 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2014-2016 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+aux have_cache 1 3 0 || skip
+aux prepare_vg 3
+
+aux lvmconf 'global/cache_disabled_features = [ "policy_smq" ]'
+
+lvcreate --type cache-pool -an -v -L 2 -n cpool $vg
+lvcreate -H -L 4 -n corigin --cachepool $vg/cpool
+lvcreate -n noncache -l 1 $vg
+
+# cannot change major minor for pools
+not lvchange --yes -M y --minor 235 --major 253 $vg/cpool
+not lvchange -M n $vg/cpool
+
+not lvchange --cachepolicy mq $vg/noncache
+not lvchange --cachesettings foo=bar $vg/noncache
+
+lvchange --cachepolicy cleaner $vg/corigin
+check lv_field $vg/corigin kernel_cache_policy "cleaner"
+
+# Skip these test on older cache driver as it shows errors with these lvchanges
+# device-mapper: space map common: index_check failed: blocknr 17179869216 != wanted 11
+if aux have_cache 1 5 0 ; then
+
+lvchange --cachepolicy mq --cachesettings migration_threshold=1333 $vg/corigin
+
+# TODO once mq->smq happens we will get here some 0 for mq settings
+check lv_field $vg/corigin kernel_cache_policy "mq"
+get lv_field $vg/corigin kernel_cache_settings | grep 'migration_threshold=1333'
+
+lvchange --refresh $vg/corigin
+get lv_field $vg/corigin kernel_cache_settings | grep 'migration_threshold=1333'
+lvchange -an $vg
+lvchange -ay $vg
+get lv_field $vg/corigin kernel_cache_settings | grep 'migration_threshold=1333'
+
+lvchange --cachesettings 'migration_threshold = 1233 sequential_threshold = 13' $vg/corigin
+get lv_field $vg/corigin kernel_cache_settings | tee out
+grep 'migration_threshold=1233' out
+
+if grep 'sequential_threshold=13' out ; then
+
+lvchange --cachesettings 'migration_threshold = 1117' $vg/corigin
+get lv_field $vg/corigin kernel_cache_settings | tee out
+grep 'migration_threshold=1117' out
+grep 'sequential_threshold=13' out
+
+lvchange --cachesettings 'migration_threshold = default' $vg/corigin
+get lv_field $vg/corigin kernel_cache_settings | tee out
+grep 'migration_threshold=2048' out
+grep 'sequential_threshold=13' out
+
+lvchange --cachesettings 'migration_threshold = 1233 sequential_threshold = 13 random_threshold = 1' $vg/corigin
+lvchange --cachesettings 'random_threshold = default migration_threshold = default' $vg/corigin
+get lv_field $vg/corigin kernel_cache_settings | tee out
+grep 'migration_threshold=2048' out
+grep 'sequential_threshold=13' out
+grep 'random_threshold=4' out
+
+lvchange --cachesettings migration_threshold=1233 --cachesettings sequential_threshold=13 --cachesettings random_threshold=1 $vg/corigin
+get lv_field $vg/corigin kernel_cache_settings | tee out
+grep 'migration_threshold=1233' out
+grep 'sequential_threshold=13' out
+grep 'random_threshold=1' out
+
+lvchange --cachesettings random_threshold=default --cachesettings migration_threshold=default $vg/corigin
+get lv_field $vg/corigin kernel_cache_settings | tee out
+grep 'migration_threshold=2048' out
+grep 'sequential_threshold=13' out
+grep 'random_threshold=4' out
+
+else
+# When MQ is emulated by SMQ policy it does not hold settings.
+# So just skip testing of param changes when sequential_threshold=0
+# or some older kernel instancies show also value 512
+grep 'sequential_threshold=0' out || grep 'sequential_threshold=512' out
+fi
+
+fi # have_cache 1 5 0
+
+vgremove -f $vg
diff --git a/test/shell/lvchange-mirror.sh b/test/shell/lvchange-mirror.sh
index 26656d4..f21a0fa 100644
--- a/test/shell/lvchange-mirror.sh
+++ b/test/shell/lvchange-mirror.sh
@@ -1,4 +1,5 @@
-#!/bin/sh
+#!/usr/bin/env bash
+
# Copyright (C) 2010 Red Hat, Inc. All rights reserved.
#
# This copyrighted material is made available to anyone wishing to use,
@@ -7,24 +8,31 @@
#
# 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
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+# FIXME RESYNC doesn't work in cluster with exclusive activation
+# seriously broken!
+
+SKIP_WITH_CLVMD=1
+SKIP_WITH_LVMPOLLD=1
-. lib/test
+. lib/inittest
aux prepare_dmeventd
aux prepare_vg 3
# force resync 2-way active mirror
-lvcreate -l2 -m1 -n $lv1 $vg "$dev1" "$dev2" "$dev3":0-1
+lvcreate -aey -l2 --type mirror -m1 -n $lv1 $vg "$dev1" "$dev2" "$dev3":0-1
check mirror $vg $lv1 "$dev3"
-echo y | lvchange --resync $vg/$lv1
+lvchange -y --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
+lvcreate -aey -l2 --type mirror -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
+
+vgremove -ff $vg
diff --git a/test/shell/lvchange-partial-raid10.sh b/test/shell/lvchange-partial-raid10.sh
new file mode 100644
index 0000000..2c96108
--- /dev/null
+++ b/test/shell/lvchange-partial-raid10.sh
@@ -0,0 +1,34 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2013 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+aux have_raid 1 3 2 || skip
+
+aux prepare_vg 4
+
+# rhbz 889358
+# Should be able to activate when RAID10
+# has failed devs in different mirror sets.
+lvcreate --type raid10 -m 1 -i 2 -l 2 -n $lv1 $vg
+aux wait_for_sync $vg $lv1
+lvchange -an $vg/$lv1
+aux disable_dev "$dev1" "$dev3"
+lvchange -ay --partial $vg/$lv1
+lvchange -an $vg/$lv1
+
+aux enable_dev "$dev1"
+
+vgremove -ff $vg
diff --git a/test/shell/lvchange-partial.sh b/test/shell/lvchange-partial.sh
index fe642d4..7913811 100644
--- a/test/shell/lvchange-partial.sh
+++ b/test/shell/lvchange-partial.sh
@@ -1,4 +1,5 @@
-#!/bin/bash
+#!/usr/bin/env bash
+
# Copyright (C) 2012 Red Hat, Inc. All rights reserved.
#
# This copyrighted material is made available to anyone wishing to use,
@@ -7,15 +8,19 @@
#
# 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
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
-. lib/test
+SKIP_WITH_LVMPOLLD=1
-aux target_at_least dm-raid 1 1 0 || skip
+. lib/inittest
-aux prepare_vg 2
+aux prepare_vg 4
-lvcreate --type raid1 -m 1 -l 2 -n $lv1 $vg
+TYPE=raid1
+aux have_raid 1 3 0 || TYPE=mirror
+
+lvcreate -aey --type $TYPE -m 1 -l 2 -n $lv1 $vg
lvchange -an $vg/$lv1
aux disable_dev "$dev1"
@@ -64,3 +69,6 @@ not lvchange --zero y $vg/$lv1
not lvchange --resync -ay $vg/$lv1
not lvchange --resync --addtag foo $vg/$lv1
+aux enable_dev "$dev1"
+
+vgremove -ff $vg
diff --git a/test/shell/lvchange-raid-transient-failures.sh b/test/shell/lvchange-raid-transient-failures.sh
new file mode 100644
index 0000000..35b4898
--- /dev/null
+++ b/test/shell/lvchange-raid-transient-failures.sh
@@ -0,0 +1,70 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2016 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+aux have_raid 1 10 1 || skip
+aux prepare_vg 6
+
+#
+# FIXME: add multi-segment leg tests
+#
+
+function _check_raid
+{
+ local vg=$1
+ shift
+ local lv=$1
+ shift
+ local fail=$1
+ shift
+ local good=$1
+ shift
+ local devs=( "$@" )
+
+ aux wait_for_sync $vg $lv
+ aux disable_dev --error --silent "${devs[@]}"
+ mkfs.ext4 "$DM_DEV_DIR/$vg/$lv"
+ fsck.ext4 -fn "$DM_DEV_DIR/$vg/$lv"
+ check raid_leg_status $vg $lv "$fail"
+ aux enable_dev --silent "${devs[@]}"
+ lvs -a -o +devices $vg | tee out
+ not grep unknown out
+ lvchange --refresh $vg/$lv
+ fsck.ext4 -fn "$DM_DEV_DIR/$vg/$lv"
+ aux wait_for_sync $vg $lv
+ fsck.ext4 -fn "$DM_DEV_DIR/$vg/$lv"
+ check raid_leg_status $vg $lv "$good"
+}
+
+# raid1 with transiently failing devices
+lv=4way
+lvcreate -aey --type raid1 -m 3 --ignoremonitoring -L 1 -n $lv $vg
+_check_raid $vg $lv "ADAD" "AAAA" "$dev2" "$dev4"
+lvremove -y $vg/$lv
+
+# raid6 with transiently failing devices
+lv=6way
+lvcreate -aey --type raid6 -i 4 --ignoremonitoring -L 1 -n $lv $vg
+_check_raid $vg $lv "ADADAA" "AAAAAA" "$dev2" "$dev4"
+lvremove -y $vg/$lv
+
+# raid10 with transiently failing devices
+lv=6way
+lvcreate -aey --type raid10 -i 3 -m 1 --ignoremonitoring -L 1 -n $lv $vg
+_check_raid $vg $lv "ADADDA" "AAAAAA" "$dev2" "$dev4" "$dev5"
+lvremove -y $vg/$lv
+
+vgremove -f $vg
diff --git a/test/shell/lvchange-raid.sh b/test/shell/lvchange-raid.sh
new file mode 100644
index 0000000..3a9ed60
--- /dev/null
+++ b/test/shell/lvchange-raid.sh
@@ -0,0 +1,349 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2013 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+# Writemostly has been in every version since the begining
+# Device refresh in 1.5.1 upstream and 1.3.4 < x < 1.4.0 in RHEL6
+# Sync action in 1.5.0 upstream and 1.3.3 < x < 1.4.0 in RHEL6
+# Proper mismatch count 1.5.2 upstream,1.3.5 < x < 1.4.0 in RHEL6
+#
+# We will simplify and simple test for 1.5.2 and 1.3.5 < x < 1.4.0
+aux have_raid 1 3 5 &&
+ ! aux have_raid 1 4 0 ||
+ aux have_raid 1 5 2 || skip
+
+# DEVICE "$dev6" is reserved for non-RAID LVs that
+# will not undergo failure
+aux prepare_vg 6
+
+# run_writemostly_check <VG> <LV>
+run_writemostly_check() {
+ local vg=$1
+ local lv=${2}${THIN_POSTFIX}
+ local segtype=
+ local d0
+ local d1
+
+ segtype=$(get lv_field $vg/$lv segtype -a)
+ d0=$(get lv_devices $vg/${lv}_rimage_0)
+ d1=$(get lv_devices $vg/${lv}_rimage_1)
+
+ printf "#\n#\n#\n# %s/%s (%s): run_writemostly_check\n#\n#\n#\n" \
+ $vg $lv $segtype
+
+ # I've seen this sync fail. when it does, it looks like sync
+ # thread has not been started... haven't repo'ed yet.
+ aux wait_for_sync $vg $lv
+
+ # No writemostly flag should be there yet.
+ check lv_attr_bit health $vg/${lv}_rimage_0 "-"
+ check lv_attr_bit health $vg/${lv}_rimage_1 "-"
+
+ if [ "$segtype" != "raid1" ]; then
+ not lvchange --writemostly $d0 $vg/$lv
+ return
+ fi
+
+ # Set the flag
+ lvchange --writemostly $d0 $vg/$lv
+ check lv_attr_bit health $vg/${lv}_rimage_0 "w"
+
+ # Running again should leave it set (not toggle)
+ lvchange --writemostly $d0 $vg/$lv
+ check lv_attr_bit health $vg/${lv}_rimage_0 "w"
+
+ # Running again with ':y' should leave it set
+ lvchange --writemostly $d0:y $vg/$lv
+ check lv_attr_bit health $vg/${lv}_rimage_0 "w"
+
+ # ':n' should unset it
+ lvchange --writemostly $d0:n $vg/$lv
+ check lv_attr_bit health $vg/${lv}_rimage_0 "-"
+
+ # ':n' again should leave it unset
+ lvchange --writemostly $d0:n $vg/$lv
+ check lv_attr_bit health $vg/${lv}_rimage_0 "-"
+
+ # ':t' toggle to set
+ lvchange --writemostly $d0:t $vg/$lv
+ check lv_attr_bit health $vg/${lv}_rimage_0 "w"
+
+ # ':t' toggle to unset
+ lvchange --writemostly $d0:t $vg/$lv
+ check lv_attr_bit health $vg/${lv}_rimage_0 "-"
+
+ # ':y' to set
+ lvchange --writemostly $d0:y $vg/$lv
+ check lv_attr_bit health $vg/${lv}_rimage_0 "w"
+
+ # Toggle both at once
+ lvchange --writemostly $d0:t --writemostly $d1:t $vg/$lv
+ check lv_attr_bit health $vg/${lv}_rimage_0 "-"
+ check lv_attr_bit health $vg/${lv}_rimage_1 "w"
+
+ # Toggle both at once again
+ lvchange --writemostly $d0:t --writemostly $d1:t $vg/$lv
+ check lv_attr_bit health $vg/${lv}_rimage_0 "w"
+ check lv_attr_bit health $vg/${lv}_rimage_1 "-"
+
+ # Toggle one, unset the other
+ lvchange --writemostly $d0:n --writemostly $d1:t $vg/$lv
+ check lv_attr_bit health $vg/${lv}_rimage_0 "-"
+ check lv_attr_bit health $vg/${lv}_rimage_1 "w"
+
+ # Toggle one, set the other
+ lvchange --writemostly $d0:y --writemostly $d1:t $vg/$lv
+ check lv_attr_bit health $vg/${lv}_rimage_0 "w"
+ check lv_attr_bit health $vg/${lv}_rimage_1 "-"
+
+ # Partial flag supercedes writemostly flag
+ aux disable_dev $d0
+ check lv_attr_bit health $vg/${lv}_rimage_0 "p"
+
+ # It is possible for the kernel to detect the failed device before
+ # we re-enable it. If so, the field will be set to 'r'efresh since
+ # that also takes precedence over 'w'ritemostly. If this has happened,
+ # we refresh the LV and then check for 'w'.
+ aux enable_dev $d0
+ check lv_attr_bit health $vg/${lv}_rimage_0 "r" && lvchange --refresh $vg/$lv
+ check lv_attr_bit health $vg/${lv}_rimage_0 "w"
+
+ # Catch Bad writebehind values
+ invalid lvchange --writebehind "invalid" $vg/$lv
+ invalid lvchange --writebehind -256 $vg/$lv
+
+ # Set writebehind
+ check lv_field $vg/$lv raid_write_behind ""
+ lvchange --writebehind 512 $vg/$lv
+ check lv_field $vg/$lv raid_write_behind "512"
+
+ # Converting to linear should clear flags and writebehind
+ not lvconvert -m 0 $vg/$lv $d1
+ lvconvert -y -m 0 $vg/$lv $d1
+ lvconvert -y --type raid1 -m 1 $vg/$lv $d1
+ check lv_field $vg/$lv raid_write_behind ""
+ check lv_attr_bit health $vg/${lv}_rimage_0 "-"
+ check lv_attr_bit health $vg/${lv}_rimage_1 "-"
+}
+
+
+# run_syncaction_check <VG> <LV>
+run_syncaction_check() {
+ local device
+ local seek
+ local size
+ local tmp
+ local vg=$1
+ local lv=${2}${THIN_POSTFIX}
+
+ printf "#\n#\n#\n# %s/%s (%s): run_syncaction_check\n#\n#\n#\n" \
+ $vg $lv "$(get lv_field "$vg/$lv" segtype -a)"
+ aux wait_for_sync $vg $lv
+
+ device=$(get lv_devices $vg/${lv}_rimage_1)
+
+ size=$(get lv_field $vg/${lv}_rimage_1 size -a --units 1k)
+ size=$(( ${size%\.00k} / 2 ))
+
+ tmp=$(get pv_field "$device" mda_size --units 1k)
+ seek=${tmp%\.00k} # Jump over MDA
+
+ tmp=$(get lv_field $vg/${lv}_rmeta_1 size -a --units 1k)
+ seek=$(( seek + ${tmp%\.00k} )) # Jump over RAID metadata image
+
+ seek=$(( seek + size )) # Jump halfway through the RAID image
+
+ check lv_attr_bit health $vg/$lv "-"
+ check lv_field $vg/$lv raid_mismatch_count "0"
+
+ # Overwrite the last half of one of the PVs with crap
+ dd if=/dev/urandom of="$device" bs=1k count=$size seek=$seek
+ sync
+
+ # Cycle the LV so we don't grab stripe cache buffers instead
+ # of reading disk. This can happen with RAID 4/5/6. You
+ # may think this is bad because those buffers could prevent
+ # us from seeing bad disk blocks, however, the stripe cache
+ # is not long lived. (RAID1/10 are immediately checked.)
+ lvchange -an $vg/$lv
+ lvchange -ay $vg/$lv
+
+ # "check" should find discrepancies but not change them
+ # 'lvs' should show results
+ lvchange --syncaction check $vg/$lv
+ not lv_field $vg/$lv sync_percent "100.00"
+ aux wait_for_sync $vg $lv
+ check lv_attr_bit health $vg/$lv "m"
+ not check lv_field $vg/$lv raid_mismatch_count "0"
+
+ # "repair" will fix discrepancies
+ lvchange --syncaction repair $vg/$lv
+ not lv_field $vg/$lv sync_percent "100.00"
+ aux wait_for_sync $vg $lv
+
+ # Final "check" should show no mismatches
+ # 'lvs' should show results
+ lvchange --syncaction check $vg/$lv
+ not lv_field $vg/$lv sync_percent "100.00"
+ aux wait_for_sync $vg $lv
+ check lv_attr_bit health $vg/$lv "-"
+ check lv_field $vg/$lv raid_mismatch_count "0"
+}
+
+# run_refresh_check <VG> <LV>
+# Assumes "$dev2" is in the array
+run_refresh_check() {
+ local size
+ local sizelv
+ local vg=$1
+ local lv=${2}${THIN_POSTFIX}
+
+ printf "#\n#\n#\n# %s/%s (%s): run_refresh_check\n#\n#\n#\n" \
+ $vg $lv "$(get lv_field $vg/$lv segtype -a)"
+
+ aux wait_for_sync $vg $lv
+
+ sizelv=$vg/$lv
+ test -z "$THIN_POSTFIX" || sizelv=$vg/thinlv
+ size=$(get lv_field $sizelv size --units 1k)
+ size=${size%\.00k}
+
+ # Disable dev2 and do some I/O to make the kernel notice
+ aux disable_dev "$dev2"
+ dd if=/dev/urandom of="$DM_DEV_DIR/$sizelv" bs=1k count=$size
+ sync
+
+ # Check for 'p'artial flag
+ check lv_attr_bit health $vg/$lv "p"
+ dmsetup status
+ lvs -a -o name,attr,devices $vg
+
+ aux enable_dev "$dev2"
+
+ dmsetup status
+ lvs -a -o name,attr,devices $vg
+
+ # Check for 'r'efresh flag
+ check lv_attr_bit health $vg/$lv "r"
+
+ lvchange --refresh $vg/$lv
+ aux wait_for_sync $vg $lv
+ check lv_attr_bit health $vg/$lv "-"
+
+ # Writing random data above should mean that the devices
+ # were out-of-sync. The refresh should have taken care
+ # of properly reintegrating the device.
+ lvchange --syncaction repair $vg/$lv
+ aux wait_for_sync $vg $lv
+ check lv_attr_bit health $vg/$lv "-"
+}
+
+# run_recovery_rate_check <VG> <LV>
+# Assumes "$dev2" is in the array
+run_recovery_rate_check() {
+ local vg=$1
+ local lv=${2}${THIN_POSTFIX}
+
+ printf "#\n#\n#\n# %s/%s (%s): run_recovery_rate_check\n#\n#\n#\n" \
+ $vg $lv "$(get lv_field $vg/$lv segtype -a)"
+ lvchange --minrecoveryrate 50 $vg/$lv
+ lvchange --maxrecoveryrate 100 $vg/$lv
+
+ check lv_field $vg/$lv raid_min_recovery_rate "50"
+ check lv_field $vg/$lv raid_max_recovery_rate "100"
+}
+
+# run_checks <VG> <LV> <"-"|snapshot_dev|"thinpool_data"|"thinpool_meta">
+run_checks() {
+ THIN_POSTFIX=""
+
+ if [ -z "$3" ]; then
+ printf "#\n#\n# run_checks: Too few arguments\n#\n#\n"
+ return 1
+ elif [ '-' = "$3" ]; then
+ printf "#\n#\n# run_checks: Simple check\n#\n#\n"
+
+ run_writemostly_check $1 $2
+ run_syncaction_check $1 $2
+ run_refresh_check $1 $2
+ run_recovery_rate_check $1 $2
+ elif [ "thinpool_data" = "$3" ]; then
+ printf "#\n#\n# run_checks: RAID as thinpool data\n#\n#\n"
+
+# Hey, specifying devices for thin allocation doesn't work
+# lvconvert -y --thinpool $1/$2 "$dev6"
+ lvcreate -aey -L 2M -n ${2}_meta $1 "$dev6"
+ lvconvert --thinpool $1/$2 --poolmetadata ${2}_meta
+ lvcreate -T $1/$2 -V 1 -n thinlv
+ THIN_POSTFIX="_tdata"
+
+ run_writemostly_check $1 $2
+ run_syncaction_check $1 $2
+ run_refresh_check $1 $2
+ run_recovery_rate_check $1 $2
+ elif [ "thinpool_meta" = "$3" ]; then
+ printf "#\n#\n# run_checks: RAID as thinpool metadata\n#\n#\n"
+
+ lvrename $1/$2 ${2}_meta
+ lvcreate -aey -L 2M -n $2 $1 "$dev6"
+ lvconvert -y --thinpool $1/$2 --poolmetadata ${2}_meta
+ lvcreate -T $1/$2 -V 1 -n thinlv
+ THIN_POSTFIX="_tmeta"
+
+ run_writemostly_check $1 $2
+ run_syncaction_check $1 $2
+ run_refresh_check $1 $2
+ run_recovery_rate_check $1 $2
+ elif [ "snapshot" = "$3" ]; then
+ printf "#\n#\n# run_checks: RAID under snapshot\n#\n#\n"
+ lvcreate -aey -s $1/$2 -l 4 -n snap "$dev6"
+
+ run_writemostly_check $1 $2
+ run_syncaction_check $1 $2
+ run_refresh_check $1 $2
+ run_recovery_rate_check $1 $2
+
+ lvremove -ff $1/snap
+ else
+ printf "#\n#\n# run_checks: Invalid argument\n#\n#\n"
+ return 1
+ fi
+}
+
+run_types() {
+ for i in $TEST_TYPES ; do
+ lvcreate -n $lv1 $vg -L2M --type "$@"
+ run_checks $vg $lv1 $i
+ lvremove -ff $vg
+ done
+}
+
+########################################################
+# MAIN
+########################################################
+
+TEST_TYPES="- snapshot"
+# RAID works EX in cluster
+# thinpool works EX in cluster
+# but they don't work together in a cluster yet
+# (nor does thinpool+mirror work in a cluster yet)
+test ! -e LOCAL_CLVMD && aux have_thin 1 8 0 && TEST_TYPE="$TEST_TYPES thinpool_data thinpool_meta"
+
+# Implicit test for 'raid1' only
+if test "${TEST_RAID:-raid1}" = raid1 ; then
+ run_types raid1 -m 1 "$dev1" "$dev2"
+ vgremove -ff $vg
+fi
diff --git a/test/shell/lvchange-raid1-writemostly.sh b/test/shell/lvchange-raid1-writemostly.sh
new file mode 100644
index 0000000..039429a
--- /dev/null
+++ b/test/shell/lvchange-raid1-writemostly.sh
@@ -0,0 +1,44 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2017 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., 51 Franklin Street, Fifth Floor, Boston, MA2110-1301 USA
+
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+which mkfs.ext4 || skip
+aux have_raid 1 3 5 || skip
+
+aux prepare_vg 4
+get_devs
+
+for d in "$dev1" "$dev2" "$dev3" "$dev4"
+do
+ aux delay_dev "$d" 0 20 "$(get first_extent_sector "$d")"
+done
+
+#
+# Test writemostly prohibited on resynchronizing raid1
+#
+
+# Create 4-way raid1 LV
+lvcreate -aey --ty raid1 -m 3 -Zn -L16M -n $lv1 $vg
+not lvchange -y --writemostly "$dev1" "$vg/$lv1"
+check lv_field $vg/$lv1 segtype "raid1"
+check lv_field $vg/$lv1 stripes 4
+check lv_attr_bit health $vg/${lv1}_rimage_0 "-"
+aux enable_dev "${DEVICES[@]}"
+aux wait_for_sync $vg $lv1
+lvchange -y --writemostly "$dev1" "$vg/$lv1"
+check lv_attr_bit health $vg/${lv1}_rimage_0 "w"
+
+vgremove -ff $vg
diff --git a/test/shell/lvmetad-pvscan-cache.sh b/test/shell/lvchange-raid10.sh
index a27b6ad..a29ade9 100644
--- a/test/shell/lvmetad-pvscan-cache.sh
+++ b/test/shell/lvchange-raid10.sh
@@ -1,5 +1,6 @@
-#!/bin/sh
-# Copyright (C) 2012 Red Hat, Inc. All rights reserved.
+#!/usr/bin/env bash
+
+# Copyright (C) 2014 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
@@ -7,17 +8,14 @@
#
# 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
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
-test -e LOCAL_LVMETAD || skip
+TEST_RAID=raid10
-aux prepare_pvs 2
+. shell/lvchange-raid.sh
-vgcreate $vg1 $dev1 $dev2
-vgs | grep $vg1
+aux have_raid 1 5 2 || skip
-pvscan --cache
+run_types raid10 -m 1 -i 2 "$dev1" "$dev2" "$dev3" "$dev4"
-vgs | grep $vg1
+vgremove -ff $vg
diff --git a/test/shell/lvchange-raid456.sh b/test/shell/lvchange-raid456.sh
new file mode 100644
index 0000000..ea4b4e2
--- /dev/null
+++ b/test/shell/lvchange-raid456.sh
@@ -0,0 +1,24 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2014 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+TEST_RAID=raid456
+
+. shell/lvchange-raid.sh
+
+aux raid456_replace_works || skip
+aux have_raid 1 5 2 || skip
+
+aux have_raid4 && run_types raid4 -i 2 "$dev1" "$dev2" "$dev3" "$dev4"
+run_types raid5 -i 2 "$dev1" "$dev2" "$dev3" "$dev4"
+run_types raid6 -i 3 "$dev1" "$dev2" "$dev3" "$dev4" "$dev5"
+
+vgremove -ff $vg
diff --git a/test/shell/lvchange-rebuild-raid.sh b/test/shell/lvchange-rebuild-raid.sh
new file mode 100644
index 0000000..d2bb723
--- /dev/null
+++ b/test/shell/lvchange-rebuild-raid.sh
@@ -0,0 +1,144 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2016 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+aux have_raid 1 3 2 || skip
+v1_9_0=0
+aux have_raid 1 9 0 && v1_9_0=1
+
+aux prepare_vg 8
+get_devs
+
+_sync() {
+ aux enable_dev "${DEVICES[@]}"
+
+ aux wait_for_sync $vg $lv1
+ test "$#" -eq 0 || check raid_leg_status $vg $lv1 "$@"
+
+ # restore to delay_dev tables for all devices
+ aux restore_from_devtable "${DEVICES[@]}"
+}
+
+# Delay legs so that rebuilding status characters can be read
+for d in "${DEVICES[@]}"
+do
+ aux delay_dev "$d" 0 50 "$(get first_extent_sector "$d")"
+done
+
+# rhbz 1064592
+
+##############################################
+# Create an 8-way striped raid10 with 4 mirror
+# groups and rebuild selected PVs.
+lvcreate --type raid10 -m 1 -i 4 -l 64 -n $lv1 $vg
+_sync "AAAAAAAA"
+
+# Rebuild 1st and 2nd device would rebuild a
+# whole mirror group and needs to be rejected.
+not lvchange --yes --rebuild "$dev1" --rebuild "$dev2" $vg/$lv1
+not check raid_leg_status $vg $lv1 "aaAAAAA"
+_sync "AAAAAAAA"
+
+# Rebuild 1st and 3rd device from different mirror groups is fine.
+lvchange --yes --rebuild "$dev1" --rebuild "$dev3" $vg/$lv1
+[ $v1_9_0 -eq 1 ] && check raid_leg_status $vg $lv1 "aAaAAAAA"
+_sync "AAAAAAAA"
+
+# Rebuild devices 1, 3, 6 from different mirror groups is fine.
+lvchange --yes --rebuild "$dev1" --rebuild "$dev3" --rebuild "$dev6" $vg/$lv1
+[ $v1_9_0 -eq 1 ] && check raid_leg_status $vg $lv1 "aAaAAaAA"
+_sync "AAAAAAAA"
+
+# Rebuild devices 1, 3, 5 and 6 with 5+6 being
+# being a whole mirror group needs to be rejected.
+not lvchange --yes --rebuild "$dev1" --rebuild "$dev3" --rebuild "$dev6" --rebuild "$dev5" $vg/$lv1
+not check raid_leg_status $vg $lv1 "aAaAaaAA"
+_sync "AAAAAAAA"
+
+# Rebuild devices 1, 3, 5 and 7 from different mirror groups is fine.
+lvchange --yes --rebuild "$dev1" --rebuild "$dev3" --rebuild "$dev5" --rebuild "$dev7" $vg/$lv1
+[ $v1_9_0 -eq 1 ] && check raid_leg_status $vg $lv1 "aAaAaAaA"
+_sync
+
+# Rebuild devices 2, 4, 6 and 8 from different mirror groups is fine.
+lvchange --yes --rebuild "$dev2" --rebuild "$dev4" --rebuild "$dev6" --rebuild "$dev8" $vg/$lv1
+[ $v1_9_0 -eq 1 ] && check raid_leg_status $vg $lv1 "AaAaAaAa"
+_sync "AAAAAAAA"
+
+##############################################
+# Create an 8-legged raid1 and rebuild selected PVs
+lvremove --yes $vg/$lv1
+lvcreate --yes --type raid1 -m 7 -l 2 -n $lv1 $vg
+_sync "AAAAAAAA"
+
+# Rebuilding all raid1 legs needs to be rejected.
+not lvchange --yes --rebuild "$dev1" --rebuild "$dev2" --rebuild "$dev3" --rebuild "$dev4" \
+ --rebuild "$dev5" --rebuild "$dev6" --rebuild "$dev7" --rebuild "$dev8" $vg/$lv1
+not check raid_leg_status $vg $lv1 "aaaaaaaa"
+_sync "AAAAAAAA"
+
+# Rebuilding all but the raid1 master leg is fine.
+lvchange --yes --rebuild "$dev2" --rebuild "$dev3" --rebuild "$dev4" \
+ --rebuild "$dev5" --rebuild "$dev6" --rebuild "$dev7" --rebuild "$dev8" $vg/$lv1
+[ $v1_9_0 -eq 1 ] && check raid_leg_status $vg $lv1 "Aaaaaaaa"
+_sync "AAAAAAAA"
+
+# Rebuilding the raid1 master leg is fine.
+lvchange --yes --rebuild "$dev1" $vg/$lv1
+[ $v1_9_0 -eq 1 ] && check raid_leg_status $vg $lv1 "aAAAAAAA"
+_sync "AAAAAAAA"
+
+# Rebuild legs on devices 2, 4, 6 and 8 is fine.
+lvchange --yes --rebuild "$dev2" --rebuild "$dev4" --rebuild "$dev6" --rebuild "$dev8" $vg/$lv1
+[ $v1_9_0 -eq 1 ] && check raid_leg_status $vg $lv1 "AaAaAaAa"
+_sync "AAAAAAAA"
+
+##############################################
+# Create an 6-legged raid6 and rebuild selected PVs
+lvremove --yes $vg/$lv1
+lvcreate --yes --type raid6 -i 4 -l 2 -n $lv1 $vg
+_sync "AAAAAA"
+
+# Rebuilding all raid6 stripes needs to be rejected.
+not lvchange --yes --rebuild "$dev1" --rebuild "$dev2" --rebuild "$dev3" \
+ --rebuild "$dev4" --rebuild "$dev5" --rebuild "$dev6" $vg/$lv1
+not check raid_leg_status $vg $lv1 "aaaaaa"
+_sync "AAAAAA"
+
+# Rebuilding more than 2 raid6 stripes needs to be rejected.
+not lvchange --yes --rebuild "$dev2" --rebuild "$dev4" --rebuild "$dev6" $vg/$lv1
+not check raid_leg_status $vg $lv1 "AaAaAa"
+_sync "AAAAAA"
+
+# Rebuilding any 1 raid6 stripe is fine.
+lvchange --yes --rebuild "$dev2" $vg/$lv1
+[ $v1_9_0 -eq 1 ] && check raid_leg_status $vg $lv1 "AaAAAA"
+_sync
+
+lvchange --yes --rebuild "$dev5" $vg/$lv1
+[ $v1_9_0 -eq 1 ] && check raid_leg_status $vg $lv1 "AAAAaA"
+_sync "AAAAAA"
+
+# Rebuilding any 2 raid6 stripes is fine.
+lvchange --yes --rebuild "$dev2" --rebuild "$dev4" $vg/$lv1
+[ $v1_9_0 -eq 1 ] && check raid_leg_status $vg $lv1 "AaAaAA"
+_sync "AAAAAA"
+
+lvchange --yes --rebuild "$dev1" --rebuild "$dev5" $vg/$lv1
+[ $v1_9_0 -eq 1 ] && check raid_leg_status $vg $lv1 "aAAAaA"
+_sync "AAAAAA"
+
+vgremove -ff $vg
diff --git a/test/shell/lvchange-syncaction-raid.sh b/test/shell/lvchange-syncaction-raid.sh
new file mode 100644
index 0000000..73270f0
--- /dev/null
+++ b/test/shell/lvchange-syncaction-raid.sh
@@ -0,0 +1,92 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2014-2015 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+# test activation race for raid's --syncaction check
+
+
+SKIP_WITH_LVMPOLLD=1
+
+
+# Current support for syncaction in cluster is broken
+# might get fixed one day though
+# meanwhile skipped
+SKIP_WITH_CLVMD=1
+
+. lib/inittest
+
+# Proper mismatch count 1.5.2+ upstream, 1.3.5 < x < 1.4.0 in RHEL6
+aux have_raid 1 3 5 &&
+ ! aux have_raid 1 4 0 ||
+ aux have_raid 1 5 2 || skip
+aux prepare_vg 3
+
+lvcreate -n $lv1 $vg -l1 --type raid1
+
+aux wait_for_sync $vg $lv1
+
+START=$(get pv_field "$dev2" pe_start --units 1k)
+METASIZE=$(get lv_field $vg/${lv1}_rmeta_1 size -a --units 1k)
+SEEK=$((${START%\.00k} + ${METASIZE%\.00k}))
+# Overwrite some portion of _rimage_1
+
+#aux delay_dev "$dev2" 10 10
+dd if=/dev/urandom of="$dev2" bs=1K count=1 seek=$SEEK oflag=direct
+# FIXME
+# Some delay - there is currently race in upstream kernel
+# test may occasionaly fail with:
+# device-mapper: message ioctl on failed: Device or resource busy
+#
+# Heinz's kernel seems to fix this particular issue but
+# has some other problem for now
+aux udev_wait
+
+lvchange --syncaction check $vg/$lv1
+
+# Wait till scrubbing is finished
+aux wait_for_sync $vg $lv1
+
+check lv_field $vg/$lv1 raid_mismatch_count "128"
+
+# Let's deactivate
+lvchange -an $vg/$lv1
+
+lvchange -ay $vg/$lv1
+# noone has it open and target is read & running
+dmsetup info -c | grep $vg
+
+#sleep 10 < "$DM_DEV_DIR/$vg/$lv1" &
+# "check" should find discrepancies but not change them
+# 'lvs' should show results
+
+# FIXME
+# this looks like some race with 'write' during activation
+# and syncaction...
+# For now it fails with:
+# device-mapper: message ioctl on failed: Device or resource busy
+#
+# As solution for now - user needs to run --synaction on synchronous raid array
+#
+aux wait_for_sync $vg $lv1
+
+# Check raid array doesn't know about error yet
+check lv_field $vg/$lv1 raid_mismatch_count "0"
+
+# Start scrubbing
+lvchange --syncaction check $vg/$lv1
+
+# Wait till scrubbing is finished
+aux wait_for_sync $vg $lv1
+
+# Retest mistmatch exists
+check lv_field $vg/$lv1 raid_mismatch_count "128"
+
+vgremove -ff $vg
diff --git a/test/shell/lvchange-thin.sh b/test/shell/lvchange-thin.sh
new file mode 100644
index 0000000..5c23103
--- /dev/null
+++ b/test/shell/lvchange-thin.sh
@@ -0,0 +1,204 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2013-2016 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+
+SKIP_WITH_LVMPOLLD=1
+
+export LVM_TEST_THIN_REPAIR_CMD=${LVM_TEST_THIN_REPAIR_CMD-/bin/false}
+
+. lib/inittest
+
+aux have_thin 1 0 0 || skip
+
+aux prepare_pvs 3
+
+vgcreate $SHARED -s 128k $vg "$dev1" "$dev2"
+vgcreate $SHARED -s 128k $vg2 "$dev3"
+
+lvcreate -L10M -T $vg/pool
+
+# When PV does not support discard
+# tests for checking thin-pool discard passdown are skipped
+pvmajor=$(get pv_field "$dev1" major)
+pvminor=$(get pv_field "$dev1" minor)
+
+if test "$(< "/sys/dev/block/$pvmajor:$pvminor/queue/discard_granularity")" -eq 0 ; then
+ no_discard=1
+else
+ no_discard=
+fi
+
+#
+# Check change operations on a thin-pool without any thin LV
+#
+# discards_ARG (default is passdown)
+test -n "$no_discard" || check grep_dmsetup status $vg-pool " discard_passdown" || {
+ # trace device layout
+ grep -r "" /sys/block/*
+ die "Device was expected to support passdown"
+}
+
+lvchange --discards nopassdown $vg/pool
+check grep_dmsetup table $vg-pool " no_discard_passdown"
+test -n "$no_discard" || check grep_dmsetup status $vg-pool " no_discard_passdown"
+
+lvchange --discards passdown $vg/pool
+check grep_dmsetup table $vg-pool -v "passdown"
+test -n "$no_discard" || check grep_dmsetup status $vg-pool " discard_passdown"
+
+# zero_ARG (default is 'yes')
+check grep_dmsetup table $vg-pool -v "zeroing"
+lvchange --zero n $vg/pool
+check grep_dmsetup table $vg-pool " skip_block_zeroing"
+lvchange --zero y $vg/pool
+check grep_dmsetup table $vg-pool -v "zeroing"
+
+# errorwhenfull_ARG (default is 'no')
+check grep_dmsetup status $vg-pool "queue_if_no_space"
+lvchange --errorwhenfull y $vg/pool
+check grep_dmsetup status $vg-pool "error_if_no_space"
+check grep_dmsetup table $vg-pool "error_if_no_space"
+lvchange --errorwhenfull n $vg/pool
+check grep_dmsetup status $vg-pool "queue_if_no_space"
+check grep_dmsetup table $vg-pool -v "error_if_no_space"
+
+
+# Attach thin volume
+lvcreate -V10M -n $lv1 $vg/pool
+lvcreate -L10M -n $lv2 $vg
+
+lvchange -an $vg/$lv1
+
+# Test activation
+lvchange -aly $vg/$lv1
+check active $vg $lv1
+
+lvchange -aln $vg/$lv1
+check inactive $vg $lv1
+
+# Test for allowable 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
+
+# FIXME
+#should lvchange -p r $vg/pool
+#should lvchange -p rw $vg/pool
+
+# readahead_ARG
+lvchange -r none $vg/$lv1
+lvchange -r auto $vg/$lv1
+# FIXME
+# Think about more support
+
+# minor_ARG
+lvchange --yes -M y --minor 234 --major 253 $vg/$lv1
+lvchange -M n $vg/$lv1
+
+# cannot change major minor for pools
+not lvchange --yes -M y --minor 235 --major 253 $vg/pool
+not lvchange -M n $vg/pool
+
+# addtag_ARG
+lvchange --addtag foo $vg/$lv1
+lvchange --addtag foo $vg/pool
+
+# deltag_ARG
+lvchange --deltag foo $vg/$lv1
+lvchange --deltag foo $vg/pool
+
+# discards_ARG
+lvchange --discards nopassdown $vg/pool
+check grep_dmsetup table $vg-pool-tpool " no_discard_passdown"
+test -n "$no_discard" || check grep_dmsetup status $vg-pool-tpool " no_discard_passdown"
+lvchange --discards passdown $vg/pool
+check grep_dmsetup table $vg-pool-tpool -v "passdown"
+test -n "$no_discard" || check grep_dmsetup status $vg-pool-tpool " discard_passdown"
+
+# zero_ARG
+lvchange --zero n $vg/pool
+check grep_dmsetup table $vg-pool-tpool " skip_block_zeroing"
+lvchange --zero y $vg/pool
+check grep_dmsetup table $vg-pool-tpool -v "zeroing"
+
+
+lvchange --errorwhenfull y $vg/pool
+check grep_dmsetup status $vg-pool-tpool "error_if_no_space"
+check grep_dmsetup table $vg-pool-tpool "error_if_no_space"
+lvchange --errorwhenfull n $vg/pool
+check grep_dmsetup status $vg-pool-tpool "queue_if_no_space"
+check grep_dmsetup table $vg-pool-tpool -v "error_if_no_space"
+
+
+#
+# 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
+
+#
+# Play with tags and activation
+#
+TAG=$(uname -n)
+aux lvmconf "activation/volume_list = [ \"$vg/$lv2\", \"@mytag\" ]"
+
+lvchange -ay $vg/$lv1
+check inactive $vg $lv1
+
+lvchange --addtag mytag $vg/$lv1
+
+lvchange -ay @mytag_fake
+check inactive $vg $lv1
+
+lvchange -ay $vg/$lv1
+# Volume has matching tag
+check active $vg $lv1
+lvchange -an $vg/$lv1
+
+lvchange -ay @mytag
+check active $vg $lv1
+
+# Fails here since it cannot clear device header
+not lvcreate -Zy -L10 -n $lv3 $vg2
+# OK when zeroing is disabled
+lvcreate -Zn -L10 -n $lv3 $vg2
+check inactive $vg2 $lv3
+
+aux lvmconf "activation/volume_list = [ \"$vg2\" ]"
+vgchange -an $vg
+vgchange -ay $vg $vg2
+lvs -a -o+lv_active $vg $vg2
+
+aux lvmconf "activation/volume_list = [ \"$vg\", \"$vg2\" ]"
+
+vgremove -ff $vg $vg2
diff --git a/test/shell/lvchange-vdo.sh b/test/shell/lvchange-vdo.sh
new file mode 100644
index 0000000..b11edf3
--- /dev/null
+++ b/test/shell/lvchange-vdo.sh
@@ -0,0 +1,170 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2018 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+aux have_vdo 6 2 0 || skip
+
+aux prepare_vg 2 6400
+
+lvcreate --vdo -L5G -n $lv1 $vg/vdopool
+
+# deduplication_ARG (default is 'yes')
+# compression_ARG (default is 'yes')
+
+# Wait till index gets openned
+for i in {1..10} ; do
+ sleep .1
+ check grep_dmsetup status $vg-vdopool-vpool " online online " || continue
+ break
+done
+
+
+# compression_ARG
+lvchange --compression n $vg/vdopool
+check grep_dmsetup status $vg-vdopool-vpool " online offline "
+lvchange --compression y $vg/vdopool
+check grep_dmsetup status $vg-vdopool-vpool " online online "
+
+# dedulication_ARG
+lvchange --deduplication n $vg/vdopool
+check grep_dmsetup status $vg-vdopool-vpool -E " offline|closed online "
+
+lvchange --deduplication y $vg/vdopool
+check grep_dmsetup status $vg-vdopool-vpool -E " online|opening online "
+
+
+lvchange --compression n --deduplication n $vg/vdopool
+check grep_dmsetup status $vg-vdopool-vpool -E " offline|closed offline "
+
+# --vdosettings needs inactive LV
+not lvchange --vdosettings 'ack_threads=8' $vg/vdopool
+
+lvchange -an $vg/$lv1
+
+# With inactive vdo-pool changes are applied
+# explicit option --compression has highest priority
+lvchange --vdosettings 'ack_threads=5 compression=0' --compression y $vg/vdopool
+check lv_field $vg/$lv1 vdo_ack_threads "5"
+check lv_field $vg/$lv1 vdo_compression "enabled"
+
+# Test activation
+lvchange -aly $vg/$lv1
+check active $vg $lv1
+
+lvchange -aln $vg/$lv1
+check inactive $vg $lv1
+
+# Test for allowable 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
+
+# FIXME
+#should lvchange -p r $vg/vdopool
+#should lvchange -p rw $vg/vdopool
+
+# readahead_ARG
+lvchange -r none $vg/$lv1
+lvchange -r auto $vg/$lv1
+# FIXME
+# Think about more support
+
+# minor_ARG
+lvchange --yes -M y --minor 234 --major 253 $vg/$lv1
+lvchange -M n $vg/$lv1
+
+# cannot change major minor for pools
+not lvchange --yes -M y --minor 235 --major 253 $vg/vdopool
+not lvchange -M n $vg/vdopool
+
+# addtag_ARG
+lvchange --addtag foo $vg/$lv1
+lvchange --addtag foo $vg/vdopool
+
+# deltag_ARG
+lvchange --deltag foo $vg/$lv1
+lvchange --deltag foo $vg/vdopool
+
+
+#
+# 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
+
+# Check activation of VDO alone works (like for thin-pools)
+lvchange -an $vg
+
+lvchange -ay $vg/vdopool
+check active $vg vdopool
+check inactive $vg $lv1
+
+lvchange -ay $vg/$lv1
+check active $vg $lv1
+
+lvchange -an $vg/$lv1
+check active $vg vdopool
+check inactive $vg $lv1
+
+lvchange -ay $vg/$lv1
+lvchange -an $vg/vdopool
+lvchange -an $vg/$lv1
+check inactive $vg vdopool
+
+#
+# Play with tags and activation
+#
+TAG=$(uname -n)
+aux lvmconf "activation/volume_list = [ \"$vg/$lv2\", \"@mytag\" ]"
+
+lvchange -ay $vg/$lv1
+check inactive $vg $lv1
+
+lvchange --addtag mytag $vg/$lv1
+
+lvchange -ay @mytag_fake
+check inactive $vg $lv1
+
+lvchange -ay $vg/$lv1
+# Volume has matching tag
+check active $vg $lv1
+lvchange -an $vg/$lv1
+
+lvchange -ay @mytag
+check active $vg $lv1
+
+vgremove -ff $vg
diff --git a/test/shell/lvconvert-cache-abort.sh b/test/shell/lvconvert-cache-abort.sh
new file mode 100644
index 0000000..f0f9220
--- /dev/null
+++ b/test/shell/lvconvert-cache-abort.sh
@@ -0,0 +1,89 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2017 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+# Exercise cache flushing is abortable
+
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+aux have_cache 1 3 0 || skip
+
+aux prepare_vg
+
+SIZE_MB=200
+
+# Use large zero device and later delayed metadata dev1
+lvcreate -L$((SIZE_MB * 2))M --type zero -n cpool $vg
+lvconvert -y --type cache-pool --chunksize 32k $vg/cpool "$dev1"
+lvcreate -L$((SIZE_MB * 2))M --type zero -n $lv1 $vg
+lvconvert -y -H --chunksize 32k --cachemode writeback --cachepool $vg/cpool $vg/$lv1
+
+#
+# Ensure cache gets promoted blocks
+#
+for i in $(seq 1 2) ; do
+dd if=/dev/zero of="$DM_DEV_DIR/$vg/$lv1" bs=1M count=$SIZE_MB oflag=direct || true
+dd if="$DM_DEV_DIR/$vg/$lv1" of=/dev/null bs=1M count=$SIZE_MB iflag=direct || true
+done
+
+aux delay_dev "$dev1" 0 200 "$(get first_extent_sector "$dev1"):"
+dd if=/dev/zero of="$DM_DEV_DIR/$vg/$lv1" bs=1M count=$SIZE_MB
+
+lvdisplay --maps $vg
+# Delay dev to ensure we have some time to 'capture' interrupt in flush
+
+# TODO, how to make writeback cache dirty
+test "$(get lv_field $vg/$lv1 cache_dirty_blocks)" -gt 0 || {
+ lvdisplay --maps $vg
+ skip "Cannot make a dirty writeback cache LV."
+}
+
+LVM_TEST_TAG="kill_me_$PREFIX" lvconvert -vvvv --splitcache $vg/$lv1 >logconvert 2>&1 &
+PID_CONVERT=$!
+for i in {1..50}; do
+ out=$(dmsetup status --noflush "$vg-$lv1")
+ case "$out" in
+ *cleaner*) break;;
+ esac
+ echo "$i: Waiting for cleaner policy on $vg/$lv1"
+ sleep .01
+done
+test "$i" -ge 49 && die "Waited for cleaner policy on $vg/$lv1 too long!"
+
+# While lvconvert updated table to 'cleaner' policy now it
+# should be running in 'Flushing' loop and just 1 KILL should
+# cause abortion of flushing
+kill -INT $PID_CONVERT
+aux enable_dev "$dev2"
+wait
+#cat logconvert || true
+
+# Problem of this test is, in older kernels, even the initial change to cleaner
+# policy table line causes long suspend which in practice is cleaning all the
+# dirty blocks - so the test can't really break the cache clearing.
+#
+# So the failure of test is reported only for recent kernels > 5.6
+# ans skipped otherwise - as those can't be fixed anyway
+grep -E "Flushing.*aborted" logconvert || {
+ cat logconvert || true
+ vgremove -f $vg
+ aux kernel_at_least 5 6 || skip "Cache missed to abort flushing with older kernel"
+ die "Flushing of $vg/$lv1 not aborted ?"
+}
+
+# check the table got restored
+check grep_dmsetup table $vg-$lv1 "writeback"
+lvdisplay --maps $vg
+
+vgremove -f $vg
diff --git a/test/shell/lvconvert-cache-chunks.sh b/test/shell/lvconvert-cache-chunks.sh
new file mode 100644
index 0000000..72a64de
--- /dev/null
+++ b/test/shell/lvconvert-cache-chunks.sh
@@ -0,0 +1,62 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2016-2017 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+# Exercise number of cache chunks in cache pool
+# Skips creation of real cached device for older cache targets...
+
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+aux have_cache 1 3 0 || skip
+
+aux prepare_vg 2 1000000
+
+# Really large cache pool data LV
+lvcreate -L1T -n cpool $vg
+
+# Works and pick higher chunks size then default
+lvconvert -y --type cache-pool $vg/cpool
+
+# Check chunk size in sectors is more then 512K
+test "$(get lv_field "$vg/cpool" chunk_size --units s --nosuffix)" -gt 1000
+
+lvcreate -L1M -n $lv1 $vg
+
+# Not let pass small chunks when caching origin
+fail lvconvert -y -H --chunksize 128K --cachepool $vg/cpool $vg/$lv1 >out 2>&1
+cat out
+grep "too small chunk size" out
+
+# Thought 2M is valid
+if aux have_cache 1 8 0 ; then
+ # Without SMQ we run out of kernel memory easily
+ lvconvert -y -H --chunksize 2M --cachepool $vg/cpool $vg/$lv1
+fi
+
+lvremove -f $vg
+
+###
+
+# Really large cache pool data LV
+lvcreate -L1T -n cpool $vg
+# Not allowed to create more then 10e6 chunks
+fail lvconvert -y --type cache-pool --chunksize 128K $vg/cpool
+
+if aux have_cache 1 8 0 ; then
+ # Let operation pass when max_chunk limit is raised
+ lvconvert -y --type cache-pool --chunksize 128K $vg/cpool \
+ --config 'allocation/cache_pool_max_chunks=10000000'
+fi
+
+vgremove -f $vg
diff --git a/test/shell/lvconvert-cache-raid.sh b/test/shell/lvconvert-cache-raid.sh
new file mode 100644
index 0000000..033376d
--- /dev/null
+++ b/test/shell/lvconvert-cache-raid.sh
@@ -0,0 +1,115 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2014-2015 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+# Exercise usage of stacked cache volume using raid volume
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+aux have_cache 1 3 0 || skip
+aux have_raid 1 0 0 || skip
+
+aux lvmconf 'global/cache_disabled_features = [ "policy_smq" ]'
+
+aux prepare_vg 5 80
+
+# Bug 1095843
+# lvcreate RAID1 origin, lvcreate cache-pool, and lvconvert to cache
+lvcreate --type raid1 -m 1 --nosync -l 2 -n $lv1 $vg
+lvcreate --type cache-pool -l 1 -n ${lv1}_cachepool $vg
+lvconvert --cache -Zy --cachepool $vg/${lv1}_cachepool $vg/$lv1
+check lv_exists $vg/${lv1}_corig_rimage_0 # ensure images are properly renamed
+dmsetup table ${vg}-$lv1 | grep cache # ensure it is loaded in kernel
+lvremove -f $vg
+
+
+# lvcreate RAID1 origin, lvcreate RAID1 cache-pool, and lvconvert to cache
+lvcreate --type raid1 -m 1 --nosync -l 2 -n $lv1 $vg
+lvcreate --type raid1 -m 1 --nosync -l 2 -n ${lv1}_cachepool $vg
+#should lvs -a $vg/${lv1}_cdata_rimage_0 # ensure images are properly renamed
+lvconvert --yes --type cache --cachemode writeback --cachepool $vg/${lv1}_cachepool $vg/$lv1 2>&1 | tee out
+grep "WARNING: Data redundancy could be lost" out
+check lv_exists $vg/${lv1}_corig_rimage_0 # ensure images are properly renamed
+dmsetup table ${vg}-$lv1 | grep cache # ensure it is loaded in kernel
+lvremove -f $vg
+
+
+lvcreate -n corigin -m 1 --type raid1 --nosync -l 10 $vg
+lvcreate -n cpool --type cache $vg/corigin --cachemode writeback -l 10 2>&1 | tee out
+grep "WARNING: Data redundancy could be lost" out
+not lvconvert --splitmirrors 1 --name split $vg/corigin "$dev1"
+lvconvert --yes --splitmirrors 1 --name split $vg/corigin "$dev1"
+
+lvremove -f $vg
+
+lvcreate -n cpool_meta -m 1 --type raid1 -l 10 $vg
+lvcreate -n cpool -m 1 --type raid1 -l 10 $vg
+aux wait_for_sync $vg cpool_meta
+aux wait_for_sync $vg cpool
+lvs -a -o+seg_pe_ranges $vg
+lvconvert --yes --type cache-pool --poolmetadata $vg/cpool_meta $vg/cpool
+lvcreate -n corigin --type cache --cachepool $vg/cpool -l 10
+
+lvchange --syncaction repair $vg/cpool_cpool_cmeta
+aux wait_for_sync $vg cpool_cpool_cmeta
+
+lvchange --syncaction repair $vg/cpool_cpool_cdata
+aux wait_for_sync $vg cpool_cpool_cdata
+
+lvconvert -y --repair $vg/cpool_cpool_cmeta
+lvconvert -y --repair $vg/cpool_cpool_cdata
+
+# do not allow reserved names for *new* LVs
+not lvconvert --splitmirrors 1 --name split_cmeta $vg/cpool_cpool_cmeta "$dev1"
+not lvconvert --splitmirrors 1 --name split_cdata $vg/cpool_cpool_cdata "$dev1"
+
+# but allow manipulating existing LVs with reserved names
+aux wait_for_sync $vg cpool_cpool_cmeta
+aux wait_for_sync $vg cpool_cpool_cdata
+lvconvert --yes --splitmirrors 1 --name split_meta $vg/cpool_cpool_cmeta "$dev1"
+lvconvert --yes --splitmirrors 1 --name split_data $vg/cpool_cpool_cdata "$dev1"
+not lvconvert --splitmirrors 1 --name split_data $vg/cpool_cpool_cdata "$dev1"
+
+lvremove -f $vg
+
+
+# Test up/down raid conversion of cache pool data and metadata
+
+lvcreate -l 10 -n cp1 $vg
+lvconvert -y --type cache-pool $vg/cp1
+
+lvcreate -l 20 -n co1 $vg
+lvconvert -y --type cache --cachepool cp1 $vg/co1
+
+lvconvert -y -m +1 --type raid1 $vg/cp1_cpool_cmeta
+check lv_field $vg/cp1_cpool_cmeta layout "raid,raid1"
+check lv_field $vg/cp1_cpool_cmeta role "private,cache,pool,metadata"
+
+lvconvert -y -m +1 --type raid1 $vg/cp1_cpool_cdata
+check lv_field $vg/cp1_cpool_cdata layout "raid,raid1"
+check lv_field $vg/cp1_cpool_cdata role "private,cache,pool,data"
+
+sleep 5
+
+lvs -a -o+devices $vg
+
+not lvconvert -m -1 $vg/cp1_cpool_cmeta
+
+lvconvert -y -m -1 $vg/cp1_cpool_cmeta
+check lv_field $vg/cp1_cpool_cmeta layout "linear"
+lvconvert -y -m -1 $vg/cp1_cpool_cdata
+check lv_field $vg/cp1_cpool_cdata layout "linear"
+
+lvremove -f $vg
+
+vgremove -f $vg
diff --git a/test/shell/lvconvert-cache-smq.sh b/test/shell/lvconvert-cache-smq.sh
new file mode 100644
index 0000000..67710fa
--- /dev/null
+++ b/test/shell/lvconvert-cache-smq.sh
@@ -0,0 +1,34 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2014 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+# Exercise conversion of cache and cache pool
+
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+aux have_cache 1 8 0 || skip
+
+aux prepare_vg 5 80
+
+lvcreate --type cache-pool -an -v -L 2 -n cpool $vg
+
+lvcreate -H --cachepolicy smq -L 4 -n corigin --cachepool $vg/cpool
+
+check lv_field $vg/corigin cache_policy "smq"
+
+lvconvert --splitcache $vg/corigin
+
+lvs -o+cache_policy -a $vg
+
+vgremove -f $vg
diff --git a/test/shell/lvconvert-cache-snapshot.sh b/test/shell/lvconvert-cache-snapshot.sh
new file mode 100644
index 0000000..ac9d3dd
--- /dev/null
+++ b/test/shell/lvconvert-cache-snapshot.sh
@@ -0,0 +1,63 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2016 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+# Test various supported conversion of snapshot of cached volume
+
+SKIP_WITH_LVMLOCKD=1
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+aux have_cache 1 3 0 || skip
+
+aux prepare_vg 1
+
+
+# Prepare cached LV
+lvcreate -aey -L1 -n $lv1 $vg
+lvcreate -H -L2 -n cpool $vg/$lv1
+
+# Prepare snapshot 'cow' LV
+lvcreate -L3 -n cow $vg
+
+# Can't use 'cached' cow volume
+not lvconvert -s cow $vg/$lv1
+
+# Use cached LV with 'striped' cow volume
+lvconvert -y -s $vg/$lv1 cow
+check lv_field $vg/cow segtype linear
+check lv_field $vg/$lv1 segtype cache
+
+# Drop cache while being in-use origin
+lvconvert --splitcache $vg/$lv1
+check lv_field $vg/$lv1 segtype linear
+
+# Cache existing origin
+lvconvert -y --cache $vg/$lv1 --cachepool $vg/cpool
+check lv_field $vg/$lv1 segtype cache
+
+# Cannot split from 'origin' (being cached LV)
+not lvconvert -y --splitsnapshot $vg/$lv1
+
+lvchange --cachemode writeback $vg/$lv1
+check lv_field $vg/$lv1 cache_mode "writeback"
+check grep_dmsetup status ${vg}-${lv1}-real "writeback"
+
+lvchange --cachemode writethrough $vg/$lv1
+check lv_field $vg/$lv1 cache_mode "writethrough"
+check grep_dmsetup status ${vg}-${lv1}-real "writethrough"
+
+# Split 'cow' from cached origin
+lvconvert -y --splitsnapshot $vg/cow
+get lv_field $vg/cow attr | grep "^-wi"
+
+vgremove -f $vg
diff --git a/test/shell/lvconvert-cache-thin.sh b/test/shell/lvconvert-cache-thin.sh
new file mode 100644
index 0000000..3fdd258
--- /dev/null
+++ b/test/shell/lvconvert-cache-thin.sh
@@ -0,0 +1,125 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2014-2023 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+# Exercise usage of stacked cache volume used in thin pool volumes
+
+SKIP_WITH_LVMLOCKD=1
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+aux have_cache 1 3 0 || skip
+aux have_thin 1 0 0 || skip
+
+aux prepare_vg 5 80
+
+#
+# Check caching of whole thin-pool
+#
+lvcreate -L10 -n cpool $vg
+lvcreate -L10 -n tpool $vg
+lvcreate -L10 -n $lv1 $vg
+
+lvconvert --yes --cache --cachepool cpool $vg/tpool
+
+lvconvert --yes --type thin-pool $vg/tpool
+
+lvcreate -V10 -T -n $lv2 $vg/tpool
+
+aux mkdev_md5sum $vg $lv2
+
+lvconvert --splitcache $vg/tpool
+
+check dev_md5sum $vg $lv2
+lvchange -an $vg
+lvchange -ay $vg
+check dev_md5sum $vg $lv2
+
+lvs -a $vg
+lvconvert --yes --cache --cachepool cpool $vg/tpool
+
+lvconvert --yes -T --thinpool $vg/tpool $vg/$lv1
+check lv_field $vg/tpool segtype "thin-pool"
+check lv_field $vg/$lv1 segtype "thin"
+lvconvert --uncache $vg/tpool
+lvs -a $vg
+
+lvremove -f $vg
+
+
+#
+# Check caching of single individual thin LV
+#
+lvcreate --type cache-pool -L10 -n cpool $vg
+lvcreate -T -L10 -V10 -n $lv1 $vg/tpool
+
+lvconvert --yes -H --cachepool $vg/cpool $vg/$lv1
+check lv_field $vg/${lv1}_corig segtype "thin" -a
+check lv_field $vg/$lv1 segtype "cache"
+
+# Other thins from the thin-pool can be created
+lvcreate -V10 $vg/tpool
+
+# ATM there is no support to take snapshot of cache thin LV
+not lvcreate -s $vg/$lv1
+
+# Use can take thick snapshot
+lvcreate -s -L10 -n $lv2 $vg/$lv1
+check lv_field $vg/$lv2 segtype "linear"
+
+lvchange -an $vg
+lvchange -ay $vg
+
+lvconvert --uncache $vg/$lv1
+
+lvremove -f $vg
+
+
+#
+# Check conversion of cached LV works as thin-pool
+#
+lvcreate -L10 -n $lv $vg
+lvcreate -L10 -n $lv1 $vg
+lvcreate -H -L10 $vg/$lv
+
+# Stack of cache over cache is unsupported ATM
+fail lvconvert --yes --cachepool $vg/$lv
+
+# Thin-pool cannot use cached metaddata LV (meta should be on FAST device)
+fail lvconvert --yes --thinpool $vg/$lv1 --poolmetadata $vg/$lv
+
+# Thin-pool CAN use cached data LV
+lvconvert --yes --thinpool $vg/$lv
+
+lvremove -f $vg
+
+# Check we can active snapshot of cached external origin (BZ: 1967744)
+lvcreate -T -L10M $vg/pool "$dev1"
+
+lvcreate -L10M -n origin $vg "$dev1"
+lvcreate -H -L4M -n CPOOL $vg/origin "$dev2"
+
+# Use cached origin as external origin
+lvconvert -y -T --thinpool $vg/pool --originname extorig origin
+
+# Check we can easily create snapshot of such LV
+lvcreate -y -kn -n snap -s $vg/origin
+
+# Deactivate everything and do a component activation of _cmeta volume
+lvchange -an $vg
+lvchange -ay -y $vg/CPOOL_cpool_cmeta
+
+# Now this must fail since component volume is active
+not lvcreate -y -kn -n snap2 -s $vg/origin |& tee err
+grep "cmeta is active" err
+
+vgremove -f $vg
diff --git a/test/shell/lvconvert-cache-vdo.sh b/test/shell/lvconvert-cache-vdo.sh
new file mode 100644
index 0000000..39caf5e
--- /dev/null
+++ b/test/shell/lvconvert-cache-vdo.sh
@@ -0,0 +1,71 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2014 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+# Exercise usage of stacked cache volume used in thin pool volumes
+
+SKIP_WITH_LVMLOCKD=1
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+percent_() {
+ get lv_field $vg/vpool data_percent | cut -d. -f1
+}
+
+aux have_vdo 6 2 0 || skip
+aux have_cache 1 3 0 || skip
+
+aux prepare_vg 1 9000
+
+lvcreate -L10 -n cpool $vg
+lvcreate -L4G -n vpool $vg
+
+# Cache volume
+lvconvert --yes --cache --cachepool cpool $vg/vpool
+
+# Stack cached LV as VDODataLV for VDOPoolLV
+lvconvert --yes --type vdo-pool -V50M --name $lv1 $vg/vpool
+
+aux mkdev_md5sum $vg $lv1
+
+lvconvert --splitcache $vg/vpool
+
+check dev_md5sum $vg $lv1
+lvchange -an $vg
+lvchange -ay $vg
+check dev_md5sum $vg $lv1
+
+lvconvert --yes --cache --cachepool cpool $vg/vpool
+
+VDODATA="$(percent_)"
+# Check resize of cached VDO pool
+lvextend -L+1G $vg/vpool
+
+lvs -a $vg
+# Check after resize usage is reduced
+test "$(percent_)" -lt $VDODATA
+lvconvert --splitcache $vg/vpool
+
+lvconvert --yes --cache --cachepool cpool $vg/$lv1
+check dev_md5sum $vg $lv1
+lvchange -an $vg
+lvchange -ay $vg
+check dev_md5sum $vg $lv1
+
+lvs -a $vg
+not lvconvert --splitcache $vg/vpool
+lvconvert --splitcache $vg/$lv1
+lvs -a $vg
+
+# Also check, removal of cached VDO LV works
+lvconvert --yes --cache --cachepool cpool $vg/$lv1
+vgremove -f $vg
diff --git a/test/shell/lvconvert-cache.sh b/test/shell/lvconvert-cache.sh
new file mode 100644
index 0000000..cfc8281
--- /dev/null
+++ b/test/shell/lvconvert-cache.sh
@@ -0,0 +1,202 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2014-2016 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+# Exercise conversion of cache and cache pool
+
+SKIP_WITH_LVMLOCKD=1
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+aux have_cache 1 3 0 || skip
+
+aux prepare_vg 5 80
+
+lvcreate --type cache-pool -an -v -L 2 -n cpool $vg
+lvcreate -H -L 4 -n corigin --cachepool $vg/cpool
+
+fail lvcreate -s -L2 $vg/cpool
+fail lvcreate -s -L2 $vg/cpool_cdata
+fail lvcreate -s -L2 $vg/cpool_cmeta
+
+###########################
+# Check regular converion #
+###########################
+# lvcreate origin, lvcreate cache-pool, and lvconvert to cache
+lvcreate -an -Zn -L 2 -n $lv1 $vg
+lvcreate -L 8 -n $lv2 $vg
+lvcreate -an -Zn -L 8 -n $lv3 $vg
+lvcreate -an -Zn -L 8 -n $lv4 $vg
+lvcreate -an -Zn -L 16 -n $lv5 $vg
+
+# check validation of cachemode arg works
+invalid lvconvert --yes --type cache-pool --cachemode writethroughX --cachepool $vg/$lv1
+
+# by default no cache settings are attached to converted cache-pool
+lvconvert --yes --type cache-pool --chunksize 256 $vg/$lv1
+check inactive $vg ${lv1}_cdata
+check lv_field $vg/$lv1 cache_mode ""
+check lv_field $vg/$lv1 cache_policy ""
+check lv_field $vg/$lv1 cache_settings ""
+check lv_field $vg/$lv1 chunk_size "256.00k"
+
+# but allow to set them when specified explicitely on command line
+lvconvert --yes --type cache-pool --cachemode writeback --cachepolicy mq \
+ --cachesettings sequential_threshold=1234 --cachesettings random_threshold=56 \
+ --cachepool $vg/$lv2
+check inactive $vg ${lv2}_cdata
+check lv_field $vg/$lv2 cache_mode "writeback"
+check lv_field $vg/$lv2 cache_policy "mq"
+check lv_field $vg/$lv2 cache_settings "random_threshold=56,sequential_threshold=1234"
+
+# Check swap of cache pool metadata
+lvconvert --yes --type cache-pool --poolmetadata $lv4 $vg/$lv3
+UUID=$(get lv_field $vg/$lv5 uuid)
+lvconvert --yes --cachepool $vg/$lv3 --poolmetadata $lv5
+check lv_field $vg/${lv3}_cmeta uuid "$UUID"
+
+# Check swap of cache pool metadata with --swapmetadata
+# (should swap back to lv5)
+lvconvert --yes --swapmetadata $vg/$lv3 --poolmetadata $lv5
+check lv_field $vg/$lv5 uuid "$UUID"
+
+#fail lvconvert --cachepool $vg/$lv1 --poolmetadata $vg/$lv2
+#lvconvert --yes --type cache-pool --poolmetadata $vg/$lv2 $vg/$lv1
+#lvconvert --yes --poolmetadata $vg/$lv2 --cachepool $vg/$lv1
+
+lvremove -ff $vg
+
+lvcreate -L 2 -n $lv1 $vg
+lvcreate --type cache-pool -l 1 -n ${lv1}_cachepool $vg
+lvconvert --cache --cachepool $vg/${lv1}_cachepool --cachemode writeback -Zy $vg/$lv1
+check lv_field $vg/$lv1 cache_mode "writeback"
+dmsetup table ${vg}-$lv1 | grep cache # ensure it is loaded in kernel
+
+#lvconvert --cachepool $vg/${lv1}_cachepool $vg/$lv1
+#lvconvert --cachepool $vg/${lv1}_cachepool --poolmetadatasize 20 "$dev3"
+
+
+fail lvconvert --type cache --cachepool $vg/${lv1}_cachepool -Zy $vg/$lv1
+
+# Test --splitcache leaves both cache origin and cache pool
+lvconvert --splitcache $vg/$lv1
+check lv_exists $vg $lv1 ${lv1}_cachepool
+lvremove -f $vg
+
+
+lvcreate -L 2 -n $lv1 $vg
+lvcreate --type cache-pool -l 1 -n ${lv1}_cachepool "$DM_DEV_DIR/$vg"
+lvconvert --cache --cachepool "$DM_DEV_DIR/$vg/${lv1}_cachepool" --cachemode writeback -Zy "$DM_DEV_DIR/$vg/$lv1"
+lvremove -f $vg
+
+
+lvcreate -n corigin -l 10 $vg
+lvcreate -n pool -l 10 $vg
+lvs -a -o +devices
+fail lvconvert --type cache --cachepool $vg/pool $vg/corigin
+lvconvert --yes --cache --cachepool $vg/pool $vg/corigin
+lvconvert --splitcache $vg/corigin
+lvremove -ff $vg
+
+# Check we also support conversion that uses 'cleaner' cache policy
+lvcreate -n corigin -l 10 $vg
+lvcreate -n pool -l 10 $vg
+lvconvert --yes --cache --cachepool $vg/pool $vg/corigin --cachepolicy cleaner
+lvremove -ff $vg
+
+#######################
+# Invalid conversions #
+#######################
+lvcreate -an -Zn -L 2 -n $lv1 $vg
+lvcreate -an -Zn -L 8 -n $lv2 $vg
+lvcreate -an -Zn -L 8 -n $lv3 $vg
+lvcreate -an -Zn -L 8 -n $lv4 $vg
+
+# Undefined cachepool
+invalid lvconvert --type cache --poolmetadata $vg/$lv2 $vg/$lv1
+
+# Cannot mix with thins
+invalid lvconvert --type cache --poolmetadata $vg/$lv2 --thinpool $vg/$lv1
+invalid lvconvert --type cache --thin --poolmetadata $vg/$lv2 $vg/$lv1
+
+# Undefined cached volume
+invalid lvconvert --type cache --cachepool $vg/$lv1
+invalid lvconvert --cache --cachepool $vg/$lv1
+
+# FIXME: temporarily we return error code 5
+INVALID=not
+# Single vg is required
+$INVALID lvconvert --type cache --cachepool $vg/$lv1 --poolmetadata $vg1/$lv2 $vg/$lv3
+$INVALID lvconvert --type cache --cachepool "$DM_DEV_DIR/$vg/$lv1" --poolmetadata "$DM_DEV_DIR/$vg1/$lv2" $vg/$lv3
+$INVALID lvconvert --type cache --cachepool $vg/$lv1 --poolmetadata $lv2 $vg1/$lv3
+$INVALID lvconvert --type cache --cachepool $vg1/$lv1 --poolmetadata $vg2/$lv2 $vg/$lv3
+$INVALID lvconvert --type cache --cachepool $vg1/$lv1 --poolmetadata $vg2/$lv2 "$DM_DEV_DIR/$vg/$lv3"
+$INVALID lvconvert --type cache-pool --poolmetadata $vg2/$lv2 $vg1/$lv1
+
+$INVALID lvconvert --cachepool $vg1/$lv1 --poolmetadata $vg2/$lv2
+
+# Invalid syntax, vg is unknown
+$INVALID lvconvert --yes --cachepool $lv3 --poolmetadata $lv4
+
+# Invalid chunk size is <32KiB >1GiB
+$INVALID lvconvert --type cache-pool --chunksize 16 --poolmetadata $lv2 $vg/$lv1
+$INVALID lvconvert --type cache-pool --chunksize 2G --poolmetadata $lv2 $vg/$lv1
+
+# Invalid chunk size is bigger then data size, needs to open VG
+fail lvconvert --yes --type cache-pool --chunksize 16M --poolmetadata $lv2 $vg/$lv1
+
+lvremove -f $vg
+
+########################
+# Repair of cache pool #
+########################
+lvcreate --type cache-pool -an -v -L 2 -n cpool $vg
+lvcreate -H -L 4 -n corigin --cachepool $vg/cpool
+
+# unsupported yet
+fail lvconvert --repair $vg/cpool 2>&1 | tee out
+#grep "Cannot convert internal LV" out
+
+lvremove -f $vg
+
+#########################
+# Some testing variants #
+#########################
+
+for i in error zero
+do
+ lvcreate --type "$i" -L50G -n $lv1 $vg
+ lvcreate --type "$i" -L10G -n cpool $vg
+ lvconvert -y --cachepool $vg/cpool
+ lvconvert -y -H --cachepool $vg/cpool $vg/$lv1
+ lvremove -f $vg
+done
+
+##########################
+# Prohibited conversions #
+##########################
+lvcreate --type cache-pool -L10 $vg/$lv1
+lvcreate --cache -L20 $vg/$lv1
+lvcreate -L10 -n $lv2 $vg
+
+fail lvconvert --yes --type cache $vg/$lv2 --cachepool $vg/$lv1
+fail lvconvert --yes --type cache $vg/$lv1 --cachepool $vg/$lv2
+fail lvconvert --yes --type cache-pool $vg/$lv1
+fail lvconvert --yes --type mirror -m1 $vg/$lv1
+not aux have_raid 1 0 0 || fail lvconvert --yes --type raid1 -m1 $vg/$lv1
+fail lvconvert --yes --type snapshot $vg/$lv1 $vg/$lv2
+fail lvconvert --yes --type snapshot $vg/$lv2 $vg/$lv1
+not aux have_thin 1 0 0 || fail lvconvert --yes -T --thinpool $vg/$lv2 $vg/$lv1
+
+lvremove -f $vg
+
+vgremove -f $vg
diff --git a/test/shell/lvconvert-m-raid1-degraded.sh b/test/shell/lvconvert-m-raid1-degraded.sh
new file mode 100644
index 0000000..05c3e89
--- /dev/null
+++ b/test/shell/lvconvert-m-raid1-degraded.sh
@@ -0,0 +1,47 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2018 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+aux have_raid 1 3 0 || skip
+
+aux lvmconf 'activation/raid_fault_policy = "warn"'
+
+aux prepare_vg 3 32
+get_devs
+
+# Create 2-legged RAID1 and wait for it to complete initial resync
+lvcreate --type raid1 -m 1 -l 4 -n $lv $vg "$dev1" "$dev2"
+aux wait_for_sync $vg $lv
+
+# Disable first PV thus erroring first leg
+aux disable_dev "$dev1"
+
+# Reduce VG by missing PV
+vgreduce --force --removemissing $vg
+check raid_leg_status $vg $lv "DA"
+
+# Conversion to 2 legs must fail on degraded 2-legged raid1 LV
+not lvconvert -y -m1 $vg/$lv
+check raid_leg_status $vg $lv "DA"
+
+# Repair has to succeed
+lvconvert -y --repair $vg/$lv
+aux wait_for_sync $vg $lv
+check raid_leg_status $vg $lv "AA"
+
+lvremove -ff $vg/$lv
+
+vgremove -ff $vg
diff --git a/test/shell/lvconvert-mirror-basic-0.sh b/test/shell/lvconvert-mirror-basic-0.sh
index dc71bb8..02f32a9 100644
--- a/test/shell/lvconvert-mirror-basic-0.sh
+++ b/test/shell/lvconvert-mirror-basic-0.sh
@@ -1,4 +1,5 @@
-#!/bin/sh
+#!/usr/bin/env bash
+
# Copyright (C) 2010 Red Hat, Inc. All rights reserved.
#
# This copyrighted material is made available to anyone wishing to use,
@@ -7,7 +8,10 @@
#
# 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
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
. ./shell/lvconvert-mirror-basic.sh
+
test_many 0
+
+vgremove -ff $vg
diff --git a/test/shell/lvconvert-mirror-basic-1.sh b/test/shell/lvconvert-mirror-basic-1.sh
index b7ebf9e..76d1315 100644
--- a/test/shell/lvconvert-mirror-basic-1.sh
+++ b/test/shell/lvconvert-mirror-basic-1.sh
@@ -1,4 +1,5 @@
-#!/bin/sh
+#!/usr/bin/env bash
+
# Copyright (C) 2010 Red Hat, Inc. All rights reserved.
#
# This copyrighted material is made available to anyone wishing to use,
@@ -7,7 +8,10 @@
#
# 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
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
. ./shell/lvconvert-mirror-basic.sh
+
test_many 1
+
+vgremove -ff $vg
diff --git a/test/shell/lvconvert-mirror-basic-2.sh b/test/shell/lvconvert-mirror-basic-2.sh
index d47f77d..eb6de87 100644
--- a/test/shell/lvconvert-mirror-basic-2.sh
+++ b/test/shell/lvconvert-mirror-basic-2.sh
@@ -1,4 +1,5 @@
-#!/bin/sh
+#!/usr/bin/env bash
+
# Copyright (C) 2010 Red Hat, Inc. All rights reserved.
#
# This copyrighted material is made available to anyone wishing to use,
@@ -7,7 +8,10 @@
#
# 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
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
. ./shell/lvconvert-mirror-basic.sh
+
test_many 2
+
+vgremove -ff $vg
diff --git a/test/shell/lvconvert-mirror-basic-3.sh b/test/shell/lvconvert-mirror-basic-3.sh
index 732fb2d..fa4b3cd 100644
--- a/test/shell/lvconvert-mirror-basic-3.sh
+++ b/test/shell/lvconvert-mirror-basic-3.sh
@@ -1,4 +1,5 @@
-#!/bin/sh
+#!/usr/bin/env bash
+
# Copyright (C) 2010 Red Hat, Inc. All rights reserved.
#
# This copyrighted material is made available to anyone wishing to use,
@@ -7,7 +8,10 @@
#
# 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
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
. ./shell/lvconvert-mirror-basic.sh
+
test_many 3
+
+vgremove -ff $vg
diff --git a/test/shell/lvconvert-mirror-basic.sh b/test/shell/lvconvert-mirror-basic.sh
index a0f50f6..96d30d2 100644
--- a/test/shell/lvconvert-mirror-basic.sh
+++ b/test/shell/lvconvert-mirror-basic.sh
@@ -1,4 +1,5 @@
-#!/bin/sh
+#!/usr/bin/env bash
+
# Copyright (C) 2010-2012 Red Hat, Inc. All rights reserved.
#
# This copyrighted material is made available to anyone wishing to use,
@@ -7,9 +8,13 @@
#
# 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
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+
+
+. lib/inittest
-. lib/test
+aux lvmconf "global/support_mirrored_mirror_log=1"
log_name_to_count() {
case "$1" in
@@ -38,28 +43,27 @@ log_name_to_count() {
test_lvconvert() {
local start_count=$1
- local start_count_p1=$(($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_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 active="-aey"
local i
- test "$5" = "active" && active=false
+ test "$5" = "active" && active="-an"
#test $finish_count -gt $start_count && up=true
# Do we have enough devices for the mirror images?
- test $start_count_p1 -gt ${#dev_array[@]} && \
+ test $start_count_p1 -gt ${#DEVICES[@]} && \
die "Action requires too many devices"
# Do we have enough devices for the mirror images?
- test $finish_count_p1 -gt ${#dev_array[@]} && \
+ test $finish_count_p1 -gt ${#DEVICES[@]} && \
die "Action requires too many devices"
start_log_count=$(log_name_to_count $start_log_type)
@@ -72,30 +76,37 @@ test_lvconvert() {
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
+ if [ $(( start_count_p1 + start_log_count )) -gt ${#DEVICES[@]} ]; then
alloc="--alloc anywhere"
fi
- lvcreate -l2 -m $start_count --mirrorlog $start_log_type \
+ lvcreate "$active" -Zn -l2 --type mirror -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
+ lvcreate "$active" -Zn -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
+ if [ $(( finish_count_p1 + finish_log_count )) -gt ${#DEVICES[@]} ]; then
alloc="--alloc anywhere"
fi
- lvconvert -m $finish_count --mirrorlog $finish_log_type \
+ # --mirrorlog is invalid with -m0
+ if [ "$finish_count" -eq 0 ]; then
+ mirrorlog=""
+ finish_log_type=""
+ else
+ mirrorlog="--mirrorlog"
+ fi
+
+ lvconvert --type mirror -m $finish_count $mirrorlog $finish_log_type \
$vg/$lv1 $alloc
- test $active || lvchange -ay $vg/$lv1
+ test "$active" = "-an" || lvchange "$active" $vg/$lv1
check mirror_no_temporaries $vg $lv1
if [ "$finish_count_p1" -eq 1 ]; then
@@ -110,14 +121,18 @@ test_lvconvert() {
fi
}
-aux prepare_pvs 5 5
-vgcreate -c n -s 128k $vg $(cat DEVICES)
+aux prepare_vg 5 5
+get_devs
+
+MIRRORED="mirrored"
+# FIXME: Cluster is not supporting exlusive activation of mirrored log
+test -e LOCAL_CLVMD && MIRRORED=
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
+ 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"
diff --git a/test/shell/lvconvert-mirror-split.sh b/test/shell/lvconvert-mirror-split.sh
new file mode 100644
index 0000000..00291ec
--- /dev/null
+++ b/test/shell/lvconvert-mirror-split.sh
@@ -0,0 +1,32 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2018 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+# Check --splitmirrors for mirror segtype
+
+. lib/inittest
+
+aux prepare_vg 3
+
+###########################################
+# Mirror split tests
+###########################################
+# 3-way to 2-way/linear
+lvcreate -aey --type mirror -m 2 -l 2 -n $lv1 $vg
+aux wait_for_sync $vg $lv1
+lvconvert --splitmirrors 1 -n $lv2 -vvvv $vg/$lv1
+
+check lv_exists $vg $lv1
+check linear $vg $lv2
+check active $vg $lv2
+# FIXME: ensure no residual devices
+
+vgremove -ff $vg
diff --git a/test/shell/lvconvert-mirror-updown.sh b/test/shell/lvconvert-mirror-updown.sh
new file mode 100644
index 0000000..4aea496
--- /dev/null
+++ b/test/shell/lvconvert-mirror-updown.sh
@@ -0,0 +1,42 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2018 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+# Demonstrate problem when upconverting and cutting leg in clvmd
+
+
+
+. lib/inittest
+
+aux prepare_pvs 3 100
+get_devs
+
+vgcreate $SHARED -s 64k "$vg" "${DEVICES[@]}"
+
+# Use zero devices for big mirror legs
+aux zero_dev "$dev2" "$(get first_extent_sector "$dev2"):"
+aux zero_dev "$dev3" "$(get first_extent_sector "$dev3"):"
+
+lvcreate -aey -L90 --type mirror --corelog --regionsize 16k -m1 -n $lv1 $vg "$dev1" "$dev2"
+
+lvconvert -m+1 -b $vg/$lv1 "$dev3"
+
+
+# We want here ongoing conversion
+
+lvs -a -o+seg_pe_ranges $vg
+
+# Now it should be able to drop 2nd. leg
+lvconvert -m-1 $vg/$lv1 "$dev2"
+
+lvs -a $vg
+
+vgremove -f $vg
diff --git a/test/shell/lvconvert-mirror.sh b/test/shell/lvconvert-mirror.sh
index c09b8fd..17ed033 100644
--- a/test/shell/lvconvert-mirror.sh
+++ b/test/shell/lvconvert-mirror.sh
@@ -1,5 +1,6 @@
-#!/bin/sh
-# Copyright (C) 2010 Red Hat, Inc. All rights reserved.
+#!/usr/bin/env bash
+
+# Copyright (C) 2010-2018 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
@@ -7,116 +8,78 @@
#
# 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
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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"
+. lib/inittest
+
+aux lvmconf "global/support_mirrored_mirror_log=1"
+
+aux prepare_pvs 5
+get_devs
+
+# proper DEVRANGE needs to be set according to extent size
+DEVRANGE="0-32"
+vgcreate $SHARED -s 32k "$vg" "${DEVICES[@]}"
+
+# convert from linear to 2-way mirror ("mirror" default type)
+lvcreate -aey -l2 -n $lv1 $vg "$dev1"
+lvconvert -i1 -m+1 -R32k $vg/$lv1 "$dev2" "$dev3:0-1" \
+ --config 'global { mirror_segtype_default = "mirror" }'
+lvs --noheadings -o attr $vg/$lv1 | grep '^[[:space:]]*m'
+lvremove -ff $vg
+
+# convert from linear to 2-way mirror (override "raid1" default type)
+lvcreate -aey -l2 -n $lv1 $vg "$dev1"
+lvconvert -i1 --type mirror -m+1 $vg/$lv1 "$dev2" "$dev3:0-1" \
+ --config 'global { mirror_segtype_default = "raid1" }'
+lvs --noheadings -o attr $vg/$lv1 | grep '^[[:space:]]*m'
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 \
+lvcreate -aey -l2 -n $lv1 $vg --addtag hello
+lvconvert -i1 --type mirror -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
+lvcreate -aey -l2 --type mirror -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"
+lvcreate -aey -l2 --type mirror -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"
+lvcreate -aey -l2 --type mirror -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"
+lvcreate -aey -l2 --type mirror -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
+lvcreate -aey -l2 --type mirror -m1 --mirrorlog core -n $lv1 $vg "$dev1" "$dev2"
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"
+lvcreate -aey -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"
+lvcreate -aey -l2 --type mirror -m1 --mirrorlog core -n $lv1 $vg "$dev1" "$dev2"
lvconvert -m +1 -i1 $vg/$lv1
check mirror $vg $lv1 core
@@ -125,7 +88,7 @@ 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
+lvcreate -aey -l2 --type mirror -m2 --corelog -n $lv1 $vg
lvconvert -m -1 -i1 $vg/$lv1
check mirror $vg $lv1 core
@@ -135,7 +98,7 @@ 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
+#lvcreate -l2 --type mirror -m1 -n $lv1 $vg "$dev1" "$dev2" "$dev3":0
#lvconvert -m+1 -b $vg/$lv1 "$dev4"
#lvconvert -m+1 $vg/$lv1 "$dev5"
#
@@ -144,17 +107,11 @@ lvremove -ff $vg
#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"
+lvcreate -aey -l2 --type mirror -m1 -n $lv1 $vg "$dev1" "$dev2" "$dev3:$DEVRANGE"
lvchange -an $vg/$lv1
lvconvert -m+1 $vg/$lv1 "$dev4"
-lvchange -ay $vg/$lv1
+lvchange -aey $vg/$lv1
lvconvert $vg/$lv1 # wait
check mirror $vg $lv1 "$dev3"
check mirror_no_temporaries $vg $lv1
@@ -164,8 +121,8 @@ 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"
+lvcreate -aey -l2 --type mirror -m1 -n $lv1 $vg "$dev1" "$dev2" "$dev3:$DEVRANGE"
+LVM_TEST_TAG="kill_me_$PREFIX" lvconvert -m+1 -b $vg/$lv1 "$dev4"
lvconvert -m-1 $vg/$lv1 "$dev4"
lvconvert $vg/$lv1 # wait
@@ -175,8 +132,8 @@ 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"
+lvcreate -aey -l2 --type mirror -m1 -n $lv1 $vg "$dev1" "$dev2" "$dev3:$DEVRANGE"
+LVM_TEST_TAG="kill_me_$PREFIX" lvconvert -m+2 -b $vg/$lv1 "$dev4" "$dev5"
lvconvert -m-1 $vg/$lv1 "$dev4"
lvconvert $vg/$lv1 # wait
@@ -186,8 +143,12 @@ 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"
+lvcreate -aey -l2 --type mirror -m2 -n $lv1 $vg "$dev1" "$dev2" "$dev5" "$dev3:$DEVRANGE"
+LVM_TEST_TAG="kill_me_$PREFIX" lvconvert -m+1 -b $vg/$lv1 "$dev4"
+# FIXME: Extra wait here for mirror upconvert synchronization
+# otherwise we may fail her on parallel upconvert and downconvert
+# lvconvert-mirror-updown.sh tests this errornous case separately
+lvconvert $vg/$lv1
lvconvert -m-1 $vg/$lv1 "$dev2"
lvconvert $vg/$lv1
@@ -197,8 +158,12 @@ 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"
+lvcreate -aey -l2 --type mirror -m1 -n $lv1 $vg "$dev1" "$dev2" "$dev3:$DEVRANGE"
+LVM_TEST_TAG="kill_me_$PREFIX" lvconvert -m+1 -b $vg/$lv1 "$dev4"
+# FIXME: Extra wait here for mirror upconvert synchronization
+# otherwise we may fail her on parallel upconvert and downconvert
+# lvconvert-mirror-updown.sh tests this errornous case separately
+lvconvert $vg/$lv1
lvconvert -m-1 $vg/$lv1 "$dev2"
lvconvert $vg/$lv1
@@ -207,34 +172,44 @@ check mirror_no_temporaries $vg $lv1
check mirror_legs $vg $lv1 2
lvremove -ff $vg
-# ---------------------------------------------------------------------
+# Check the same with new --startpool lvconvert command option
+lvcreate -aey -l2 --type mirror -m1 -n $lv1 $vg "$dev1" "$dev2" "$dev3:$DEVRANGE"
+LVM_TEST_TAG="kill_me_$PREFIX" lvconvert -m+1 -b $vg/$lv1 "$dev4"
+# FIXME: Extra wait here for mirror upconvert synchronization
+# otherwise we may fail her on parallel upconvert and downconvert
+# lvconvert-mirror-updown.sh tests this errornous case separately
+lvconvert $vg/$lv1
+lvconvert -m-1 $vg/$lv1 "$dev2"
+lvconvert $vg/$lv1
-# "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
+check mirror $vg $lv1 "$dev3"
+check mirror_no_temporaries $vg $lv1
+check mirror_legs $vg $lv1 2
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
+# ---------------------------------------------------------------------
+
+# "rhbz264241: lvm mirror doesn't lose it's "M" --nosync attribute
+# after being down and the up converted"
+lvcreate -aey -l2 --type mirror -m1 -n $lv1 --nosync $vg
lvconvert -m0 $vg/$lv1
-lvconvert -m1 $vg/$lv1
-lvs --noheadings -o attr $vg/$lv1 | grep '^ *m'
+lvconvert --type mirror -m1 $vg/$lv1
+lvs --noheadings -o attr $vg/$lv1 | grep '^[[:space:]]*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
+lvcreate -aey -l 8 -n $lv1 $vg "$dev1:0-3" "$dev2:0-3"
+lvconvert --type mirror -m1 $vg/$lv1
-should check mirror $vg $lv1
+# FIXME: lvm should be able to make legs redundant
+#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"
+lvcreate -aey -l1 --type mirror -m2 --corelog -n $lv1 $vg "$dev1" "$dev2" "$dev3"
aux wait_for_sync $vg $lv1
-lvconvert -m1 --mirrorlog disk $vg/$lv1
+lvconvert --type mirror -m1 --mirrorlog disk $vg/$lv1
check mirror $vg $lv1
not check mirror $vg $lv1 core
lvremove -ff $vg
@@ -243,10 +218,10 @@ lvremove -ff $vg
# add mirror and disk log
# "add 1 mirror and disk log"
-lvcreate -l2 -m1 --mirrorlog core -n $lv1 $vg "$dev1" "$dev2"
+lvcreate -aey -l2 --type mirror -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"
+lvconvert -m+1 --mirrorlog disk -i1 $vg/$lv1 "$dev4" "$dev3:$DEVRANGE"
check mirror $vg $lv1 "$dev3"
check mirror_no_temporaries $vg $lv1
@@ -254,27 +229,143 @@ check mirror_legs $vg $lv1 3
lvremove -ff $vg
# simple mirrored stripe
-lvcreate -i2 -l10 -n $lv1 $vg
-lvconvert -m1 -i1 $vg/$lv1
+lvcreate -aey -i2 -l10 -n $lv1 $vg
+# FIXME: ATM reduce LV still must be bigger then region size!
+# LVM should do a better job here
+lvconvert --type mirror -m1 -i1 --regionsize 16k $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
+lvcreate -aey -l15 -n $lv1 $vg
+not lvconvert --type mirror -m1 --corelog --stripes 2 $vg/$lv1
+lvremove -ff $vg
+
+
+# Linear to mirror with mirrored log using --alloc anywhere
+lvcreate -aey -l2 -n $lv1 $vg "$dev1"
+if test -e LOCAL_CLVMD; then
+# This is not supposed to work in cluster
+not lvconvert --type mirror -m +1 --mirrorlog mirrored --alloc anywhere $vg/$lv1 "$dev1" "$dev2"
+else
+lvconvert --type mirror -m +1 --mirrorlog mirrored --alloc anywhere $vg/$lv1 "$dev1" "$dev2"
+check mirror $vg $lv1
+fi
lvremove -ff $vg
+
+if test -e LOCAL_CLVMD; then
+: # FIXME - cases which needs to be fixed to work in cluster
+else
# 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
+lvcreate -aey --type mirror -m 1 -l1 -n $lv1 $vg --nosync
not lvconvert -m +1 $vg/$lv1
-lvchange --resync -y $vg/$lv1
+lvchange -aey --resync -y $vg/$lv1
lvconvert -m +1 $vg/$lv1
lvremove -ff $vg
-lvcreate -m 1 --corelog -l1 -n $lv1 $vg --nosync
+lvcreate -aey --type mirror -m 1 --corelog -l1 -n $lv1 $vg --nosync
not lvconvert -m +1 $vg/$lv1
-lvchange --resync -y $vg/$lv1
+lvchange -aey --resync -y $vg/$lv1
lvconvert -m +1 $vg/$lv1
lvremove -ff $vg
+
+# FIXME: Cluster exclusive activation does not work here
+# unsure why lib/metadata/mirror.c
+# has this code:
+#
+# } else if (vg_is_clustered(vg)) {
+# log_error("Unable to convert the log of an inactive "
+# "cluster mirror, %s", lv->name);
+# return 0;
+# disabling this in the code passes this test
+
+# bz192865: lvconvert log of an inactive mirror lv
+# convert from disklog to corelog, inactive
+lvcreate -aey -l2 --type mirror -m1 -n $lv1 $vg "$dev1" "$dev2" "$dev3:0-1"
+lvchange -an $vg/$lv1
+lvconvert -y -f --mirrorlog core $vg/$lv1
+check mirror $vg $lv1 core
+lvremove -ff $vg
+
+# convert from corelog to disklog, inactive
+lvcreate -aey -l2 --type mirror -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
+
+# bz1272175: check lvconvert reports progress while waiting for mirror
+# to get synced
+lvcreate -l2 -n $lv1 $vg
+lvconvert --type mirror -i1 -m1 $vg/$lv1 | tee out
+grep -e "$vg/$lv1: Converted:" out || die "Missing sync info in foreground mode"
+lvremove -ff $vg
+fi
+
+
+#########################################################################
+# Start w/ 3-way mirror
+# Test that the correct devices remain in the mirror
+# Make $dev2 & $dev4 zero backend device so large mirrors can be user
+# without consuming any real space. Clearly such mirrors can't be read back
+# but tests here are validating possibilies of those conversions
+#
+# Test pulling primary image before mirror in-sync (should fail)
+# Test pulling primary image after mirror in-sync (should work)
+#
+aux zero_dev "$dev2" "$(get first_extent_sector "$dev2"):"
+aux zero_dev "$dev4" "$(get first_extent_sector "$dev4"):"
+
+SHOULD=
+aux throttle_dm_mirror || SHOULD=should
+
+# Use large enough mirror that takes time to sychronize with small regionsize
+lvcreate -aey -L30 -Zn -Wn --type mirror --regionsize 16k -m2 -n $lv1 $vg "$dev1" "$dev2" "$dev4" "$dev3:$DEVRANGE"
+$SHOULD not lvconvert -m-1 $vg/$lv1 "$dev1" 2>&1 | tee out
+aux restore_dm_mirror
+grep "not in-sync" out
+
+lvconvert $vg/$lv1 # wait
+
+lvconvert -m-1 $vg/$lv1 "$dev1"
+check mirror_images_on $vg $lv1 "$dev2" "$dev4"
+lvconvert -m-1 $vg/$lv1 "$dev2"
+check linear $vg $lv1
+check lv_on $vg $lv1 "$dev4"
+lvremove -ff $vg
+
+
+aux throttle_dm_mirror || :
+# No parallel lvconverts on a single LV please
+# Use big enough mirror size and small regionsize to run on all test machines succesfully
+lvcreate -aey -Zn -Wn -L30 --type mirror --regionsize 16k -m1 -n $lv1 $vg "$dev1" "$dev2" "$dev3:0-8"
+check mirror $vg $lv1
+check mirror_legs $vg $lv1 2
+
+LVM_TEST_TAG="kill_me_$PREFIX" lvconvert -m+1 -b $vg/$lv1 "$dev4"
+# ATM upconversion should be running
+
+# Next convert should fail b/c we can't have 2 at once
+$SHOULD not lvconvert -m+1 $vg/$lv1 "$dev5" 2>&1 | tee out
+aux restore_dm_mirror
+grep "is already being converted" out
+
+lvconvert $vg/$lv1 # wait
+check mirror $vg $lv1 "$dev3"
+check mirror_no_temporaries $vg $lv1
+check mirror_legs $vg $lv1 3
+lvremove -ff $vg
+
+
+# "rhbz440405: lvconvert -m0 incorrectly fails if all PEs allocated"
+lvcreate -aey -l "$(get pv_field "$dev1" pe_count)" --type mirror -m1 -n $lv1 $vg "$dev1" "$dev2" "$dev3:$DEVRANGE"
+lvs -a -o+seg_pe_ranges $vg
+aux wait_for_sync $vg $lv1
+lvconvert -m0 $vg/$lv1 "$dev1"
+check linear $vg $lv1
+lvremove -ff $vg
+
+vgremove -ff $vg
diff --git a/test/shell/lvconvert-raid-allocation.sh b/test/shell/lvconvert-raid-allocation.sh
new file mode 100644
index 0000000..5420d58
--- /dev/null
+++ b/test/shell/lvconvert-raid-allocation.sh
@@ -0,0 +1,81 @@
+#!/usr/bin/env 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+aux have_raid 1 3 0 || skip
+
+aux prepare_pvs 5
+get_devs
+
+vgcreate $SHARED -s 256k "$vg" "${DEVICES[@]}"
+
+# Start with linear on 2 PV and ensure that converting to
+# RAID is not allowed to reuse PVs for different images. (Bug 1113180)
+lvcreate -aey -l 4 -n $lv1 $vg "$dev1:0-1" "$dev2:0-1"
+not lvconvert -y --type raid1 -m 1 $vg/$lv1 "$dev1" "$dev2"
+not lvconvert -y --type raid1 -m 1 $vg/$lv1 "$dev1" "$dev3:0-2"
+lvconvert -y --type raid1 -m 1 $vg/$lv1 "$dev3"
+not lvconvert -m 0 $vg/$lv1
+lvconvert -y -m 0 $vg/$lv1
+# RAID conversions are not honoring allocation policy!
+# lvconvert -y --type raid1 -m 1 --alloc anywhere $vg/$lv1 "$dev1" "$dev2"
+lvremove -ff $vg
+
+
+# Setup 2-way RAID1 LV, spread across 4 devices.
+# For each image:
+# - metadata LV + 1 image extent (2 total extents) on one PV
+# - 2 image extents on the other PV
+# Then attempt allocation of another image from 2 extents on
+# a 5th PV and the remainder of the rest of already used PVs.
+#
+# This should fail because there is insufficient space on the
+# non-parallel PV (i.e. there is not enough space for the image
+# if it doesn't share a PV with another image).
+lvcreate --type raid1 -m 1 -l 3 -n $lv1 $vg \
+ "$dev1:0-1" "$dev2:0-1" "$dev3:0-1" "$dev4:0-1"
+aux wait_for_sync $vg $lv1
+# Should not be enough non-overlapping space.
+not lvconvert -m +1 $vg/$lv1 \
+ "$dev5:0-1" "$dev1" "$dev2" "$dev3" "$dev4"
+lvconvert -y -m +1 $vg/$lv1 "$dev5"
+aux wait_for_sync $vg $lv1
+# Cannot pass without --yes
+not lvconvert -m 0 $vg/$lv1
+lvconvert -y -m 0 $vg/$lv1
+# Should work due to '--alloc anywhere'
+# RAID conversion not honoring allocation policy!
+#lvconvert -y -m +1 --alloc anywhere $vg/$lv1 \
+# "$dev5:0-1" "$dev1" "$dev2" "$dev3" "$dev4"
+lvremove -ff $vg
+
+
+# Setup 2-way RAID1 LV, spread across 4 devices
+# - metadata LV + 1 image extent (2 total extents) on one PV
+# - 2 image extents on the other PV
+# Kill one PV. There should be enough space on the remaining
+# PV for that image to reallocate the entire image there and
+# still maintain redundancy.
+lvcreate --type raid1 -m 1 -l 3 -n $lv1 $vg \
+ "$dev1:0-1" "$dev2:0-1" "$dev3:0-1" "$dev4:0-1"
+aux wait_for_sync $vg $lv1
+aux disable_dev "$dev1"
+lvconvert -y --repair $vg/$lv1 "$dev2" "$dev3" "$dev4"
+#FIXME: ensure non-overlapping images (they should not share PVs)
+aux enable_dev "$dev1"
+lvremove -ff $vg
+
+vgremove -ff $vg
diff --git a/test/shell/lvconvert-raid-regionsize.sh b/test/shell/lvconvert-raid-regionsize.sh
new file mode 100644
index 0000000..23d54d0
--- /dev/null
+++ b/test/shell/lvconvert-raid-regionsize.sh
@@ -0,0 +1,104 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2017 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+which mkfs.ext4 || skip
+aux have_raid 1 9 0 || skip
+
+aux prepare_vg 6
+
+function _test_regionsize
+{
+ local type=$1
+ local regionsize=$2
+ local regionsize_str=$3
+ local vg=$4
+ local lv=$5
+
+ lvconvert --type "$type" --yes -R "$regionsize" "$vg/$lv"
+ check lv_field $vg/$lv regionsize "$regionsize_str"
+
+ not lvconvert --regionsize "$regionsize" "$vg/$lv" 2>err
+ grep "is already" err
+
+ fsck -fn "$DM_DEV_DIR/$vg/$lv"
+}
+
+function _test_regionsizes
+{
+ # FIXME: have to provide raid type or region size ain't set until cli validation merged
+ local type=$1
+
+ # Test RAID regionsize changes
+ _test_regionsize "$type" 128K "128.00k" $vg $lv1
+ _test_regionsize "$type" 256K "256.00k" $vg $lv1
+ not _test_regionsize "$type" 1K "1.00k" $vg $lv1
+ _test_regionsize "$type" 1m "1.00m" $vg $lv1
+ not _test_regionsize "$type" 1G "1.00g" $vg $lv1
+ not _test_regionsize "$type" 16K "16.00k" $vg $lv1
+}
+
+# Create 3-way raid1
+lvcreate --yes -aey --type raid1 -m 2 -R64K -L8M -n $lv1 $vg
+check lv_field $vg/$lv1 segtype "raid1"
+check lv_field $vg/$lv1 stripes 3
+check lv_field $vg/$lv1 regionsize "64.00k"
+mkfs.ext4 "$DM_DEV_DIR/$vg/$lv1"
+aux wait_for_sync $vg $lv1
+fsck -fn "$DM_DEV_DIR/$vg/$lv1"
+
+_test_regionsizes raid1
+
+# Clean up
+lvremove --yes $vg
+
+# Needs reshaping kernel for raid6 conversion
+if aux have_raid 1 14 0; then
+# Create 5-way raid6
+lvcreate --yes -aey --type raid6 -i 3 --stripesize 128K -R 256K -L8M -n $lv1 $vg
+check lv_field $vg/$lv1 segtype "raid6"
+check lv_field $vg/$lv1 stripes 5
+check lv_field $vg/$lv1 stripesize "128.00k"
+check lv_field $vg/$lv1 regionsize "256.00k"
+mkfs.ext4 "$DM_DEV_DIR/$vg/$lv1"
+aux wait_for_sync $vg $lv1
+fsck -fn "$DM_DEV_DIR/$vg/$lv1"
+
+_test_regionsizes raid6
+
+# Clean up
+lvremove --yes $vg
+else
+ echo "Skipping RAID6 tests"
+fi
+
+if aux have_raid 1 12 0; then
+# Create 6-way raid01
+lvcreate --yes -aey --type raid10 -i 3 -m 1 --stripesize 128K -R 256K -L8M -n $lv1 $vg
+check lv_field $vg/$lv1 segtype "raid10"
+check lv_field $vg/$lv1 stripes 6
+check lv_field $vg/$lv1 stripesize "128.00k"
+check lv_field $vg/$lv1 regionsize "256.00k"
+mkfs.ext4 -t ext4 "$DM_DEV_DIR/$vg/$lv1"
+aux wait_for_sync $vg $lv1
+fsck -fn "$DM_DEV_DIR/$vg/$lv1"
+
+_test_regionsizes raid10
+else
+ echo "Skipping RAID10 tests"
+fi
+
+vgremove -ff $vg
diff --git a/test/shell/lvconvert-raid-reshape-linear_to_raid6-single-type.sh b/test/shell/lvconvert-raid-reshape-linear_to_raid6-single-type.sh
new file mode 100644
index 0000000..731f006
--- /dev/null
+++ b/test/shell/lvconvert-raid-reshape-linear_to_raid6-single-type.sh
@@ -0,0 +1,102 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2018 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., 51 Franklin Street, Fifth Floor, Boston, MA2110-1301 USA
+
+SKIP_WITH_LVMLOCKD=1
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+# Ensure expected default region size
+aux lvmconf 'activation/raid_region_size = 512'
+
+which mkfs.ext4 || skip
+aux have_raid 1 14 0 || skip
+
+aux prepare_vg 5
+
+#
+# Test multi step linear -> striped conversion
+#
+
+# Create linear LV
+lvcreate -aey -L 16M -n $lv $vg
+check lv_field $vg/$lv segtype "linear"
+check lv_field $vg/$lv stripes 1
+check lv_field $vg/$lv data_stripes 1
+wipefs -a "$DM_DEV_DIR/$vg/$lv"
+mkfs -t ext4 "$DM_DEV_DIR/$vg/$lv"
+fsck -fn "$DM_DEV_DIR/$vg/$lv"
+
+# Convert linear -> raid1 (takeover)
+lvconvert -y --type raid6 --stripes 3 --stripesize 64K --regionsize 128K $vg/$lv
+fsck -fn "$DM_DEV_DIR/$vg/$lv"
+check lv_field $vg/$lv segtype "raid1"
+check lv_field $vg/$lv stripes 2
+check lv_field $vg/$lv data_stripes 2
+check lv_field $vg/$lv regionsize "128.00k"
+aux wait_for_sync $vg $lv
+fsck -fn "$DM_DEV_DIR/$vg/$lv"
+
+# Convert raid1 -> raid5_ls (takeover)
+lvconvert -y --type raid6 --stripes 3 --stripesize 64K --regionsize 128K $vg/$lv
+fsck -fn "$DM_DEV_DIR/$vg/$lv"
+check lv_field $vg/$lv segtype "raid5_ls"
+check lv_field $vg/$lv stripes 2
+check lv_field $vg/$lv data_stripes 1
+check lv_field $vg/$lv stripesize "64.00k"
+check lv_field $vg/$lv regionsize "128.00k"
+
+# Convert raid5_ls adding stripes (reshape)
+lvconvert -y --type raid6 --stripes 3 --stripesize 64K --regionsize 128K $vg/$lv
+fsck -fn "$DM_DEV_DIR/$vg/$lv"
+check lv_first_seg_field $vg/$lv segtype "raid5_ls"
+check lv_first_seg_field $vg/$lv stripes 4
+check lv_first_seg_field $vg/$lv data_stripes 3
+check lv_first_seg_field $vg/$lv stripesize "64.00k"
+check lv_first_seg_field $vg/$lv regionsize "128.00k"
+check lv_first_seg_field $vg/$lv reshape_len_le 8
+aux wait_for_sync $vg $lv
+fsck -fn "$DM_DEV_DIR/$vg/$lv"
+
+# Convert raid5_ls -> raid6_ls_6 (takeover)
+lvconvert -y --type raid6 --stripes 3 --stripesize 64K --regionsize 128K $vg/$lv
+fsck -fn "$DM_DEV_DIR/$vg/$lv"
+check lv_first_seg_field $vg/$lv segtype "raid6_ls_6"
+check lv_first_seg_field $vg/$lv stripes 5
+check lv_first_seg_field $vg/$lv data_stripes 3
+check lv_first_seg_field $vg/$lv stripesize "64.00k"
+check lv_first_seg_field $vg/$lv regionsize "128.00k"
+check lv_first_seg_field $vg/$lv reshape_len_le 0
+aux wait_for_sync $vg $lv
+
+# Convert raid6_ls_6 -> raid6(_zr) (reshape)
+lvconvert -y --type raid6 --stripes 3 --stripesize 64K --regionsize 128K $vg/$lv
+fsck -fn "$DM_DEV_DIR/$vg/$lv"
+check lv_first_seg_field $vg/$lv segtype "raid6"
+check lv_first_seg_field $vg/$lv stripes 5
+check lv_first_seg_field $vg/$lv data_stripes 3
+check lv_first_seg_field $vg/$lv stripesize "64.00k"
+check lv_first_seg_field $vg/$lv regionsize "128.00k"
+check lv_first_seg_field $vg/$lv reshape_len_le 10
+aux wait_for_sync $vg $lv
+
+# Remove reshape space
+lvconvert -y --type raid6 --stripes 3 --stripesize 64K --regionsize 128K $vg/$lv
+fsck -fn "$DM_DEV_DIR/$vg/$lv"
+check lv_first_seg_field $vg/$lv segtype "raid6"
+check lv_first_seg_field $vg/$lv stripes 5
+check lv_first_seg_field $vg/$lv data_stripes 3
+check lv_first_seg_field $vg/$lv stripesize "64.00k"
+check lv_first_seg_field $vg/$lv regionsize "128.00k"
+check lv_first_seg_field $vg/$lv reshape_len_le 0
+
+vgremove -ff $vg
diff --git a/test/shell/lvconvert-raid-reshape-linear_to_striped-single-type.sh b/test/shell/lvconvert-raid-reshape-linear_to_striped-single-type.sh
new file mode 100644
index 0000000..09f90dc
--- /dev/null
+++ b/test/shell/lvconvert-raid-reshape-linear_to_striped-single-type.sh
@@ -0,0 +1,78 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2018 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., 51 Franklin Street, Fifth Floor, Boston, MA2110-1301 USA
+
+SKIP_WITH_LVMLOCKD=1
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+aux lvmconf 'activation/raid_region_size = 512'
+
+which mkfs.ext4 || skip
+aux have_raid 1 14 0 || skip
+
+aux prepare_vg 5
+
+#
+# Test multi step linear -> striped conversion
+#
+
+# Create linear LV
+lvcreate -aey -L 16M -n $lv $vg
+check lv_field $vg/$lv segtype "linear"
+check lv_field $vg/$lv stripes 1
+check lv_field $vg/$lv data_stripes 1
+wipefs -a "$DM_DEV_DIR/$vg/$lv"
+mkfs -t ext4 "$DM_DEV_DIR/$vg/$lv"
+fsck -fn "$DM_DEV_DIR/$vg/$lv"
+
+# Convert linear -> raid1
+lvconvert -y --type striped --stripes 4 --stripesize 64K --regionsize 128K $vg/$lv
+fsck -fn "$DM_DEV_DIR/$vg/$lv"
+check lv_field $vg/$lv segtype "raid1"
+check lv_field $vg/$lv stripes 2
+check lv_field $vg/$lv data_stripes 2
+check lv_field $vg/$lv regionsize "128.00k"
+aux wait_for_sync $vg $lv
+fsck -fn "$DM_DEV_DIR/$vg/$lv"
+
+# Convert raid1 -> raid5_n
+lvconvert -y --type striped --stripes 4 --stripesize 64K --regionsize 128K $vg/$lv
+fsck -fn "$DM_DEV_DIR/$vg/$lv"
+check lv_field $vg/$lv segtype "raid5_n"
+check lv_field $vg/$lv stripes 2
+check lv_field $vg/$lv data_stripes 1
+check lv_field $vg/$lv stripesize "64.00k"
+check lv_field $vg/$lv regionsize "128.00k"
+
+# Convert raid5_n adding stripes
+lvconvert -y --type striped --stripes 4 --stripesize 64K --regionsize 128K $vg/$lv
+fsck -fn "$DM_DEV_DIR/$vg/$lv"
+check lv_first_seg_field $vg/$lv segtype "raid5_n"
+check lv_first_seg_field $vg/$lv data_stripes 4
+check lv_first_seg_field $vg/$lv stripes 5
+check lv_first_seg_field $vg/$lv data_stripes 4
+check lv_first_seg_field $vg/$lv stripesize "64.00k"
+check lv_first_seg_field $vg/$lv regionsize "128.00k"
+check lv_first_seg_field $vg/$lv reshape_len_le 10
+aux wait_for_sync $vg $lv
+fsck -fn "$DM_DEV_DIR/$vg/$lv"
+
+# Convert raid5_n -> striped
+lvconvert -y --type striped --stripes 4 --stripesize 64K --regionsize 128K $vg/$lv
+fsck -fn "$DM_DEV_DIR/$vg/$lv"
+check lv_first_seg_field $vg/$lv segtype "striped"
+check lv_first_seg_field $vg/$lv stripes 4
+check lv_first_seg_field $vg/$lv data_stripes 4
+check lv_first_seg_field $vg/$lv stripesize "64.00k"
+
+vgremove -ff $vg
diff --git a/test/shell/lvconvert-raid-reshape-linear_to_striped.sh b/test/shell/lvconvert-raid-reshape-linear_to_striped.sh
new file mode 100644
index 0000000..7df25f1
--- /dev/null
+++ b/test/shell/lvconvert-raid-reshape-linear_to_striped.sh
@@ -0,0 +1,72 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2017 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., 51 Franklin Street, Fifth Floor, Boston, MA2110-1301 USA
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+aux lvmconf 'activation/raid_region_size = 512'
+
+which mkfs.ext4 || skip
+aux have_raid 1 14 0 || skip
+
+aux prepare_vg 5
+
+#
+# Test single step linear -> striped conversion
+#
+
+# Create linear LV
+lvcreate -aey -L 16M -n $lv1 $vg
+check lv_field $vg/$lv1 segtype "linear"
+check lv_field $vg/$lv1 stripes 1
+check lv_field $vg/$lv1 data_stripes 1
+wipefs -a "$DM_DEV_DIR/$vg/$lv1"
+mkfs -t ext4 "$DM_DEV_DIR/$vg/$lv1"
+fsck -fn "$DM_DEV_DIR/$vg/$lv1"
+
+# Convert linear -> raid1
+lvconvert -y -m 1 $vg/$lv1
+fsck -fn "$DM_DEV_DIR/$vg/$lv1"
+check lv_field $vg/$lv1 segtype "raid1"
+check lv_field $vg/$lv1 stripes 2
+check lv_field $vg/$lv1 data_stripes 2
+check lv_field $vg/$lv1 regionsize "512.00k"
+aux wait_for_sync $vg $lv1
+fsck -fn "$DM_DEV_DIR/$vg/$lv1"
+
+# Convert raid1 -> raid5_n
+lvconvert -y --ty raid5_n --stripesize 64K --regionsize 512K $vg/$lv1
+fsck -fn "$DM_DEV_DIR/$vg/$lv1"
+check lv_field $vg/$lv1 segtype "raid5_n"
+check lv_field $vg/$lv1 stripes 2
+check lv_field $vg/$lv1 data_stripes 1
+check lv_field $vg/$lv1 stripesize "64.00k"
+check lv_field $vg/$lv1 regionsize "512.00k"
+
+# Convert raid5_n adding stripes
+lvconvert -y --stripes 4 $vg/$lv1
+fsck -fn "$DM_DEV_DIR/$vg/$lv1"
+check lv_first_seg_field $vg/$lv1 segtype "raid5_n"
+check lv_first_seg_field $vg/$lv1 data_stripes 4
+check lv_first_seg_field $vg/$lv1 stripes 5
+check lv_first_seg_field $vg/$lv1 stripesize "64.00k"
+check lv_first_seg_field $vg/$lv1 regionsize "512.00k"
+check lv_first_seg_field $vg/$lv1 reshape_len_le 10
+aux wait_for_sync $vg $lv1
+fsck -fn "$DM_DEV_DIR/$vg/$lv1"
+
+# Convert raid5_n -> striped
+lvconvert -y --type striped $vg/$lv1
+fsck -fn "$DM_DEV_DIR/$vg/$lv1"
+
+vgremove -ff $vg
diff --git a/test/shell/lvconvert-raid-reshape-load.sh b/test/shell/lvconvert-raid-reshape-load.sh
new file mode 100644
index 0000000..5b381ac
--- /dev/null
+++ b/test/shell/lvconvert-raid-reshape-load.sh
@@ -0,0 +1,75 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2017 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., 51 Franklin Street, Fifth Floor, Boston, MA2110-1301 USA
+
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+case "$(uname -r)" in
+5.19*) skip "Skippen test that kills this kernel" ;;
+esac
+
+# Test reshaping under io load
+
+which mkfs.ext4 || skip
+aux have_raid 1 14 0 || skip
+
+mount_dir="mnt"
+
+cleanup_mounted_and_teardown()
+{
+ umount "$mount_dir" || true
+ aux teardown
+}
+
+aux prepare_pvs 16 32
+
+get_devs
+
+vgcreate $SHARED -s 1M "$vg" "${DEVICES[@]}"
+
+trap 'cleanup_mounted_and_teardown' EXIT
+
+# Create 13-way striped raid5 (14 legs total)
+lvcreate --yes --type raid5_ls --stripes 13 -L4 -n$lv1 $vg
+check lv_first_seg_field $vg/$lv1 segtype "raid5_ls"
+check lv_first_seg_field $vg/$lv1 data_stripes 13
+check lv_first_seg_field $vg/$lv1 stripes 14
+wipefs -a "$DM_DEV_DIR/$vg/$lv1"
+mkfs -t ext4 "$DM_DEV_DIR/$vg/$lv1"
+aux wait_for_sync $vg $lv1
+
+mkdir -p $mount_dir
+mount "$DM_DEV_DIR/$vg/$lv1" $mount_dir
+mkdir -p $mount_dir/1 $mount_dir/2
+
+aux delay_dev "$dev2" 0 100
+
+echo 3 >/proc/sys/vm/drop_caches
+cp -r /usr/bin $mount_dir/1 >/dev/null 2>/dev/null &
+cp -r /usr/bin $mount_dir/2 >/dev/null 2>/dev/null &
+sync &
+
+# Reshape it to 256K stripe size
+lvconvert --yes --stripesize 256 $vg/$lv1
+aux delay_dev "$dev2" 0 0
+check lv_first_seg_field $vg/$lv1 stripesize "256.00k"
+
+kill -9 %%
+wait
+
+umount $mount_dir
+
+fsck -fn "$DM_DEV_DIR/$vg/$lv1"
+
+vgremove -ff $vg
diff --git a/test/shell/lvconvert-raid-reshape-striped_to_linear-single-type.sh b/test/shell/lvconvert-raid-reshape-striped_to_linear-single-type.sh
new file mode 100644
index 0000000..d7d4715
--- /dev/null
+++ b/test/shell/lvconvert-raid-reshape-striped_to_linear-single-type.sh
@@ -0,0 +1,86 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2018 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., 51 Franklin Street, Fifth Floor, Boston, MA2110-1301 USA
+
+SKIP_WITH_LVMLOCKD=1
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+aux lvmconf 'activation/raid_region_size = 512'
+
+which mkfs.ext4 || skip
+aux have_raid 1 14 0 || skip
+
+aux prepare_vg 5
+
+#
+# Test multi step striped -> linear conversion
+#
+
+# Create 4-way striped LV
+lvcreate -aey --type striped -L 16M --stripes 4 --stripesize 64K -n $lv $vg
+check lv_first_seg_field $vg/$lv segtype "striped"
+check lv_first_seg_field $vg/$lv stripes 4
+check lv_first_seg_field $vg/$lv data_stripes 4
+check lv_first_seg_field $vg/$lv stripesize "64.00k"
+wipefs -a "$DM_DEV_DIR/$vg/$lv"
+mkfs -t ext4 "$DM_DEV_DIR/$vg/$lv"
+fsck -fn "$DM_DEV_DIR/$vg/$lv"
+lvextend -y -L64M $vg/$lv
+
+# Convert striped -> raid5_n
+lvconvert -y --type linear $vg/$lv
+check lv_field $vg/$lv segtype "raid5_n"
+check lv_field $vg/$lv data_stripes 4
+check lv_field $vg/$lv stripes 5
+check lv_field $vg/$lv data_stripes 4
+check lv_field $vg/$lv stripesize "64.00k"
+check lv_field $vg/$lv regionsize "512.00k"
+check lv_field $vg/$lv reshape_len_le 0
+aux wait_for_sync $vg $lv
+fsck -fn "$DM_DEV_DIR/$vg/$lv"
+
+# Restripe raid5_n LV to single data stripe
+#
+# Need --force in order to remove stripes thus shrinking LV size!
+lvconvert -y --force --type linear $vg/$lv
+aux wait_for_sync $vg $lv 1
+fsck -fn "$DM_DEV_DIR/$vg/$lv"
+# Remove the now freed stripes
+lvconvert -y --type linear $vg/$lv
+check lv_field $vg/$lv segtype "raid5_n"
+check lv_field $vg/$lv stripes 2
+check lv_field $vg/$lv data_stripes 1
+check lv_field $vg/$lv stripesize "64.00k"
+check lv_field $vg/$lv regionsize "512.00k"
+check lv_field $vg/$lv reshape_len_le 4
+
+# Convert raid5_n -> raid1
+lvconvert -y --type linear $vg/$lv
+check lv_field $vg/$lv segtype "raid1"
+check lv_field $vg/$lv stripes 2
+check lv_field $vg/$lv data_stripes 2
+check lv_field $vg/$lv stripesize 0
+check lv_field $vg/$lv regionsize "512.00k"
+check lv_field $vg/$lv reshape_len_le ""
+fsck -fn "$DM_DEV_DIR/$vg/$lv"
+
+# Convert raid1 -> linear
+lvconvert -y --type linear $vg/$lv
+check lv_first_seg_field $vg/$lv segtype "linear"
+check lv_first_seg_field $vg/$lv stripes 1
+check lv_first_seg_field $vg/$lv data_stripes 1
+check lv_first_seg_field $vg/$lv stripesize 0
+check lv_first_seg_field $vg/$lv regionsize 0
+fsck -fn "$DM_DEV_DIR/$vg/$lv"
+
+vgremove -ff $vg
diff --git a/test/shell/lvconvert-raid-reshape-striped_to_linear.sh b/test/shell/lvconvert-raid-reshape-striped_to_linear.sh
new file mode 100644
index 0000000..ab075e1
--- /dev/null
+++ b/test/shell/lvconvert-raid-reshape-striped_to_linear.sh
@@ -0,0 +1,115 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2017 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., 51 Franklin Street, Fifth Floor, Boston, MA2110-1301 USA
+
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+aux lvmconf 'activation/raid_region_size = 512'
+
+which mkfs.ext4 || skip
+aux have_raid 1 14 0 || skip
+
+aux prepare_vg 5 20
+
+#
+# Test single step linear -> striped conversion
+#
+
+# Create 4-way striped LV
+lvcreate -aey -i 4 -I 32k -L 16M -n $lv1 $vg
+check lv_field $vg/$lv1 segtype "striped"
+check lv_field $vg/$lv1 data_stripes 4
+check lv_field $vg/$lv1 stripes 4
+check lv_field $vg/$lv1 stripesize "32.00k"
+check lv_field $vg/$lv1 reshape_len_le ""
+wipefs -a "$DM_DEV_DIR/$vg/$lv1"
+mkfs -t ext4 "$DM_DEV_DIR/$vg/$lv1"
+fsck -fn "$DM_DEV_DIR/$vg/$lv1"
+
+# Convert striped -> raid5(_n)
+lvconvert -y --ty raid5 -R 128k $vg/$lv1
+fsck -fn "$DM_DEV_DIR/$vg/$lv1"
+check lv_field $vg/$lv1 segtype "raid5_n"
+check lv_field $vg/$lv1 data_stripes 4
+check lv_field $vg/$lv1 stripes 5
+check lv_field $vg/$lv1 stripesize "32.00k"
+check lv_field $vg/$lv1 regionsize "128.00k"
+check lv_field $vg/$lv1 reshape_len_le 0
+aux wait_for_sync $vg $lv1
+fsck -fn "$DM_DEV_DIR/$vg/$lv1"
+
+# Extend raid5_n LV by factor 4 to keep size once linear
+lvresize -y -L 64M $vg/$lv1
+aux wait_for_sync $vg $lv1
+
+check lv_field $vg/$lv1 segtype "raid5_n"
+check lv_field $vg/$lv1 data_stripes 4
+check lv_field $vg/$lv1 stripes 5
+check lv_field $vg/$lv1 stripesize "32.00k"
+check lv_field $vg/$lv1 regionsize "128.00k"
+check lv_field $vg/$lv1 reshape_len_le "0"
+aux wait_for_sync $vg $lv1
+fsck -fn "$DM_DEV_DIR/$vg/$lv1"
+
+# Convert raid5_n LV to 1 stripe (2 legs total),
+# 64k stripesize and 1024k regionsize
+# FIXME: "--type" superfluous (cli fix needed)
+lvconvert -y -f --ty raid5_n --stripes 1 -I 64k -R 1024k $vg/$lv1
+fsck -fn "$DM_DEV_DIR/$vg/$lv1"
+check lv_first_seg_field $vg/$lv1 segtype "raid5_n"
+check lv_first_seg_field $vg/$lv1 data_stripes 1
+check lv_first_seg_field $vg/$lv1 stripes 5
+check lv_first_seg_field $vg/$lv1 stripesize "32.00k"
+check lv_first_seg_field $vg/$lv1 regionsize "1.00m"
+check lv_first_seg_field $vg/$lv1 reshape_len_le 10
+# for slv in {0..4}
+# do
+# check lv_first_seg_field $vg/${lv1}_rimage_${slv} reshape_len_le 2
+# done
+aux wait_for_sync $vg $lv1 1
+fsck -fn "$DM_DEV_DIR/$vg/$lv1"
+
+# Remove the now freed legs
+lvconvert -y --stripes 1 $vg/$lv1
+check lv_first_seg_field $vg/$lv1 segtype "raid5_n"
+check lv_first_seg_field $vg/$lv1 data_stripes 1
+check lv_first_seg_field $vg/$lv1 stripes 2
+check lv_first_seg_field $vg/$lv1 stripesize "32.00k"
+check lv_first_seg_field $vg/$lv1 regionsize "1.00m"
+check lv_first_seg_field $vg/$lv1 reshape_len_le 4
+fsck -fn "$DM_DEV_DIR/$vg/$lv1"
+
+# Convert raid5_n to raid1
+lvconvert -y --type raid1 $vg/$lv1
+fsck -fn "$DM_DEV_DIR/$vg/$lv1"
+check lv_first_seg_field $vg/$lv1 segtype "raid1"
+check lv_first_seg_field $vg/$lv1 data_stripes 2
+check lv_first_seg_field $vg/$lv1 stripes 2
+check lv_first_seg_field $vg/$lv1 stripesize "0"
+check lv_first_seg_field $vg/$lv1 regionsize "1.00m"
+check lv_first_seg_field $vg/$lv1 reshape_len_le ""
+fsck -fn "$DM_DEV_DIR/$vg/$lv1"
+
+# Convert raid1 -> linear
+lvconvert -y --type linear $vg/$lv1
+fsck -fn "$DM_DEV_DIR/$vg/$lv1"
+check lv_first_seg_field $vg/$lv1 segtype "linear"
+check lv_first_seg_field $vg/$lv1 data_stripes 1
+check lv_first_seg_field $vg/$lv1 stripes 1
+check lv_first_seg_field $vg/$lv1 stripesize "0"
+check lv_first_seg_field $vg/$lv1 regionsize "0"
+check lv_first_seg_field $vg/$lv1 reshape_len_le ""
+fsck -fn "$DM_DEV_DIR/$vg/$lv1"
+
+vgremove -ff $vg
diff --git a/test/shell/lvconvert-raid-reshape-stripes-load-fail.sh b/test/shell/lvconvert-raid-reshape-stripes-load-fail.sh
new file mode 100644
index 0000000..b35cd8d
--- /dev/null
+++ b/test/shell/lvconvert-raid-reshape-stripes-load-fail.sh
@@ -0,0 +1,84 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2017 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., 51 Franklin Street, Fifth Floor, Boston, MA2110-1301 USA
+
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+# Test reshaping under io load
+
+case "$(uname -r)" in
+ 3.10.0-862*) skip "Cannot run this test on unfixed kernel." ;;
+esac
+
+which mkfs.ext4 || skip
+aux have_raid 1 13 2 || skip
+
+mount_dir="mnt"
+
+cleanup_mounted_and_teardown()
+{
+ umount "$mount_dir" || true
+ aux teardown
+}
+
+aux prepare_pvs 16 32
+
+get_devs
+
+vgcreate $SHARED -s 1M "$vg" "${DEVICES[@]}"
+
+trap 'cleanup_mounted_and_teardown' EXIT
+
+# Create 10-way striped raid5 (11 legs total)
+lvcreate --yes --type raid5_ls --stripesize 64K --stripes 10 -L4 -n$lv1 $vg
+check lv_first_seg_field $vg/$lv1 segtype "raid5_ls"
+check lv_first_seg_field $vg/$lv1 stripesize "64.00k"
+check lv_first_seg_field $vg/$lv1 data_stripes 10
+check lv_first_seg_field $vg/$lv1 stripes 11
+wipefs -a "$DM_DEV_DIR/$vg/$lv1"
+mkfs -t ext4 "$DM_DEV_DIR/$vg/$lv1"
+fsck -fn "$DM_DEV_DIR/$vg/$lv1"
+
+mkdir -p "$mount_dir"
+mount "$DM_DEV_DIR/$vg/$lv1" "$mount_dir"
+mkdir -p "$mount_dir/1" "$mount_dir/2"
+
+
+echo 3 >/proc/sys/vm/drop_caches
+cp -r /usr/bin "$mount_dir/1" &>/dev/null &
+cp -r /usr/bin "$mount_dir/2" &>/dev/null &
+sync &
+
+aux wait_for_sync $vg $lv1
+aux delay_dev "$dev2" 0 100
+
+# Reshape it to 15 data stripes
+lvconvert --yes --stripes 15 $vg/$lv1
+aux disable_dev $dev1
+aux delay_dev "$dev2" 0 0
+check lv_first_seg_field $vg/$lv1 segtype "raid5_ls"
+check lv_first_seg_field $vg/$lv1 stripesize "64.00k"
+check lv_first_seg_field $vg/$lv1 data_stripes 15
+check lv_first_seg_field $vg/$lv1 stripes 16
+
+kill -9 %%
+wait
+rm -fr "$mount_dir/[12]"
+
+sync
+umount "$mount_dir"
+
+fsck -fn "$DM_DEV_DIR/$vg/$lv1"
+
+vgremove -ff $vg
diff --git a/test/shell/lvconvert-raid-reshape-stripes-load-reload.sh b/test/shell/lvconvert-raid-reshape-stripes-load-reload.sh
new file mode 100644
index 0000000..fb4b3d1
--- /dev/null
+++ b/test/shell/lvconvert-raid-reshape-stripes-load-reload.sh
@@ -0,0 +1,103 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2017 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., 51 Franklin Street, Fifth Floor, Boston, MA2110-1301 USA
+
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+# Test reshaping under io load
+
+which md5sum || skip
+which mkfs.ext4 || skip
+aux have_raid 1 14 || skip
+
+mount_dir="mnt"
+
+cleanup_mounted_and_teardown()
+{
+ umount "$mount_dir" || true
+ aux teardown
+}
+
+checksum_()
+{
+ md5sum "$1" | cut -f1 -d' '
+}
+
+aux prepare_pvs 16 32
+
+get_devs
+
+vgcreate $SHARED -s 1M "$vg" "${DEVICES[@]}"
+
+trap 'cleanup_mounted_and_teardown' EXIT
+
+# Create 10-way striped raid5 (11 legs total)
+lvcreate --yes --type raid5_ls --stripesize 64K --stripes 10 -L4 -n$lv1 $vg
+check lv_first_seg_field $vg/$lv1 segtype "raid5_ls"
+check lv_first_seg_field $vg/$lv1 stripesize "64.00k"
+check lv_first_seg_field $vg/$lv1 data_stripes 10
+check lv_first_seg_field $vg/$lv1 stripes 11
+wipefs -a "$DM_DEV_DIR/$vg/$lv1"
+mkfs -t ext4 "$DM_DEV_DIR/$vg/$lv1"
+
+mkdir -p "$mount_dir"
+mount "$DM_DEV_DIR/$vg/$lv1" "$mount_dir"
+
+echo 3 >/proc/sys/vm/drop_caches
+# FIXME: This is filling up ram disk. Use sane amount of data please! Rate limit the data written!
+dd if=/dev/urandom of="$mount_dir/random" bs=1M count=4 conv=fdatasync
+checksum_ "$mount_dir/random" >MD5
+
+# FIXME: wait_for_sync - is this really testing anything under load?
+aux wait_for_sync $vg $lv1
+aux delay_dev "$dev2" 0 200
+
+# Reshape it to 15 data stripes
+lvconvert --yes --stripes 15 $vg/$lv1
+check lv_first_seg_field $vg/$lv1 segtype "raid5_ls"
+check lv_first_seg_field $vg/$lv1 stripesize "64.00k"
+check lv_first_seg_field $vg/$lv1 data_stripes 15
+check lv_first_seg_field $vg/$lv1 stripes 16
+
+# Reload table during reshape to test for data corruption
+case "$(uname -r)" in
+ 5.[89]*|5.1[012].*|3.10.0-862*|4.18.0-*.el8*)
+ should not echo "Skipping table reload test on on unfixed kernel!!!" ;;
+ *)
+for i in {0..5}
+do
+ dmsetup table $vg-$lv1|dmsetup load $vg-$lv1
+ dmsetup suspend --noflush $vg-$lv1
+ dmsetup resume $vg-$lv1
+ sleep 0.3
+done
+
+esac
+
+aux delay_dev "$dev2" 0
+
+kill -9 %% || true
+wait
+
+checksum_ "$mount_dir/random" >MD5_new
+
+umount "$mount_dir"
+
+fsck -fn "$DM_DEV_DIR/$vg/$lv1"
+
+# Compare checksum is matching
+cat MD5 MD5_new
+diff MD5 MD5_new
+
+vgremove -ff $vg
diff --git a/test/shell/lvconvert-raid-reshape-stripes-load.sh b/test/shell/lvconvert-raid-reshape-stripes-load.sh
new file mode 100644
index 0000000..af15534
--- /dev/null
+++ b/test/shell/lvconvert-raid-reshape-stripes-load.sh
@@ -0,0 +1,80 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2017 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., 51 Franklin Street, Fifth Floor, Boston, MA2110-1301 USA
+
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+case "$(uname -r)" in
+ 3.10.0-862*) skip "Cannot run this test on unfixed kernel." ;;
+esac
+
+# Test reshaping under io load
+
+which mkfs.ext4 || skip
+aux have_raid 1 13 2 || skip
+
+mount_dir="mnt"
+
+cleanup_mounted_and_teardown()
+{
+ umount "$mount_dir" || true
+ aux teardown
+}
+
+aux prepare_pvs 16 32
+
+get_devs
+
+vgcreate $SHARED -s 1M "$vg" "${DEVICES[@]}"
+
+trap 'cleanup_mounted_and_teardown' EXIT
+
+# Create 10-way striped raid5 (11 legs total)
+lvcreate --yes --type raid5_ls --stripesize 64K --stripes 10 -L4 -n$lv1 $vg
+check lv_first_seg_field $vg/$lv1 segtype "raid5_ls"
+check lv_first_seg_field $vg/$lv1 stripesize "64.00k"
+check lv_first_seg_field $vg/$lv1 data_stripes 10
+check lv_first_seg_field $vg/$lv1 stripes 11
+wipefs -a "$DM_DEV_DIR/$vg/$lv1"
+mkfs -t ext4 "$DM_DEV_DIR//$vg/$lv1"
+
+mkdir -p $mount_dir
+mount "$DM_DEV_DIR/$vg/$lv1" $mount_dir
+mkdir -p $mount_dir/1 $mount_dir/2
+
+
+echo 3 >/proc/sys/vm/drop_caches
+cp -r /usr/bin $mount_dir/1 >/dev/null 2>/dev/null &
+cp -r /usr/bin $mount_dir/2 >/dev/null 2>/dev/null &
+sync &
+
+aux wait_for_sync $vg $lv1
+aux delay_dev "$dev2" 0 100
+
+# Reshape it to 15 data stripes
+lvconvert --yes --stripes 15 $vg/$lv1
+aux delay_dev "$dev2" 0 0
+check lv_first_seg_field $vg/$lv1 segtype "raid5_ls"
+check lv_first_seg_field $vg/$lv1 stripesize "64.00k"
+check lv_first_seg_field $vg/$lv1 data_stripes 15
+check lv_first_seg_field $vg/$lv1 stripes 16
+
+kill -9 %%
+wait
+
+umount $mount_dir
+
+fsck -fn "$DM_DEV_DIR/$vg/$lv1"
+
+vgremove -ff $vg
diff --git a/test/shell/lvconvert-raid-reshape.sh b/test/shell/lvconvert-raid-reshape.sh
new file mode 100644
index 0000000..abea0ff
--- /dev/null
+++ b/test/shell/lvconvert-raid-reshape.sh
@@ -0,0 +1,242 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2017 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., 51 Franklin Street, Fifth Floor, Boston, MA2110-1301 USA
+
+
+SKIP_WITH_LVMPOLLD=1
+
+LVM_SKIP_LARGE_TESTS=0
+
+. lib/inittest
+
+case "$(uname -r)" in
+5.19*) skip "Skippen test that kills this kernel" ;;
+esac
+
+which mkfs.ext4 || skip
+aux have_raid 1 14 0 || skip
+
+test "$(aux total_mem)" -gt 1048576 || skip "Not enough RAM for this test"
+
+if [ $LVM_SKIP_LARGE_TESTS -eq 0 ]
+then
+ aux prepare_pvs 65 9
+else
+ aux prepare_pvs 20 9
+fi
+
+get_devs
+
+vgcreate $SHARED -s 1M "$vg" "${DEVICES[@]}"
+
+function _lvcreate
+{
+ local level=$1
+ local req_stripes=$2
+ local stripes=$3
+ local size=$4
+ local vg=$5
+ local lv=$6
+
+ lvcreate -y -aey --type $level -i $req_stripes -L $size -n $lv $vg
+ check lv_first_seg_field $vg/$lv segtype "$level"
+ check lv_first_seg_field $vg/$lv datastripes $req_stripes
+ check lv_first_seg_field $vg/$lv stripes $stripes
+ mkfs.ext4 "$DM_DEV_DIR/$vg/$lv"
+ fsck -fn "$DM_DEV_DIR/$vg/$lv"
+}
+
+function _lvconvert
+{
+ local req_level=$1
+ local level=$2
+ local data_stripes=$3
+ local stripes=$4
+ local vg=$5
+ local lv=$6
+ local region_size=${7-}
+ local wait_and_check=1
+ local R=""
+
+ [ -n "$region_size" ] && R="-R $region_size"
+ [ "${level:0:7}" = "striped" ] && wait_and_check=0
+ [ "${level:0:5}" = "raid0" ] && wait_and_check=0
+
+ lvconvert -y --ty $req_level $R $vg/$lv || return $?
+
+ check lv_first_seg_field $vg/$lv segtype "$level"
+ check lv_first_seg_field $vg/$lv data_stripes $data_stripes
+ check lv_first_seg_field $vg/$lv stripes $stripes
+ [ -n "$region_size" ] && check lv_field $vg/$lv regionsize $region_size
+ if [ "$wait_and_check" -eq 1 ]
+ then
+ fsck -fn "$DM_DEV_DIR/$vg/$lv"
+ aux wait_for_sync $vg $lv
+ fi
+ fsck -fn "$DM_DEV_DIR/$vg/$lv"
+}
+
+function _reshape_layout
+{
+ local type=$1
+ shift
+ local data_stripes=$1
+ shift
+ local stripes=$1
+ shift
+ local vg=$1
+ shift
+ local lv=$1
+ shift
+ local opts="$*"
+ local ignore_a_chars=0
+
+ [[ "$opts" =~ "--stripes" ]] && ignore_a_chars=1
+
+ lvconvert -y --ty $type $opts $vg/$lv
+ check lv_first_seg_field $vg/$lv segtype "$type"
+ check lv_first_seg_field $vg/$lv data_stripes $data_stripes
+ check lv_first_seg_field $vg/$lv stripes $stripes
+ aux wait_for_sync $vg $lv $ignore_a_chars
+ fsck -fn "$DM_DEV_DIR/$vg/$lv"
+}
+
+# Delay leg so that rebuilding status characters
+# can be read before resync finished too quick.
+# aux delay_dev "$dev1" 1
+
+#
+# Start out with raid5(_ls)
+#
+
+# Create 3-way striped raid5 (4 legs total)
+# _lvcreate raid5_ls 3 4 16M $vg $lv1
+_lvcreate raid5_ls 3 4 16M $vg $lv1
+check lv_first_seg_field $vg/$lv1 segtype "raid5_ls"
+aux wait_for_sync $vg $lv1
+
+# Reshape it to 256K stripe size
+_reshape_layout raid5_ls 3 4 $vg $lv1 --stripesize 256K
+check lv_first_seg_field $vg/$lv1 stripesize "256.00k"
+
+# Convert raid5(_n) -> striped testing raid5_ls gets rejected
+not _lvconvert striped striped 3 3 $vg $lv1 512k
+_reshape_layout raid5_n 3 4 $vg $lv1
+_lvconvert striped striped 3 3 $vg $lv1
+
+# Convert striped -> raid5_n
+_lvconvert raid5_n raid5_n 3 4 $vg $lv1 "" 1
+
+# Convert raid5_n -> raid5_ls
+_reshape_layout raid5_ls 3 4 $vg $lv1
+
+# Convert raid5_ls to 5 stripes
+_reshape_layout raid5_ls 5 6 $vg $lv1 --stripes 5
+
+# Convert raid5_ls back to 3 stripes
+_reshape_layout raid5_ls 3 6 $vg $lv1 --stripes 3 --force
+_reshape_layout raid5_ls 3 4 $vg $lv1 --stripes 3
+
+# Convert raid5_ls to 7 stripes
+_reshape_layout raid5_ls 7 8 $vg $lv1 --stripes 7
+
+# Convert raid5_ls to 9 stripes
+_reshape_layout raid5_ls 9 10 $vg $lv1 --stripes 9
+
+# Convert raid5_ls to 14 stripes
+_reshape_layout raid5_ls 14 15 $vg $lv1 --stripes 14
+
+if [ $LVM_SKIP_LARGE_TESTS -eq 0 ]
+then
+ # Convert raid5_ls to 63 stripes
+ _reshape_layout raid5_ls 63 64 $vg $lv1 --stripes 63
+
+ # Convert raid5_ls back to 27 stripes
+ _reshape_layout raid5_ls 27 64 $vg $lv1 --stripes 27 --force
+ _reshape_layout raid5_ls 27 28 $vg $lv1 --stripes 27
+
+ # Convert raid5_ls back to 4 stripes checking
+ # conversion to striped/raid* gets rejected
+ # with existing LVs to be removed afer reshape
+ _reshape_layout raid5_ls 4 28 $vg $lv1 --stripes 4 --force
+else
+ # Convert raid5_ls back to 4 stripes checking
+ # conversion to striped/raid* gets rejected
+ # with existing LVs to be removed afer reshape
+ _reshape_layout raid5_ls 4 15 $vg $lv1 --stripes 4 --force
+fi
+
+# No we got the data reshaped and the freed SubLVs still present
+# -> check takeover request gets rejected
+not lvconvert --yes --type striped $vg/$lv1
+not lvconvert --yes --type raid0 $vg/$lv1
+not lvconvert --yes --type "$DM_DEV_DIR/raid0_meta $vg/$lv1"
+not lvconvert --yes --type "$DM_DEV_DIR/raid6 $vg/$lv1"
+# Remove the freed SubLVs
+_reshape_layout raid5_ls 4 5 $vg $lv1 --stripes 4
+
+# Convert raid5_ls back to 3 stripes
+_reshape_layout raid5_ls 3 5 $vg $lv1 --stripes 3 --force
+_reshape_layout raid5_ls 3 4 $vg $lv1 --stripes 3
+
+# Convert raid5_ls -> raid5_rs
+_reshape_layout raid5_rs 3 4 $vg $lv1
+
+# Convert raid5_rs -> raid5_la
+_reshape_layout raid5_la 3 4 $vg $lv1
+
+# Convert raid5_la -> raid5_ra
+_reshape_layout raid5_ra 3 4 $vg $lv1
+
+# Convert raid5_ra -> raid6_ra_6
+_lvconvert raid6_ra_6 raid6_ra_6 3 5 $vg $lv1 "4.00m" 1
+
+# Convert raid5_la -> raid6(_zr)
+_reshape_layout raid6 3 5 $vg $lv1
+
+# Convert raid6(_zr) -> raid6_nc
+_reshape_layout raid6_nc 3 5 $vg $lv1
+
+# Convert raid6(_nc) -> raid6_nr
+_reshape_layout raid6_nr 3 5 $vg $lv1
+
+# Convert raid6_nr) -> raid6_rs_6
+_reshape_layout raid6_rs_6 3 5 $vg $lv1
+
+# Convert raid6_rs_6 to 5 stripes
+_reshape_layout raid6_rs_6 5 7 $vg $lv1 --stripes 5
+
+# Convert raid6_rs_6 to 4 stripes
+_reshape_layout raid6_rs_6 4 7 $vg $lv1 --stripes 4 --force
+_reshape_layout raid6_rs_6 4 6 $vg $lv1 --stripes 4
+check lv_first_seg_field $vg/$lv1 stripesize "256.00k"
+
+# Convert raid6_rs_6 to raid6_n_6
+_reshape_layout raid6_n_6 4 6 $vg $lv1
+
+# Convert raid6_n_6 -> striped
+_lvconvert striped striped 4 4 $vg $lv1
+check lv_first_seg_field $vg/$lv1 stripesize "256.00k"
+
+# Convert striped -> raid10(_near)
+_lvconvert raid10 raid10 4 8 $vg $lv1
+
+# Convert raid10 to 10 stripes and 64K stripesize
+# FIXME: change once we support odd numbers of raid10 stripes
+not _reshape_layout raid10 4 9 $vg $lv1 --stripes 9 --stripesize 64K
+_reshape_layout raid10 10 20 $vg $lv1 --stripes 10 --stripesize 64K
+check lv_first_seg_field $vg/$lv1 stripesize "64.00k"
+
+# Convert raid6_n_6 -> striped
+_lvconvert striped striped 10 10 $vg $lv1
+check lv_first_seg_field $vg/$lv1 stripesize "64.00k"
+
+vgremove -ff $vg
diff --git a/test/shell/lvconvert-raid-restripe-linear.sh b/test/shell/lvconvert-raid-restripe-linear.sh
new file mode 100644
index 0000000..59b4d5d
--- /dev/null
+++ b/test/shell/lvconvert-raid-restripe-linear.sh
@@ -0,0 +1,74 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2017 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., 51 Franklin Street, Fifth Floor, Boston, MA2110-1301 USA
+
+SKIP_WITH_LVMLOCKD=1
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+which mkfs.ext4 || skip
+aux have_raid 1 14 0 || skip
+
+aux prepare_vg 5
+
+#
+# Test single step linear -> striped conversion
+#
+
+# Create linear LV
+lvcreate -aey -L 16M -n $lv $vg
+check lv_field $vg/$lv segtype "linear"
+check lv_field $vg/$lv stripes 1
+check lv_field $vg/$lv data_stripes 1
+wipefs -a "$DM_DEV_DIR/$vg/$lv"
+mkfs -t ext4 "$DM_DEV_DIR/$vg/$lv"
+fsck -fn "$DM_DEV_DIR/$vg/$lv"
+
+# Convert linear -> raid1
+not lvconvert -y --stripes 4 $vg/$lv
+not lvconvert -y --stripes 4 --stripesize 64K $vg/$lv
+not lvconvert -y --stripes 4 --stripesize 64K --regionsize 512K $vg/$lv
+lvconvert -y --type striped --stripes 4 --stripesize 64K --regionsize 512K $vg/$lv
+fsck -fn "$DM_DEV_DIR/$vg/$lv"
+check lv_field $vg/$lv segtype "raid1"
+check lv_field $vg/$lv stripes 2
+check lv_field $vg/$lv data_stripes 2
+check lv_field $vg/$lv regionsize "512.00k"
+aux wait_for_sync $vg $lv
+fsck -fn "$DM_DEV_DIR/$vg/$lv"
+
+# Convert raid1 -> raid5_n
+lvconvert -y --type striped --stripes 4 --stripesize 64K --regionsize 512K $vg/$lv
+check lv_field $vg/$lv segtype "raid5_n"
+check lv_field $vg/$lv stripes 2
+check lv_field $vg/$lv data_stripes 1
+check lv_field $vg/$lv stripesize "64.00k"
+check lv_field $vg/$lv regionsize "512.00k"
+fsck -fn "$DM_DEV_DIR/$vg/$lv"
+
+# Convert raid5_n adding stripes
+lvconvert -y --type striped --stripes 4 --stripesize 64K --regionsize 512K $vg/$lv
+check lv_first_seg_field $vg/$lv segtype "raid5_n"
+check lv_first_seg_field $vg/$lv data_stripes 4
+check lv_first_seg_field $vg/$lv stripes 5
+check lv_first_seg_field $vg/$lv stripesize "64.00k"
+check lv_first_seg_field $vg/$lv regionsize "512.00k"
+check lv_first_seg_field $vg/$lv reshape_len_le 10
+aux wait_for_sync $vg $lv
+fsck -fn "$DM_DEV_DIR/$vg/$lv"
+resize2fs "$DM_DEV_DIR/$vg/$lv"
+
+# Convert raid5_n -> striped
+lvconvert -y --type striped $vg/$lv
+fsck -fn "$DM_DEV_DIR/$vg/$lv"
+
+vgremove -ff $vg
diff --git a/test/shell/lvconvert-raid-status-validation.sh b/test/shell/lvconvert-raid-status-validation.sh
new file mode 100644
index 0000000..d923bf5
--- /dev/null
+++ b/test/shell/lvconvert-raid-status-validation.sh
@@ -0,0 +1,172 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2017 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., 51 Franklin Street, Fifth Floor, Boston, MA2110-1301 USA
+
+#######################################################################
+# This series of tests is meant to validate the correctness of
+# 'dmsetup status' for RAID LVs - especially during various sync action
+# transitions, like: recover, resync, check, repair, idle, reshape, etc
+#######################################################################
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+# check for version 1.9.0
+# - it is the point at which linear->raid1 uses "recover"
+# check for version 1.13.0 instead
+# - it is the point at which a finishing "recover" doesn't print all 'a's
+aux have_raid 1 13 0 || skip
+
+
+
+aux prepare_pvs 9
+get_devs
+
+vgcreate $SHARED -s 2m "$vg" "${DEVICES[@]}"
+
+###########################################
+# Upconverted RAID1 should never have all 'a's in status output
+###########################################
+aux delay_dev "$dev2" 0 20
+lvcreate -aey -l 2 -n $lv1 $vg "$dev1"
+lvconvert --type raid1 -y -m 1 $vg/$lv1 "$dev2"
+for i in {100..0}; do
+ check in_sync $vg $lv1 && break
+ a=( $(dmsetup status $vg-$lv1) ) || die "Unable to get status of $vg/$lv1"
+ b=( $(echo "${a[6]}" | sed s:/:' ':) )
+ if [ "${b[0]}" -ne "${b[1]}" ]; then
+ # First, 'check in_sync' should only need to check the ratio
+ # If we are here, it is probably doing more than that.
+ # If not in-sync, then we should only ever see "Aa"
+ # Ignore until raid starts to report consistent data
+ [ "${b[0]}" = "0" ] || [ "${a[5]}" == "Aa" ]
+ else
+ [ "${a[5]}" != "aa" ]
+ should [ "${a[5]}" == "AA" ] # RHBZ 1507719
+ fi
+ sleep .1
+done
+aux enable_dev "$dev2"
+lvremove -ff $vg
+test "$i" -gt 0 || die "Unable to get in sync $vg/$lv1"
+
+###########################################
+# Upconverted RAID1 should not be at 100% right after upconvert
+###########################################
+aux delay_dev "$dev2" 0 50
+lvcreate -aey -l 2 -n $lv1 $vg "$dev1"
+lvconvert --type raid1 -y -m 1 $vg/$lv1 "$dev2"
+a=( $(dmsetup status $vg-$lv1) ) || die "Unable to get status of $vg/$lv1"
+b=( $(echo "${a[6]}" | sed s:/:' ':) )
+should [ "${b[0]}" -ne "${b[1]}" ] # RHBZ 1507729
+aux enable_dev "$dev2"
+lvremove -ff $vg
+
+###########################################
+# Catch anything suspicious with linear -> RAID1 upconvert
+###########################################
+aux delay_dev "$dev2" 0 20
+lvcreate -aey -l 2 -n $lv1 $vg "$dev1"
+lvconvert --type raid1 -y -m 1 $vg/$lv1 "$dev2"
+for i in {100..0}; do
+ a=( $(dmsetup status $vg-$lv1) ) || die "Unable to get status of $vg/$lv1"
+ b=( $(echo "${a[6]}" | sed s:/:' ':) )
+ if [ "${b[0]}" -eq "0" ]; then
+ : # Ignore until raid starts to report consistent data
+ elif [ "${b[0]}" -ne "${b[1]}" ]; then
+ # If the sync operation ("recover" in this case) is not
+ # finished, then it better be as follows:
+ [ "${a[5]}" = "Aa" ]
+
+ # Might be transitioning from "idle" to "recover".
+ # Kernel could check mddev->recovery for the intent to
+ # begin a "recover" and report that... probably would be
+ # better. RHBZ 1507719
+ should [ "${a[7]}" = "recover" ]
+ else
+ # Tough to tell the INVALID case,
+ # Before starting sync thread: "Aa X/X recover"
+ # from the valid case,
+ # Just finished sync thread: "Aa X/X recover"
+ should [ "${a[5]}" = "AA" ] # RHBZ 1507719
+ should [ "${a[7]}" = "idle" ] # RHBZ 1507719
+ break
+ fi
+ sleep .1
+done
+aux enable_dev "$dev2"
+lvremove -ff $vg
+
+###########################################
+# Catch anything suspicious with RAID1 2-way -> 3-way upconvert
+###########################################
+aux delay_dev "$dev3" 0 20
+lvcreate --type raid1 -m 1 -aey -l 2 -n $lv1 $vg "$dev1" "$dev2"
+aux wait_for_sync $vg $lv1
+lvconvert -y -m +1 $vg/$lv1 "$dev3"
+for i in {100..0}; do
+ a=( $(dmsetup status $vg-$lv1) ) || die "Unable to get status of $vg/$lv1"
+ b=( $(echo "${a[6]}" | sed s:/:' ':) )
+ if [ "${b[0]}" -eq "0" ]; then
+ : # Ignore until raid starts to report consistent data
+ elif [ "${b[0]}" -ne "${b[1]}" ]; then
+ # If the sync operation ("recover" in this case) is not
+ # finished, then it better be as follows:
+ [ "${a[5]}" = "AAa" ]
+ [ "${a[7]}" = "recover" ]
+ else
+ # Tough to tell the INVALID case,
+ # Before starting sync thread: "AAa X/X recover"
+ # from the valid case,
+ # Just finished sync thread: "AAa X/X recover"
+ should [ "${a[5]}" = "AAA" ] # RHBZ 1507719
+ should [ "${a[7]}" = "idle" ] # RHBZ 1507719
+ break
+ fi
+ sleep .1
+done
+aux enable_dev "$dev3"
+lvremove -ff $vg
+test "$i" -gt 0 || die "Unable to get in sync $vg/$lv1"
+
+###########################################
+# Catch anything suspicious with RAID1 initial resync
+###########################################
+aux delay_dev "$dev2" 0 20
+lvcreate --type raid1 -m 1 -aey -l 2 -n $lv1 $vg "$dev1" "$dev2"
+for i in {100..0}; do
+ a=( $(dmsetup status $vg-$lv1) ) || die "Unable to get status of $vg/$lv1"
+ b=( $(echo "${a[6]}" | sed s:/:' ':) )
+ if [ "${b[0]}" -eq "0" ]; then
+ : # Ignore until raid starts to report consistent data
+ elif [ "${b[0]}" -ne "${b[1]}" ]; then
+ # If the sync operation ("resync" in this case) is not
+ # finished, then it better be as follows:
+ [ "${a[5]}" = "aa" ]
+
+ # Should be in "resync", but it is possible things are only
+ # just getting going - in which case, it could be "idle"
+ # with 0% sync ratio
+ [ "${a[7]}" = "resync" ] || \
+ [[ "${a[7]}" = "idle" && "${b[0]}" -eq "0" ]]
+ else
+ should [ "${a[5]}" = "AA" ] # RHBZ 1507719
+ should [ "${a[7]}" = "idle" ] # RHBZ 1507719
+ break
+ fi
+ sleep .1
+done
+aux enable_dev "$dev2"
+lvremove -ff $vg
+test "$i" -gt 0 || die "Unable to get in sync $vg/$lv1"
+
+vgremove -ff $vg
diff --git a/test/shell/lvconvert-raid-takeover-alloc-failure.sh b/test/shell/lvconvert-raid-takeover-alloc-failure.sh
new file mode 100644
index 0000000..21d0511
--- /dev/null
+++ b/test/shell/lvconvert-raid-takeover-alloc-failure.sh
@@ -0,0 +1,104 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 017 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., 51 Franklin Street, Fifth Floor, Boston, MA2110-1301 USA
+
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+aux have_raid 1 9 1 || skip
+
+aux prepare_vg 6
+
+function check_sub_lvs
+{
+ local vg=$1
+ local lv=$2
+ local end=$3
+
+ for s in $(seq 0 "$end")
+ do
+ check lv_exists $vg ${lv}_rmeta_$s
+ check lv_exists $vg ${lv}_rimage_$s
+ done
+}
+
+function check_no_sub_lvs
+{
+ local vg=$1
+ local lv=$2
+ local start=$3
+ local end=$4
+
+ for s in $(seq "$start" "$end")
+ do
+ check lv_not_exists $vg ${lv}_rmeta_$s
+ check lv_not_exists $vg ${lv}_rimage_$s
+ done
+}
+
+# Check takover upconversion fails allocation errors nicely without leaving image pair remnants behind
+
+# 6-way striped: neither conversion to raid5 nor raid6 possible
+lvcreate -aey --yes --stripes 6 --size 4M --name $lv1 $vg
+not lvconvert --yes --type raid4 $vg/$lv1
+check lv_field $vg/$lv1 segtype "striped"
+check_no_sub_lvs $vg $lv1 0 5
+
+not lvconvert --yes --type raid5 $vg/$lv1
+check lv_field $vg/$lv1 segtype "striped"
+check_no_sub_lvs $vg $lv1 0 5
+
+not lvconvert --yes --type raid6 $vg/$lv1
+check lv_field $vg/$lv1 segtype "striped"
+check_no_sub_lvs $vg $lv1 0 5
+
+# raid0_meta conversion is possible
+lvconvert --yes --type raid0_meta $vg/$lv1
+check lv_field $vg/$lv1 segtype "raid0_meta"
+check_sub_lvs $vg $lv1 0 5
+
+lvremove -y $vg
+
+# 5-way striped: conversion to raid5 possible but not to raid6
+lvcreate -aey --stripes 5 --size 4M --name $lv1 $vg
+not lvconvert --yes --type raid6 $vg/$lv1
+check lv_field $vg/$lv1 segtype "striped"
+check_no_sub_lvs $vg $lv1 0 5
+
+lvconvert --yes --type raid5 $vg/$lv1
+check lv_field $vg/$lv1 segtype "raid5_n"
+check lv_field $vg/$lv1 stripes 6
+check lv_field $vg/$lv1 datastripes 5
+check_sub_lvs $vg $lv1 0 5
+
+lvremove -y $vg
+
+# 4-way striped: conversion to raid5 and raid6 possible
+lvcreate -aey --stripes 4 --size 4M --name $lv1 $vg
+lvconvert --yes --type raid5 $vg/$lv1
+check lv_field $vg/$lv1 segtype "raid5_n"
+check lv_field $vg/$lv1 stripes 5
+check lv_field $vg/$lv1 datastripes 4
+check_sub_lvs $vg $lv1 0 4
+check_no_sub_lvs $vg $lv1 5 5
+
+lvremove -y $vg
+
+lvcreate -aey --stripes 4 --size 4M --name $lv1 $vg
+lvconvert --yes --type raid6 $vg/$lv1
+check lv_field $vg/$lv1 segtype "raid6_n_6"
+check lv_field $vg/$lv1 stripes 6
+check lv_field $vg/$lv1 datastripes 4
+check_sub_lvs $vg $lv1 0 5
+
+vgremove -ff $vg
diff --git a/test/shell/lvconvert-raid-takeover-linear_to_raid4.sh b/test/shell/lvconvert-raid-takeover-linear_to_raid4.sh
new file mode 100644
index 0000000..6b28cad
--- /dev/null
+++ b/test/shell/lvconvert-raid-takeover-linear_to_raid4.sh
@@ -0,0 +1,60 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2018 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., 51 Franklin Street, Fifth Floor, Boston, MA2110-1301 USA
+
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+which mkfs.ext4 || skip
+aux have_raid 1 14 0 || skip
+
+aux prepare_vg 4 32
+
+# FIXME: lvconvert leaks 'error' devices
+detect_error_leak_()
+{
+ dmsetup table -S "name=~^$vg-" | not grep "error" || \
+ die "Device(s) with error target should not be here."
+}
+
+# Create linear LV
+lvcreate -y -L 9M -n $lv $vg
+check lv_field $vg/$lv segtype "linear"
+check lv_field $vg/$lv data_stripes 1
+check lv_field $vg/$lv stripes 1
+mkfs.ext4 "$DM_DEV_DIR/$vg/$lv"
+fsck -fn "$DM_DEV_DIR/$vg/$lv"
+
+# Step 1: convert linear -> raid4 (convert to 2-legged raid1)
+lvconvert -y --stripes 3 --ty raid4 $vg/$lv
+detect_error_leak_
+check lv_field $vg/$lv segtype "raid1"
+check lv_field $vg/$lv data_stripes 2
+check lv_field $vg/$lv stripes 2
+aux wait_for_sync $vg $lv
+
+# Step 2: convert linear ->raid4 (convert to raid4)
+lvconvert -y --stripes 3 --ty raid4 $vg/$lv
+detect_error_leak_
+check lv_field $vg/$lv segtype "raid4"
+check lv_field $vg/$lv data_stripes 1
+check lv_field $vg/$lv stripes 2
+
+# Step 3: convert linear ->raid4 (reshape to add stripes)
+lvconvert -y --stripes 3 --ty raid4 $vg/$lv
+detect_error_leak_
+check lv_field $vg/$lv segtype "raid4"
+check lv_field $vg/$lv data_stripes 3
+check lv_field $vg/$lv stripes 4
+
+vgremove -ff $vg
diff --git a/test/shell/lvconvert-raid-takeover-raid4_to_linear.sh b/test/shell/lvconvert-raid-takeover-raid4_to_linear.sh
new file mode 100644
index 0000000..6201af4
--- /dev/null
+++ b/test/shell/lvconvert-raid-takeover-raid4_to_linear.sh
@@ -0,0 +1,71 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2018 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., 51 Franklin Street, Fifth Floor, Boston, MA2110-1301 USA
+
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+which mkfs.ext4 || skip
+aux have_raid 1 14 0 || skip
+
+aux prepare_vg 4 32
+
+# FIXME: lvconvert leaks 'error' devices
+detect_error_leak_()
+{
+ dmsetup table -S "name=~^$vg-" | not grep "error" || \
+ die "Device(s) with error target should not be here."
+}
+
+# Create 3-way striped raid4 (4 legs total)
+lvcreate -y --ty raid4 --stripes 3 -L 9M -n $lv $vg
+check lv_field $vg/$lv segtype "raid4"
+check lv_field $vg/$lv data_stripes 3
+check lv_field $vg/$lv stripes 4
+mkfs.ext4 "$DM_DEV_DIR/$vg/$lv"
+fsck -fn "$DM_DEV_DIR/$vg/$lv"
+
+# Step 1: grow before removing stripes
+lvextend -y -L27M $vg/$lv
+aux wait_for_sync $vg $lv
+
+# Step 2: convert raid4 -> linear (reshape to remove stripes)
+lvconvert -y -f --ty linear $vg/$lv
+detect_error_leak_
+check lv_field $vg/$lv segtype "raid4"
+check lv_field $vg/$lv data_stripes 1
+check lv_field $vg/$lv stripes 4
+aux wait_for_sync $vg $lv 1
+
+# Step 2: convert raid4 -> linear (remove freed stripes)
+lvconvert -y --ty linear $vg/$lv
+detect_error_leak_
+check lv_field $vg/$lv segtype "raid4"
+check lv_field $vg/$lv data_stripes 1
+check lv_field $vg/$lv stripes 2
+
+# Step 3: convert raid4 -> linear (convert to raid1)
+lvconvert -y --ty linear $vg/$lv
+detect_error_leak_
+check lv_field $vg/$lv segtype "raid1"
+check lv_field $vg/$lv data_stripes 2
+check lv_field $vg/$lv stripes 2
+
+# Step 4: convert raid4 -> linear (convert to linear)
+lvconvert -y --ty linear $vg/$lv
+detect_error_leak_
+check lv_field $vg/$lv segtype "linear"
+check lv_field $vg/$lv data_stripes 1
+check lv_field $vg/$lv stripes 1
+
+vgremove -ff $vg
diff --git a/test/shell/lvconvert-raid-takeover-thin.sh b/test/shell/lvconvert-raid-takeover-thin.sh
new file mode 100644
index 0000000..8bea244
--- /dev/null
+++ b/test/shell/lvconvert-raid-takeover-thin.sh
@@ -0,0 +1,73 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2017 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., 51 Franklin Street, Fifth Floor, Boston, MA2110-1301 USA
+
+# check we may convert thin-pool to raid1/raid10 and back
+# RHBZ#1365286
+
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+aux have_thin 1 0 0 || skip
+aux have_raid 1 9 0 || skip
+
+aux prepare_vg 6
+
+lvcreate -L4 -i3 -T $vg/pool -V10
+
+for i in 1 2 ; do
+lvconvert --type raid10 -y $vg/pool_tdata
+check grep_dmsetup table $vg-pool_tdata "raid10"
+aux wait_for_sync $vg pool_tdata
+
+lvconvert --type striped -y $vg/pool_tdata
+check grep_dmsetup table $vg-pool_tdata "striped"
+done
+
+lvremove -f $vg
+
+lvcreate -L4 -T $vg/pool -V10 -n $lv1
+
+for j in data meta ; do
+ LV=pool_t${j}
+ for i in 1 2 ; do
+ lvconvert --type raid1 -m1 -y $vg/$LV
+ check grep_dmsetup table $vg-${LV} "raid1"
+ aux wait_for_sync $vg $LV
+
+ lvconvert --type raid1 -m0 -y $vg/$LV
+ check grep_dmsetup table ${vg}-${LV} "linear"
+ done
+done
+
+
+#
+# Now same test again, when lock holding LV is not a thin-poll
+# but thinLV $lv1
+#
+lvchange -an $vg
+lvchange -ay $vg/$lv1
+
+for j in data meta ; do
+ LV=pool_t${j}
+ for i in 1 2 ; do
+ lvconvert --type raid1 -m1 -y $vg/$LV
+ check grep_dmsetup table $vg-${LV} "raid1"
+ aux wait_for_sync $vg $LV
+
+ lvconvert --type raid1 -m0 -y $vg/$LV
+ check grep_dmsetup table ${vg}-${LV} "linear"
+ done
+done
+
+vgremove -ff $vg
diff --git a/test/shell/lvconvert-raid-takeover.sh b/test/shell/lvconvert-raid-takeover.sh
new file mode 100644
index 0000000..0265d48
--- /dev/null
+++ b/test/shell/lvconvert-raid-takeover.sh
@@ -0,0 +1,372 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2016,2017 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., 51 Franklin Street, Fifth Floor, Boston, MA2110-1301 USA
+
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+which mkfs.ext4 || skip
+aux have_raid 1 12 0 || skip
+
+correct_raid4_layout=0
+aux have_raid 1 9 1 && correct_raid4_layout=1
+
+aux prepare_vg 8
+
+# FIXME: lvconvert leaks 'error' devices
+detect_error_leak_()
+{
+ dmsetup table -S "name=~^$vg-" | awk '{print $3}'| not grep error || \
+ die "Device(s) with error target should not be here."
+}
+
+function _lvcreate
+{
+ local level=$1
+ local req_stripes=$2
+ local stripes=$3
+ local size=$4
+ local vg=$5
+ local lv=$6
+
+ lvcreate -y -aey --type $level -i $req_stripes -L $size -n $lv $vg
+ check lv_field $vg/$lv segtype "$level"
+ check lv_field $vg/$lv data_stripes $req_stripes
+ check lv_field $vg/$lv stripes $stripes
+ mkfs.ext4 "$DM_DEV_DIR/$vg/$lv"
+ fsck -fn "$DM_DEV_DIR/$vg/$lv"
+}
+
+function _lvconvert
+{
+ local req_level=$1
+ local level=$2
+ local data_stripes=$3
+ local stripes=$4
+ local vg=$5
+ local lv=$6
+ local region_size=${7-}
+ local wait_and_check=1
+ local R=""
+
+ [ -n "$region_size" ] && R="-R $region_size"
+ [ "${level:0:7}" = "striped" ] && wait_and_check=0
+ [ "${level:0:5}" = "raid0" ] && wait_and_check=0
+
+ lvconvert -y --ty $req_level $R $vg/$lv
+ detect_error_leak_
+
+ check lv_field $vg/$lv segtype "$level"
+ check lv_field $vg/$lv data_stripes $data_stripes
+ check lv_field $vg/$lv stripes $stripes
+ if [ "$wait_and_check" -eq 1 ]
+ then
+ fsck -fn "$DM_DEV_DIR/$vg/$lv"
+ aux wait_for_sync $vg $lv
+ fi
+ fsck -fn "$DM_DEV_DIR/$vg/$lv"
+}
+
+function _invalid_raid5_conversions
+{
+ local vg=$1
+ local lv=$2
+
+ not _lvconvert striped 4 4 $vg $lv1
+ not _lvconvert raid0 raid0 4 4 $vg $lv1
+ not _lvconvert raid0_meta raid0_meta 4 4 $vg $lv1
+ not _lvconvert raid4 raid4 4 5 $vg $lv1
+ not _lvconvert raid5_ls raid5_ls 4 5 $vg $lv1
+ not _lvconvert raid5_rs raid5_rs 4 5 $vg $lv1
+ not _lvconvert raid5_la raid5_la 4 5 $vg $lv1
+ not _lvconvert raid5_ra raid5_ra 4 5 $vg $lv1
+ not _lvconvert raid6_zr raid6_zr 4 6 $vg $lv1
+ not _lvconvert raid6_nr raid6_nr 4 6 $vg $lv1
+ not _lvconvert raid6_nc raid6_nc 4 6 $vg $lv1
+ not _lvconvert raid6_n_6 raid6_n_6 4 6 $vg $lv1
+ not _lvconvert raid6 raid6_n_6 4 6 $vg $lv1
+}
+
+# Check raid6 conversion constrainst for 2 stripes
+for type in striped raid0 raid0_meta
+do
+ _lvcreate $type 2 2 4m $vg $lv1
+ not _lvconvert raid6 raid6_n_6 2 4 $vg $lv1
+ _lvconvert raid6 raid5_n 2 3 $vg $lv1
+ _lvconvert raid6 raid5_n 3 4 $vg $lv1
+ _lvconvert raid6 raid6_n_6 3 5 $vg $lv1
+ lvremove -y $vg
+done
+
+
+# Check raid6 conversion constrainst of minimum 3 stripes
+_lvcreate raid0 3 3 4m $vg $lv1
+_lvconvert raid6 raid6_n_6 3 5 $vg $lv1
+lvremove -y $vg
+
+# Delay 1st leg so that rebuilding status characters
+# can be read before resync finished too quick.
+# aux delay_dev "$dev1" 1
+
+# Create 3-way mirror
+lvcreate --yes -aey --type mirror -R 64K -m 2 -L8M -n $lv1 $vg
+check lv_field $vg/$lv1 segtype "mirror"
+check lv_field $vg/$lv1 stripes 3
+check lv_field $vg/$lv1 regionsize "64.00k"
+mkfs.ext4 "$DM_DEV_DIR/$vg/$lv1"
+aux wait_for_sync $vg $lv1
+fsck -fn "$DM_DEV_DIR/$vg/$lv1"
+
+# Convert 3-way to 4-way mirror
+lvconvert -y -m 3 $vg/$lv1
+detect_error_leak_
+check lv_field $vg/$lv1 segtype "mirror"
+check lv_field $vg/$lv1 stripes 4
+fsck -fn "$DM_DEV_DIR/$vg/$lv1"
+aux wait_for_sync $vg $lv1
+fsck -fn "$DM_DEV_DIR/$vg/$lv1"
+
+# Takeover 4-way mirror to raid1
+lvconvert --yes --type raid1 -R 64k $vg/$lv1
+detect_error_leak_
+check lv_field $vg/$lv1 segtype "raid1"
+check lv_field $vg/$lv1 stripes 4
+check lv_field $vg/$lv1 regionsize "64.00k"
+fsck -fn "$DM_DEV_DIR/$vg/$lv1"
+
+## Convert 4-way raid1 to 5-way
+lvconvert -y -m 4 -R 128K $vg/$lv1
+detect_error_leak_
+check lv_field $vg/$lv1 segtype "raid1"
+check lv_field $vg/$lv1 stripes 5
+check lv_field $vg/$lv1 regionsize "128.00k"
+fsck -fn "$DM_DEV_DIR/$vg/$lv1"
+aux wait_for_sync $vg $lv1
+fsck -fn "$DM_DEV_DIR/$vg/$lv1"
+
+# FIXME: enable once lvconvert rejects early
+## Try converting 4-way raid1 to 9-way
+#not lvconvert --yes -m 8 $vg/$lv1
+#check lv_field $vg/$lv1 segtype "raid1"
+#check lv_field $vg/$lv1 stripes 4
+
+# Convert 5-way raid1 to 2-way
+lvconvert --yes -m 1 $vg/$lv1
+detect_error_leak_
+lvs $vg/$lv1
+dmsetup status $vg-$lv1
+dmsetup table $vg-$lv1
+check lv_field $vg/$lv1 segtype "raid1"
+check lv_field $vg/$lv1 stripes 2
+fsck -fn "$DM_DEV_DIR/$vg/$lv1"
+
+# Convert 2-way raid1 to mirror
+lvconvert --yes --type mirror -R 32K $vg/$lv1
+detect_error_leak_
+check lv_field $vg/$lv1 segtype "mirror"
+check lv_field $vg/$lv1 stripes 2
+check lv_field $vg/$lv1 regionsize "32.00k"
+aux wait_for_sync $vg $lv1
+fsck -fn "$DM_DEV_DIR/$vg/$lv1"
+aux wait_for_sync $vg $lv1
+
+# Clean up
+lvremove --yes $vg/$lv1
+
+
+if [ $correct_raid4_layout -eq 1 ]
+then
+
+#
+# Start out with raid4
+#
+
+# Create 3-way striped raid4 (4 legs total)
+_lvcreate raid4 3 4 8M $vg $lv1
+aux wait_for_sync $vg $lv1
+
+# Convert raid4 -> striped
+not _lvconvert striped striped 3 3 $vg $lv1 512k
+_lvconvert striped striped 3 3 $vg $lv1
+
+# Convert striped -> raid4
+_lvconvert raid4 raid4 3 4 $vg $lv1 64k
+check lv_field $vg/$lv1 regionsize "64.00k"
+
+# Convert raid4 -> raid5_n
+_lvconvert raid5 raid5_n 3 4 $vg $lv1 128k
+check lv_field $vg/$lv1 regionsize "128.00k"
+
+# Convert raid5_n -> striped
+_lvconvert striped striped 3 3 $vg $lv1
+
+# Convert striped -> raid5_n
+_lvconvert raid5_n raid5_n 3 4 $vg $lv1
+
+# Convert raid5_n -> raid4
+_lvconvert raid4 raid4 3 4 $vg $lv1
+
+# Convert raid4 -> raid0
+_lvconvert raid0 raid0 3 3 $vg $lv1
+
+# Convert raid0 -> raid5_n
+_lvconvert raid5_n raid5_n 3 4 $vg $lv1
+
+# Convert raid5_n -> raid0_meta
+_lvconvert raid0_meta raid0_meta 3 3 $vg $lv1
+
+# Convert raid0_meta -> raid5_n
+_lvconvert raid5 raid5_n 3 4 $vg $lv1
+
+# Convert raid4 -> raid0_meta
+not _lvconvert raid0_meta raid0_meta 3 3 $vg $lv1 256k
+_lvconvert raid0_meta raid0_meta 3 3 $vg $lv1
+
+# Convert raid0_meta -> raid4
+_lvconvert raid4 raid4 3 4 $vg $lv1
+
+# Convert raid4 -> raid0
+_lvconvert raid0 raid0 3 3 $vg $lv1
+
+# Convert raid0 -> raid4
+_lvconvert raid4 raid4 3 4 $vg $lv1
+
+# Convert raid4 -> striped
+_lvconvert striped striped 3 3 $vg $lv1
+
+# Convert striped -> raid6_n_6
+_lvconvert raid6_n_6 raid6_n_6 3 5 $vg $lv1
+
+# Convert raid6_n_6 -> striped
+_lvconvert striped striped 3 3 $vg $lv1
+
+# Convert striped -> raid6_n_6
+_lvconvert raid6 raid6_n_6 3 5 $vg $lv1
+
+# Convert raid6_n_6 -> raid5_n
+_lvconvert raid5_n raid5_n 3 4 $vg $lv1
+
+# Convert raid5_n -> raid6_n_6
+_lvconvert raid6_n_6 raid6_n_6 3 5 $vg $lv1
+
+# Convert raid6_n_6 -> raid4
+_lvconvert raid4 raid4 3 4 $vg $lv1
+
+# Convert raid4 -> raid6_n_6
+_lvconvert raid6 raid6_n_6 3 5 $vg $lv1
+
+# Convert raid6_n_6 -> raid0
+_lvconvert raid0 raid0 3 3 $vg $lv1
+
+# Convert raid0 -> raid6_n_6
+_lvconvert raid6_n_6 raid6_n_6 3 5 $vg $lv1
+
+# Convert raid6_n_6 -> raid0_meta
+_lvconvert raid0_meta raid0_meta 3 3 $vg $lv1
+
+# Convert raid0_meta -> raid6_n_6
+_lvconvert raid6 raid6_n_6 3 5 $vg $lv1
+
+# Convert raid6_n_6 -> striped
+not _lvconvert striped striped 3 3 $vg $lv1 128k
+_lvconvert striped striped 3 3 $vg $lv1
+
+# Convert striped -> raid10
+_lvconvert raid10 raid10 3 6 $vg $lv1
+
+# Convert raid10 -> raid0
+not _lvconvert raid0 raid0 3 3 $vg $lv1 64k
+_lvconvert raid0 raid0 3 3 $vg $lv1
+
+# Convert raid0 -> raid10
+_lvconvert raid10 raid10 3 6 $vg $lv1
+
+# Convert raid10 -> raid0_meta
+_lvconvert raid0_meta raid0_meta 3 3 $vg $lv1
+
+# Convert raid0_meta -> raid5
+_lvconvert raid5_n raid5_n 3 4 $vg $lv1
+
+# Convert raid5_n -> raid0_meta
+_lvconvert raid0_meta raid0_meta 3 3 $vg $lv1
+
+# Convert raid0_meta -> raid10
+_lvconvert raid10 raid10 3 6 $vg $lv1
+
+# Convert raid10 -> striped
+not _lvconvert striped striped 3 3 $vg $lv1 256k
+_lvconvert striped striped 3 3 $vg $lv1
+
+# Clean up
+lvremove -y $vg
+
+# Create + convert 4-way raid5 variations
+_lvcreate raid5 4 5 8M $vg $lv1
+aux wait_for_sync $vg $lv1
+_invalid_raid5_conversions $vg $lv1
+not _lvconvert raid6_rs_6 raid6_rs_6 4 6 $vg $lv1
+not _lvconvert raid6_la_6 raid6_la_6 4 6 $vg $lv1
+not _lvconvert raid6_ra_6 raid6_ra_6 4 6 $vg $lv1
+_lvconvert raid6_ls_6 raid6_ls_6 4 6 $vg $lv1
+_lvconvert raid5_ls raid5_ls 4 5 $vg $lv1
+lvremove -y $vg
+
+_lvcreate raid5_ls 4 5 8M $vg $lv1
+aux wait_for_sync $vg $lv1
+_invalid_raid5_conversions $vg $lv1
+not _lvconvert raid6_rs_6 raid6_rs_6 4 6 $vg $lv1
+not _lvconvert raid6_la_6 raid6_la_6 4 6 $vg $lv1
+not _lvconvert raid6_ra_6 raid6_ra_6 4 6 $vg $lv1
+_lvconvert raid6_ls_6 raid6_ls_6 4 6 $vg $lv1
+_lvconvert raid5_ls raid5_ls 4 5 $vg $lv1
+lvremove -y $vg
+
+_lvcreate raid5_rs 4 5 8M $vg $lv1
+aux wait_for_sync $vg $lv1
+_invalid_raid5_conversions $vg $lv1
+not _lvconvert raid6_ra_6 raid6_ra_6 4 6 $vg $lv1
+not _lvconvert raid6_la_6 raid6_la_6 4 6 $vg $lv1
+not _lvconvert raid6_ra_6 raid6_ra_6 4 6 $vg $lv1
+_lvconvert raid6_rs_6 raid6_rs_6 4 6 $vg $lv1
+_lvconvert raid5_rs raid5_rs 4 5 $vg $lv1
+lvremove -y $vg
+
+_lvcreate raid5_la 4 5 8M $vg $lv1
+aux wait_for_sync $vg $lv1
+_invalid_raid5_conversions $vg $lv1
+not _lvconvert raid6_ls_6 raid6_ls_6 4 6 $vg $lv1
+not _lvconvert raid6_rs_6 raid6_rs_6 4 6 $vg $lv1
+not _lvconvert raid6_ra_6 raid6_ra_6 4 6 $vg $lv1
+_lvconvert raid6_la_6 raid6_la_6 4 6 $vg $lv1
+_lvconvert raid5_la raid5_la 4 5 $vg $lv1
+lvremove -y $vg
+
+_lvcreate raid5_ra 4 5 8M $vg $lv1
+aux wait_for_sync $vg $lv1
+_invalid_raid5_conversions $vg $lv1
+not _lvconvert raid6_ls_6 raid6_ls_6 4 6 $vg $lv1
+not _lvconvert raid6_rs_6 raid6_rs_6 4 6 $vg $lv1
+not _lvconvert raid6_la_6 raid6_la_6 4 6 $vg $lv1
+_lvconvert raid6_ra_6 raid6_ra_6 4 6 $vg $lv1
+_lvconvert raid5_ra raid5_ra 4 5 $vg $lv1
+lvremove -y $vg
+
+else
+
+not lvcreate -y -aey --type raid4 -i 3 -L8M -n $lv4 $vg
+not lvconvert -y --ty raid4 $vg/$lv1
+not lvconvert -y --ty raid4 $vg/$lv2
+
+fi
+
+vgremove -ff $vg
diff --git a/test/shell/lvconvert-raid.sh b/test/shell/lvconvert-raid.sh
index 4fa766d..aa50fbb 100644
--- a/test/shell/lvconvert-raid.sh
+++ b/test/shell/lvconvert-raid.sh
@@ -1,5 +1,6 @@
-#!/bin/sh
-# Copyright (C) 2011-2012 Red Hat, Inc. All rights reserved.
+#!/usr/bin/env bash
+
+# Copyright (C) 2011-2017 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
@@ -7,34 +8,39 @@
#
# 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
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+# disable lvmetad logging as it bogs down test systems
-. lib/test
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
get_image_pvs() {
local d
- local images
+ local images=()
- images=`dmsetup ls | grep ${1}-${2}_.image_.* | cut -f1 | sed -e s:-:/:`
- lvs --noheadings -a -o devices $images | sed s/\(.\)//
+ 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
+aux have_raid 1 3 0 || skip
+
+aux prepare_pvs 9
+get_devs
-# 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)
+# vgcreate -s 256k "$vg" "${DEVICES[@]}"
+vgcreate $SHARED -s 2m "$vg" "${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
+for i in 1 2 3; do
+ for j in 1 2 3; do
if [ $i -eq 1 ]; then
from="linear"
else
@@ -56,17 +62,29 @@ for i in 1 2 3 4; do
# 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
+ lvcreate -aey -l 2 -n $lv1 $vg
else
- lvcreate --type raid1 -m $(($i - 1)) -l 2 -n $lv1 $vg
+ 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
+ lvcreate -aey -s $vg/$lv1 -n snap -l 2
fi
- lvconvert -m $((j - 1)) $vg/$lv1
+ mirrors=$((j - 1))
+ if [ $i -eq 1 ]
+ then
+ [ $mirrors -eq 0 ] && lvconvert -y -m $mirrors $vg/$lv1
+ else
+ if [ $mirrors -eq 0 ]
+ then
+ not lvconvert -m $mirrors $vg/$lv1
+ lvconvert -y -m $mirrors $vg/$lv1
+ else
+ lvconvert -y -m $mirrors $vg/$lv1
+ fi
+ fi
# FIXME: ensure no residual devices
@@ -87,13 +105,13 @@ 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
+lvconvert -y -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
+lvcreate --type raid1 -m 2 -l 2 -n $lv1 $vg "$dev1" "$dev2" "$dev3"
aux wait_for_sync $vg $lv1
-lvconvert -m1 $vg/$lv1 $dev2
+lvconvert -y -m 1 $vg/$lv1 "$dev2"
lvremove -ff $vg
#
@@ -109,77 +127,201 @@ aux wait_for_sync $vg $lv1
lvconvert --splitmirrors 1 -n $lv2 $vg/$lv1
check lv_exists $vg $lv1
check linear $vg $lv2
+check active $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
+not lvconvert --splitmirrors 1 -n $lv2 $vg/$lv1
+lvconvert --yes --splitmirrors 1 -n $lv2 $vg/$lv1
check linear $vg $lv1
check linear $vg $lv2
+check active $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
+# 4-way
+lvcreate --type raid1 -m 4 -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
+lvconvert --splitmirrors 1 --name $lv2 $vg/$lv1 "$dev2"
lvremove -ff $vg
###########################################
-# RAID1 split + trackchanges / merge
+# RAID1 split + trackchanges / merge with content check
###########################################
# 3-way to 2-way/linear
-lvcreate --type raid1 -m 2 -l 2 -n $lv1 $vg
+lvcreate --type raid1 -m 2 -l 1 -n $lv1 $vg
+mkfs.ext4 "$DM_DEV_DIR/$vg/$lv1"
+fsck.ext4 -fn "$DM_DEV_DIR/$vg/$lv1"
aux wait_for_sync $vg $lv1
+fsck.ext4 -fn "$DM_DEV_DIR/$vg/$lv1"
lvconvert --splitmirrors 1 --trackchanges $vg/$lv1
check lv_exists $vg $lv1
check linear $vg ${lv1}_rimage_2
+fsck.ext4 -fn "$DM_DEV_DIR/mapper/$vg-${lv1}_rimage_2"
+dd of="$DM_DEV_DIR/$vg/$lv1" if=/dev/zero bs=512 oflag=direct count="$(blockdev --getsz "$DM_DEV_DIR/$vg/$lv1")"
+not fsck.ext4 -fn "$DM_DEV_DIR/$vg/$lv1"
+fsck.ext4 -fn "$DM_DEV_DIR/mapper/$vg-${lv1}_rimage_2"
+# FIXME: needed on tiny loop but not on real block backend ?
+lvchange --refresh $vg/$lv1
lvconvert --merge $vg/${lv1}_rimage_2
+aux wait_for_sync $vg $lv1
+lvconvert --splitmirrors 1 --trackchanges $vg/$lv1
+not fsck.ext4 -fn "$DM_DEV_DIR/mapper/$vg-${lv1}_rimage_2"
+# FIXME: ensure no residual devices
+lvremove -ff $vg
+
+# Check split track changes gets rejected w/o -y on 2-legged raid1
+lvcreate --type raid1 -m 1 -l 1 -n $lv1 $vg
+mkfs.ext4 "$DM_DEV_DIR/$vg/$lv1"
+fsck.ext4 -fn "$DM_DEV_DIR/$vg/$lv1"
+aux wait_for_sync $vg $lv1
+fsck.ext4 -fn "$DM_DEV_DIR/$vg/$lv1"
+not lvconvert --splitmirrors 1 --trackchanges $vg/$lv1
+lvconvert --yes --splitmirrors 1 --trackchanges $vg/$lv1
# FIXME: ensure no residual devices
lvremove -ff $vg
###########################################
+# Linear to RAID1 conversion ("raid1" default segtype)
+###########################################
+lvcreate -aey -l 2 -n $lv1 $vg
+lvconvert -y -m 1 $vg/$lv1 \
+ --config 'global { mirror_segtype_default = "raid1" }'
+lvs --noheadings -o attr $vg/$lv1 | grep '^[[:space:]]*r'
+lvremove -ff $vg
+
+###########################################
+# Linear to RAID1 conversion (override "mirror" default segtype)
+###########################################
+lvcreate -aey -l 2 -n $lv1 $vg
+lvconvert --yes --type raid1 -m 1 $vg/$lv1 \
+ --config 'global { mirror_segtype_default = "mirror" }'
+lvs --noheadings -o attr $vg/$lv1 | grep '^[[:space:]]*r'
+lvremove -ff $vg
+
+###########################################
+# Must not be able to convert non-EX LVs in a cluster
+###########################################
+if [ -e LOCAL_CLVMD ]; then
+ lvcreate -l 2 -n $lv1 $vg
+ not lvconvert -y --type raid1 -m 1 $vg/$lv1 \
+ --config 'global { mirror_segtype_default = "mirror" }'
+ lvremove -ff $vg
+fi
+
+###########################################
# Mirror to RAID1 conversion
###########################################
for i in 1 2 3 ; do
- lvcreate --type mirror -m $i -l 2 -n $lv1 $vg
+ lvcreate -aey --type mirror -m $i -l 2 -n $lv1 $vg
aux wait_for_sync $vg $lv1
- lvconvert --type raid1 $vg/$lv1
+ lvconvert -y --type raid1 $vg/$lv1
lvremove -ff $vg
done
###########################################
+# Upconverted RAID1 should not allow loss of primary
+# - don't allow removal of primary while syncing
+# - DO allow removal of secondaries while syncing
+###########################################
+aux delay_dev "$dev2" 0 100
+lvcreate -aey -l 2 -n $lv1 $vg "$dev1"
+lvconvert -y -m 1 $vg/$lv1 \
+ --config 'global { mirror_segtype_default = "raid1" }' "$dev2"
+lvs --noheadings -o attr $vg/$lv1 | grep '^[[:space:]]*r'
+not lvconvert --yes -m 0 $vg/$lv1 "$dev1"
+lvconvert --yes -m 0 $vg/$lv1 "$dev2"
+aux enable_dev "$dev2"
+lvremove -ff $vg
+
+###########################################
+# lvcreated RAID1 should allow all down-conversion
+# - DO allow removal of primary while syncing
+# - DO allow removal of secondaries while syncing
+###########################################
+aux delay_dev "$dev2" 0 100
+lvcreate --type raid1 -m 2 -aey -l 2 -n $lv1 $vg "$dev1" "$dev2" "$dev3"
+case "$(uname -r)" in
+4.8.14*)
+echo "Skippen test that kills this kernel"
+;;
+*)
+lvconvert --yes -m 1 $vg/$lv1 "$dev3"
+
+# FIXME: it is unclear what should happen - older kernel
+# do use 'resync' for initial array building so then
+# we are not able to recognize difference
+# Should we check version target as react differentely ??
+# Otherwise we have problem with the above test case.
+should lvconvert --yes -m 0 $vg/$lv1 "$dev1"
+aux enable_dev "$dev2"
+;;
+esac
+lvremove -ff $vg
+
+###########################################
+# Converting from 2-way RAID1 to 3-way
+# - DO allow removal of one of primary sources
+# - Do not allow removal of all primary sources
+###########################################
+lvcreate --type raid1 -m 1 -aey -l 2 -n $lv1 $vg "$dev1" "$dev2"
+aux wait_for_sync $vg $lv1
+aux delay_dev "$dev3" 0 100
+lvconvert --yes -m +1 $vg/$lv1 "$dev3"
+# should allow 1st primary to be removed
+lvconvert --yes -m -1 $vg/$lv1 "$dev1"
+# should NOT allow last primary to be removed
+not lvconvert --yes -m -1 $vg/$lv1 "$dev2"
+# should allow non-primary to be removed
+lvconvert --yes -m 0 $vg/$lv1 "$dev3"
+aux enable_dev "$dev3"
+lvremove -ff $vg
+
+###########################################
+# Converting from 2-way RAID1 to 3-way
+# - Should allow removal of two devices,
+# as long as they aren't both primary
+###########################################
+lvcreate --type raid1 -m 1 -aey -l 2 -n $lv1 $vg "$dev1" "$dev2"
+aux wait_for_sync $vg $lv1
+aux delay_dev "$dev3" 0 100
+lvconvert --yes -m +1 $vg/$lv1 "$dev3"
+# should NOT allow both primaries to be removed
+not lvconvert -m 0 $vg/$lv1 "$dev1" "$dev2"
+# should allow primary + non-primary
+lvconvert --yes -m 0 $vg/$lv1 "$dev1" "$dev3"
+aux enable_dev "$dev3"
+lvremove -ff $vg
+
+###########################################
# 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
+ 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 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=""
+ replace=()
devices=( $(get_image_pvs $vg $lv1) )
- for k in $(seq $j); do
- index=$((($k + $o) % ($i + 1)))
- replace="$replace --replace ${devices[$index]}"
+ 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
+ if [ "$j" -ge $(( i + 1 )) ]; then
# Can't replace all at once.
- not lvconvert $replace $vg/$lv1
+ not lvconvert "${replace[@]}" $vg/$lv1
else
- lvconvert $replace $vg/$lv1
+ lvconvert "${replace[@]}" $vg/$lv1
fi
done
done
@@ -187,37 +329,4 @@ for i in {1..3}; do
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
+vgremove -ff $vg
diff --git a/test/shell/lvconvert-raid0-striped.sh b/test/shell/lvconvert-raid0-striped.sh
new file mode 100644
index 0000000..4521b34
--- /dev/null
+++ b/test/shell/lvconvert-raid0-striped.sh
@@ -0,0 +1,25 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2018 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+aux have_raid 1 7 0 || skip
+
+aux prepare_vg 3 16
+
+lvcreate -aey --type raid0 -i 3 -l3 -n $lv $vg
+lvconvert -y --type striped $vg/$lv
+check lv_field $vg/$lv segtype "striped"
+vgremove -ff $vg
diff --git a/test/shell/lvconvert-raid0_to_raid10.sh b/test/shell/lvconvert-raid0_to_raid10.sh
new file mode 100644
index 0000000..62c2c24
--- /dev/null
+++ b/test/shell/lvconvert-raid0_to_raid10.sh
@@ -0,0 +1,30 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2017 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+# rhbz1514500
+
+aux have_raid 1 12 0 || skip
+
+# 8 PVs needed for RAID10 testing (4-stripes/2-mirror)
+aux prepare_vg 8 64
+
+lvcreate -y --type raid0 -R32k -i 4 -n $lv1 -L 64M $vg
+lvcreate -y -i4 -l4 -n $lv2 $vg
+lvextend -y -l +4 $vg/$lv1
+lvconvert -y -R512K --ty raid10 $vg/$lv1
+
+vgremove -ff $vg
diff --git a/test/shell/lvconvert-raid1-split-trackchanges.sh b/test/shell/lvconvert-raid1-split-trackchanges.sh
new file mode 100644
index 0000000..92b034c
--- /dev/null
+++ b/test/shell/lvconvert-raid1-split-trackchanges.sh
@@ -0,0 +1,41 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2018 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+# rhbz1579072/rhbz1579438
+
+aux have_raid 1 3 0 || skip
+
+# 8 PVs needed for RAID10 testing (4-stripes/2-mirror)
+aux prepare_vg 4 2
+
+lvcreate -y --ty raid1 -m 2 -n $lv1 -l 1 $vg
+lvconvert -y --splitmirrors 1 --trackchanges $vg/$lv1
+
+not lvconvert -y --ty linear $vg/$lv1
+not lvconvert -y --ty striped -i 3 $vg/$lv1
+not lvconvert -y --ty mirror $vg/$lv1
+not lvconvert -y --ty raid4 $vg/$lv1
+not lvconvert -y --ty raid5 $vg/$lv1
+not lvconvert -y --ty raid6 $vg/$lv1
+not lvconvert -y --ty raid10 $vg/$lv1
+not lvconvert -y --ty striped -m 1 $vg/${lv1}_rimage_2
+not lvconvert -y --ty raid1 -m 1 $vg/${lv1}_rimage_2
+not lvconvert -y --ty mirror -m 1 $vg/${lv1}_rimage_2
+not lvconvert -y --ty cache-pool $vg/${lv1}_rimage_2
+not lvconvert -y --ty thin-pool $vg/${lv1}_rimage_2
+
+vgremove -ff $vg
diff --git a/test/shell/lvconvert-raid10.sh b/test/shell/lvconvert-raid10.sh
index 2e4381d..04c912c 100644
--- a/test/shell/lvconvert-raid10.sh
+++ b/test/shell/lvconvert-raid10.sh
@@ -1,4 +1,5 @@
-#!/bin/sh
+#!/usr/bin/env bash
+
# Copyright (C) 2012 Red Hat, Inc. All rights reserved.
#
# This copyrighted material is made available to anyone wishing to use,
@@ -7,15 +8,18 @@
#
# 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
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
-. lib/test
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
get_image_pvs() {
local d
local images
- images=`dmsetup ls | grep ${1}-${2}_.image_.* | cut -f1 | sed -e s:-:/:`
+ images=$(dmsetup ls | grep "${1}-${2}_.image_.*" | cut -f1 | sed -e s:-:/:)
lvs --noheadings -a -o devices $images | sed s/\(.\)//
}
@@ -24,11 +28,10 @@ get_image_pvs() {
########################################################
# 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
+aux have_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)
+aux prepare_vg 9 80
lvcreate --type raid10 -m 1 -i 3 -l 3 -n $lv1 $vg
aux wait_for_sync $vg $lv1
@@ -41,16 +44,18 @@ 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
+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))]} \
+ --replace "${devices[$i]}" \
+ --replace "${devices[$(( i + 2 ))]}" \
+ --replace "${devices[$(( i + 4 ))]}" \
$vg/$lv1
aux wait_for_sync $vg $lv1
done
+
+vgremove -ff $vg
diff --git a/test/shell/lvconvert-raid456.sh b/test/shell/lvconvert-raid456.sh
new file mode 100644
index 0000000..5198753
--- /dev/null
+++ b/test/shell/lvconvert-raid456.sh
@@ -0,0 +1,72 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2013-2014 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+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 raid456_replace_works || skip
+aux have_raid 1 3 0 || skip
+
+aux prepare_vg 7 # 7 devices for 2 dev replacement of 5-dev RAID6
+
+levels="5 6"
+aux have_raid4 && levels="4 5 6"
+
+# RAID 4/5/6 (can replace up to 'parity' devices)
+for i in $levels; 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
+
+vgremove -ff $vg
diff --git a/test/shell/lvconvert-raid5_to_raid10.sh b/test/shell/lvconvert-raid5_to_raid10.sh
new file mode 100644
index 0000000..e7ecbc4
--- /dev/null
+++ b/test/shell/lvconvert-raid5_to_raid10.sh
@@ -0,0 +1,64 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2018 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., 51 Franklin Street, Fifth Floor, Boston, MA2110-1301 USA
+
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+which mkfs.ext4 || skip
+aux have_raid 1 13 2 || skip
+
+aux prepare_vg 6
+
+#
+# Test multi step raid5 -> raid10 conversion
+#
+
+# Create raid5(_ls) LV
+lvcreate -y --type raid5 -i 3 -L 16M -R 256K -n $lv1 $vg
+check lv_field $vg/$lv1 segtype "raid5"
+check lv_field $vg/$lv1 stripes 4
+check lv_field $vg/$lv1 data_stripes 3
+check lv_field $vg/$lv1 region_size "256.00k"
+wipefs -a "$DM_DEV_DIR/$vg/$lv1"
+mkfs -t ext4 "$DM_DEV_DIR/$vg/$lv1"
+fsck -fn "$DM_DEV_DIR/$vg/$lv1"
+aux wait_for_sync $vg $lv1
+fsck -fn "$DM_DEV_DIR/$vg/$lv1"
+
+# Convert raid5 -> raid10 (first step raid5 -> raid5_n)
+lvconvert -y --ty raid10 $vg/$lv1
+fsck -fn "$DM_DEV_DIR/$vg/$lv1"
+check lv_field $vg/$lv1 segtype "raid5_n"
+check lv_field $vg/$lv1 stripes 4
+check lv_field $vg/$lv1 data_stripes 3
+check lv_field $vg/$lv1 region_size "256.00k"
+aux wait_for_sync $vg $lv1
+fsck -fn "$DM_DEV_DIR/$vg/$lv1"
+
+# Convert raid5 -> raid10 (second step raid5_n -> raid0_meta)
+lvconvert -y --ty raid10 $vg/$lv1
+check lv_field $vg/$lv1 segtype "raid0_meta"
+check lv_field $vg/$lv1 stripes 3
+check lv_field $vg/$lv1 data_stripes 3
+fsck -fn "$DM_DEV_DIR/$vg/$lv1"
+
+# Convert raid5 -> raid10 (third + last step raid0_meta -> raid10)
+lvconvert -y --ty raid10 -R 256K $vg/$lv1
+fsck -fn "$DM_DEV_DIR/$vg/$lv1"
+check lv_field $vg/$lv1 segtype "raid10"
+check lv_field $vg/$lv1 stripes 6
+check lv_field $vg/$lv1 data_stripes 3
+check lv_field $vg/$lv1 region_size "256.00k"
+
+vgremove -ff $vg
diff --git a/test/shell/lvconvert-repair-cache.sh b/test/shell/lvconvert-repair-cache.sh
new file mode 100644
index 0000000..a09007c
--- /dev/null
+++ b/test/shell/lvconvert-repair-cache.sh
@@ -0,0 +1,156 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2016 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+# Test repairing of broken cached LV
+
+SKIP_WITH_LVMLOCKD=1
+
+. lib/inittest
+
+MKFS=mkfs.ext4
+FSCK=fsck
+
+which "$MKFS" || skip
+which "$FSCK" || skip
+
+#
+# Main
+#
+# older versions of cache target reported unreliably write failures
+aux have_cache 1 7 0 || skip
+
+aux prepare_vg 4
+
+#if [ 1 -eq 0 ] ; then
+#############################
+###### WRITETHROUGH #########
+#############################
+
+# Create cached LV
+lvcreate --type cache-pool -L10 $vg/cpool "$dev1"
+lvcreate -H -L20 --cachemode writethrough -n $lv1 $vg/cpool "$dev2"
+
+"$MKFS" "$DM_DEV_DIR/$vg/$lv1"
+sync
+
+aux disable_dev "$dev1"
+
+#lvchange -an $vg
+
+# Check it is prompting for confirmation
+not lvconvert --uncache $vg/$lv1
+# --yes to drop when Check its prompting
+lvconvert --yes --uncache $vg/$lv1
+should not dmsetup remove ${vg}-cpool_cmeta-missing_0_0
+should not dmsetup remove ${vg}-cpool_cdata-missing_0_0
+
+"$FSCK" -n "$DM_DEV_DIR/$vg/$lv1"
+
+aux enable_dev "$dev1"
+
+##################
+
+lvcreate --type cache-pool -L10 $vg/cpool "$dev1"
+lvconvert -H --cachemode writethrough --cachepool $vg/cpool -Zy $lv1
+
+# Check basic --repair of cachepool metadata
+lvchange -an $vg/$lv1
+lvconvert --repair $vg/$lv1
+
+lvs -a $vg
+check lv_exists $vg cpool_cpool_meta0
+
+eval "$(lvs -S 'name=~_pmspare' -a --config 'report/mark_hidden_devices=0' -o name --noheading --nameprefixes $vg)"
+lvremove -f --yes "$vg/$LVM2_LV_NAME"
+
+# check --repair without creation of _pmspare device
+lvconvert --repair --poolmetadataspare n $vg/$lv1
+check lv_exists $vg cpool_cpool_meta1
+
+# check no _pmspare has been created in previous --repair
+test "0" = "$(lvs -S 'name=~_pmspare' -a -o name --noheading --nameprefixes $vg | wc -l)"
+
+
+aux disable_dev "$dev2"
+
+# Deactivate before remove
+# FIXME: handle this while LV is alive
+lvchange -an $vg/$lv1
+
+# Check it is prompting for confirmation
+not lvconvert --uncache $vg/$lv1
+# --yes to drop when Check its prompting
+lvconvert --yes --uncache $vg/$lv1
+
+aux enable_dev "$dev2"
+
+# vg was changed while dev was missing
+vgextend --restoremissing $vg "$dev2"
+
+# FIXME: temporary workaround
+lvcreate -L1 -n $lv5 $vg
+lvremove -ff $vg
+
+##########################
+###### WRITEBACK #########
+##########################
+#fi
+
+# Create cached LV so metadata is on dev1 and data on dev2
+lvcreate -L5 -n meta $vg "$dev1"
+lvcreate -L10 -n cpool $vg "$dev2"
+lvconvert --yes --poolmetadata $vg/meta --cachepool $vg/cpool
+
+lvcreate -H -L20 --cachemode writeback -n $lv1 $vg/cpool "$dev3"
+
+lvs -a -o+seg_pe_ranges,cachemode $vg
+
+"$MKFS" "$DM_DEV_DIR/$vg/$lv1"
+sync
+
+# Seriously damage cache metadata
+aux error_dev "$dev1" 2054:2
+
+# flushing status
+dmsetup status $vg-$lv1
+
+# On fixed kernel we get instant Fail here
+get lv_field $vg/$lv1 lv_attr | tee out
+grep "Cwi-a-C-F-" out || {
+ # while on older unfixed we just notice needs_check
+ grep "Cwi-c-C---" out
+ sleep .1
+ # And now cache is finaly Failed
+ check lv_attr_bit health $vg/$lv1 "F"
+}
+check lv_field $vg/$lv1 lv_health_status "failed"
+
+aux disable_dev "$dev1"
+
+# Check it is prompting for confirmation
+not lvconvert --uncache $vg/$lv1
+# Check --yes is not enought to drop writethrough caching
+not lvconvert --yes --uncache $vg/$lv1
+# --force needs --yes to drop when Check its prompting
+not lvconvert --force --uncache $vg/$lv1
+
+lvconvert --force --yes --uncache $vg/$lv1
+
+not "$FSCK" -n "$DM_DEV_DIR/$vg/$lv1"
+
+aux enable_dev "$dev1"
+
+vgremove -ff $vg
+
+# FIXME - device should not be here
+should not dmsetup remove ${vg}-cpool_cmeta-missing_0_0
+should not dmsetup remove ${vg}-cpool_cdata-missing_0_0
diff --git a/test/shell/lvconvert-repair-dmeventd.sh b/test/shell/lvconvert-repair-dmeventd.sh
index 66e4cc8..9e0dd8c 100644
--- a/test/shell/lvconvert-repair-dmeventd.sh
+++ b/test/shell/lvconvert-repair-dmeventd.sh
@@ -1,4 +1,5 @@
-#!/bin/sh
+#!/usr/bin/env bash
+
# Copyright (C) 2008 Red Hat, Inc. All rights reserved.
#
# This copyrighted material is made available to anyone wishing to use,
@@ -7,19 +8,23 @@
#
# 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
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+
+SKIP_WITH_LVMPOLLD=1
-. lib/test
+. lib/inittest
which mkfs.ext2 || skip
+aux mirror_recovery_works || skip
-aux prepare_vg 5
aux prepare_dmeventd
+aux prepare_vg 5
-lvcreate -m 3 --ig -L 1 -n 4way $vg
+lvcreate -aey --type mirror -m 3 --ignoremonitoring -L 1 -n 4way $vg
lvchange --monitor y $vg/4way
aux disable_dev "$dev2" "$dev4"
-mkfs.ext2 $DM_DEV_DIR/$vg/4way
+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
diff --git a/test/shell/lvconvert-repair-mirror.sh b/test/shell/lvconvert-repair-mirror.sh
new file mode 100644
index 0000000..a37dec9
--- /dev/null
+++ b/test/shell/lvconvert-repair-mirror.sh
@@ -0,0 +1,78 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2016 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+MOUNT_DIR=mnt
+MKFS=$(which mkfs.ext3) || skip
+
+cleanup_mounted_and_teardown()
+{
+ umount "$MOUNT_DIR" || true
+ aux teardown
+}
+
+aux lvmconf 'allocation/mirror_logs_require_separate_pvs = 1'
+
+aux prepare_vg 5
+
+################### Check lost mirror leg #################
+#
+# NOTE: using --regionsize 1M has major impact on my box
+# on read performance while mirror is synchronized
+# with the default 512K - my C2D T61 reads just couple MB/s!
+#
+lvcreate -aey --type mirror -L10 --regionsize 1M -m1 -n $lv1 $vg "$dev1" "$dev2" "$dev3"
+"$MKFS" "$DM_DEV_DIR/$vg/$lv1"
+mkdir "$MOUNT_DIR"
+
+aux delay_dev "$dev2" 0 500 "$(get first_extent_sector "$dev2"):"
+aux delay_dev "$dev4" 0 500 "$(get first_extent_sector "$dev4"):"
+#
+# Enforce syncronization
+# ATM requires unmounted/unused LV??
+#
+lvchange --yes --resync $vg/$lv1
+trap 'cleanup_mounted_and_teardown' EXIT
+mount "$DM_DEV_DIR/$vg/$lv1" "$MOUNT_DIR"
+
+# run 'dd' operation during failure of 'mlog/mimage' device
+
+dd if=/dev/zero of=mnt/zero bs=4K count=100 conv=fdatasync 2>err &
+
+PERCENT=$(get lv_field $vg/$lv1 copy_percent)
+PERCENT=${PERCENT%%\.*} # cut decimal
+# and check less than 50% mirror is in sync (could be unusable delay_dev ?)
+test "$PERCENT" -lt 50 || skip
+#lvs -a -o+devices $vg
+
+#aux disable_dev "$dev3"
+aux disable_dev "$dev2"
+
+lvconvert --yes --repair $vg/$lv1
+lvs -a $vg
+
+aux enable_dev "$dev2"
+
+wait
+# dd MAY NOT HAVE produced any error message
+not grep error err
+
+lvs -a -o+devices $vg
+umount "$MOUNT_DIR"
+fsck -n "$DM_DEV_DIR/$vg/$lv1"
+
+aux enable_dev "$dev4"
+lvremove -ff $vg
diff --git a/test/shell/lvconvert-repair-policy.sh b/test/shell/lvconvert-repair-policy.sh
index e595d34..b69658e 100644
--- a/test/shell/lvconvert-repair-policy.sh
+++ b/test/shell/lvconvert-repair-policy.sh
@@ -1,4 +1,5 @@
-#!/bin/sh
+#!/usr/bin/env bash
+
# Copyright (C) 2008 Red Hat, Inc. All rights reserved.
#
# This copyrighted material is made available to anyone wishing to use,
@@ -7,85 +8,92 @@
#
# 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
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
-. lib/test
+
+. lib/inittest
aux prepare_vg 4
-aux lvmconf 'allocation/maximise_cling = 0'
-aux lvmconf 'allocation/mirror_logs_require_separate_pvs = 1'
+aux lvmconf 'allocation/maximise_cling = 0' \
+ '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() {
+cleanup_() {
vgreduce --removemissing $vg
for d in "$@"; do aux enable_dev "$d"; done
+ # clear the outdated metadata on enabled devs before we can reuse them
+ vgck --updatemetadata $vg
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
+ lvcreate -aey --type mirror -m 1 --ignoremonitoring -l 2 -n mirror $vg "$dev1" "$dev2" "$dev3:0"
}
-repair() {
+repair_() {
lvconvert --repair --use-policies --config "$1" $vg/mirror
}
-lvcreate -m 1 -L 1 -n mirror $vg
+lvcreate -aey --type mirror -m 1 --ignoremonitoring -l 2 -n mirror $vg "$dev1" "$dev2" "$dev3:0"
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" }'
+lvchange --partial -aey $vg/mirror
+repair_ 'activation { mirror_image_fault_policy = "remove" }'
check linear $vg mirror
-cleanup "$dev1"
+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" }'
+repair_ 'activation { mirror_image_fault_policy = "replace" mirror_log_fault_policy = "remove" }'
check mirror $vg mirror
check active $vg mirror_mlog
-cleanup "$dev1"
+cleanup_ "$dev1"
# Fail a leg of a mirror.
# Expected result: Mirror (leg replaced)
aux disable_dev "$dev1"
-repair 'activation { mirror_image_fault_policy = "replace" }'
+repair_ 'activation { mirror_image_fault_policy = "replace" }'
check mirror $vg mirror
check active $vg mirror_mlog
-cleanup "$dev1"
+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" }'
+repair_ 'activation { mirror_image_fault_policy = "replace" }'
check mirror $vg mirror
check active $vg mirror_mlog
-cleanup "$dev1"
+not pvdisplay $vg
+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" }'
+repair_ 'activation { mirror_image_fault_policy = "replace" }'
check mirror $vg mirror
-not check lv_exists $vg mirror_mlog
-cleanup "$dev2" "$dev4"
+check lv_not_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
+repair_ 'activation { mirror_image_fault_policy = "replace" }' $vg/mirror
check mirror $vg mirror
-not check lv_exists $vg mirror_mlog
-cleanup "$dev3" "$dev4"
+check lv_not_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
+lvchange -aey $vg/mirror
aux disable_dev "$dev3" "$dev4"
-repair 'activation { mirror_log_fault_policy = "remove" }'
+repair_ 'activation { mirror_log_fault_policy = "remove" }'
check mirror $vg mirror core
-not check lv_exists $vg mirror_mlog
-cleanup "$dev3" "$dev4"
+check lv_not_exists $vg mirror_mlog
+cleanup_ "$dev3" "$dev4"
+
+vgremove -ff $vg
diff --git a/test/shell/lvconvert-repair-raid-dmeventd.sh b/test/shell/lvconvert-repair-raid-dmeventd.sh
new file mode 100644
index 0000000..5519c4e
--- /dev/null
+++ b/test/shell/lvconvert-repair-raid-dmeventd.sh
@@ -0,0 +1,40 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2014 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+which mkfs.ext3 || skip
+aux have_raid 1 3 0 || skip
+
+aux lvmconf \
+ 'activation/raid_fault_policy = "allocate"'
+
+aux prepare_dmeventd
+aux prepare_vg 5
+
+lvcreate -aey --type raid1 -m 3 --ignoremonitoring -L 1 -n 4way $vg
+lvchange --monitor y $vg/4way
+lvs -a -o all,lv_modules $vg
+lvdisplay --maps $vg
+aux wait_for_sync $vg 4way
+aux disable_dev "$dev2" "$dev4"
+mkfs.ext3 "$DM_DEV_DIR/$vg/4way"
+sleep 5 # FIXME: need a "poll" utility, akin to "check"
+aux enable_dev "$dev2" "$dev4"
+
+dmsetup table
+dmsetup status
+dmsetup info -c
+vgremove -vvvv -ff $vg
diff --git a/test/shell/lvconvert-repair-raid.sh b/test/shell/lvconvert-repair-raid.sh
new file mode 100644
index 0000000..de0c9ba
--- /dev/null
+++ b/test/shell/lvconvert-repair-raid.sh
@@ -0,0 +1,176 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2013-2017 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+aux have_raid 1 3 0 || skip
+aux raid456_replace_works || skip
+
+aux lvmconf 'allocation/maximise_cling = 0' \
+ 'allocation/mirror_logs_require_separate_pvs = 1' \
+ 'activation/raid_fault_policy = "allocate"'
+
+aux prepare_vg 8 80
+get_devs
+
+offset=$(get first_extent_sector "$dev1")
+
+function delay
+{
+ for d in "${DEVICES[@]}"; do
+ aux delay_dev "$d" 0 $1 "$offset"
+ done
+}
+
+# It's possible small raid arrays do have problems with reporting in-sync.
+# So try bigger size
+RAID_SIZE=32
+
+# Fast sync and repair afterwards
+delay 0
+
+# RAID1 transient failure check
+lvcreate --type raid1 -m 1 -L $RAID_SIZE -n $lv1 $vg "$dev1" "$dev2"
+aux wait_for_sync $vg $lv1
+# enforce replacing live rimage leg with error target
+dmsetup remove -f $vg-${lv1}_rimage_1 || true
+# let it notice there is problem
+echo a > "$DM_DEV_DIR/$vg/$lv1"
+check grep_dmsetup status $vg-$lv1 AD
+lvconvert -y --repair $vg/$lv1 "$dev3"
+lvs -a -o+devices $vg
+aux wait_for_sync $vg $lv1
+# Raid should have fixed device
+check grep_dmsetup status $vg-$lv1 AA
+check lv_on $vg ${lv1}_rimage_1 "$dev3"
+lvremove -ff $vg/$lv1
+
+
+# RAID1 dual-leg single replace after initial sync
+lvcreate --type raid1 -m 1 -L $RAID_SIZE -n $lv1 $vg "$dev1" "$dev2"
+aux wait_for_sync $vg $lv1
+aux disable_dev "$dev2"
+lvconvert -y --repair $vg/$lv1
+vgreduce --removemissing $vg
+aux enable_dev "$dev2"
+vgck --updatemetadata $vg
+vgextend $vg "$dev2"
+lvremove -ff $vg/$lv1
+
+# Delayed sync to allow for repair during rebuild
+delay 50
+
+# RAID1 triple-leg single replace during initial sync
+lvcreate --type raid1 -m 2 -L $RAID_SIZE -n $lv1 $vg "$dev1" "$dev2" "$dev3"
+aux disable_dev "$dev2" "$dev3"
+# FIXME 2016/11/04 AGK: Disabled next line as it fails to guarantee it is not already in sync.
+#not lvconvert -y --repair $vg/$lv1
+aux wait_for_sync $vg $lv1
+lvconvert -y --repair $vg/$lv1
+vgreduce --removemissing $vg
+aux enable_dev "$dev2" "$dev3"
+vgck --updatemetadata $vg
+vgextend $vg "$dev2" "$dev3"
+lvremove -ff $vg/$lv1
+
+
+# Larger RAID size possible for striped RAID
+RAID_SIZE=64
+
+# Fast sync and repair afterwards
+delay 0
+# RAID5 single replace after initial sync
+lvcreate --type raid5 -i 2 -L $RAID_SIZE -n $lv1 $vg "$dev1" "$dev2" "$dev3"
+aux wait_for_sync $vg $lv1
+aux disable_dev "$dev3"
+vgreduce --removemissing -f $vg
+lvconvert -y --repair $vg/$lv1
+aux enable_dev "$dev3"
+vgck --updatemetadata $vg
+pvcreate -yff "$dev3"
+vgextend $vg "$dev3"
+lvremove -ff $vg/$lv1
+
+# Delayed sync to allow for repair during rebuild
+delay 60
+
+# RAID5 single replace during initial sync
+lvcreate --type raid5 -i 2 -L $RAID_SIZE -n $lv1 $vg "$dev1" "$dev2" "$dev3"
+aux disable_dev "$dev3"
+# FIXME: there is quite big sleep on several 'status' read retries
+# so over 3sec - it may actually finish full sync
+# Use 'should' for this test result.
+should not lvconvert -y --repair $vg/$lv1
+aux wait_for_sync $vg $lv1
+lvconvert -y --repair $vg/$lv1
+vgreduce --removemissing $vg
+aux enable_dev "$dev3"
+vgck --updatemetadata $vg
+vgextend $vg "$dev3"
+lvremove -ff $vg/$lv1
+
+# Fast sync and repair afterwards
+delay 0
+
+# RAID6 double replace after initial sync
+lvcreate --type raid6 -i 3 -L $RAID_SIZE -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" "$dev5"
+vgck --updatemetadata $vg
+vgextend $vg "$dev4" "$dev5"
+lvremove -ff $vg/$lv1
+
+# Delayed sync to allow for repair during rebuild
+delay 50
+
+# RAID6 single replace after initial sync
+lvcreate --type raid6 -i 3 -L $RAID_SIZE -n $lv1 $vg \
+ "$dev1" "$dev2" "$dev3" "$dev4" "$dev5"
+aux disable_dev "$dev4"
+not lvconvert -y --repair $vg/$lv1
+delay 0 # Fast sync and repair afterwards
+aux disable_dev "$dev4" # Need to disable again after changing delay
+aux wait_for_sync $vg $lv1
+lvconvert -y --repair $vg/$lv1
+vgreduce --removemissing $vg
+aux enable_dev "$dev4"
+vgck --updatemetadata $vg
+vgextend $vg "$dev4"
+lvremove -ff $vg/$lv1
+
+# Delayed sync to allow for repair during rebuild
+delay 50
+
+# RAID10 single replace after initial sync
+lvcreate --type raid10 -m 1 -i 2 -L $RAID_SIZE -n $lv1 $vg \
+ "$dev1" "$dev2" "$dev3" "$dev4"
+aux disable_dev "$dev4"
+not lvconvert -y --repair $vg/$lv1
+delay 0 # Fast sync and repair afterwards
+aux disable_dev "$dev4" # Need to disable again after changing delay
+aux disable_dev "$dev1"
+aux wait_for_sync $vg $lv1
+lvconvert -y --repair $vg/$lv1
+vgreduce --removemissing $vg
+aux enable_dev "$dev4"
+vgck --updatemetadata $vg
+vgextend $vg "$dev4"
+lvremove -ff $vg/$lv1
+
+vgremove -ff $vg
diff --git a/test/shell/lvconvert-repair-replace.sh b/test/shell/lvconvert-repair-replace.sh
index 974628a..0233e19 100644
--- a/test/shell/lvconvert-repair-replace.sh
+++ b/test/shell/lvconvert-repair-replace.sh
@@ -1,5 +1,6 @@
-#!/bin/sh
-# Copyright (C) 2008 Red Hat, Inc. All rights reserved.
+#!/usr/bin/env bash
+
+# Copyright (C) 2008,2018 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
@@ -7,86 +8,96 @@
#
# 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
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+
-. lib/test
+. lib/inittest
aux prepare_vg 6
-aux lvmconf 'allocation/maximise_cling = 0'
-aux lvmconf 'allocation/mirror_logs_require_separate_pvs = 1'
+
+aux lvmconf 'global/support_mirrored_mirror_log = 1' \
+ 'allocation/maximise_cling = 0' \
+ '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
+lvcreate -aey --mirrorlog disk --type mirror -m 2 --ignoremonitoring --nosync -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
+lvconvert -y --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"
+vgremove -ff $vg
# 3-way, disk log
# multiple failures, partial replace
-lvcreate --mirrorlog disk -m 2 --ig -L 1 -n 3way $vg "$dev1" "$dev2" "$dev3" "$dev4"
+vgcreate $SHARED $vg "$dev1" "$dev2" "$dev3" "$dev4" "$dev5"
+lvcreate -aey --mirrorlog disk --type mirror -m 2 --ignoremonitoring --nosync -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
+lvconvert -y --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"
+vgremove -ff $vg
-lvcreate --mirrorlog disk -m 1 --ig -L 1 -n 2way $vg "$dev1" "$dev2" "$dev3"
+vgcreate $SHARED $vg "$dev1" "$dev2" "$dev3"
+lvcreate -aey --mirrorlog disk --type mirror -m 1 --ignoremonitoring --nosync -l 1 -n 2way $vg "$dev1" "$dev2" "$dev3"
aux disable_dev "$dev1"
-echo y | lvconvert --repair $vg/2way 2>&1 | tee 2way.out
+lvconvert -y --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
+
+# FIXME - exclusive activation for mirrors should work here
+# conversion of inactive cluster logs is also unsupported
+test -e LOCAL_CLVMD && exit 0
-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
+# Replacement should fail, but convert should succeed (switch to corelog)
+vgcreate $SHARED $vg "$dev1" "$dev2" "$dev3" "$dev4"
+lvcreate -aey --type mirror -m 2 --ignoremonitoring -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
+lvconvert -y --repair $vg/mirror2
check mirror $vg mirror2
vgs $vg
+vgremove -ff $vg
+
+if aux kernel_at_least 3 0 0; then
+ # 2-way, mirrored log
+ # Double log failure, full replace
+ vgcreate $SHARED $vg "$dev1" "$dev2" "$dev3" "$dev4" "$dev5" "$dev6"
+ lvcreate -aey --mirrorlog mirrored --type mirror -m 1 --ignoremonitoring --nosync -L 1 -n 2way $vg \
+ "$dev1" "$dev2" "$dev3":0 "$dev4":0
+ aux disable_dev "$dev3" "$dev4"
+ lvconvert -y --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
+fi
+
+# 3-way, mirrored log
+# Single log failure, replace
+vgcreate $SHARED $vg "$dev1" "$dev2" "$dev3" "$dev4" "$dev5" "$dev6"
+lvcreate -aey --mirrorlog mirrored --type mirror -m 2 --ignoremonitoring --nosync -L 1 -n 3way $vg \
+ "$dev1" "$dev2" "$dev3" "$dev4":0 "$dev5":0
+aux disable_dev "$dev4"
+lvconvert -y --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
diff --git a/test/shell/lvconvert-repair-snapshot.sh b/test/shell/lvconvert-repair-snapshot.sh
index 786b950..0e9b2a3 100644
--- a/test/shell/lvconvert-repair-snapshot.sh
+++ b/test/shell/lvconvert-repair-snapshot.sh
@@ -1,4 +1,5 @@
-#!/bin/sh
+#!/usr/bin/env bash
+
# Copyright (C) 2011 Red Hat, Inc. All rights reserved.
#
# This copyrighted material is made available to anyone wishing to use,
@@ -7,15 +8,18 @@
#
# 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
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
-. lib/test
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
aux prepare_vg 5
-aux lvmconf 'allocation/maximise_cling = 0'
-aux lvmconf 'allocation/mirror_logs_require_separate_pvs = 1'
+aux lvmconf 'allocation/maximise_cling = 0' \
+ 'allocation/mirror_logs_require_separate_pvs = 1'
-lvcreate -m 3 --ig -L 2M -n 4way $vg "$dev1" "$dev2" "$dev3" "$dev4" "$dev5":0
+lvcreate -aey --type mirror -m 3 --ignoremonitoring -L 2M -n 4way $vg "$dev1" "$dev2" "$dev3" "$dev4" "$dev5":0
lvcreate -s $vg/4way -L 2M -n snap
aux disable_dev "$dev2" "$dev4"
@@ -25,3 +29,6 @@ vgreduce --removemissing $vg
aux enable_dev "$dev2" "$dev4"
lvs -a -o +devices $vg
check mirror $vg 4way "$dev5"
+
+vgchange -an $vg
+vgremove -ff $vg
diff --git a/test/shell/lvconvert-repair-thin-raid.sh b/test/shell/lvconvert-repair-thin-raid.sh
new file mode 100644
index 0000000..b97c5b4
--- /dev/null
+++ b/test/shell/lvconvert-repair-thin-raid.sh
@@ -0,0 +1,69 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2015 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+# Test repairing of broken thin pool on raid
+
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+aux have_thin 1 0 0 || skip
+aux have_raid 1 4 0 || skip
+
+#
+# To continue this test - we need real tools available
+# When they are not present mark test as skipped, but still
+# let proceed initial part which should work even without tools
+#
+aux have_tool_at_least "$LVM_TEST_THIN_CHECK_CMD" 0 3 1 || skip
+aux have_tool_at_least "$LVM_TEST_THIN_DUMP_CMD" 0 3 1 || skip
+aux have_tool_at_least "$LVM_TEST_THIN_REPAIR_CMD" 0 3 1 || skip
+
+#
+# Main
+#
+
+aux prepare_vg 4
+
+lvcreate --type raid1 -L1 -n pool $vg
+lvcreate --type raid1 -L2 -n meta $vg
+# raid _tdata & _tmeta
+lvconvert -y --thinpool $vg/pool --poolmetadata $vg/meta
+
+lvcreate -V1G $vg/pool
+
+# Pool has to be inactive (ATM) for repair
+fail lvconvert -y --repair $vg/pool "$dev3"
+
+lvchange -an $vg
+
+check lv_field $vg/pool_tmeta lv_role "private,thin,pool,metadata"
+
+lvconvert -y --repair $vg/pool "$dev3"
+
+lvs -a -o+devices,seg_pe_ranges,role,layout $vg
+check lv_field $vg/pool_meta0 lv_role "public"
+check lv_field $vg/pool_meta0 lv_layout "raid,raid1"
+check lv_field $vg/pool_tmeta lv_layout "linear"
+check lv_on $vg pool_tmeta "$dev1"
+
+# Hmm name is generated in order
+SPARE=$(lvs --noheadings -a --select "name=~_pmspare" -o name $vg)
+SPARE=${SPARE##*[}
+SPARE=${SPARE%%]*}
+
+check lv_on $vg $SPARE "$dev3"
+
+lvchange -ay $vg
+
+vgremove -ff $vg
diff --git a/test/shell/lvconvert-repair-thin.sh b/test/shell/lvconvert-repair-thin.sh
new file mode 100644
index 0000000..0fb0d76
--- /dev/null
+++ b/test/shell/lvconvert-repair-thin.sh
@@ -0,0 +1,105 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2013-2014 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+# Test repairing of broken thin pool metadata
+
+SKIP_WITH_LVMLOCKD=1
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+which mkfs.ext2 || skip
+
+#
+# Main
+#
+aux have_thin 1 0 0 || skip
+
+aux prepare_vg 4
+
+# Create LV
+# TODO: investigate problem with --zero n and my repairable damage trick
+#lvcreate -T -L20 -V10 -n $lv1 $vg/pool --discards ignore --zero n --chunksize 128 "$dev1" "$dev2"
+lvcreate -T -L20 -V10 -n $lv1 $vg/pool --chunksize 128 --discards ignore "$dev1" "$dev2"
+lvcreate -T -V10 -n $lv2 $vg/pool
+
+mkfs.ext2 "$DM_DEV_DIR/$vg/$lv1"
+mkfs.ext2 "$DM_DEV_DIR/$vg/$lv2"
+
+lvcreate -L20 -n repair $vg
+lvcreate -L2 -n fixed $vg
+
+lvs -a -o+seg_pe_ranges $vg
+#aux error_dev "$dev2" 2050:1
+
+lvchange -an $vg/$lv2 $vg/$lv1 $vg/pool $vg/repair
+
+# Manual repair steps:
+# Test swapping - swap out thin-pool's metadata with our repair volume
+lvconvert -y -f --poolmetadata $vg/repair --thinpool $vg/pool
+
+lvchange -ay $vg/repair
+
+#
+# To continue this test - we need real tools available
+# When they are not present mark test as skipped, but still
+# let proceed initial part which should work even without tools
+#
+aux have_tool_at_least "$LVM_TEST_THIN_CHECK_CMD" 0 3 1 || skip
+aux have_tool_at_least "$LVM_TEST_THIN_DUMP_CMD" 0 3 1 || skip
+aux have_tool_at_least "$LVM_TEST_THIN_REPAIR_CMD" 0 3 1 || skip
+
+# Make some 'repairable' damage??
+dd if=/dev/zero of="$DM_DEV_DIR/$vg/repair" bs=1 seek=40960 count=1
+
+# Investige how to make such damage across different versions of thin-pool target.
+should not "$LVM_TEST_THIN_CHECK_CMD" "$DM_DEV_DIR/$vg/repair"
+
+should not "$LVM_TEST_THIN_DUMP_CMD" "$DM_DEV_DIR/$vg/repair" | tee dump
+
+"$LVM_TEST_THIN_REPAIR_CMD" -i "$DM_DEV_DIR/$vg/repair" -o "$DM_DEV_DIR/$vg/fixed"
+
+"$LVM_TEST_THIN_DUMP_CMD" --repair "$DM_DEV_DIR/$vg/repair" | tee repaired_xml
+
+"$LVM_TEST_THIN_CHECK_CMD" "$DM_DEV_DIR/$vg/fixed"
+
+lvchange -an $vg
+
+# Swap repaired metadata back
+lvconvert -y -f --poolmetadata $vg/fixed --thinpool $vg/pool
+
+# Check pool still preserves its original settings
+check lv_field $vg/pool chunksize "128.00k"
+check lv_field $vg/pool discards "ignore"
+check lv_field $vg/pool zero "zero"
+
+# Activate pool - this should now work
+vgchange -ay $vg
+
+vgchange -an $vg
+
+# Put back 'broken' metadata
+lvconvert -y -f --poolmetadata $vg/repair --thinpool $vg/pool
+
+# Check --repair usage
+lvconvert -v --repair $vg/pool
+
+# Check repaired pool could be activated
+lvchange -ay $vg/pool
+
+vgchange -an $vg
+
+# Restore damaged metadata
+lvconvert -y -f --poolmetadata $vg/pool_meta0 --thinpool $vg/pool
+
+# Check lvremove -ff works even with damaged pool
+lvremove -ff $vg
diff --git a/test/shell/lvconvert-repair-transient-dmeventd.sh b/test/shell/lvconvert-repair-transient-dmeventd.sh
index ac687eb..6679dd6 100644
--- a/test/shell/lvconvert-repair-transient-dmeventd.sh
+++ b/test/shell/lvconvert-repair-transient-dmeventd.sh
@@ -1,4 +1,5 @@
-#!/bin/sh
+#!/usr/bin/env bash
+
# Copyright (C) 2011 Red Hat, Inc. All rights reserved.
#
# This copyrighted material is made available to anyone wishing to use,
@@ -7,23 +8,30 @@
#
# 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
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
-. lib/test
-aux prepare_vg 5
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
aux prepare_dmeventd
+aux mirror_recovery_works || skip
+aux prepare_vg 5
-lvcreate -m 3 --ig -L 1 -n 4way $vg
+lvcreate -aey --type mirror -m 3 --ignoremonitoring -L 1 -n 4way $vg
lvchange --monitor y $vg/4way
aux disable_dev "$dev2" "$dev4"
-mkfs.ext3 $DM_DEV_DIR/$vg/4way
+mkfs.ext3 "$DM_DEV_DIR/$vg/4way"
aux enable_dev "$dev2" "$dev4"
sleep 3
-lvs -a -o +devices $vg | not grep unknown
+lvs -a -o +devices $vg | tee out
+not grep unknown out
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
+lvs -a -o +devices $vg | tee out
+not grep mimage_1 out
+lvs -a -o +devices $vg | tee out
+not grep mimage_3 out
vgremove -f $vg
diff --git a/test/shell/lvconvert-repair-transient.sh b/test/shell/lvconvert-repair-transient.sh
index beacf89..aa697f9 100644
--- a/test/shell/lvconvert-repair-transient.sh
+++ b/test/shell/lvconvert-repair-transient.sh
@@ -1,4 +1,5 @@
-#!/bin/sh
+#!/usr/bin/env bash
+
# Copyright (C) 2008 Red Hat, Inc. All rights reserved.
#
# This copyrighted material is made available to anyone wishing to use,
@@ -7,19 +8,29 @@
#
# 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
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+
+SKIP_WITH_LVMPOLLD=1
-. lib/test
+. lib/inittest
+aux mirror_recovery_works || skip
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 &
+# ordinary mirrors
+
+lvcreate -aey --type mirror -m 3 --ignoremonitoring -L 1 -n 4way $vg
+aux wait_for_sync $vg 4way
+aux disable_dev --error --silent "$dev2" "$dev4"
+mkfs.ext3 "$DM_DEV_DIR/$vg/4way" &
sleep 1
-aux enable_dev "$dev2" "$dev4"
+dmsetup status
echo n | lvconvert --repair $vg/4way 2>&1 | tee 4way.out
-lvs -a -o +devices | not grep unknown
+aux enable_dev --silent "$dev2" "$dev4"
+
+lvs -a -o +devices $vg | tee out
+not grep unknown out
vgreduce --removemissing $vg
check mirror $vg 4way
lvchange -a n $vg/4way
diff --git a/test/shell/lvconvert-repair.sh b/test/shell/lvconvert-repair.sh
index 51bc9de..0d0231e 100644
--- a/test/shell/lvconvert-repair.sh
+++ b/test/shell/lvconvert-repair.sh
@@ -1,5 +1,6 @@
-#!/bin/sh
-# Copyright (C) 2008 Red Hat, Inc. All rights reserved.
+#!/usr/bin/env bash
+
+# Copyright (C) 2008-2013,2018 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
@@ -7,24 +8,37 @@
#
# 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
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+. lib/inittest
-. lib/test
+aux lvmconf "global/support_mirrored_mirror_log=1"
recreate_vg_()
{
vgremove -ff $vg
- vgcreate -c n $vg $(cat DEVICES)
+ vgcreate $SHARED "$vg" "$@" "${DEVICES[@]}"
+}
+
+_check_mlog()
+{
+ lvs -a -o +devices $vg | tee out
+ not grep unknown out
+ not grep mlog out
+ dmsetup ls | grep $PREFIX | tee out
+ not grep mlog out
}
-aux lvmconf 'allocation/maximise_cling = 0'
-aux lvmconf 'allocation/mirror_logs_require_separate_pvs = 1'
+aux lvmconf "allocation/maximise_cling = 0" \
+ "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
+get_devs
+
+lvcreate -aey --type mirror -m 3 --ignoremonitoring -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
@@ -34,13 +48,11 @@ check mirror $vg 4way "$dev5"
# 3-way, disk log => linear
recreate_vg_
-lvcreate -m 2 --ig -L 1 -n 3way $vg
+lvcreate -aey --type mirror -m 2 --ignoremonitoring -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
+_check_mlog
vgreduce --removemissing $vg
aux enable_dev "$dev1" "$dev2"
check linear $vg 3way
@@ -49,37 +61,32 @@ check linear $vg 3way
# 3-way, disk log => 3-way, core log
recreate_vg_
-lvcreate -m 2 --ig -L 1 -n 3way $vg "$dev1" "$dev2" "$dev3" "$dev4":0
+lvcreate -aey --type mirror -m 2 --ignoremonitoring -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
+_check_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 \
+lvcreate -aey --type mirror -m 2 --mirrorlog mirrored --ignoremonitoring -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
+_check_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
+lvcreate -aey --type mirror -m 1 --ignoremonitoring -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
+_check_mlog
vgreduce --removemissing $vg
aux enable_dev "$dev3"
@@ -88,53 +95,34 @@ aux enable_dev "$dev3"
recreate_vg_
vgreduce $vg "$dev4"
-lvcreate -m 1 --ig -L 1 -n mirror $vg
+lvcreate -aey --type mirror -m 1 --ignoremonitoring -L 1 -n mirror $vg
lvchange -a n $vg/mirror
vgextend $vg "$dev4"
aux disable_dev "$dev1"
-lvchange --partial -a y $vg/mirror
+lvchange --partial -aey $vg/mirror
not vgreduce -v --removemissing $vg
lvconvert -y --repair $vg/mirror
vgreduce --removemissing $vg
aux enable_dev "$dev1"
+# clear the outdated dev before we can reuse it
+vgck --updatemetadata $vg
vgextend $vg "$dev1"
aux disable_dev "$dev2"
lvconvert -y --repair $vg/mirror
vgreduce --removemissing $vg
aux enable_dev "$dev2"
+# clear the outdated dev before we can reuse it
+vgck --updatemetadata $vg
vgextend $vg "$dev2"
aux disable_dev "$dev3"
lvconvert -y --repair $vg/mirror
vgreduce --removemissing $vg
aux enable_dev "$dev3"
+# clear the outdated dev before we can reuse it
+vgck --updatemetadata $vg
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-snapshot-cache.sh b/test/shell/lvconvert-snapshot-cache.sh
new file mode 100644
index 0000000..9cb383a
--- /dev/null
+++ b/test/shell/lvconvert-snapshot-cache.sh
@@ -0,0 +1,78 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2017 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+# Test various supported conversion of snapshot with cache
+
+SKIP_WITH_LVMLOCKD=1
+SKIP_WITH_LVMPOLLD=1
+
+export LVM_TEST_THIN_REPAIR_CMD=${LVM_TEST_THIN_REPAIR_CMD-/bin/false}
+
+. lib/inittest
+
+aux have_cache 1 3 0 || skip
+
+aux prepare_vg 1
+
+vgchange -s 16k $vg
+
+lvcreate -L1 -n cow $vg
+
+# Thin and snapshot conversion
+lvcreate -aey -L1 -n ch $vg
+lvcreate -H -L1 -n cpool $vg/ch
+
+# Cannot create snapshot of cpool
+not lvcreate -s -L1 $vg/cpool_cpool 2>&1 | tee err
+grep "not supported" err
+
+# Cannot create snapshot of cpool's meta
+not lvcreate -s -L1 $vg/cpool_cpool_cmeta 2>&1 | tee err
+grep "not supported" err
+
+# Cannot create snapshot of cpool's data
+not lvcreate -s -L1 $vg/cpool_cpool_cdata 2>&1 | tee err
+grep "not supported" err
+
+# Cannot use cache-type as COW
+not lvconvert --yes --type snapshot $vg/cow $vg/ch 2>&1 | tee err
+grep "not accept" err
+
+not lvconvert --yes --type snapshot $vg/cow $vg/cpool_cpool 2>&1 | tee err
+grep "not accept" err
+
+not lvconvert --yes --type snapshot $vg/cow $vg/cpool_cpool_cdata 2>&1 | tee err
+grep "lv_is_visible" err
+
+not lvconvert --yes --type snapshot $vg/cow $vg/cpool_cpool_cmeta 2>&1 | tee err
+grep "lv_is_visible" err
+
+# Cannot use thin-pool, _tdata, _tmeta as origin
+not lvconvert --yes --type snapshot $vg/cpool_cpool $vg/cow 2>&1 | tee err
+grep "not supported" err
+
+not lvconvert --yes --type snapshot $vg/cpool_cpool_cdata $vg/cow 2>&1 | tee err
+grep "not supported" err
+
+not lvconvert --yes --type snapshot $vg/cpool_cpool_cmeta $vg/cow 2>&1 | tee err
+grep "not supported" err
+
+lvconvert --yes -s $vg/ch $vg/cow
+
+check lv_field $vg/ch segtype cache
+check lv_field $vg/cow segtype linear
+check lv_attr_bit type $vg/cow "s"
+check lv_attr_bit type $vg/ch "o"
+
+lvs -a -o+lv_role,lv_layout $vg
+
+vgremove -f $vg
diff --git a/test/shell/lvconvert-snapshot-mirror.sh b/test/shell/lvconvert-snapshot-mirror.sh
new file mode 100644
index 0000000..22f40f7
--- /dev/null
+++ b/test/shell/lvconvert-snapshot-mirror.sh
@@ -0,0 +1,60 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2017 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+# Test various supported conversion of snapshot with mirrors
+
+SKIP_WITH_LVMLOCKD=1
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+aux prepare_vg 3
+
+vgchange -s 16k $vg
+
+lvcreate -L1 -n cow $vg
+
+# Mirror and snapshot conversion
+lvcreate -aye --type mirror -L1 -m1 -n mir $vg
+
+# Cannot create snapshot of mirror leg
+not lvcreate -s -L1 $vg/mir_mimage_0 2>&1 | tee err
+grep "not supported" err
+
+# cannot use 'mirror' as COW
+not lvconvert --yes --type snapshot $vg/cow $vg/mir 2>&1 | tee err
+grep "not accept" err
+
+not lvconvert --yes --type snapshot $vg/cow $vg/mir_mimage_0 2>&1 | tee err
+grep "lv_is_visible" err
+
+not lvconvert --yes --type snapshot $vg/cow $vg/mir_mlog 2>&1 | tee err
+grep "lv_is_visible" err
+
+# cannot use _mimage
+not lvconvert --yes --type snapshot $vg/mir_mimage_0 $vg/cow 2>&1 | tee err
+grep "not supported" err
+
+# cannot use _mlog
+not lvconvert --yes --type snapshot $vg/mir_mlog $vg/cow 2>&1 | tee err
+grep "not supported" err
+
+lvconvert --yes -s $vg/mir $vg/cow
+
+check lv_field $vg/mir segtype mirror
+check lv_field $vg/cow segtype linear
+check lv_attr_bit type $vg/cow "s"
+check lv_attr_bit type $vg/mir "o"
+
+lvs -a -o+lv_role,lv_layout $vg
+
+vgremove -f $vg
diff --git a/test/shell/lvconvert-snapshot-raid.sh b/test/shell/lvconvert-snapshot-raid.sh
new file mode 100644
index 0000000..8deb60f
--- /dev/null
+++ b/test/shell/lvconvert-snapshot-raid.sh
@@ -0,0 +1,62 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2017 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+# Test various supported conversion of snapshot with raid
+
+SKIP_WITH_LVMLOCKD=1
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+aux have_raid 1 3 0 || skip
+
+aux prepare_vg 3
+
+vgchange -s 16k $vg
+
+lvcreate -L1 -n cow $vg
+
+# Raid and snapshot conversion
+lvcreate --type raid1 -L1 -m1 -n rd $vg
+
+# Cannot create snapshot of raid leg
+not lvcreate -s -L1 $vg/rd_rimage_0 2>&1 | tee err
+grep "not supported" err
+
+# Cannot use raid-type as COW
+not lvconvert --yes --type snapshot $vg/cow $vg/rd 2>&1 | tee err
+grep "not accept" err
+
+not lvconvert --yes --type snapshot $vg/cow $vg/rd_rimage_0 2>&1 | tee err
+grep "lv_is_visible" err
+
+not lvconvert --yes --type snapshot $vg/cow $vg/rd_rmeta_0 2>&1 | tee err
+grep "lv_is_visible" err
+
+# Cannot use _rimage
+not lvconvert --yes --type snapshot $vg/rd_rimage_0 $vg/cow 2>&1 | tee err
+grep "not supported" err
+
+# Cannot use _rmeta
+not lvconvert --yes --type snapshot $vg/rd_rmeta_0 $vg/cow 2>&1 | tee err
+grep "not supported" err
+
+lvconvert --yes -s $vg/rd $vg/cow
+
+check lv_field $vg/rd segtype raid1
+check lv_field $vg/cow segtype linear
+check lv_attr_bit type $vg/cow "s"
+check lv_attr_bit type $vg/rd "o"
+
+lvs -a -o+lv_role,lv_layout $vg
+
+vgremove -f $vg
diff --git a/test/shell/lvconvert-snapshot-thin.sh b/test/shell/lvconvert-snapshot-thin.sh
new file mode 100644
index 0000000..cc4dade
--- /dev/null
+++ b/test/shell/lvconvert-snapshot-thin.sh
@@ -0,0 +1,80 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2017 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+# Test various supported conversion of snapshot with raid
+
+SKIP_WITH_LVMLOCKD=1
+SKIP_WITH_LVMPOLLD=1
+
+export LVM_TEST_THIN_REPAIR_CMD=${LVM_TEST_THIN_REPAIR_CMD-/bin/false}
+
+. lib/inittest
+
+aux have_thin 1 0 0 || skip
+
+aux prepare_vg 1
+
+vgchange -s 16k $vg
+
+lvcreate -L1 -n cow $vg
+
+# Thin and snapshot conversion
+lvcreate -T -L1 -V10 -n th $vg/pool
+eval "$(lvs -S 'name=~_pmspare' -a -o name --config 'report/mark_hidden_devices=0' --noheading --nameprefixes $vg)"
+
+# Cannot create snapshot of pool's meta
+not lvcreate -s -L1 $vg/pool_tmeta 2>&1 | tee err
+grep "not supported" err
+
+# Cannot create snapshot of pool's data
+not lvcreate -s -L1 $vg/pool_tdata 2>&1 | tee err
+grep "not supported" err
+
+# Cannot use thin-type as COW
+not lvconvert --yes --type snapshot $vg/cow $vg/th 2>&1 | tee err
+grep "not accept" err
+
+not lvconvert --yes --type snapshot $vg/cow $vg/pool 2>&1 | tee err
+grep "not accept" err
+
+not lvconvert --yes --type snapshot $vg/cow $vg/$LVM2_LV_NAME 2>&1 | tee err
+grep "lv_is_visible" err
+
+not lvconvert --yes --type snapshot $vg/cow $vg/pool_tdata 2>&1 | tee err
+grep "lv_is_visible" err
+
+not lvconvert --yes --type snapshot $vg/cow $vg/pool_tmeta 2>&1 | tee err
+grep "lv_is_visible" err
+
+# Cannot use thin-pool, _tdata, _tmeta as origin
+not lvconvert --yes --type snapshot $vg/pool $vg/cow 2>&1 | tee err
+grep "not supported" err
+
+not lvconvert --yes --type snapshot $vg/$LVM2_LV_NAME $vg/cow 2>&1 | tee err
+grep "not supported" err
+
+not lvconvert --yes --type snapshot $vg/pool_tdata $vg/cow 2>&1 | tee err
+grep "not supported" err
+
+not lvconvert --yes --type snapshot $vg/pool_tmeta $vg/cow 2>&1 | tee err
+grep "not supported" err
+
+lvconvert --yes -s $vg/th $vg/cow
+
+check lv_field $vg/th segtype thin
+check lv_field $vg/cow segtype linear
+check lv_attr_bit type $vg/cow "s"
+check lv_attr_bit type $vg/th "o"
+
+lvs -a -o+lv_role,lv_layout $vg
+
+vgremove -f $vg
diff --git a/test/shell/lvconvert-snapshot.sh b/test/shell/lvconvert-snapshot.sh
new file mode 100644
index 0000000..9a32776
--- /dev/null
+++ b/test/shell/lvconvert-snapshot.sh
@@ -0,0 +1,73 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2014 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+# Test various supported conversion of snapshot
+
+SKIP_WITH_LVMLOCKD=1
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+aux prepare_pvs 2
+get_devs
+
+vgcreate -s 4k "$vg" "${DEVICES[@]}"
+
+lvcreate --type snapshot -V50 -L1 -n $lv1 -s $vg
+
+lvcreate -aey -L1 -n $lv2 $vg
+lvcreate -L1 -s -n $lv3 $vg/$lv2
+
+lvcreate -l1 -n $lv4 $vg
+lvcreate -L1 -n $lv5 $vg
+lvcreate -L1 -n $lv6 $vg
+
+not lvconvert -s $vg/$lv1 $vg/not_exist
+
+# Can't convert to snapshot of origin
+not lvconvert -s $vg/$lv1 $vg/$lv2
+not lvconvert -s $vg/$lv2 $vg/$lv1
+not lvconvert -s $vg/$lv5 $vg/$lv1
+
+not lvconvert -s $vg/$lv5 $vg/$lv2
+not lvconvert -s $vg/$lv5 $vg/$lv3
+
+# Can't be itself
+not lvconvert -s $vg/$lv1 $vg/$lv1
+not lvconvert -s $vg/$lv2 $vg/$lv2
+
+# Can't convert snapshot to snapshot
+not lvconvert -s $vg/$lv1 $vg/$lv3
+not lvconvert -s $vg/$lv2 $vg/$lv3
+
+# Can't make a real LV snapshot of virtual 'zero' snapshot
+not lvconvert -s $vg/$lv1 $vg/$lv4
+
+# Check minimum size
+not lvconvert -s $vg/$lv2 $vg/$lv4 2>&1 | tee err
+grep "smaller" err
+
+# This should pass
+lvconvert --yes -s $vg/$lv2 $vg/$lv5
+lvconvert --yes --type snapshot $vg/$lv2 $vg/$lv6
+
+vgremove -f $vg
+
+# FIXME: older stripe target can't handle 1K chunks
+vgcreate -s 4k "$vg" "${DEVICES[@]}"
+lvcreate -aey -L1 -n $lv2 $vg
+lvcreate -L1 -i2 -n $lv7 $vg
+
+# Striped LV is also supported
+lvconvert --yes --snapshot $vg/$lv2 $vg/$lv7
+
+vgremove -f $vg
diff --git a/test/shell/lvconvert-striped-raid0.sh b/test/shell/lvconvert-striped-raid0.sh
new file mode 100644
index 0000000..5cfb792
--- /dev/null
+++ b/test/shell/lvconvert-striped-raid0.sh
@@ -0,0 +1,25 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2018 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+aux have_raid 1 7 0 || skip
+
+aux prepare_vg 3 16
+
+lvcreate -aey --type striped -i 3 -l3 -n $lv $vg
+lvconvert -y --type raid0_meta $vg/$lv
+check lv_field $vg/$lv segtype "raid0_meta"
+vgremove -ff $vg
diff --git a/test/shell/lvconvert-thin-external-cache.sh b/test/shell/lvconvert-thin-external-cache.sh
new file mode 100644
index 0000000..a8b95b2
--- /dev/null
+++ b/test/shell/lvconvert-thin-external-cache.sh
@@ -0,0 +1,110 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2016 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+# Test conversion cached LV to thin with cached external origin
+
+SKIP_WITH_LVMLOCKD=1
+SKIP_WITH_LVMPOLLD=1
+
+export LVM_TEST_THIN_REPAIR_CMD=${LVM_TEST_THIN_REPAIR_CMD-/bin/false}
+
+. lib/inittest
+
+which mkfs.ext2 || skip
+which fsck || skip
+
+#
+# Main
+#
+aux have_thin 1 5 0 || skip
+aux have_cache 1 7 0 || skip
+
+aux prepare_vg 2 64
+
+# Test will use thin-pool
+lvcreate -L10 -T $vg/tpool
+
+lvcreate -aey -L20 -n $lv1 $vg
+
+
+mkfs.ext2 "$DM_DEV_DIR/$vg/$lv1"
+mkdir mnt
+mount "$DM_DEV_DIR/$vg/$lv1" mnt
+touch mnt/test
+
+# Prepared cached LV - first in 'writeback' mode
+lvcreate -H --cachemode writeback -L10 -n cpool $vg/$lv1
+
+# Can't convert 'writeback' cache
+not lvconvert --thin --thinpool $vg/tpool $vg/$lv1
+
+# Switch to 'writethrough' - this should be supported
+lvchange --cachemode writethrough $vg/$lv1
+
+# Check $lv1 remains mounted (so it's not been unmounted by systemd)
+mountpoint "$PWD/mnt"
+
+lvconvert --thin $vg/$lv1 --originname extorg --thinpool $vg/tpool
+
+# check cache exist as extorg-real
+check grep_dmsetup table ${vg}-extorg-real "cache"
+
+
+# Split cache from external origin (while in-use)
+lvconvert --splitcache $vg/extorg
+
+# check linear exist as extorg-real
+check grep_dmsetup table ${vg}-extorg-real "linear"
+check lv_field $vg/extorg segtype linear
+
+# Cache external origin in-use again
+lvconvert -y -H $vg/extorg --cachepool $vg/cpool
+
+get lv_field $vg/extorg attr | grep "^ori"
+
+umount mnt
+
+# Is filesystem still ok ?
+fsck -n "$DM_DEV_DIR/$vg/$lv1"
+
+lvchange -an $vg
+lvchange -ay $vg
+
+# Remove thin, external origin remains
+lvremove -f $vg/$lv1
+
+#lvchange -prw $vg/extorg
+lvconvert --uncache $vg/extorg
+
+lvremove -f $vg
+
+#
+# Check some more API variants
+#
+
+lvcreate -L10 -n pool $vg
+
+lvcreate -aey -L2 -n $lv1 $vg
+lvcreate -H -L2 $vg/$lv1
+
+# Converts $vg/pool to thin-pool AND $vg/$lv1 to thin
+lvconvert -y --type thin $vg/$lv1 --originname extorg --thinpool $vg/pool
+
+check lv_field $vg/$lv1 segtype thin
+check lv_field $vg/pool segtype thin-pool
+check lv_field $vg/extorg segtype cache
+
+lvconvert --uncache $vg/extorg
+
+check lv_field $vg/extorg segtype linear
+
+vgremove -ff $vg
diff --git a/test/shell/lvconvert-thin-external.sh b/test/shell/lvconvert-thin-external.sh
new file mode 100644
index 0000000..ee0463c
--- /dev/null
+++ b/test/shell/lvconvert-thin-external.sh
@@ -0,0 +1,180 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2013 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+# Test conversion to thin external origin
+
+SKIP_WITH_LVMLOCKD=1
+SKIP_WITH_LVMPOLLD=1
+
+export LVM_TEST_THIN_REPAIR_CMD=${LVM_TEST_THIN_REPAIR_CMD-/bin/false}
+
+. lib/inittest
+
+which mkfs.ext2 || skip
+which fsck || skip
+
+#
+# Main
+#
+aux have_thin 1 5 0 || skip
+
+aux prepare_pvs 2 64
+get_devs
+
+vgcreate "$vg" --metadatasize 128K -s 64K "${DEVICES[@]}"
+
+if test 0 -eq 1 ; then
+# FIXME: needs patch to allow inactive old-snap creation
+lvcreate -l10 -T $vg/pool
+lvcreate -an -pr --zero n -l10 --name $lv1 $vg
+lvcreate -s $vg/$lv1 --name $lv2 --thinpool $vg/pool
+vgchange -an $vg
+# oldstyle read-only inactive snapshot
+lvcreate -an -s $vg/$lv2 -l10 -p r --name $lv3
+
+lvcreate -s $vg/$lv3 --name $lv4 --thinpool $vg/pool
+lvremove -ff $vg/$lv3
+
+lvremove -ff $vg
+fi
+
+#lvcreate -L20M --name orig $vg
+#lvconvert -T --thinpool $vg/pool $vg/orig
+#lvcreate -s -aey -L10M $vg/orig
+#lvremove -f $vg
+#exit 0
+
+lvcreate -l10 -T $vg/pool
+# Can't convert pool to external origin
+lvcreate -l10 -T $vg/pool1 -c 192k
+not lvconvert -T --thinpool $vg/pool1 $vg/pool --originname origin
+# Create pool1 chunk_size unaligned LV and check failing conversion
+lvcreate -l2 -n $lv1 $vg
+# Newer thin-pool target (>= 1.13) supports unaligned external origin
+aux lvmconf 'global/thin_disabled_features = [ "external_origin_extend" ]'
+not lvconvert -T --thinpool $vg/pool1 $vg/$lv1
+
+lvremove -f $vg/pool1 $vg/$lv1
+
+# create plain LV (will be used for external origin)
+lvcreate -L8M -n $lv1 $vg
+
+# Can't convert same LV to the thin pool and thin volume
+not lvconvert --thinpool $vg/$lv1 -T $vg/$lv1
+check lv_field $vg/$lv1 segtype linear
+
+mkfs.ext2 "$DM_DEV_DIR/$vg/$lv1"
+mkdir mnt
+mount "$DM_DEV_DIR/$vg/$lv1" mnt
+
+dd if=/dev/zero of=mnt/test1 bs=1M count=1
+
+# convert plain LV into thin external snapshot volume
+# during conversion dd above could be still flushed
+
+lvconvert -T --originname extorg --thinpool $vg/pool $vg/$lv1
+
+check active $vg $lv1
+# FIXME handling attr is ...
+get lv_field $vg/extorg attr | grep "^ori"
+check inactive $vg extorg
+
+touch mnt/test
+umount mnt
+
+# check fs is without errors
+fsck -n "$DM_DEV_DIR/$vg/$lv1"
+
+lvchange -aey $vg/extorg
+lvchange -an $vg/$lv1
+
+check active $vg extorg
+check inactive $vg $lv1
+
+# fsck in read-only mode
+fsck -n "$DM_DEV_DIR/$vg/extorg"
+
+not lvresize -l+8 $vg/extorg
+not lvresize -l-4 $vg/extorg
+not lvchange -p rw $vg/extorg
+
+#lvresize -L+8M $vg/$lv1
+#lvresize -L-4M $vg/$lv1
+#lvchange -p r $vg/$lv1
+#lvchange -p rw $vg/$lv1
+
+lvchange -aey $vg
+
+lvs -a -o+origin_size,seg_size $vg
+
+# Chain external origins
+lvconvert --type thin --originname extorg1 --thinpool $vg/pool $vg/extorg
+check inactive $vg extorg1
+
+lvconvert --originname extorg2 --thinpool $vg/pool -T $vg/extorg1
+check inactive $vg extorg1
+check inactive $vg extorg2
+
+lvchange -an $vg/extorg
+lvchange -ay $vg/extorg1
+
+lvcreate -l4 -s $vg/$lv1 -n $lv2
+lvcreate -l8 -s $vg/extorg -n $lv3
+lvcreate -l12 -s $vg/extorg1 -n $lv4
+lvcreate -l16 -s $vg/extorg2 -n $lv5
+#vgchange -aey $vg
+#lvremove -f $vg/extorg2
+#exit 0
+# Converting old-snapshot into external origin is not supported
+not lvconvert -T --thinpool $vg/pool --originname lv5origin $vg/$lv4
+
+lvs -a -o +segtype $vg
+
+check lv_field $vg/$lv1 segtype thin
+check lv_field $vg/$lv2 segtype linear
+check lv_field $vg/$lv3 segtype linear
+check lv_field $vg/$lv4 segtype linear
+check lv_field $vg/$lv5 segtype linear
+check lv_field $vg/extorg segtype thin
+check lv_field $vg/extorg1 segtype thin
+check lv_field $vg/extorg2 segtype linear
+
+vgchange -ay $vg
+
+lvs -a -o+origin_size,seg_size $vg
+
+lvchange -an $vg/extorg2
+check inactive $vg extorg2
+
+# Remove all volumes dependent on external origin
+lvs -a -o+origin_size,seg_size,segtype $vg
+lvremove -f $vg/extorg2
+# Only pool is left
+check vg_field $vg lv_count 1
+lvremove -ff $vg
+
+# Test conversion to the pool and thin external at the same time (rhbz #1003461)
+lvcreate -l50 -n pool $vg
+lvcreate -l100 -n thin $vg
+lvconvert --yes --thin --thinpool $vg/pool $vg/thin --originname thin-origin
+check lv_field $vg/thin segtype thin
+check lv_field $vg/thin-origin segtype linear
+lvremove -ff $vg
+
+# Test conversion with non-zeroing thin-pool, should not WARN about zeroing
+lvcreate -l50 -n pool $vg
+lvcreate -l100 -n thin $vg
+lvconvert --yes --thin --thinpool $vg/pool $vg/thin --zero n --originname thin-origin 2>&1 | tee out
+not grep "not zeroed" out
+check lv_field $vg/pool zero ""
+
+vgremove -ff $vg
diff --git a/test/shell/lvconvert-thin-from-thick.sh b/test/shell/lvconvert-thin-from-thick.sh
new file mode 100644
index 0000000..d0c7718
--- /dev/null
+++ b/test/shell/lvconvert-thin-from-thick.sh
@@ -0,0 +1,93 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2023 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+# Test conversion to thin volume from thick LVs
+
+SKIP_WITH_LVMPOLLD=1
+
+export LVM_TEST_THIN_REPAIR_CMD=${LVM_TEST_THIN_REPAIR_CMD-/bin/false}
+
+. lib/inittest
+
+which mkfs.ext4 || skip
+which fsck || skip
+aux have_tool_at_least "$LVM_TEST_THIN_RESTORE_CMD" 0 3 1 || skip
+aux have_thin 1 5 0 || skip
+
+_convert_to_thin() {
+ mkfs.ext4 -E nodiscard "$DM_DEV_DIR/$vg/$lv1"
+ lvconvert --yes --type thin $vg/$lv1
+ fsck -n "$DM_DEV_DIR/$vg/$lv1"
+ check lv_field $vg/$lv1 segtype thin
+ lvs -ao+segtype $vg
+ lvremove -f $vg
+}
+
+
+#
+# Main
+#
+aux prepare_vg 2 6000
+
+# error -> thin
+lvcreate --type error -Zn -L10 -n $lv1 $vg
+lvconvert --yes --type thin $vg/$lv1
+not dd if="$DM_DEV_DIR/$vg/$lv1" of=/dev/null bs=512 count=1
+lvremove -f $vg
+
+# zero -> thin
+lvcreate --type zero -L2T -n $lv1 $vg
+lvconvert --yes --type thin $vg/$lv1
+lvremove -f $vg
+
+# zero -> thin --test
+if [ ! -e LOCAL_LVMLOCKD ] ; then
+# FIXME: missing support with lvmlockd
+lvcreate --type zero -L2T -n $lv1 $vg
+lvconvert --yes --type thin --test $vg/$lv1
+check lv_field $vg/$lv1 segtype zero
+check vg_field $vg lv_count 1
+lvremove -f $vg
+fi
+
+# linear -> thin
+lvcreate -L10 -n $lv1 $vg
+_convert_to_thin
+
+# raid1 -> thin
+if aux have_raid 1 7 0 ; then
+ lvcreate --type raid1 -L10 -n $lv1 $vg
+ _convert_to_thin
+fi
+
+# cache -> thin
+if aux have_cache 1 3 0 ; then
+ lvcreate -L10 -n $lv1 $vg
+ lvcreate -H -L10 $vg/$lv1
+ _convert_to_thin
+fi
+
+# writecache -> thin
+if aux have_writecache 1 0 0 ; then
+ lvcreate -L10 -n $lv1 $vg
+ lvcreate -an -L10 -n $lv2 $vg
+ lvconvert --yes --type writecache --cachevol $lv2 $vg/$lv1
+ _convert_to_thin
+fi
+
+# vdo -> thin
+if aux have_vdo 6 2 0 ; then
+ lvcreate --type vdo -L4G -n $lv1 $vg/$lv2
+ _convert_to_thin
+fi
+
+vgremove -ff $vg
diff --git a/test/shell/lvconvert-thin-raid.sh b/test/shell/lvconvert-thin-raid.sh
new file mode 100644
index 0000000..c021e3b
--- /dev/null
+++ b/test/shell/lvconvert-thin-raid.sh
@@ -0,0 +1,61 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2014-2017 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+SKIP_WITH_LVMPOLLD=1
+
+export LVM_TEST_THIN_REPAIR_CMD=${LVM_TEST_THIN_REPAIR_CMD-/bin/false}
+
+. lib/inittest
+
+aux have_thin 1 0 0 || skip
+aux have_raid 1 4 0 || skip
+
+aux prepare_vg 4
+
+# create RAID LVs for data and metadata volumes
+lvcreate -aey -L10M --type raid1 -m3 -n $lv1 $vg
+lvcreate -aey -L8M --type raid1 -m3 -n $lv2 $vg
+aux wait_for_sync $vg $lv1
+aux wait_for_sync $vg $lv2
+lvchange -an $vg/$lv1
+
+# FIXME: temporarily we return error code 5
+INVALID=not
+# conversion fails for internal volumes
+$INVALID lvconvert --thinpool $vg/${lv1}_rimage_0
+$INVALID lvconvert --yes --thinpool $vg/$lv1 --poolmetadata $vg/${lv2}_rimage_0
+
+lvconvert --yes --thinpool $vg/$lv1 --poolmetadata $vg/$lv2
+
+lvchange -ay $vg
+
+lvconvert --splitmirrors 1 --name data2 $vg/${lv1}_tdata "$dev2"
+lvconvert --splitmirrors 1 --name data3 $vg/${lv1}_tdata "$dev3"
+# Check split and track gets rejected on 2-legged raid1
+not lvconvert --splitmirrors 1 --trackchanges $vg/${lv1}_tdata "$dev4"
+lvconvert -y --splitmirrors 1 --trackchanges $vg/${lv1}_tdata "$dev4"
+
+lvconvert --splitmirrors 1 --name meta1 $vg/${lv1}_tmeta "$dev1"
+lvconvert --splitmirrors 1 --name meta2 $vg/${lv1}_tmeta "$dev2"
+# Check split and track gets rejected on 2-legged raid1
+not lvconvert --splitmirrors 1 --trackchanges $vg/${lv1}_tmeta "$dev4"
+lvconvert -y --splitmirrors 1 --trackchanges $vg/${lv1}_tmeta "$dev4"
+
+lvremove -ff $vg/data2 $vg/data3 $vg/meta1 $vg/meta2
+
+lvconvert --merge $vg/${lv1}_tdata_rimage_1
+lvconvert --merge $vg/${lv1}_tmeta_rimage_1
+
+lvconvert -y -m +1 $vg/${lv1}_tdata "$dev2"
+lvconvert -y -m +1 $vg/${lv1}_tmeta "$dev1"
+
+vgremove -ff $vg
diff --git a/test/shell/lvconvert-thin.sh b/test/shell/lvconvert-thin.sh
index 97ccc09..b1b11ab 100644
--- a/test/shell/lvconvert-thin.sh
+++ b/test/shell/lvconvert-thin.sh
@@ -1,4 +1,4 @@
-#!/bin/sh
+#!/usr/bin/env bash
# Copyright (C) 2012 Red Hat, Inc. All rights reserved.
#
@@ -8,9 +8,20 @@
#
# 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
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
-. lib/test
+SKIP_WITH_LVMLOCKD=1
+SKIP_WITH_LVMPOLLD=1
+
+export LVM_TEST_THIN_REPAIR_CMD=${LVM_TEST_THIN_REPAIR_CMD-/bin/false}
+
+. lib/inittest
+
+prepare_lvs() {
+ lvremove -f $vg
+ lvcreate -L10M -n $lv1 $vg
+ lvcreate -L8M -n $lv2 $vg
+}
#
# Main
@@ -18,26 +29,133 @@
aux have_thin 1 0 0 || skip
aux prepare_pvs 4 64
+get_devs
+
+# build one large PV
+vgcreate $vg1 "$dev1" "$dev2" "$dev3"
+
+# 32bit linux kernels are fragille with device size >= 16T
+# maybe uname -m [ x86_64 | i686 ]
+TSIZE=64T
+aux can_use_16T || TSIZE=15T
+lvcreate --type snapshot -l 100%FREE -n $lv $vg1 --virtualsize $TSIZE
+aux extend_filter_LVMTEST
+
+pvcreate "$DM_DEV_DIR/$vg1/$lv"
+vgcreate $vg -s 64K "$dev4" "$DM_DEV_DIR/$vg1/$lv"
-vgcreate $vg -s 64K $(cat DEVICES)
+lvcreate -L1T -n $lv1 $vg
+lvconvert --yes -c 8M --type thin --poolmetadatasize 1G $vg/$lv1
+
+# needs some --cachepool or --thinpool
+invalid lvconvert --yes --poolmetadatasize 1G $vg/$lv1
+lvremove -f $vg
# 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
+lvcreate -aey -L10M --type mirror -m1 --mirrorlog core -n $lv1 $vg
+lvcreate -aey -L10M -n $lv2 $vg
+lvchange -an $vg/$lv1
+
+# conversion fails for mirror segment type
+fail lvconvert --thinpool $vg/$lv1
+
+# FIXME: temporarily we return error code 5
+INVALID=not
+# cannot use same LV
+$INVALID lvconvert --yes --thinpool $vg/$lv2 --poolmetadata $vg/$lv2
+
+prepare_lvs
+
+# conversion fails for internal volumes
+# can't use --readahead with --poolmetadata
+invalid lvconvert --thinpool $vg/$lv1 --poolmetadata $vg/$lv2 --readahead 512
+lvconvert --yes --thinpool $vg/$lv1 --poolmetadata $vg/$lv2
+
+prepare_lvs
+lvconvert --yes -c 64 --stripes 2 --thinpool $vg/$lv1 --readahead 48
+lvremove -f $vg
+
+
+# Swaping of metadata volume
+lvcreate -L1T -n $lv1 $vg
+lvcreate -L32 -n $lv2 $vg
+lvconvert --yes -c 8M --type thin-pool $vg/$lv1 2>&1 | tee err
+# Check there is a warning for large chunk size and zeroing enabled
+grep "WARNING: Pool zeroing and" err
+UUID=$(get lv_field $vg/$lv2 uuid)
+# Fail is pool is active
+# TODO maybe detect inactive pool and deactivate
+fail lvconvert --yes --thinpool $vg/$lv1 --poolmetadata $lv2
+lvchange -an $vg
+lvconvert --yes --thinpool $vg/$lv1 --poolmetadata $lv2
+check lv_field $vg/${lv1}_tmeta uuid "$UUID"
+
+# and swap again with new command --swapmetadata
+lvconvert --yes --swapmetadata $vg/$lv1 --poolmetadata $lv2
+check lv_field $vg/$lv2 uuid "$UUID"
+lvremove -f $vg
+
+
+# test with bigger sizes
+lvcreate -L1T -n $lv1 $vg
+lvcreate -L8M -n $lv2 $vg
+lvcreate -L1M -n $lv3 $vg
+
+# chunk size is bigger then size of thin pool data
+fail lvconvert --yes -c 1G --thinpool $vg/$lv3
+# stripes can't be used with poolmetadata
+invalid lvconvert --stripes 2 --thinpool $vg/$lv1 --poolmetadata $vg/$lv2
+# too small metadata (<2M)
+fail lvconvert --yes -c 64 --thinpool $vg/$lv1 --poolmetadata $vg/$lv3
+# too small chunk size fails
+$INVALID lvconvert -c 4 --thinpool $vg/$lv1 --poolmetadata $vg/$lv2
+# too big chunk size fails
+$INVALID lvconvert -c 2G --thinpool $vg/$lv1 --poolmetadata $vg/$lv2
+# negative chunk size fails
+$INVALID lvconvert -c -256 --thinpool $vg/$lv1 --poolmetadata $vg/$lv2
+# non multiple of 64KiB fails
+$INVALID lvconvert -c 88 --thinpool $vg/$lv1 --poolmetadata $vg/$lv2
+
+# cannot use same LV for pool and convertion
+$INVALID lvconvert --yes --thinpool $vg/$lv3 -T $vg/$lv3
+
+# Warning about smaller then suggested
+lvconvert --yes -c 256 --thinpool $vg/$lv1 --poolmetadata $vg/$lv2 2>&1 | tee err
+grep "WARNING: Chunk size is smaller" err
+lvremove -f $vg
+
+
+lvcreate -L1T -n $lv1 $vg
+lvcreate -L32G -n $lv2 $vg
+# Warning about bigger then needed
+lvconvert --yes --thinpool $vg/$lv1 --poolmetadata $vg/$lv2 2>&1 | tee err
+grep -i "maximum" err
+lvremove -f $vg
-lvconvert -c 64K --thinpool $vg/$lv1 --poolmetadata $vg/$lv2
-lvcreate -V10M -T $vg/$lv1 --name $lv3
+if test "$TSIZE" = 64T; then
+lvcreate -L24T -n $lv1 $vg
+# Warning about bigger then needed (24T data and 16G -> 128K chunk)
+fail lvconvert --yes -c 64 --thinpool $vg/$lv1 2>&1 | tee err
+grep "WARNING: Chunk size is too small" err
+lvremove -f $vg
+fi
-# check lvrename work properly
-lvrename $vg/$lv1 $vg/pool
-check lv_field $vg/pool name "pool"
+#lvs -a -o+chunk_size,stripe_size,seg_pe_ranges
-lvrename $vg/$lv3 $vg/$lv4
-check lv_field $vg/$lv4 name "$lv4"
+####################################
+# Prohibites thin pool conversions #
+####################################
+lvcreate -L32 -n $lv1 $vg
+lvcreate -L16 -n $lv2 $vg
+lvconvert --yes --thinpool $vg/$lv1
-# not yet supported conversions
-not lvconvert -m 1 $vg/pool
-not lvconvert -m 1 $vg/$lv3
+not aux have_cache 1 3 0 || fail lvconvert --yes --type cache-pool $vg/$lv1
+fail lvconvert --yes --type mirror -m1 $vg/$lv1
+not aux have_raid 1 0 0 || fail lvconvert --yes --type raid1 -m1 $vg/$lv1
+fail lvconvert --yes --type snapshot $vg/$lv1 $vg/$lv2
+fail lvconvert --yes --type snapshot $vg/$lv2 $vg/$lv1
+fail lvconvert --yes --type thin-pool $vg/$lv1
vgremove -ff $vg
+vgremove -ff $vg1
diff --git a/test/shell/lvconvert-twostep.sh b/test/shell/lvconvert-twostep.sh
index c45e7bc..dc072f0 100644
--- a/test/shell/lvconvert-twostep.sh
+++ b/test/shell/lvconvert-twostep.sh
@@ -1,5 +1,6 @@
-#!/bin/sh
-# Copyright (C) 2010 Red Hat, Inc. All rights reserved.
+#!/usr/bin/env bash
+
+# Copyright (C) 2010,2018 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
@@ -7,13 +8,17 @@
#
# 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
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+SKIP_WITH_LVMPOLLD=1
-. lib/test
+. lib/inittest
+
+aux lvmconf "global/support_mirrored_mirror_log=1"
aux prepare_vg 4
-lvcreate -m 1 --mirrorlog disk --ig -L 1 -n mirror $vg
+lvcreate -aey --type mirror -m 1 --mirrorlog disk --ignoremonitoring -L 1 -n mirror $vg
not lvconvert -m 2 --mirrorlog core $vg/mirror "$dev3" 2>&1 | tee errs
grep "two steps" errs
@@ -22,5 +27,10 @@ lvconvert --mirrorlog core $vg/mirror
not lvconvert -m 1 --mirrorlog disk $vg/mirror "$dev3" 2>&1 | tee errs
grep "two steps" errs
+if test ! -e LOCAL_CLVMD ; then
+# FIXME mirrored unsupported in cluster
not lvconvert -m 1 --mirrorlog mirrored $vg/mirror "$dev3" "$dev4" 2>&1 | tee errs
grep "two steps" errs
+fi
+
+vgremove -ff $vg
diff --git a/test/shell/lvconvert-vdo-raid.sh b/test/shell/lvconvert-vdo-raid.sh
new file mode 100644
index 0000000..1383145
--- /dev/null
+++ b/test/shell/lvconvert-vdo-raid.sh
@@ -0,0 +1,70 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2020 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+# Exercise vdo-pool's on raidLV
+
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+#
+# Main
+#
+
+#
+aux have_vdo 6 2 1 || skip
+aux have_raid 1 3 0 || skip
+
+
+aux prepare_vg 2 9000
+
+lvcreate --yes --vdo -L4G $vg/vpool
+
+aux zero_dev "$dev1" "$(( $(get first_extent_sector "$dev1") + 8192 )):"
+aux zero_dev "$dev2" "$(( $(get first_extent_sector "$dev2") + 8192 )):"
+
+# convert _vdata to raid
+lvconvert --yes --type raid1 $vg/vpool_vdata
+check lv_field $vg/vpool_vdata segtype raid1 -a
+
+lvconvert --yes -m 0 $vg/vpool_vdata "$dev2"
+check lv_field $vg/vpool_vdata segtype linear -a
+
+# vpool should redirect to _vdata
+lvconvert --yes --type raid1 $vg/vpool
+check lv_field $vg/vpool_vdata segtype raid1 -a
+
+lvremove -f $vg
+
+aux enable_dev "$dev1" "$dev2"
+
+
+lvcreate --type raid1 -L4G --nosync -n vpool1 $vg
+
+lvconvert --yes --vdopool $vg/vpool1 -V2G -n $lv1
+
+mkfs.ext4 -E nodiscard "$DM_DEV_DIR/$vg/$lv1"
+
+not lvrename $vg/vpool1
+
+lvchange -an $vg
+
+lvrename $vg/vpool1 $vg/vpool
+
+lvchange -ay $vg
+
+fsck -n "$DM_DEV_DIR/$vg/$lv1"
+
+lvs -a $vg
+
+vgremove -ff $vg
diff --git a/test/shell/lvconvert-vdo.sh b/test/shell/lvconvert-vdo.sh
new file mode 100644
index 0000000..7c0bce5
--- /dev/null
+++ b/test/shell/lvconvert-vdo.sh
@@ -0,0 +1,78 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2018 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+SKIP_WITH_LVMLOCKD=1
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+#
+# Main
+#
+aux prepare_vg 2 6400
+
+# Conversion to vdo-pool
+lvcreate -L5G -n $lv1 $vg
+
+if not aux have_vdo 6 2 0 ; then
+# For unsupported VDO let's check lvconvert fails
+ not lvconvert --yes --type vdo-pool $vg/$lv1 |& tee out
+ vgremove -ff $vg
+ exit
+fi
+
+# Check there is big prompting warning
+not lvconvert --type vdo-pool $vg/$lv1 |& tee out
+grep "WARNING" out
+
+# Check --vdosettings is also applied to converted vdo-pool
+lvconvert -y --type vdo-pool --vdosettings 'ack_threads=5' $vg/$lv1
+check lv_field $vg/$lv1 vdo_ack_threads "5"
+lvremove -f $vg
+
+#
+lvcreate -L5G -n $lv1 $vg
+lvconvert -y --vdopool $vg/$lv1
+lvremove -f $vg
+
+
+lvcreate -L5G -n $lv1 $vg
+lvconvert -y --vdopool $vg/$lv1 -n $lv2
+check lv_field $vg/$lv1 segtype vdo-pool
+check lv_field $vg/${lv1}_vdata segtype linear -a
+check lv_field $vg/$lv2 segtype vdo
+lvremove -f $vg
+
+
+lvcreate -L5G -n $lv1 $vg
+lvconvert -y --type vdo-pool $vg/$lv1 -n $lv2 -V10G
+lvremove -f $vg
+
+
+lvcreate -L5G -n $lv1 $vg
+lvconvert -y --vdopool $vg/$lv1 -n $lv2 -V10G --compression n --deduplication n
+check lv_field $vg/$lv1 size "5.00g"
+check lv_field $vg/${lv1}_vdata size "5.00g" -a
+check lv_field $vg/$lv2 size "10.00g"
+lvremove -f $vg
+
+
+# Simple stacking works...
+# Just be sure test do not try to synchronize 5G of mirror!!
+lvcreate -L5G --type mirror --nosync -n $lv1 $vg
+lvconvert -y --vdopool $vg/$lv1 -n $lv2
+lvs -a $vg
+check lv_field $vg/${lv1}_vdata segtype mirror -a
+lvremove -f $vg
+
+
+vgremove -ff $vg
diff --git a/test/shell/lvcreate-cache-fail.sh b/test/shell/lvcreate-cache-fail.sh
new file mode 100644
index 0000000..39a8273
--- /dev/null
+++ b/test/shell/lvcreate-cache-fail.sh
@@ -0,0 +1,42 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2016 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+# Exercise creation of cache and cache pool volumes and failure path
+# https://bugzilla.redhat.com/1355923
+
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+aux have_cache 1 3 0 || skip
+
+#aux prepare_pvs 1 4707950
+#vgcreate $SHARED $vg "$dev1"
+#lvcreate -L4T -n $lv1 $vg
+#lvcreate -H -L500G -n cache $vg/$lv1
+#fail lvcreate -H -l 127999 -n cache $vg/$lv1
+
+aux prepare_vg 1 20
+lvcreate -L10 -n $lv1 $vg
+fail lvcreate -H -L2 -n cache $vg/$lv1
+
+lvs -a $vg
+vgs $vg
+lvdisplay $vg
+
+#dmsetup table
+#dmsetup status
+#time dmsetup suspend ${vg}-${lv1}
+#time dmsetup resume ${vg}-${lv1}
+
+vgremove -ff $vg
diff --git a/test/shell/lvcreate-cache-no-tools.sh b/test/shell/lvcreate-cache-no-tools.sh
new file mode 100644
index 0000000..2e4ee46
--- /dev/null
+++ b/test/shell/lvcreate-cache-no-tools.sh
@@ -0,0 +1,119 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2018 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+# Exercise creation of cache without cache_check
+
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+if test -e LOCAL_CLVMD ; then
+# In cluster, the error from activation is logged in clvmd
+# so we can only check resulting state of activation
+ GREP="echo"
+else
+ GREP="grep"
+fi
+
+make_fake_() {
+ cat <<- EOF >fake-tool.sh
+#!/bin/sh
+echo "$1"
+exit 1
+EOF
+ chmod +x fake-tool.sh
+}
+
+check_change_() {
+ lvchange -an $vg |& tee out
+ "$GREP" "$1" out
+
+ lvchange -ay $vg |& tee out
+ "$GREP" "$1" out
+}
+
+# Integrity check fails, but deactivation is OK
+check_change_failed_() {
+ lvchange -an $vg |& tee out
+ "$GREP" "failed" out
+
+ # Activation must fail
+ fail lvchange -ay $vg |& tee out
+ "$GREP" "failed" out
+
+ cat <<- EOF >fake-tool.sh
+#!/bin/sh
+exit
+EOF
+ chmod +x fake-tool.sh
+ # Activate without any check
+ lvchange -ay $vg
+}
+
+
+aux have_cache 1 3 0 || skip
+
+# FIXME: parallel cache metadata allocator is crashing when used value 8000!
+aux prepare_vg 5 80000
+
+aux lvmconf 'global/cache_check_executable = "./fake-tool.sh"'
+rm -f fake-tool.sh
+
+# On cache target that supports V2
+if aux have_cache 1 10 0 ; then
+
+lvcreate -aey -l1 -n $lv1 $vg
+lvcreate -H -l2 $vg/$lv1
+
+check_change_ "Check is skipped"
+
+# prepare fake version of cache_check tool that reports old version
+make_fake_ "0.1.0"
+check_change_ "upgrade"
+
+# prepare fake version of cache_check tool that reports garbage
+make_fake_ "garbage"
+check_change_ "parse"
+
+# prepare fake version of cache_check tool with high version
+make_fake_ "99.0.0"
+check_change_failed_
+
+lvremove -f $vg
+
+fi
+
+# Enforce older cache target format V1
+aux lvmconf 'allocation/cache_metadata_format = 1'
+
+rm -f fake-tool.sh
+
+lvcreate -aey -l1 -n $lv1 $vg
+lvcreate -H -l2 $vg/$lv1
+
+check_change_ "Check is skipped"
+
+# prepare fake version of cache_check tool that reports old version
+make_fake_ "0.1.0"
+check_change_failed_
+
+# prepare fake version of cache_check tool that reports garbage
+make_fake_ "garbage"
+check_change_failed_
+
+# prepare fake version of cache_check tool with high version
+make_fake_ "99.0.0"
+check_change_failed_
+
+
+vgremove -ff $vg
diff --git a/test/shell/lvcreate-cache-raid.sh b/test/shell/lvcreate-cache-raid.sh
new file mode 100644
index 0000000..d1d1c19
--- /dev/null
+++ b/test/shell/lvcreate-cache-raid.sh
@@ -0,0 +1,36 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2015 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+# Exercise creation of cache and raids
+
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+aux have_cache 1 3 0 || skip
+aux have_raid 1 0 0 || skip
+
+# FIXME: parallel cache metadata allocator is crashing when used value 8000!
+aux prepare_vg 5 80000
+
+aux lvmconf 'global/cache_disabled_features = [ "policy_smq" ]'
+
+# Bug 1110026 & Bug 1095843
+# Create RAID1 origin, then cache pool and cache
+lvcreate -aey -l 2 --type raid1 -m1 -n $lv2 $vg
+lvcreate --cache -l 1 $vg/$lv2
+check lv_exists $vg/${lv2}_corig_rimage_0 # ensure images are properly renamed
+check active $vg ${lv2}_corig
+dmsetup table ${vg}-$lv2 | grep cache # ensure it is loaded in kernel
+
+vgremove -ff $vg
diff --git a/test/shell/lvcreate-cache-snapshot.sh b/test/shell/lvcreate-cache-snapshot.sh
new file mode 100644
index 0000000..5d1c5a7
--- /dev/null
+++ b/test/shell/lvcreate-cache-snapshot.sh
@@ -0,0 +1,63 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2016 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+# Exercise creation of snapshot of cached LV
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+which mkfs.ext2 || skip
+which fsck || skip
+
+aux have_cache 1 5 0 || skip
+
+aux prepare_vg 2
+
+lvcreate --type cache-pool -L1 $vg/cpool
+lvcreate -H -L4 -n $lv1 --cachepool $vg/cpool $vg
+
+lvcreate -s -L2 -n $lv2 $vg/$lv1
+check lv_field $vg/$lv1 segtype cache
+
+
+# Make some 'fs' data in snapshot
+mkfs.ext2 "$DM_DEV_DIR/$vg/$lv2"
+mkdir mnt
+mount "$DM_DEV_DIR/$vg/$lv2" mnt
+touch mnt/test
+umount mnt
+
+sync
+aux udev_wait
+
+# Merge snap to origin
+lvconvert --merge $vg/$lv2
+
+# Check cached origin has no valid fs.
+fsck -n "$DM_DEV_DIR/$vg/$lv1"
+
+# Check deactivation
+lvchange -an $vg
+
+# Check activation
+lvchange -ay $vg
+
+
+lvconvert --uncache $vg/$lv1
+check lv_field $vg/$lv1 segtype linear
+
+# Uncached origin is fine as well
+fsck -n "$DM_DEV_DIR/$vg/$lv1"
+
+
+vgremove -ff $vg
diff --git a/test/shell/lvcreate-cache.sh b/test/shell/lvcreate-cache.sh
new file mode 100644
index 0000000..38c915e
--- /dev/null
+++ b/test/shell/lvcreate-cache.sh
@@ -0,0 +1,308 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2014 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+# Exercise creation of cache and cache pool volumes
+
+# Full CLI uses --type
+# Shorthand CLI uses -H | --cache
+
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+aux have_cache 1 3 0 || skip
+
+# FIXME: parallel cache metadata allocator is crashing when used value 8000!
+aux prepare_vg 5 80000
+
+aux lvmconf 'global/cache_disabled_features = [ "policy_smq" ]'
+
+#######################
+# Cache_Pool creation #
+#######################
+# TODO: Unsupported yet creation of cache pool and cached volume at once
+# TODO: Introduce --pooldatasize
+# TODO: Policy to determine cache pool size and cache pool name
+invalid lvcreate -H -l 1 $vg
+invalid lvcreate -H -l 1 --name $lv1 $vg
+invalid lvcreate -l 1 --cache $vg
+# Only cached volume could be created
+invalid lvcreate -l 1 --type cache $vg
+# Striping is not supported with cache-pool creation
+invalid lvcreate -l 1 -i 2 --type cache-pool $vg
+# Fails as it needs to see VG content
+fail lvcreate -l 1 --type cache --cachepool $vg/pool1
+fail lvcreate -l 1 --type cache --cachepool pool2 $vg
+fail lvcreate -l 1 --cache $vg/pool3
+fail lvcreate -l 1 -H --cachepool pool4 $vg
+fail lvcreate -l 1 -H --name $lv2 $vg/pool5
+fail lvcreate -l 1 -H --name $lv3 --cachepool $vg/pool6
+fail lvcreate -l 1 -H --name $vg/$lv4 --cachepool pool7
+
+# Unlike in thin pool case - cache pool and cache volume both need size arg.
+# So we require cache pool to exist and need to fail when it's missing.
+#
+# --cachepool gives implicit --cache
+fail lvcreate -l 1 --cachepool pool8 $vg
+
+# no size specified
+invalid lvcreate --cachepool pool $vg 2>&1 | tee err
+#grep "specify either size or extents" err
+grep "No command with matching syntax recognised" err
+
+# Check nothing has been created yet
+check vg_field $vg lv_count 0
+
+# Checks that argument passed with --cachepool is really a cache-pool
+lvcreate -an -l 1 -n $lv1 $vg
+# Hint: nice way to 'tee' only stderr.log so we can check it's log_error()
+fail lvcreate -L10 --cachepool $vg/$lv1 2> >(tee -a stderr.log >&2)
+grep "not a cache pool" stderr.log
+
+# With --type cache-pool we are clear which segtype has to be created
+lvcreate -l 1 --type cache-pool $vg/pool1
+check lv_field $vg/pool1 segtype "cache-pool"
+lvcreate -l 1 --type cache-pool --name $vg/pool2 $vg
+check lv_field $vg/pool2 segtype "cache-pool"
+lvcreate -l 1 --type cache-pool --cachepool $vg/pool3 $vg
+check lv_field $vg/pool3 segtype "cache-pool"
+lvcreate -l 1 --type cache-pool --cachepool $vg/pool4
+check lv_field $vg/pool4 segtype "cache-pool"
+lvcreate -l 1 --type cache-pool --cachepool pool5 $vg
+check lv_field $vg/pool5 segtype "cache-pool"
+lvcreate -l 1 --type cache-pool --name pool6 $vg
+check lv_field $vg/pool6 segtype "cache-pool"
+lvcreate -l 1 --type cache-pool --name $vg/pool7
+check lv_field $vg/pool7 segtype "cache-pool"
+
+lvremove -f $vg
+
+
+# Check the percentage values are reported for both cache and cache-pool
+lvcreate --type cache-pool -L1 $vg/cpool
+lvcreate -H -L4 -n $lv1 $vg/cpool
+
+check lv_field $vg/$lv1 origin "[${lv1}_corig]"
+check lv_field $vg/$lv1 copy_percent "0.00"
+# there should be something present (value differs per policy version)
+test -n "$(get lv_field $vg/$lv1 data_percent)"
+test -n "$(get lv_field $vg/$lv1 metadata_percent)"
+check lv_field $vg/cpool_cpool copy_percent "0.00"
+test -n "$(get lv_field $vg/cpool_cpool data_percent)"
+test -n "$(get lv_field $vg/cpool_cpool metadata_percent)"
+# check we also display percent value for segmented output (-o+devices)
+lvs -a -o+devices $vg/cpool_cpool | tee out
+grep "0.00" out
+lvremove -f $vg
+
+
+# Validate ambiguous pool name is detected
+invalid lvcreate -l 1 --type cache-pool --cachepool pool1 $vg/pool2
+invalid lvcreate -l 1 --type cache-pool --name pool3 --cachepool pool4 $vg
+invalid lvcreate -l 1 --type cache-pool --name pool6 --cachepool pool6 $vg/pool7
+invalid lvcreate -l 1 --type cache-pool --name pool8 $vg/pool9
+
+# Unsupported with cache & cache pool
+invalid lvcreate --type cache-pool --discards passdown -l1 $vg
+invalid lvcreate -H --discards passdown -l1 $vg
+invalid lvcreate --type cache-pool --virtualsize 1T -l1 $vg
+invalid lvcreate -H --virtualsize 1T -l1 $vg
+
+check vg_field $vg lv_count 0
+
+
+for mode in "" "--cachemode writethrough"
+do
+
+################
+# Cache creation
+# Creating a cache is a two phase process
+# - first, cache_pool (or origin)
+# - then, the cache LV (lvcreate distinguishes supplied origin vs cache_pool)
+################
+
+lvcreate --type cache-pool -l 1 -n pool $vg $mode
+# Select automatic name for cached LV
+lvcreate --type cache -l1 $vg/pool
+
+lvcreate --type cache-pool -l 1 -n pool1 $vg $mode
+lvcreate --cache -l1 -n $lv1 --cachepool $vg/pool1
+dmsetup table ${vg}-$lv1 | grep cache # ensure it is loaded in kernel
+
+lvcreate --type cache-pool -l 1 -n pool2 $vg $mode
+lvcreate -H -l1 -n $lv2 --cachepool pool2 $vg
+
+#
+# Now check removals
+#
+
+# Removal of cached LV removes every related LV
+check lv_field $vg/$lv1 segtype "cache"
+lvremove -f $vg/$lv1
+check lv_not_exists $vg $lv1 pool1 pool1_cdata pool1_cmeta
+# to preserve cachepool use lvconvert --splitcache $vg/$lv1
+
+# Removal of cache pool leaves origin uncached
+check lv_field $vg/$lv2 segtype "cache"
+lvremove -f $vg/pool2_cpool
+check lv_not_exists $vg pool2_cpool pool2_cpool_cdata pool2_cpool_cmeta
+check lv_field $vg/$lv2 segtype "linear"
+
+lvremove -f $vg
+
+done
+
+
+# Conversion through lvcreate case
+# Bug 1110026
+# Create origin, then cache pool and cache the origin
+lvcreate -aey -l 2 -n $lv1 $vg
+lvcreate --type cache -l 1 $vg/$lv1
+dmsetup table ${vg}-$lv1 | grep cache # ensure it is loaded in kernel
+
+lvremove -f $vg
+
+# Check minimum cache pool metadata size
+lvcreate -l 1 --type cache-pool --poolmetadatasize 1 $vg 2>&1 | tee out
+grep -i "minimal" out
+
+
+# FIXME: This test is failing in allocator with smaller VG sizes
+lvcreate -l 1 --type cache-pool --poolmetadatasize 17G $vg 2>&1 | tee out
+grep -i "maximum" out
+
+lvremove -f $vg
+########################################
+# Cache conversion and r/w permissions #
+########################################
+
+# writeable origin and 'default' => writable cache + origin
+lvcreate -an -l1 -n $vg/$lv1
+# do not allow stripping for cache-pool
+fail lvcreate -H -i 2 -l1 -n cpool1 $vg/$lv1
+lvcreate -H -l1 -n cpool1 $vg/$lv1
+check lv_attr_bit perm $vg/cpool1_cpool "w"
+check lv_attr_bit perm $vg/${lv1}_corig "w"
+check lv_attr_bit perm $vg/$lv1 "w"
+
+# writeable origin and -pr => conversion is not supported
+lvcreate -an -l1 -n $vg/$lv2
+fail lvcreate -H -l1 -pr -n cpool2 $vg/$lv2
+
+# read-only origin and -pr => read-only cache + origin
+lvcreate -an -pr -l1 -n $vg/$lv3
+lvcreate -an -H -l1 -pr -n cpool3 $vg/$lv3
+check lv_attr_bit perm $vg/cpool3_cpool "w"
+check lv_attr_bit perm $vg/${lv3}_corig "r"
+check lv_attr_bit perm $vg/$lv3 "r"
+check inactive $vg $lv3
+check inactive $vg cpool3_cpool
+
+# read-only origin and 'default' => read-only cache + origin
+lvcreate -an -pr -l1 -n $vg/$lv4
+lvcreate -H -l1 -n cpool4 $vg/$lv4
+check lv_attr_bit perm $vg/cpool4_cpool "w"
+check lv_attr_bit perm $vg/${lv4}_corig "r"
+check lv_attr_bit perm $vg/$lv4 "r"
+
+# read-only origin and -prw => conversion unsupported
+lvcreate -an -pr -l1 -n $vg/$lv5
+fail lvcreate -H -l1 -prw -n cpool5 $vg/$lv5
+
+# cached volume respects permissions
+lvcreate --type cache-pool -l1 -n $vg/cpool
+lvcreate -H -l1 -pr -n $lv6 $vg/cpool
+check lv_attr_bit perm $vg/cpool_cpool "w"
+check lv_attr_bit perm $vg/$lv6 "r"
+
+lvremove -f $vg
+
+########################################
+# Validate args are properly preserved #
+########################################
+lvcreate --type cache-pool -L10 --chunksize 256 --cachemode writeback $vg/cpool1
+check lv_field $vg/cpool1 chunksize "256.00k"
+check lv_field $vg/cpool1 cachemode "writeback"
+# check striping is supported when creating a cached LV
+lvcreate -H -L10 -i 2 -n $lv1 $vg/cpool1
+check lv_field $vg/${lv1}_corig stripes "2" -a
+check lv_field $vg/$lv1 chunksize "256.00k"
+check lv_field $vg/$lv1 cachemode "writeback"
+
+lvcreate --type cache-pool -L10 --chunksize 256 --cachemode writethrough $vg/cpool2
+lvcreate -H -L10 --chunksize 512 --cachemode writeback -n $lv2 $vg/cpool2
+check lv_field $vg/$lv2 chunksize "512.00k"
+check lv_field $vg/$lv2 cachemode "writeback"
+
+# Chunk bigger then pool size
+fail lvcreate --type cache-pool -l1 --chunksize 1G $vg/cpool3
+
+lvcreate --type cache-pool -L10 $vg/cpool4
+fail lvcreate -H -L10 --chunksize 16M $vg/cpool4
+
+lvdisplay --maps $vg
+
+lvremove -f $vg
+
+# migration_threshold is protected to not be smaller then 8*chunk_size
+# so even when user sets migration threshold to lower value,
+# activation will ensure the minimal size is preserved
+lvcreate --type cache-pool -L10 $vg/cpool
+lvcreate --type cache -l 1 --cachepool $vg/cpool -c 64k -n corigin $vg --cachesettings migration_threshold=233
+dmsetup status | grep $vg
+dmsetup status | grep $vg-corigin | grep 'migration_threshold 1024'
+lvchange -an $vg
+lvchange -ay $vg
+dmsetup status | grep $vg-corigin | grep 'migration_threshold 1024'
+
+lvremove -f $vg
+
+lvcreate --type cache-pool -L10 --cachepolicy mq --cachesettings migration_threshold=1233 $vg/cpool
+lvcreate --type cache -l 1 --cachepool $vg/cpool -n corigin $vg
+dmsetup status | grep $vg
+dmsetup status | grep $vg-corigin | grep 'migration_threshold 1233'
+
+lvremove -f $vg
+
+
+####################################################
+# S/MQ policy does not accept random string settings
+####################################################
+
+lvcreate -L1 -n $lv1 $vg
+lvcreate -L1 -H $vg/$lv1 --cachesettings unknown=0 |& tee out
+
+grep "not support \"unknown=0\"" out
+
+# But still the caching should proceed and LV should be available
+check lv_exists $vg/$lv1
+
+
+##############################
+# Test things that should fail
+##############################
+
+# Creation of read-only cache pool is not supported
+invalid lvcreate -pr --type cache-pool -l1 -n $vg/cpool
+
+# Attempt to use bigger chunk size then cache pool data size
+fail lvcreate -l 1 --type cache-pool --chunksize 16M $vg 2>out
+grep "chunk size" out
+
+# Option testing
+# --chunksize
+# --cachepolicy
+# --poolmetadatasize
+# --poolmetadataspare
+
+vgremove -ff $vg
diff --git a/test/shell/lvcreate-external-dmeventd.sh b/test/shell/lvcreate-external-dmeventd.sh
new file mode 100644
index 0000000..20973da
--- /dev/null
+++ b/test/shell/lvcreate-external-dmeventd.sh
@@ -0,0 +1,47 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2017 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+# Test check converted external origin remains monitored
+
+SKIP_WITH_LVMLOCKD=1
+SKIP_WITH_LVMPOLLD=1
+
+export LVM_TEST_THIN_REPAIR_CMD=${LVM_TEST_THIN_REPAIR_CMD-/bin/false}
+
+. lib/inittest
+
+#
+# Main
+#
+aux have_thin 1 3 0 || skip
+aux have_raid 1 3 0 || skip
+
+aux prepare_dmeventd
+aux prepare_vg 2
+
+# Test validation for external origin being multiple of thin pool chunk size
+lvcreate -L10M -T $vg/pool
+
+# Create raid LV (needs monitoring) for external origin.
+lvcreate -m1 -L1 -n $lv1 $vg
+
+lvconvert -T --thinpool $vg/pool --originname $lv2 $vg/$lv1
+
+# Check raid LV now as external origing with $lv2 name is still monitored
+check lv_first_seg_field $vg/$lv2 seg_monitor "monitored"
+
+lvchange -an $vg
+
+lvchange -ay $vg/$lv1
+check lv_first_seg_field $vg/$lv2 seg_monitor "monitored"
+
+vgremove -ff $vg
diff --git a/test/shell/lvcreate-large-raid.sh b/test/shell/lvcreate-large-raid.sh
index 8768bb3..a7af9cb 100644
--- a/test/shell/lvcreate-large-raid.sh
+++ b/test/shell/lvcreate-large-raid.sh
@@ -1,5 +1,6 @@
-#!/bin/sh
-# Copyright (C) 2012 Red Hat, Inc. All rights reserved.
+#!/usr/bin/env bash
+
+# Copyright (C) 2012,2016 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
@@ -7,65 +8,114 @@
#
# 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
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
# 'Exercise some lvcreate diagnostics'
-. lib/test
-aux target_at_least dm-raid 1 1 0 || skip
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+# FIXME update test to make something useful on <16T
+aux can_use_16T || skip
-aux prepare_vg 5
+aux have_raid 1 3 0 || skip
+v1_9_0=0
+aux have_raid 1 9 0 && v1_9_0=1
-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
+segtypes="raid5"
+aux have_raid4 && segtypes="raid4 raid5"
-#FIXME this should be 1024T
-#check lv_field $vg/$lv size "128.00m"
+# Prepare 5x ~1P sized devices
+aux prepare_pvs 5 1000000000
+get_devs
-aux lvmconf 'devices/filter = [ "a/dev\/mapper\/.*$/", "a/dev\/LVMTEST/", "r/.*/" ]'
+vgcreate $SHARED "$vg1" "${DEVICES[@]}"
-pvcreate $DM_DEV_DIR/$vg/$lv[12345]
-vgcreate -c n $vg1 $DM_DEV_DIR/$vg/$lv[12345]
+aux lvmconf 'devices/issue_discards = 1'
+
+# Delay PVs so that resynchronization doesn't fill too much space
+for device in "${DEVICES[@]}"
+do
+ aux zero_dev "$device" "$(( $(get first_extent_sector "$device") + 8192 )):"
+done
# bz837927 START
#
# Create large RAID LVs
#
-# We need '--nosync' or our virtual devices won't work
+
+# 200 TiB raid1
lvcreate --type raid1 -m 1 -L 200T -n $lv1 $vg1 --nosync
check lv_field $vg1/$lv1 size "200.00t"
+check raid_leg_status $vg1 $lv1 "AA"
+lvremove -ff $vg1
+
+# 1 PiB raid1
+lvcreate --type raid1 -m 1 -L 1P -n $lv1 $vg1 --nosync
+check lv_field $vg1/$lv1 size "1.00p"
+check raid_leg_status $vg1 $lv1 "AA"
lvremove -ff $vg1
-for segtype in raid4 raid5 raid6; do
+# 750 TiB raid4/5
+for segtype in $segtypes; do
lvcreate --type $segtype -i 3 -L 750T -n $lv1 $vg1 --nosync
check lv_field $vg1/$lv1 size "750.00t"
+ check raid_leg_status $vg1 $lv1 "AAAA"
lvremove -ff $vg1
done
#
-# Convert large linear to RAID1 (belong in different test script?)
+# Extending large 200 TiB RAID LV to 400 TiB (belong in different 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
+lvcreate --type raid1 -m 1 -L 200T -n $lv1 $vg1 --nosync
check lv_field $vg1/$lv1 size "200.00t"
+check raid_leg_status $vg1 $lv1 "AA"
+lvextend -L +200T $vg1/$lv1
+check lv_field $vg1/$lv1 size "400.00t"
+check raid_leg_status $vg1 $lv1 "AA"
+lvremove -ff $vg1
+
+
+# Check --nosync is rejected for raid6
+if [ $v1_9_0 -eq 1 ] ; then
+ not lvcreate --type raid6 -i 3 -L 750T -n $lv1 $vg1 --nosync
+fi
+
+# 750 TiB raid6
+lvcreate --type raid6 -i 3 -L 750T -n $lv1 $vg1
+check lv_field $vg1/$lv1 size "750.00t"
+check raid_leg_status $vg1 $lv1 "aaaaa"
+lvremove -ff $vg1
+
+# 1 PiB raid6, then extend up to 2 PiB
+lvcreate --type raid6 -i 3 -L 1P -n $lv1 $vg1
+check lv_field $vg1/$lv1 size "1.00p"
+check raid_leg_status $vg1 $lv1 "aaaaa"
+lvextend -L +1P $vg1/$lv1
+check lv_field $vg1/$lv1 size "2.00p"
+check raid_leg_status $vg1 $lv1 "aaaaa"
lvremove -ff $vg1
#
-# Extending large RAID LV (belong in different script?)
+# Convert large 200 TiB linear to RAID1 (belong in different test script?)
#
-lvcreate --type raid1 -m 1 -L 200T -n $lv1 $vg1 --nosync
+lvcreate -aey -L 200T -n $lv1 $vg1
+lvconvert -y --type raid1 -m 1 $vg1/$lv1
check lv_field $vg1/$lv1 size "200.00t"
-lvextend -L +200T $vg1/$lv1
-check lv_field $vg1/$lv1 size "400.00t"
+if [ $v1_9_0 -eq 1 ] ; then
+ # The 1.9.0 version of dm-raid is capable of performing
+ # linear -> RAID1 upconverts as "recover" not "resync"
+ # The LVM code now checks the dm-raid version when
+ # upconverting and if 1.9.0+ is found, it uses "recover"
+ check raid_leg_status $vg1 $lv1 "Aa"
+else
+ check raid_leg_status $vg1 $lv1 "aa"
+fi
lvremove -ff $vg1
# bz837927 END
-lvremove -ff $vg
+vgremove -ff $vg1
diff --git a/test/shell/lvcreate-large-raid10.sh b/test/shell/lvcreate-large-raid10.sh
index c9d4a2a..89eb0a6 100644
--- a/test/shell/lvcreate-large-raid10.sh
+++ b/test/shell/lvcreate-large-raid10.sh
@@ -1,5 +1,6 @@
-#!/bin/sh
-# Copyright (C) 2012 Red Hat, Inc. All rights reserved.
+#!/usr/bin/env bash
+
+# Copyright (C) 2012,2016 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
@@ -7,34 +8,46 @@
#
# 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
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
# 'Exercise some lvcreate diagnostics'
-. lib/test
+SKIP_WITH_LVMLOCKD=1
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
-aux target_at_least dm-raid 1 3 0 || skip
+# FIXME update test to make something useful on <16T
+aux can_use_16T || skip
+aux have_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
+# Fake ~2.5PiB volume group $vg1 via snapshot LVs
+for device in "$lv1" "$lv2" "$lv3" "$lv4" "$lv5"
+do
+ lvcreate --type snapshot -s -l 20%FREE -n $device $vg --virtualsize 520T
+done
-aux lvmconf 'devices/filter = [ "a/dev\/mapper\/.*$/", "a/dev\/LVMTEST/", "r/.*/" ]'
+aux extend_filter_LVMTEST
+
+pvcreate "$DM_DEV_DIR"/$vg/${lv}[12345]
+vgcreate $vg1 "$DM_DEV_DIR"/$vg/${lv}[12345]
-pvcreate $DM_DEV_DIR/$vg/$lv[12345]
-vgcreate -c n $vg1 $DM_DEV_DIR/$vg/$lv[12345]
#
-# Create large RAID LVs
+# Create and extend large RAID10 LV
#
# 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
+lvextend -L +200T $vg1/$lv1
+check lv_field $vg1/$lv1 size "400.00t"
+lvextend -L +100T $vg1/$lv1
+check lv_field $vg1/$lv1 size "500.00t"
+lvextend -L 1P $vg1/$lv1
+check lv_field $vg1/$lv1 size "1.00p"
+
+vgremove -ff $vg1
+vgremove -ff $vg
diff --git a/test/shell/lvcreate-large.sh b/test/shell/lvcreate-large.sh
index b61ccca..473b0ed 100644
--- a/test/shell/lvcreate-large.sh
+++ b/test/shell/lvcreate-large.sh
@@ -1,4 +1,5 @@
-#!/bin/sh
+#!/usr/bin/env bash
+
# Copyright (C) 2011 Red Hat, Inc. All rights reserved.
#
# This copyrighted material is made available to anyone wishing to use,
@@ -7,34 +8,42 @@
#
# 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
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
# 'Exercise some lvcreate diagnostics'
-. lib/test
+SKIP_WITH_LVMLOCKD=1
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+# FIXME update test to make something useful on <16T
+aux can_use_16T || skip
aux prepare_vg 4
-lvcreate -s -l 100%FREE -n $lv $vg --virtualsize 1024T
+lvcreate --type snapshot -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/.*/" ]'
+aux extend_filter_LVMTEST
-pvcreate $DM_DEV_DIR/$vg/$lv
-vgcreate -c n $vg1 $DM_DEV_DIR/$vg/$lv
+pvcreate "$DM_DEV_DIR/$vg/$lv"
+vgcreate $vg1 "$DM_DEV_DIR/$vg/$lv"
lvcreate -l 100%FREE -n $lv1 $vg1
-check lv_field $vg1/$lv1 size "1024.00t"
+check lv_field $vg1/$lv1 size "1024.00t" --units t
lvresize -f -l 72%VG $vg1/$lv1
-check lv_field $vg1/$lv1 size "737.28t"
+check lv_field $vg1/$lv1 size "737.28t" --units t
lvremove -ff $vg1/$lv1
lvcreate -l 100%VG -n $lv1 $vg1
-check lv_field $vg1/$lv1 size "1024.00t"
+check lv_field $vg1/$lv1 size "1024.00t" --units t
lvresize -f -l 72%VG $vg1/$lv1
-check lv_field $vg1/$lv1 size "737.28t"
+check lv_field $vg1/$lv1 size "737.28t" --units t
lvremove -ff $vg1/$lv1
lvremove -ff $vg/$lv
+
+vgremove -ff $vg
diff --git a/test/shell/lvcreate-mirror.sh b/test/shell/lvcreate-mirror.sh
index 1f95387..1cec4c5 100644
--- a/test/shell/lvcreate-mirror.sh
+++ b/test/shell/lvcreate-mirror.sh
@@ -1,4 +1,5 @@
-#!/bin/sh
+#!/usr/bin/env bash
+
# Copyright (C) 2010 Red Hat, Inc. All rights reserved.
#
# This copyrighted material is made available to anyone wishing to use,
@@ -7,35 +8,36 @@
#
# 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
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
-. lib/test
aux prepare_vg 5 80
-aux lvmconf 'allocation/maximise_cling = 0'
-aux lvmconf 'allocation/mirror_logs_require_separate_pvs = 1'
+aux lvmconf 'allocation/maximise_cling = 0' \
+ 'allocation/mirror_logs_require_separate_pvs = 1'
# 2-way mirror with corelog, 2 PVs
-lvcreate -l2 -m1 --mirrorlog core -n $lv1 $vg "$dev1" "$dev2"
+lvcreate -aey -l2 --type mirror -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
+# lvcreate --nosync is in 100% sync after creation (bz429342)
+lvcreate -aey -l2 --type mirror -m1 --nosync -n $lv2 $vg "$dev1" "$dev2" "$dev3":0-1 2>&1 | tee out
+grep "New mirror won't be synchronized." out
+check lv_field $vg/$lv2 copy_percent "100.00"
+check mirror_images_redundant $vg $lv2
+check mirror_log_on $vg $lv2 "$dev3"
# 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
+lvcreate -aey -l2 --type mirror -m2 --nosync --mirrorlog disk -n $lv3 $vg "$dev1" "$dev2" "$dev4" "$dev3":0-1
+check mirror_images_redundant $vg $lv3
+check mirror_log_on $vg $lv3 "$dev3"
lvremove -ff $vg
# creating 2-way mirror with disklog from 2 PVs fails
-not lvcreate -l2 -m1 -n $lv1 $vg "$dev1" "$dev2"
+not lvcreate -aey -l2 --type mirror -m1 -n $lv1 $vg "$dev1" "$dev2"
+
+vgremove -ff $vg
diff --git a/test/shell/lvmetad-restart.sh b/test/shell/lvcreate-missing.sh
index 10268c2..18c979f 100644
--- a/test/shell/lvmetad-restart.sh
+++ b/test/shell/lvcreate-missing.sh
@@ -1,5 +1,6 @@
-#!/bin/sh
-# Copyright (C) 2012 Red Hat, Inc. All rights reserved.
+#!/usr/bin/env bash
+
+# Copyright (C) 2013 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
@@ -7,17 +8,19 @@
#
# 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
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
-. lib/test
+aux prepare_vg 2
-test -e LOCAL_LVMETAD || skip
-aux prepare_pvs 2
+aux disable_dev "$dev1"
-vgcreate $vg1 $dev1 $dev2
-vgs | grep $vg1
+not lvcreate -n "foo" $vg -l 1
-kill $(cat LOCAL_LVMETAD)
-aux prepare_lvmetad
+aux enable_dev "$dev1"
-vgs | grep $vg1
+vgremove -ff $vg
diff --git a/test/shell/lvcreate-operation.sh b/test/shell/lvcreate-operation.sh
index 0ef3138..568af36 100644
--- a/test/shell/lvcreate-operation.sh
+++ b/test/shell/lvcreate-operation.sh
@@ -1,5 +1,6 @@
-#!/bin/sh
-# Copyright (C) 2008 Red Hat, Inc. All rights reserved.
+#!/usr/bin/env bash
+
+# Copyright (C) 2008,2018 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
@@ -7,11 +8,16 @@
#
# 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
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
# 'Exercise some lvcreate diagnostics'
-. lib/test
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+aux lvmconf "global/support_mirrored_mirror_log=1"
cleanup_lvs() {
lvremove -ff $vg
@@ -20,22 +26,38 @@ cleanup_lvs() {
}
aux prepare_pvs 2
+get_devs
+
aux pvcreate --metadatacopies 0 "$dev1"
-aux vgcreate -c n $vg $(cat DEVICES)
+aux vgcreate $SHARED "$vg" "${DEVICES[@]}"
# ---
# Create snapshots of LVs on --metadatacopies 0 PV (bz450651)
-lvcreate -n$lv1 -l4 $vg "$dev1"
+lvcreate -aey -n$lv1 -l4 $vg "$dev1"
lvcreate -n$lv2 -l4 -s $vg/$lv1
lvcreate -n$lv3 -l4 --permission r -s $vg/$lv1
cleanup_lvs
+# Skip the rest for cluster
+if test -e LOCAL_CLVMD; then
+
+# ---
+# Create mirror on two devices with mirrored log using --alloc anywhere - should always fail in cluster
+not lvcreate --type mirror -m 1 -l4 -n $lv1 --mirrorlog mirrored $vg --alloc anywhere "$dev1" "$dev2"
+cleanup_lvs
+
+else
+
# ---
# Create mirror on two devices with mirrored log using --alloc anywhere
-lvcreate -m 1 -l4 -n $lv1 --mirrorlog mirrored $vg --alloc anywhere "$dev1" "$dev2"
+lvcreate --type mirror -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"
+not lvcreate --type mirror -m 1 -l4 -n $lv1 --mirrorlog mirrored $vg --alloc anywhere "$dev1"
cleanup_lvs
+
+fi
+
+vgremove -ff $vg
diff --git a/test/shell/lvcreate-pvtags.sh b/test/shell/lvcreate-pvtags.sh
index 806fff1..b794c45 100644
--- a/test/shell/lvcreate-pvtags.sh
+++ b/test/shell/lvcreate-pvtags.sh
@@ -1,4 +1,5 @@
-#!/bin/sh
+#!/usr/bin/env bash
+
# Copyright (C) 2008 Red Hat, Inc. All rights reserved.
#
# This copyrighted material is made available to anyone wishing to use,
@@ -7,19 +8,23 @@
#
# 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
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+SKIP_WITH_LVMPOLLD=1
-. lib/test
+. lib/inittest
aux prepare_pvs 3
-aux lvmconf 'allocation/maximise_cling = 0'
-aux lvmconf 'allocation/mirror_logs_require_separate_pvs = 1'
+get_devs
+
+aux lvmconf 'allocation/maximise_cling = 0' \
+ '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)
+vgcreate $SHARED "$vg" "${DEVICES[@]}"
+pvchange --addtag fast "${DEVICES[@]}"
# 3 stripes with 3 PVs (selected by tag, @fast) is fine
lvcreate -l3 -i3 $vg @fast
@@ -28,21 +33,21 @@ lvcreate -l3 -i3 $vg @fast
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
+not lvcreate -l2 -i2 $vg "$DM_DEV_DIR/mapper/pv1"
# lvcreate mirror
-lvcreate -l1 -m1 $vg @fast
+lvcreate -aey -l1 --type mirror -m1 --nosync $vg @fast
# lvcreate mirror w/corelog
-lvcreate -l1 -m2 --corelog $vg @fast
+lvcreate -aey -l1 --type mirror -m2 --corelog --nosync $vg @fast
# lvcreate mirror w/no free PVs
-not lvcreate -l1 -m2 $vg @fast
+not lvcreate -aey -l1 --type mirror -m2 $vg @fast
# lvcreate mirror (corelog, w/no free PVs)
-not lvcreate -l1 -m3 --corelog $vg @fast
+not lvcreate -aey -l1 --type mirror -m3 --corelog $vg @fast
# lvcreate mirror with a single PV arg
-not lvcreate -l1 -m1 --corelog $vg "$dev1"
+not lvcreate -aey -l1 --type mirror -m1 --corelog $vg "$dev1"
vgremove -ff $vg
diff --git a/test/shell/lvcreate-raid-nosync.sh b/test/shell/lvcreate-raid-nosync.sh
new file mode 100644
index 0000000..2818e94
--- /dev/null
+++ b/test/shell/lvcreate-raid-nosync.sh
@@ -0,0 +1,101 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2016 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+aux have_raid 1 7 0 || skip
+
+segtypes="raid5"
+aux have_raid4 && segtypes="raid4 $segtypes"
+
+aux prepare_vg 6
+
+_sync() {
+ aux enable_dev "$dev1"
+
+ aux wait_for_sync $vg $lv1
+ test -z "$1" || check raid_leg_status $vg $lv1 $1
+ lvremove --yes $vg/$lv1
+
+ # restore to delay_dev tables for all devices
+ aux restore_from_devtable "$dev1"
+}
+
+# Workaround for raid targets returning 'a' shortly after initialization
+# TODO: maybe there is some workaround to be made on lvm side
+_check_raid_in_loop() {
+ local vg=$1
+ local lv=$2
+ local health=$3
+ for i in {1..10} ; do
+ check raid_leg_status $vg $lv ${health} && return 0
+ sleep .05
+ done
+ die "Cannot get $A status for $vg/$lv";
+}
+
+# Delay 1st leg so that rebuilding status characters
+# can be read before resync finished too quick.
+aux delay_dev "$dev1" 0 100 "$(get first_extent_sector "$dev1")"
+
+# raid0/raid0_meta don't support resynchronization
+for r in raid0 raid0_meta
+do
+ lvcreate --type $r -Zn -i 3 -l 1 -n $lv1 $vg
+ _check_raid_in_loop $vg $lv1 "AAA"
+ lvremove --yes $vg/$lv1
+done
+
+# raid1 supports resynchronization
+lvcreate --type raid1 -m 2 -Zn -l 4 -n $lv1 $vg
+should check raid_leg_status $vg $lv1 "aaa"
+_sync "AAA"
+
+# raid1 supports --nosync
+lvcreate --type raid1 --nosync -Zn -m 2 -l 1 -n $lv1 $vg
+_check_raid_in_loop $vg $lv1 "AAA"
+lvremove --yes $vg/$lv1
+
+for r in $segtypes
+do
+ # raid4/5 support resynchronization
+ lvcreate --type $r -Zn -i 3 -L10 -n $lv1 $vg
+ should check raid_leg_status $vg $lv1 "aaaa"
+ _sync "AAAA"
+
+ # raid4/5 support --nosync
+ lvcreate --type $r -Zn --nosync -i 3 -l 1 -n $lv2 $vg
+ _check_raid_in_loop $vg $lv2 "AAAA"
+ lvremove --yes $vg
+done
+
+# raid6 supports resynchronization
+lvcreate --type raid6 -Zn -i 3 -l 4 -n $lv1 $vg
+should check raid_leg_status $vg $lv1 "aaaaa"
+_sync "AAAAA"
+
+# raid6 rejects --nosync; it has to initialize P- and Q-Syndromes
+not lvcreate --type raid6 --nosync -Zn -i 3 -l 1 -n $lv1 $vg
+
+# raid10 supports resynchronization
+lvcreate --type raid10 -m 1 -Zn -i 3 -L10 -n $lv1 $vg
+should check raid_leg_status $vg $lv1 "aaaaaa"
+_sync "AAAAAA"
+
+# raid10 supports --nosync
+lvcreate --type raid10 --nosync -m 1 -Zn -i 3 -l 1 -n $lv1 $vg
+_check_raid_in_loop $vg $lv1 "AAAAAA"
+
+vgremove -ff $vg
diff --git a/test/shell/lvcreate-raid-volume_list.sh b/test/shell/lvcreate-raid-volume_list.sh
new file mode 100644
index 0000000..052cf19
--- /dev/null
+++ b/test/shell/lvcreate-raid-volume_list.sh
@@ -0,0 +1,42 @@
+#!/usr/bin/env bash
+#
+# Copyright (C) 2018 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+
+SKIP_WITH_LVMPOLLD=1
+
+# bz1161347 - When raid creation is aborted, left-over devices appear
+
+. lib/inittest
+
+########################################################
+# MAIN
+########################################################
+aux have_raid 1 3 0 || skip
+
+aux prepare_pvs 2 # 2 devices for RAID1
+get_devs
+vgcreate $SHARED -s 512k "$vg" "${DEVICES[@]}"
+
+aux lvmconf "activation/volume_list = [ \"vg_not_exist\" ]"
+
+##########################################################
+# Create 2-way raid1 which fails due to $vg not listed on
+# activation/volume_list. Check for any (Sub)LV remnants.
+##########################################################
+not lvcreate --yes --type raid1 -l 2 -n $lv $vg
+check lv_not_exists $vg/${lv}_rmeta_0
+check lv_not_exists $vg/${lv}_rmeta_1
+check lv_not_exists $vg/${lv}_rimage_0
+check lv_not_exists $vg/${lv}_rimage_1
+check lv_not_exists $vg/$lv
+
+vgremove -ff $vg
diff --git a/test/shell/lvcreate-raid.sh b/test/shell/lvcreate-raid.sh
index 05c7428..b605443 100644
--- a/test/shell/lvcreate-raid.sh
+++ b/test/shell/lvcreate-raid.sh
@@ -1,5 +1,6 @@
-#!/bin/sh
-# Copyright (C) 2011-2012 Red Hat, Inc. All rights reserved.
+#!/usr/bin/env bash
+
+# Copyright (C) 2011-2016 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
@@ -7,22 +8,33 @@
#
# 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
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+
+SKIP_WITH_LVMPOLLD=1
-. lib/test
+. lib/inittest
+
+lv_devices() {
+ test "$3" -eq "$(get lv_devices "$1/$2" | wc -w)"
+}
########################################################
# MAIN
########################################################
-aux target_at_least dm-raid 1 1 0 || skip
+aux have_raid 1 3 0 || skip
+
+RAID4=""
+aux have_raid4 && RAID4=raid4
aux prepare_pvs 6 20 # 6 devices for RAID10 (2-mirror,3-stripe) test
-vgcreate -c n -s 512k $vg $(cat DEVICES)
+get_devs
+
+vgcreate $SHARED -s 512k "$vg" "${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
@@ -38,8 +50,17 @@ lvcreate --type raid1 -m 2 -l 2 -n $lv1 $vg
aux wait_for_sync $vg $lv1
lvremove -ff $vg
+# Create RAID1 (explicit 3-way) - Set min/max recovery rate
+lvcreate --type raid1 -m 2 -l 2 \
+ --minrecoveryrate 50 --maxrecoveryrate 1M \
+ -n $lv1 $vg
+check lv_field $vg/$lv1 raid_min_recovery_rate 50
+check lv_field $vg/$lv1 raid_max_recovery_rate 1024
+aux wait_for_sync $vg $lv1
+lvremove -ff $vg
+
# Create RAID 4/5/6 (explicit 3-stripe + parity devs)
-for i in raid4 \
+for i in $RAID4 \
raid5 raid5_ls raid5_la raid5_rs raid5_ra \
raid6 raid6_zr raid6_nr raid6_nc; do
@@ -47,3 +68,143 @@ for i in raid4 \
aux wait_for_sync $vg $lv1
lvremove -ff $vg
done
+
+# Create RAID 4/5/6 (explicit 3-stripe + parity devs) - Set min/max recovery
+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 \
+ --minrecoveryrate 50 --maxrecoveryrate 1M \
+ -n $lv1 $vg
+ check lv_field $vg/$lv1 raid_min_recovery_rate 50
+ check lv_field $vg/$lv1 raid_max_recovery_rate 1024
+ aux wait_for_sync $vg $lv1
+ lvremove -ff $vg
+done
+
+# Create RAID using 100%FREE
+############################
+# 6 PVs with 19m in each PV.
+# 1 metadata LV = 1 extent = .5m
+# 1 image = 37+38+38 extents = 56.50m = lv_size
+lvcreate --type raid1 -m 1 -l 100%FREE -an -Zn -n raid1 $vg
+check lv_field $vg/raid1 size "56.50m"
+lvremove -ff $vg
+
+# 1 metadata LV = 1 extent
+# 1 image = 37 extents = 18.5m
+# 5 images = 185 extents = 92.5m = lv_size
+lvs -a $vg
+lvcreate --type raid5 -i 5 -l 100%FREE -an -Zn -n raid5 $vg
+check lv_field $vg/raid5 size "92.50m"
+lvremove -ff $vg
+
+# 1 image = 37+38 extents
+# 2 images = 150 extents = 75.00m = lv_size
+lvcreate --type raid5 -i 2 -l 100%FREE -an -Zn -n raid5 $vg
+check lv_field $vg/raid5 size "75.00m"
+lvremove -ff $vg
+
+# 1 image = 37 extents
+# 4 images = 148 extents = 74.00m = lv_size
+lvcreate --type raid6 -i 4 -l 100%FREE -an -Zn -n raid6 $vg
+check lv_field $vg/raid6 size "74.00m"
+lvremove -ff $vg
+
+###
+# For following tests eat 18 of 37 extents from dev1, leaving 19
+lvcreate -l 18 -an -Zn -n eat_space $vg "$dev1"
+EAT_SIZE=$(get lv_field $vg/eat_space size)
+
+# Using 100% free should take the rest of dev1 and equal from dev2
+# 1 meta takes 1 extent
+# 1 image = 19 extents = 9.50m = lv_size
+lvcreate --type raid1 -m 1 -l 100%FREE -an -Zn -n raid1 $vg "$dev1" "$dev2"
+check lv_field $vg/raid1 size "9.50m"
+# Ensure image size is the same as the RAID1 size
+check lv_field $vg/raid1 size "$(get lv_field $vg/raid1_rimage_0 size -a)"
+# Amount remaining in dev2 should equal the amount taken by 'lv' in dev1
+check pv_field "$dev2" pv_free "$EAT_SIZE"
+lvremove -ff $vg/raid1
+
+# Using 100% free should take the rest of dev1 and equal amount from the rest
+# 1 meta takes 1 extent
+# 1 image = 19 extents = 9.50m
+# 5 images = 95 extents = 47.50m = lv_size
+lvcreate --type raid5 -i 5 -l 100%FREE -an -Zn -n raid5 $vg
+check lv_field $vg/raid5 size "47.50m"
+# Amount remaining in dev6 should equal the amount taken by 'lv' in dev1
+check pv_field "$dev6" pv_free "$EAT_SIZE"
+lvremove -ff $vg/raid5
+
+# Using 100% free should take the rest of dev1, an equal amount
+# from 2 more devs, and all extents from 3 additional devs
+# 1 meta takes 1 extent
+# 1 image = 19+39 extents
+# 2 images = 114 extents = 57.00m = lv_size
+lvcreate --type raid5 -i 2 -l 100%FREE -an -Zn -n raid5 $vg
+check lv_field $vg/raid5 size "57.00m"
+lvremove -ff $vg/raid5
+
+# Let's do some stripe tests too
+# Using 100% free should take the rest of dev1 and an equal amount from rest
+# 1 image = 20 extents
+# 6 images = 120 extents = 60.00m = lv_size
+lvcreate -i 6 -l 100%FREE -an -Zn -n stripe $vg
+check lv_field $vg/stripe size "60.00m"
+lvremove -ff $vg/stripe
+
+# Using 100% free should take the rest of dev1, an equal amount from
+# one more dev, and all of the remaining 4
+# 1 image = 20+38+38 extents
+# 2 images = 192 extents = 96.00m = lv_size
+lvcreate -i 2 -l 100%FREE -an -Zn -n stripe $vg
+check lv_field $vg/stripe size "96.00m"
+
+lvremove -ff $vg
+# end of use of '$vg/eat_space'
+###
+
+# Create RAID (implicit stripe count based on PV count)
+#######################################################
+
+# Not enough drives
+not lvcreate --type raid1 -l1 $vg "$dev1"
+not lvcreate --type raid5 -l2 $vg "$dev1" "$dev2"
+not lvcreate --type raid6 -l3 $vg "$dev1" "$dev2" "$dev3" "$dev4"
+
+# Implicit count comes from #PVs given (always 2 for mirror though)
+lvcreate --type raid1 -l1 -an -Zn -n raid1 $vg "$dev1" "$dev2"
+lv_devices $vg raid1 2
+lvcreate --type raid5 -l2 -an -Zn -n raid5 $vg "$dev1" "$dev2" "$dev3"
+lv_devices $vg raid5 3
+lvcreate --type raid6 -l3 -an -Zn -n raid6 $vg "$dev1" "$dev2" "$dev3" "$dev4" "$dev5"
+lv_devices $vg raid6 5
+lvremove -ff $vg
+
+# Implicit count comes from total #PVs in VG (always 2 for mirror though)
+# Defaults -i2 even though more PVs listed
+lvcreate --type raid1 -l1 -an -Zn -n raid1 $vg
+lv_devices $vg raid1 2
+lvcreate --type raid5 -l2 -an -Zn -n raid5 $vg
+lv_devices $vg raid5 3
+lvcreate --type raid6 -l3 -an -Zn -n raid6 $vg
+lv_devices $vg raid6 5
+lvremove -ff $vg
+
+
+########################################################
+# Try again with backward compatible old logic applied #
+########################################################
+aux lvmconf 'allocation/raid_stripe_all_devices = 1'
+
+# Implicit count comes from total #PVs in VG (always 2 for mirror though)
+lvcreate --type raid1 -l1 -an -Zn -n raid1 $vg
+lv_devices $vg raid1 2
+lvcreate --type raid5 -l2 -an -Zn -n raid5 $vg
+lv_devices $vg raid5 6
+lvcreate --type raid6 -l3 -an -Zn -n raid6 $vg
+lv_devices $vg raid6 6
+
+vgremove -ff $vg
diff --git a/test/shell/lvcreate-raid1-read-error.sh b/test/shell/lvcreate-raid1-read-error.sh
new file mode 100644
index 0000000..f9c6bb9
--- /dev/null
+++ b/test/shell/lvcreate-raid1-read-error.sh
@@ -0,0 +1,33 @@
+#!/bin/sh
+# Copyright (C) 2018 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+SKIP_WITH_LVMLOCKD=1
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+aux have_raid 1 3 0 || skip
+
+# Test for MD raid1 kernel bug causing read
+# errors on failing first leg sectors.
+
+# Create VG with 2 PVs
+aux prepare_vg 2 2
+
+# Create 2-legged raid1 LV
+lvcreate --yes --type raid1 --mirrors 1 --extents 1 --name $lv $vg
+aux wait_for_sync $vg $lv
+
+aux error_dev "$dev1" 20:500
+
+dd if="$DM_DEV_DIR/$vg/$lv" iflag=direct,fullblock of=/dev/zero bs=128K count=1
+
+vgremove --force $vg
diff --git a/test/shell/lvcreate-raid10.sh b/test/shell/lvcreate-raid10.sh
index 63d086f..39069af 100644
--- a/test/shell/lvcreate-raid10.sh
+++ b/test/shell/lvcreate-raid10.sh
@@ -1,5 +1,6 @@
-#!/bin/sh
-# Copyright (C) 2012 Red Hat, Inc. All rights reserved.
+#!/usr/bin/env bash
+
+# Copyright (C) 2012-2016 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
@@ -7,36 +8,90 @@
#
# 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
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
-. lib/test
+lv_devices() {
+ test "$3" -eq "$(get lv_devices "$1/$2" | wc -w)"
+}
########################################################
# 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)
+aux have_raid 1 3 0 || skip
+aux prepare_vg 6 20 # 6 devices for RAID10 (2-mirror,3-stripe) test
#
# 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
+lvremove -ff $vg/$lv1
-# 2-way mirror, 3-stripes
-lvcreate --type raid10 -m 1 -i 3 -l 3 -n $lv1 $vg
+# 2-way mirror, 2-stripes - Set min/max recovery rate
+lvcreate --type raid10 -m 1 -i 2 -l 2 \
+ --minrecoveryrate 50 --maxrecoveryrate 1M \
+ -n $lv1 $vg
+check lv_field $vg/$lv1 raid_min_recovery_rate 50
+check lv_field $vg/$lv1 raid_max_recovery_rate 1024
aux wait_for_sync $vg $lv1
+
+# 2-way mirror, 3-stripes
+lvcreate --type raid10 -m 1 -i 3 -l 3 -n $lv2 $vg
+aux wait_for_sync $vg $lv2
+
+lvremove -ff $vg
+
+# Test 100%FREE option
+# 38 extents / device
+# 1 image = 37 extents (1 for meta)
+# 3 images = 111 extents = 55.50m
+lvcreate --type raid10 -i 3 -l 100%FREE -an -Zn -n raid10 $vg
+check lv_field $vg/raid10 size "55.50m"
+lvremove -ff $vg
+
+# Create RAID (implicit stripe count based on PV count)
+#######################################################
+
+# Not enough drives
+not lvcreate --type raid10 -l2 $vg "$dev1" "$dev2" "$dev3"
+
+# Implicit count comes from #PVs given (always 2-way mirror)
+# Defaults -i2, which works with 4 PVs listed
+lvcreate --type raid10 -l2 -an -Zn -n raid10 $vg "$dev1" "$dev2" "$dev3" "$dev4"
+lv_devices $vg raid10 4
+
+# Defaults -i2 even though more PVs listed
+lvcreate --type raid10 -l2 -an -Zn -n raid10_6 $vg "$dev1" "$dev2" "$dev3" "$dev4" "$dev5" "$dev6"
+lv_devices $vg raid10_6 4
+
lvremove -ff $vg
#
# FIXME: Add tests that specify particular PVs to use for creation
#
+
+
+########################################################
+# Try again with backward compatible old logic applied #
+########################################################
+aux lvmconf 'allocation/raid_stripe_all_devices = 1'
+
+# Implicit count comes from #PVs given (always 2-way mirror)
+lvcreate --type raid10 -l2 -an -Zn -n raid10 $vg "$dev1" "$dev2" "$dev3" "$dev4"
+lv_devices $vg raid10 4
+
+# Implicit count comes from total #PVs in VG (always 2 for mirror though)
+lvcreate --type raid10 -l2 -an -Zn -n raid10_vg $vg
+lv_devices $vg raid10_vg 6
+
+vgremove -ff $vg
diff --git a/test/shell/lvcreate-repair.sh b/test/shell/lvcreate-repair.sh
index 8971536..07263a3 100644
--- a/test/shell/lvcreate-repair.sh
+++ b/test/shell/lvcreate-repair.sh
@@ -1,4 +1,5 @@
-#!/bin/sh
+#!/usr/bin/env bash
+
# Copyright (C) 2011-2012 Red Hat, Inc. All rights reserved.
#
# This copyrighted material is made available to anyone wishing to use,
@@ -7,9 +8,11 @@
#
# 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
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+SKIP_WITH_LVMPOLLD=1
-. lib/test
+. lib/inittest
aux prepare_vg 3
@@ -19,7 +22,7 @@ for i in "$dev1" "$dev2" "$dev3" ; do
if test "$i" = "$j" ; then continue ; fi
vgremove -ff $vg
- vgcreate $vg "$dev1" "$dev2" "$dev3"
+ vgcreate $SHARED $vg "$dev1" "$dev2" "$dev3"
# exit 1
lvcreate -l1 -n $lv1 $vg "$dev1"
@@ -29,7 +32,7 @@ for i in "$dev1" "$dev2" "$dev3" ; do
vgreduce --removemissing --force $vg
# check if reduced device was removed
- test "$i" = "$dev1" && dm_table | not egrep "$vg-$lv1: *[^ ]+"
+ test "$i" = "$dev1" && dm_table | not grep -E "$vg-$lv1: *[^ ]+"
lvcreate -l1 -n $lv2 $vg
@@ -45,7 +48,7 @@ for i in "$dev1" "$dev2" "$dev3" ; do
done
vgremove -ff $vg
-vgcreate $vg "$dev1" "$dev2" "$dev3"
+vgcreate $SHARED $vg "$dev1" "$dev2" "$dev3"
# use tricky 'dd'
for i in "$dev1" "$dev2" "$dev3" ; do
@@ -85,7 +88,6 @@ dd if=backup_i of="$dev1" bs=256K count=1
# dirty game
dd if=/dev/zero of="$dev3" bs=256K count=1
-aux notify_lvmetad "$dev3" # udev be watching you
vgreduce --removemissing --force $vg
@@ -97,3 +99,6 @@ vgreduce --removemissing --force $vg
# Failed to activate new LV.
should lvcreate -l1 $vg "$dev1"
+should not dmsetup remove ${vg}-lvol0
+
+vgremove -ff $vg
diff --git a/test/shell/lvcreate-signature-wiping.sh b/test/shell/lvcreate-signature-wiping.sh
new file mode 100644
index 0000000..4893d9a
--- /dev/null
+++ b/test/shell/lvcreate-signature-wiping.sh
@@ -0,0 +1,125 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2013 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+# 'Exercise signature wiping during lvcreate'
+
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+init_lv_() {
+ mkswap "$DM_DEV_DIR/$vg/$lv1"
+}
+
+test_blkid_() {
+ local type
+ type=$(blkid -s TYPE -o value -c /dev/null "$DM_DEV_DIR/$vg/$lv1")
+ test "$type" = "swap"
+}
+
+test_msg_() {
+ grep "Wiping swap signature" out
+}
+
+aux prepare_vg
+
+# lvcreate wipes signatures when found on newly created LV - test this on "swap".
+# Test all combinatios with -Z{y|n} and -W{y|n} and related lvm.conf settings.
+
+lvcreate -l1 -n $lv1 $vg
+init_lv_
+# This system has unusable blkid (does not recognize small swap, needs fix...)
+test_blkid_ || skip
+lvremove -f $vg/$lv1
+
+# Zeroing stops the command when there is a failure (write error in this case)
+aux error_dev "$dev1" "$(get first_extent_sector "$dev1"):8"
+not lvcreate -l1 -n $lv1 $vg 2>&1 | tee out
+grep "Failed to initialize" out
+aux enable_dev "$dev1"
+
+
+aux lvmconf "allocation/wipe_signatures_when_zeroing_new_lvs = 0"
+
+lvcreate -y -Zn -l1 -n $lv1 $vg 2>&1 | tee out
+not test_msg_
+test_blkid_
+lvremove -f $vg/$lv1
+
+lvcreate -y -Zn -Wn -l1 -n $lv1 $vg 2>&1 | tee out
+not test_msg_
+test_blkid_
+lvremove -f $vg/$lv1
+
+lvcreate -y -Zn -Wy -l1 -n $lv1 $vg 2>&1 | tee out
+test_msg_
+not test_blkid_
+init_lv_
+lvremove -f $vg/$lv1
+
+lvcreate -y -Zy -l1 -n $lv1 $vg 2>&1 | tee out
+not test_msg_
+not test_blkid_
+init_lv_
+lvremove -f $vg/$lv1
+
+lvcreate -y -Zy -Wn -l1 -n $lv1 $vg 2>&1 | tee out
+not test_msg_
+not test_blkid_
+init_lv_
+lvremove -f $vg/$lv1
+
+lvcreate -y -Zy -Wy -l1 -n $lv1 $vg 2>&1 | tee out
+test_msg_
+not test_blkid_
+init_lv_
+lvremove -f $vg/$lv1
+
+
+aux lvmconf "allocation/wipe_signatures_when_zeroing_new_lvs = 1"
+
+lvcreate -y -Zn -l1 -n $lv1 $vg 2>&1 | tee out
+not test_msg_
+test_blkid_
+lvremove -f $vg/$lv1
+
+lvcreate -y -Zn -Wn -l1 -n $lv1 $vg 2>&1 | tee out
+not test_msg_
+test_blkid_
+lvremove -f $vg/$lv1
+
+lvcreate -y -Zn -Wy -l1 -n $lv1 $vg 2>&1 | tee out
+test_msg_
+not test_blkid_
+init_lv_
+lvremove -f $vg/$lv1
+
+lvcreate -y -Zy -l1 -n $lv1 $vg 2>&1 | tee out
+test_msg_
+not test_blkid_
+init_lv_
+lvremove -f $vg/$lv1
+
+lvcreate -y -Zy -Wn -l1 -n $lv1 $vg 2>&1 | tee out
+not test_msg_
+not test_blkid_
+init_lv_
+lvremove -f $vg/$lv1
+
+lvcreate -y -Zy -Wy -l1 -n $lv1 $vg 2>&1 | tee out
+test_msg_
+not test_blkid_
+init_lv_
+lvremove -f $vg/$lv1
+
+vgremove -f $vg
diff --git a/test/shell/lvcreate-small-snap.sh b/test/shell/lvcreate-small-snap.sh
index 9b43868..09237ec 100644
--- a/test/shell/lvcreate-small-snap.sh
+++ b/test/shell/lvcreate-small-snap.sh
@@ -1,5 +1,6 @@
-#!/bin/sh
-# Copyright (C) 2010 Red Hat, Inc. All rights reserved.
+#!/usr/bin/env bash
+
+# Copyright (C) 2010-2014 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
@@ -7,24 +8,31 @@
#
# 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
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
-. lib/test
+SKIP_WITH_LVMPOLLD=1
-aux prepare_pvs 3
+. lib/inittest
-vgcreate -c n -s 1k $vg $(cat DEVICES)
+aux prepare_pvs
+get_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
+vgcreate $SHARED -s 4k "$vg" "${DEVICES[@]}"
+
+# 3 Chunks
+lvcreate -aey -n one -l 10 $vg
+lvcreate -s -l 3 -n snapA $vg/one
+lvcreate -s -c 4k -l 3 -n snapX1 $vg/one
+lvcreate -s -c 8k -l 6 -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 lvcreate -s -c 8k -l 2 -n snapX3 $vg/one 2>&1 | tee lvcreate.out
not grep "suspend origin one" lvcreate.out
-grep "Unable to create a snapshot" lvcreate.out
+grep "smaller" lvcreate.out
-not lvcreate -s -l 4 -n snapB $vg/one 2>&1 | tee lvcreate.out
+not lvcreate -s -l 1 -n snapB $vg/one 2>&1 | tee lvcreate.out
not grep "suspend origin one" lvcreate.out
-grep "Unable to create a snapshot" lvcreate.out
+grep "smaller" lvcreate.out
+
+vgremove -ff $vg
diff --git a/test/shell/lvcreate-striped-mirror.sh b/test/shell/lvcreate-striped-mirror.sh
index 9a55a97..b960522 100644
--- a/test/shell/lvcreate-striped-mirror.sh
+++ b/test/shell/lvcreate-striped-mirror.sh
@@ -1,4 +1,5 @@
-#!/bin/sh
+#!/usr/bin/env bash
+
# Copyright (C) 2010 Red Hat, Inc. All rights reserved.
#
# This copyrighted material is made available to anyone wishing to use,
@@ -7,59 +8,52 @@
#
# 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
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
-. lib/test
aux prepare_vg 9
-lvcreate -i2 -l2 -m1 --mirrorlog core -n $lv1 $vg 2>&1 | tee log
+lvcreate -aey --nosync -i2 -l2 --type mirror -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
+lvcreate -aey --nosync -i2 -l4 --type mirror -m1 --mirrorlog core -n $lv2 $vg 2>&1 | tee log
not grep "Rounding" log
-check mirror_images_redundant $vg $lv1
-lvremove -ff $vg
+check mirror_images_redundant $vg $lv2
-lvcreate -i3 -l3 -m1 --mirrorlog core -n $lv1 $vg 2>&1 | tee log
+lvcreate -aey --nosync -i3 -l3 --type mirror -m1 --mirrorlog core -n $lv3 $vg 2>&1 | tee log
not grep "Rounding" log
-check mirror_images_redundant $vg $lv1
-lvremove -ff $vg
+check mirror_images_redundant $vg $lv3
-lvcreate -i4 -l4 -m1 --mirrorlog core -n $lv1 $vg 2>&1 | tee log
+lvcreate -aey --nosync -i4 -l4 --type mirror -m1 --mirrorlog core -n $lv4 $vg 2>&1 | tee log
not grep "Rounding" log
-check mirror_images_redundant $vg $lv1
-lvremove -ff $vg
+check mirror_images_redundant $vg $lv4
-
-lvcreate -i2 -l2 -m2 --mirrorlog core -n $lv1 $vg 2>&1 | tee log
+lvcreate -aey --nosync -i2 -l2 --type mirror -m2 --mirrorlog core -n $lv5 $vg 2>&1 | tee log
not grep "Rounding" log
-check mirror_images_redundant $vg $lv1
-lvremove -ff $vg
+check mirror_images_redundant $vg $lv5
-lvcreate -i3 -l3 -m2 --mirrorlog core -n $lv1 $vg 2>&1 | tee log
+lvcreate -aey --nosync -i3 -l3 --type mirror -m2 --mirrorlog core -n $lv6 $vg 2>&1 | tee log
not grep "Rounding" log
-check mirror_images_redundant $vg $lv1
-lvremove -ff $vg
+check mirror_images_redundant $vg $lv6
-lvcreate -i2 -l2 -m3 --mirrorlog core -n $lv1 $vg 2>&1 | tee log
+lvcreate -aey --nosync -i2 -l2 --type mirror -m3 --mirrorlog core -n $lv7 $vg 2>&1 | tee log
not grep "Rounding" log
-check mirror_images_redundant $vg $lv1
-lvremove -ff $vg
+check mirror_images_redundant $vg $lv7
-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 -aey --nosync -i3 -l4 --type mirror -m1 --mirrorlog core -n $lv1 $vg 2>&1 | tee log
+grep "Rounding size .*(4 extents) up to .*(6 extents)" log
-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 -aey --nosync -i3 -l4 --type mirror -m2 --mirrorlog core -n $lv2 $vg 2>&1 | tee log
+grep "Rounding size .*(4 extents) up to .*(6 extents)" log
+
+lvcreate -aey --nosync -i3 -l2 --type mirror -m2 --mirrorlog core -n $lv3 $vg 2>&1 | tee log
+grep "Rounding size .*(2 extents) up to .*(3 extents)" log
-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-big.sh b/test/shell/lvcreate-thin-big.sh
new file mode 100644
index 0000000..bdb5942
--- /dev/null
+++ b/test/shell/lvcreate-thin-big.sh
@@ -0,0 +1,90 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2015 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+# test currently needs to drop
+# 'return NULL' in _lv_create_an_lv after log_error("Can't create %s without using "
+
+
+SKIP_WITH_LVMPOLLD=1
+
+export LVM_TEST_THIN_REPAIR_CMD=${LVM_TEST_THIN_REPAIR_CMD-/bin/false}
+
+. lib/inittest
+
+aux have_thin 1 0 0 || skip
+
+# Test --poolmetadatasize range
+# allocating large devices for testing
+aux prepare_pvs 10 16500
+get_devs
+
+vgcreate $SHARED -s 64K "$vg" "${DEVICES[@]}"
+
+# Size 0 is not valid
+invalid lvcreate -L4M --chunksize 128 --poolmetadatasize 0 -T $vg/pool1 2>out
+lvcreate -Zn -L4M --chunksize 128 --poolmetadatasize 16k -T $vg/pool1 >out 2>&1
+grep -i "minimal" out
+# FIXME: metadata allocation fails, if PV doesn't have at least 16GB
+# i.e. pool metadata device cannot be multisegment
+lvcreate -Zn -L4M --chunksize 64k --poolmetadatasize 17G -T $vg/pool2 >out 2>&1
+grep "maximum" out
+check lv_field $vg/pool1_tmeta size "2.00m"
+check lv_field $vg/pool2_tmeta size "<15.88g"
+
+# Check we do report correct percent values.
+lvcreate --type zero -L3G $vg -n pool3
+lvconvert -y --thinpool $vg/pool3
+lvchange --errorwhenfull y $vg/pool3
+lvchange --zero n $vg/pool3
+lvcreate -V10G $vg/pool3 -n $lv1
+lvcreate -V2G $vg/pool3 -n $lv2
+dd if=/dev/zero of="$DM_DEV_DIR/$vg/$lv1" bs=512b count=1 conv=fdatasync
+# ...excercise write speed to 'zero' device ;)
+dd if=/dev/zero of="$DM_DEV_DIR/$vg/$lv2" bs=64K count=32767 oflag=direct
+lvs -a $vg
+# Check the percentage is not shown as 0.00
+check lv_field $vg/$lv1 data_percent "0.01"
+# Check the percentage is not shown as 100.00
+check lv_field $vg/$lv2 data_percent "99.99"
+
+
+# Check can start and see thinpool with metadata size above kernel limit
+lvcreate -L4M --poolmetadatasize 16G -T $vg/poolM
+check lv_field $vg/poolM data_percent "0.00"
+
+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"
+lvremove -ff $vg
+
+# Test chunk size is rounded to power-of-2
+lvcreate -L10G --poolmetadatasize 4M -T $vg/pool
+check lv_field $vg/pool chunk_size "256.00k"
+
+# Old thinpool target required rounding to power of 2
+aux lvmconf "global/thin_disabled_features = [ \"block_size\" ]"
+lvcreate -L10G --poolmetadatasize 4M -T $vg/pool_old
+check lv_field $vg/pool_old chunk_size "256.00k"
+lvremove -ff $vg
+# reset
+#aux lvmconf "global/thin_disabled_features = []"
+
+vgremove -ff $vg
diff --git a/test/shell/lvcreate-thin-cache.sh b/test/shell/lvcreate-thin-cache.sh
new file mode 100644
index 0000000..f87526a
--- /dev/null
+++ b/test/shell/lvcreate-thin-cache.sh
@@ -0,0 +1,48 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2017 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+# Exercise caching thin-pool's data LV
+
+
+SKIP_WITH_LVMPOLLD=1
+
+export LVM_TEST_THIN_REPAIR_CMD=${LVM_TEST_THIN_REPAIR_CMD-/bin/false}
+
+. lib/inittest
+
+#
+# Main
+#
+aux have_thin 1 0 0 || skip
+aux have_cache 1 3 0 || skip
+
+which mkfs.ext4 || skip
+
+aux prepare_pvs 2 64
+get_devs
+
+vgcreate $SHARED -s 64K "$vg" "${DEVICES[@]}"
+
+lvcreate -L10M -V10M -T $vg/pool --name $lv1
+
+lvcreate -H -L10 $vg/pool
+
+mkfs.ext4 "$DM_DEV_DIR/$vg/$lv1"
+
+lvconvert --uncache $vg/pool
+fsck -n "$DM_DEV_DIR/$vg/$lv1"
+
+lvcreate -H -L10 $vg/pool_tdata
+fsck -n "$DM_DEV_DIR/$vg/$lv1"
+lvconvert --uncache $vg/pool_tdata
+
+vgremove -ff $vg
diff --git a/test/shell/lvcreate-thin-external-size.sh b/test/shell/lvcreate-thin-external-size.sh
new file mode 100644
index 0000000..862dd15
--- /dev/null
+++ b/test/shell/lvcreate-thin-external-size.sh
@@ -0,0 +1,94 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2015 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+# Test unaligned size of external origin and thin pool chunk size
+
+
+SKIP_WITH_LVMPOLLD=1
+
+export LVM_TEST_THIN_REPAIR_CMD=${LVM_TEST_THIN_REPAIR_CMD-/bin/false}
+
+. lib/inittest
+
+which cmp || skip
+
+#
+# Main
+#
+
+# Test needs thin-pool target with unaligned ext-orig size support
+aux have_thin 1 13 0 || skip
+
+aux prepare_pvs 2 640
+get_devs
+
+# Use 8K extent size
+vgcreate $SHARED -s 8K "$vg" "${DEVICES[@]}"
+
+# Prepare some numeric pattern with ~64K size
+seq -s ' ' -w 0 10922 > 64K
+
+d1="$DM_DEV_DIR/$vg/$lv1"
+d2="$DM_DEV_DIR/$vg/$lv2"
+
+# Prepare external origin LV with size not being a multiple of thin pool chunk size
+lvcreate -l47 -n $lv1 $vg
+
+# Fill end with pattern
+dd if=64K of="$d1" bs=8192 seek=45 count=2 conv=fdatasync
+
+# Switch to read-only volume
+lvchange -an $vg/$lv1
+lvchange -pr $vg/$lv1
+
+lvcreate -L2M -T $vg/pool -c 192K
+lvcreate -s $vg/$lv1 --name $lv2 --thinpool $vg/pool
+
+# Check the tail of $lv2 matches $lv1
+dd if="$d2" of=16K bs=8192 skip=45 count=2
+cmp -n 16384 -l 64K 16K
+
+# Now extend and rewrite
+lvextend -l+2 $vg/$lv2
+
+dd if=64K of="$d2" bs=8192 seek=46 count=3 conv=fdatasync
+dd if="$d2" of=24K bs=8192 skip=46 count=3 iflag=direct
+cmp -n 24576 -l 64K 24K
+
+# Consumes 2 192K chunks -> 66.67%
+check lv_field $vg/$lv2 data_percent "66.67"
+
+lvreduce -f -l-24 $vg/$lv2
+
+dd if=64K of="$d2" bs=8192 seek=24 count=1 conv=fdatasync
+dd if="$d2" of=8K bs=8192 skip=24 count=1 iflag=direct
+cmp -n 8192 -l 64K 8K
+
+# Check extension still works
+lvextend -l+2 $vg/$lv2
+
+lvremove -f $vg/pool
+
+lvcreate -L256M -T $vg/pool -c 64M
+lvcreate -s $vg/$lv1 --name $lv2 --thinpool $vg/pool
+lvextend -l+2 $vg/$lv2
+
+dd if=64K of="$d2" bs=8192 seek=45 count=4 conv=fdatasync
+dd if="$d2" of=32K bs=8192 skip=45 count=4 iflag=direct
+cmp -n 32768 -l 64K 32K
+
+lvextend -L+64M $vg/$lv2
+
+# Consumes 64M chunk -> 50%
+check lv_field $vg/$lv2 data_percent "50.00"
+
+vgremove -ff $vg
diff --git a/test/shell/lvcreate-thin-external.sh b/test/shell/lvcreate-thin-external.sh
new file mode 100644
index 0000000..20f0577
--- /dev/null
+++ b/test/shell/lvcreate-thin-external.sh
@@ -0,0 +1,109 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2013-2014 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+# Test creation of thin snapshots using external origin
+
+
+SKIP_WITH_LVMPOLLD=1
+
+export LVM_TEST_THIN_REPAIR_CMD=${LVM_TEST_THIN_REPAIR_CMD-/bin/false}
+
+. lib/inittest
+
+which mkfs.ext2 || skip
+which fsck || skip
+
+#
+# Main
+#
+aux have_thin 1 3 0 || skip
+
+aux prepare_pvs 2 64
+get_devs
+
+vgcreate $SHARED -s 64K "$vg" "${DEVICES[@]}"
+
+# Newer thin-pool target (>= 1.13) supports unaligned external origin
+# But this test is written to test and expect older behavior
+aux lvmconf 'global/thin_disabled_features = [ "external_origin_extend" ]'
+
+# Test validation for external origin being multiple of thin pool chunk size
+lvcreate -L10M -T $vg/pool192 -c 192k
+lvcreate -an -pr -Zn -l1 -n $lv1 $vg
+not lvcreate -s $vg/$lv1 --thinpool $vg/pool192
+
+lvcreate -an -pr -Zn -l5 -n $lv2 $vg
+not lvcreate -s $vg/$lv2 --thinpool $vg/pool192
+lvremove -f $vg
+
+# Prepare pool and external origin with filesystem
+lvcreate -L10M -V10M -T $vg/pool --name $lv1
+mkfs.ext2 "$DM_DEV_DIR/$vg/$lv1"
+
+lvcreate -L4M -n $lv2 $vg
+mkfs.ext2 "$DM_DEV_DIR/$vg/$lv2"
+
+# Fail to create external origin snapshot of rw LV
+not lvcreate -s $vg/$lv2 --thinpool $vg/pool
+
+lvchange -p r $vg/$lv2
+
+# Fail to create snapshot of active r LV
+# FIXME: kernel update needed
+not lvcreate -s $vg/$lv2 --thinpool $vg/pool
+
+# Deactivate LV we want to use as external origin
+# once kernel will ensure read-only this condition may go away
+lvchange -an $vg/$lv2
+
+lvcreate -s $vg/$lv2 --thinpool $vg/pool
+
+# Fail with --thin and --snapshot
+not lvcreate -s $vg/$lv5 --name $vg/$lv7 -T $vg/newpool
+
+# Cannot specify size and thin pool.
+# TODO: maybe with --poolsize
+invalid lvcreate -s $vg/$lv2 -L10 --thinpool $vg/pool
+invalid lvcreate -s -K $vg/$lv2 --name $vg/$lv3 -L20 --chunksize 128 --thinpool $vg/newpool
+
+not lvcreate -s $vg/$lv2 --chunksize 64 --thinpool $vg/pool
+not lvcreate -s $vg/$lv2 --zero y --thinpool $vg/pool
+not lvcreate -s $vg/$lv2 --poolmetadata $vg/$lv1 --thinpool $vg/pool
+
+# Fail with nonexistent pool
+not lvcreate -s $vg/$lv2 --thinpool $vg/newpool
+
+# Create pool and snap
+lvcreate -T --name $vg/$lv3 -V10 -L20 --chunksize 128 --thinpool $vg/newpool
+lvcreate -s -K $vg/$lv3 --name $vg/$lv4
+lvcreate -s -K $vg/$lv2 --name $vg/$lv5 --thinpool $vg/newpool
+# Make normal thin snapshot
+lvcreate -s -K $vg/$lv5 --name $vg/$lv6
+# We do not need to specify thinpool when doing thin snap, but it should work
+lvcreate -s -K $vg/$lv5 --name $vg/$lv7 --thinpool $vg/newpool
+
+check inactive $vg $lv2
+lvchange -ay $vg/$lv2
+lvcreate -s -K $vg/$lv2 --name $vg/$lv8 --thinpool $vg/newpool
+
+lvs -o+chunksize $vg
+
+check active $vg $lv3
+check active $vg $lv4
+check active $vg $lv5
+check active $vg $lv6
+check active $vg $lv7
+
+fsck -n "$DM_DEV_DIR/$vg/$lv1"
+fsck -n "$DM_DEV_DIR/$vg/$lv7"
+
+vgremove -ff $vg
diff --git a/test/shell/lvcreate-thin-limits.sh b/test/shell/lvcreate-thin-limits.sh
new file mode 100644
index 0000000..5dcc160
--- /dev/null
+++ b/test/shell/lvcreate-thin-limits.sh
@@ -0,0 +1,61 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2020 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+# test allocation of thin-pool on limiting extents number
+
+SKIP_WITH_LVMPOLLD=1
+
+export LVM_TEST_THIN_REPAIR_CMD=${LVM_TEST_THIN_REPAIR_CMD-/bin/false}
+
+. lib/inittest
+
+# FIXME update test to make something useful on <16T
+aux can_use_16T || skip
+
+#
+# Main
+#
+aux have_thin 1 0 0 || skip
+which mkfs.ext4 || skip
+
+# 16T device
+aux prepare_pvs 2 8388608
+get_devs
+
+# gives 16777215M device
+vgcreate $SHARED -s 4M "$vg" "${DEVICES[@]}"
+
+# For 1st. pass only single PV
+lvcreate -l100%PV --name $lv1 $vg "$dev2"
+
+for i in 1 0
+do
+ SIZE=$(get vg_field "$vg" vg_free --units m)
+ SIZE=${SIZE%%\.*}
+
+ # ~16T - 2 * 5G + something -> should not fit
+ not lvcreate -Zn -T -L$(( SIZE - 2 * 5 * 1024 + 1 )) --poolmetadatasize 5G $vg/pool
+
+ check vg_field "$vg" lv_count "$i"
+
+ # Should fit data + metadata + pmspare
+ lvcreate -Zn -T -L$(( SIZE - 2 * 5 * 1024 )) --poolmetadatasize 5G $vg/pool
+
+ check vg_field "$vg" vg_free "0"
+
+ lvs -ao+seg_pe_ranges $vg
+
+ # Remove everything for 2nd. pass
+ lvremove -ff $vg
+done
+
+vgremove -ff $vg
diff --git a/test/shell/lvcreate-thin-power2.sh b/test/shell/lvcreate-thin-power2.sh
index 882b05c..ec9755a 100644
--- a/test/shell/lvcreate-thin-power2.sh
+++ b/test/shell/lvcreate-thin-power2.sh
@@ -1,4 +1,4 @@
-#!/bin/sh
+#!/usr/bin/env bash
# Copyright (C) 2012 Red Hat, Inc. All rights reserved.
#
@@ -8,12 +8,17 @@
#
# 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
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
#
# test support for non-power-of-2 thin chunk size
#
-. lib/test
+
+SKIP_WITH_LVMPOLLD=1
+
+export LVM_TEST_THIN_REPAIR_CMD=${LVM_TEST_THIN_REPAIR_CMD-/bin/false}
+
+. lib/inittest
#
# Main
@@ -21,17 +26,19 @@
aux have_thin 1 4 0 || skip
aux prepare_pvs 2 64
+get_devs
-vgcreate $vg -s 64K $(cat DEVICES)
+vgcreate $SHARED -s 64K "$vg" "${DEVICES[@]}"
# create non-power-of-2 pool
lvcreate -l100 -c 192 -T $vg/pool
-check lv_field $vg/pool discards "ignore"
+check lv_field $vg/pool discards "passdown"
# check we cannot change discards settings
-not lvchange --discard passdown $vg/pool
-not lvchange --discard nopassdown $vg/pool
+not lvchange --discard ignore $vg/pool
+lvchange --discard nopassdown $vg/pool
+check lv_field $vg/pool discards "nopassdown"
# must be multiple of 64KB
not lvcreate -l100 -c 168 -T $vg/pool1
diff --git a/test/shell/lvcreate-thin-snap.sh b/test/shell/lvcreate-thin-snap.sh
index 23f91f9..8f19879 100644
--- a/test/shell/lvcreate-thin-snap.sh
+++ b/test/shell/lvcreate-thin-snap.sh
@@ -1,4 +1,4 @@
-#!/bin/sh
+#!/usr/bin/env bash
# Copyright (C) 2012 Red Hat, Inc. All rights reserved.
#
@@ -8,17 +8,22 @@
#
# 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
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
-. lib/test
+
+SKIP_WITH_LVMPOLLD=1
+
+export LVM_TEST_THIN_REPAIR_CMD=${LVM_TEST_THIN_REPAIR_CMD-/bin/false}
+
+. lib/inittest
check_lv_field_modules_()
{
mod=$1
shift
- for d in $*; do
- check lv_field $vg/$d modules $mod
+ for d in "$@"; do
+ check lv_field "$vg/$d" modules "$mod"
done
}
@@ -27,31 +32,67 @@ check_lv_field_modules_()
# Main
#
aux have_thin 1 0 0 || skip
+which mkfs.ext4 || skip
aux prepare_pvs 2 64
+get_devs
-vgcreate $vg -s 64K $(cat DEVICES)
+vgcreate $SHARED -s 64K "$vg" "${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
+mkfs.ext4 "$DM_DEV_DIR/$vg/$lv1"
+# create read-only thin snapshot of thin LV
+lvcreate -K -s $vg/$lv1 -pr --name snap
# 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
+fsck -n "$DM_DEV_DIR/$vg/snap"
+lvcreate -K -s $vg/$lv1 --name $lv2
+lvcreate -K -s $vg/$lv1 --name $vg/$lv3
+# old-snapshot without known size is invalid
+invalid lvcreate --type snapshot $vg/$lv1
+invalid lvcreate --type snapshot $vg/$lv1 --name $lv4
+invalid lvcreate --type snapshot $vg/$lv1 --name $vg/$lv5
+# some other ways how to take a thin snapshot
+lvcreate -T $vg/$lv1
+lvcreate --thin $vg/$lv1 --name $lv4
+lvcreate --type thin $vg/$lv1 --name $vg/$lv5
+# virtual size needs thin pool
+fail lvcreate --type thin $vg/$lv1 -V20
# 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
+lvcreate -K -s --name sn1 $vg/$lv2
+lvcreate -K -s --name sn2 $vg/sn1
+lvcreate -K -s --name sn3 $vg/sn2
+lvcreate -K -s --name sn4 $vg/sn3
+
+lvremove -ff $vg
+
+lvcreate -L10M --zero n -T $vg/pool -V10M --name $lv1
+mkfs.ext4 "$DM_DEV_DIR/$vg/$lv1"
+lvcreate -K -s $vg/$lv1 --name snap
+fsck -n "$DM_DEV_DIR/$vg/snap"
+vgchange -an $vg
+lvremove -y $vg
+
+# One thin pool and one thin LV
+lvcreate --type thin-pool -L 10M -n tp $vg
+lvcreate --type thin -n thin1 -V 20M --thinpool tp $vg
+# Different syntaxes for creating a thin snapshot
+lvcreate --type thin -n snap1 $vg/thin1
+lvcreate --type thin --snapshot -n snap2 $vg/thin1
+lvcreate --type thin --thin -n snap3 $vg/thin1
+lvcreate --type thin --snapshot --thin -n snap4 $vg/thin1
+lvcreate --snapshot -n snap5 $vg/thin1
+lvcreate --thin -n snap6 $vg/thin1
+# The command defs allow --snapshot --thin, but the internal
+# lvcreate option checks disallow it. It doesn't seem to make
+# sense to disallow this from a syntax point of view, but it's
+# possible that the lvcreate implementation would do the wrong
+# thing (that should probably be fixed.)
+not lvcreate --thin --snapshot -n snap7 $vg/thin1
+vgchange -an $vg
vgremove -ff $vg
diff --git a/test/shell/lvcreate-thin.sh b/test/shell/lvcreate-thin.sh
index e651a81..c073eaf 100644
--- a/test/shell/lvcreate-thin.sh
+++ b/test/shell/lvcreate-thin.sh
@@ -1,6 +1,6 @@
-#!/bin/sh
+#!/usr/bin/env bash
-# Copyright (C) 2011-2012 Red Hat, Inc. All rights reserved.
+# Copyright (C) 2011-2014 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
@@ -8,54 +8,88 @@
#
# 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
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
# test currently needs to drop
# 'return NULL' in _lv_create_an_lv after log_error("Can't create %s without using "
-. lib/test
+
+SKIP_WITH_LVMPOLLD=1
+
+export LVM_TEST_THIN_REPAIR_CMD=${LVM_TEST_THIN_REPAIR_CMD-/bin/false}
+
+. lib/inittest
check_lv_field_modules_()
{
mod=$1
shift
- for d in $*; do
+ for d in "$@"; do
check lv_field $vg/$d modules $mod
done
}
-
#
# Main
#
aux have_thin 1 0 0 || skip
+which mkfs.ext4 || skip
aux prepare_pvs 2 64
+get_devs
-vgcreate $vg -s 64K $(cat DEVICES)
+vgcreate $SHARED -s 64K "$vg" "${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
+invalid lvcreate -l1 --type thin $vg/pool4
+invalid lvcreate -l1 --type thin --thinpool $vg/pool5
+invalid 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
+lvremove -ff $vg/pool1 $vg/pool2 $vg/pool3 $vg/pool7 $vg/pool8 $vg/pool9
+check vg_field $vg lv_count 0
+
+
+# Let's pretend pool is like normal LV when using --type thin-pool support --name
+# Reject ambiguous thin pool names
+invalid lvcreate --type thin-pool -l1 --name pool1 $vg/pool2
+invalid lvcreate --type thin-pool -l1 --name pool3 --thinpool pool4 $vg
+invalid lvcreate --type thin-pool -l1 --name pool5 --thinpool pool6 $vg/pool7
+invalid lvcreate --type thin-pool -l1 --name pool8 --thinpool pool8 $vg/pool9
+
+# no size specified and no origin name give for snapshot
+invalid lvcreate --thinpool pool $vg
+
check vg_field $vg lv_count 0
+lvcreate --type thin-pool -l1 --name pool1 $vg
+lvcreate --type thin-pool -l1 --name $vg/pool2
+# If the thin pool name is unambiguous let it proceed
+lvcreate --type thin-pool -l1 --name pool3 $vg/pool3
+lvcreate --type thin-pool -l1 --name pool4 --thinpool $vg/pool4
+lvcreate --type thin-pool -l1 --name pool5 --thinpool $vg/pool5 $vg/pool5
+
+check lv_field $vg/pool1 segtype "thin-pool"
+check lv_field $vg/pool2 segtype "thin-pool"
+check lv_field $vg/pool3 segtype "thin-pool"
+check lv_field $vg/pool4 segtype "thin-pool"
+check lv_field $vg/pool5 segtype "thin-pool"
+
+lvremove -ff $vg
+
# Create default pool name
lvcreate -l1 -T $vg
-lvcreate -l1 --type thin $vg
+invalid lvcreate -l1 --type thin $vg
lvcreate -l1 --type thin-pool $vg
-lvremove -ff $vg/lvol0 $vg/lvol1 $vg/lvol2
+lvremove -ff $vg
check vg_field $vg lv_count 0
@@ -67,14 +101,14 @@ 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
+lvcreate -L4M -V2G --name lvo1 -T $vg/pool1
+lvcreate -L4M -V2G --name lvo2 -T --thinpool $vg/pool2
+lvcreate -L4M -V2G --name lvo3 -T --thinpool pool3 $vg
+lvcreate -L4M -V2G --name lvo4 --type thin $vg/pool4
+lvcreate -L4M -V2G --name lvo5 --type thin --thinpool $vg/pool5
+lvcreate -L4M -V2G --name lvo6 --type thin --thinpool pool6 $vg
+
+check lv_exists $vg lvo1 lvo2 lvo3
lvremove -ff $vg
@@ -103,14 +137,14 @@ 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
+lvcreate -V2G --name lvo0 -T $vg/pool
+lvcreate -V2G --name lvo1 -T --thinpool $vg/pool
+lvcreate -V2G --name lvo2 -T --thinpool pool $vg
+lvcreate -V2G --name lvo3 --type thin $vg/pool
+lvcreate -V2G --name lvo4 --type thin --thinpool $vg/pool
+lvcreate -V2G --name lvo5 --type thin --thinpool pool $vg
-check lv_exists $vg lvol0 lvol1 lvol2 lvol3 lvol4 lvol5
+check lv_exists $vg lvo0 lvo1 lvo2 lvo3 lvo4 lvo5
# Create named thin LV in existing pool
@@ -129,40 +163,52 @@ 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
+check lv_field $vg/lv1 thin_id 7
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 -L10M -I4 -i2 -V10M -T $vg/pool --name lv1
+mkfs.ext4 "$DM_DEV_DIR/$vg/lv1"
+lvcreate -K -s $vg/lv1 --name snap_lv1
+fsck -n "$DM_DEV_DIR/$vg/snap_lv1"
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
+invalid lvcreate --type snapshot $vg/lv1 --name lv6
+invalid lvcreate --type snapshot $vg/lv1 --name lv4
+invalid lvcreate --type snapshot $vg/lv1 --name $vg/lv5
+
+lvdisplay --maps $vg
+check_lv_field_modules_ thin,thin-pool lv1 snap_lv1 lv2 lv3
+check vg_field $vg lv_count 5
-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 snap_lv1
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_lv_field_modules_ snapshot snap_lv1 lv2 lv3 lv4
check vg_field $vg lv_count 6
lvremove -ff $vg
check vg_field $vg lv_count 0
-lvdisplay $vg
+
+# Check how allocator works with 2PVs where one is nearly full
+lvcreate -l99%PV $vg "$dev1"
+lvs -a $vg
+# Check when separate metadata is required, allocation needs to fail
+fail lvcreate -L10 -T --poolmetadataspare n --config 'allocation/thin_pool_metadata_require_separate_pvs=1' $vg
+# Check when data and metadata may share the same PV, it shall pass
+lvcreate -L10 -T --poolmetadataspare n --config 'allocation/thin_pool_metadata_require_separate_pvs=0' $vg
+lvremove -f $vg
+
# Fail cases
# Too small pool size (1 extent 64KB) for given chunk size
@@ -171,41 +217,56 @@ not lvcreate --chunksize 256 -l1 -T $vg/pool1
not lvcreate --chunksize 32 -l1 -T $vg/pool1
# Too large chunk size (max is 1GB)
not lvcreate -L4M --chunksize 2G -T $vg/pool1
+# Cannot specify --minor with pool
+fail lvcreate -L10M --minor 100 -T $vg/pool_minor
+
+# FIXME: Currently ambigous - is it for thin, thin-pool, both ?
+fail lvcreate -L4M -Mn -m0 -T --readahead 32 -V20 -n $lv $vg/pool_normal
+
+# Check read-ahead setting will also pass with -Mn -m0
+lvcreate -L4M -Mn -m0 -T --readahead 64k $vg/pool_readahead
+lvcreate -V20M -Mn -m0 -T --readahead 128k -n thin_readahead $vg/pool_readahead
+check lv_field $vg/pool_readahead lv_read_ahead "64.00k"
+check lv_field $vg/thin_readahead lv_read_ahead "128.00k"
+
+if test ! -d /sys/block/dm-2345; then
+# Check some unused minor and support for --minor with thins
+ lvcreate --minor 2345 -T -V20M -n thin_minor $vg/pool_readahead
+ check lv_field $vg/thin_minor lv_minor "2345"
+fi
+
+# Test creation of inactive pool
+lvcreate -an -L4M -T $vg/pool1
+lvcreate -V2G --name lv1 -T $vg/pool1
+# Check we are able remove spare volume if we want to
+lvremove -f $vg/lvol0_pmspare
-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
+# Check we cannot create mirror/raid1 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"
+# Check pool metadata volume is zeroed, when zero_metadata is enabled.
+# 1st. ensure 8megs of both PVs will have some non-0 data
+lvcreate -L8m -n $lv1 $vg "$dev1"
+lvextend -L+8m $vg/$lv1 "$dev2"
+dd if=/dev/urandom of="$DM_DEV_DIR/$vg/$lv1" bs=1M count=16 oflag=direct conv=fdatasync
+lvremove -ff $vg/$lv1
+
+lvcreate -l1 --poolmetadatasize 4m --conf 'allocation/zero_metadata=1' -vvvv -T $vg/pool
+lvchange -an $vg
+# component activation to check device was zeroed
+lvchange -y -ay $vg/pool_tmeta
+dd if="$DM_DEV_DIR/$vg/pool_tmeta" of=file bs=1M count=3 skip=1 iflag=direct conv=fdatasync
+
+md5sum -b file | tee out
+# md5sum of 3M of zeros
+grep d1dd210d6b1312cb342b56d02bd5e651 out
+lvchange -an $vg
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
index ddde401..6d46939 100644
--- a/test/shell/lvcreate-usage.sh
+++ b/test/shell/lvcreate-usage.sh
@@ -1,5 +1,6 @@
-#!/bin/sh
-# Copyright (C) 2008-2011 Red Hat, Inc. All rights reserved.
+#!/usr/bin/env bash
+
+# Copyright (C) 2008-2013 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
@@ -7,89 +8,112 @@
#
# 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
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
# 'Exercise some lvcreate diagnostics'
-. lib/test
+. lib/inittest
aux prepare_pvs 4
-aux pvcreate --metadatacopies 0 "$dev1"
-vgcreate -cn $vg $(cat DEVICES)
+get_devs
-# "lvcreate rejects repeated invocation (run 2 times) (bz178216)"
-lvcreate -n $lv -l 4 $vg
+aux pvcreate --metadatacopies 0 "$dev1"
+aux vgcreate $SHARED "$vg" "${DEVICES[@]}"
+
+invalid lvcreate --type free -l1 -n $lv1 $vg 2>err
+grep "Invalid argument for --type" err
+invalid lvcreate --type $RANDOM -l1 -n $lv1 $vg
+invalid lvcreate --type unknown -l1 -n $lv1 $vg
+
+invalid lvcreate -L10000000000000000000 -n $lv $vg 2>&1 | tee err
+grep "Size is too big" err
+invalid lvcreate -L+-10 -n $lv $vg 2>&1 | tee err
+grep "Multiple sign" err
+invalid lvcreate -L-.1 -n $lv $vg 2>&1 | tee err
+grep "Size may not be negative" err
+invalid lvcreate -L..1 -n $lv $vg 2>&1 | tee err
+grep "Can't parse size" err
+
+lvcreate --type linear -aey -m0 -l1 -n $lv1 $vg
+lvcreate --type snapshot -l1 -n $lv2 $vg/$lv1
+# Supporting decimal point with size
+lvcreate -L.1 -n $lv3 $vg
+
+# Reject 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)
+# 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
+# Reject a negative stripe_size
+invalid lvcreate -L 64m -n $lv -i2 --stripesize -4 $vg 2>err;
+grep "may not be negative" err
-# 'lvcreate rejects a too-large stripesize'
-not lvcreate -L 64m -n $lv -i2 --stripesize 4294967291 $vg 2>err
+# Reject a too-large stripesize
+invalid 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'
+# 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
+lvdisplay $vg
lvremove -ff $vg
-# 'lvcreate w/default (64KB) stripe size succeeds with diagnostics to stdout'
+# 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
+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
+# Reject an invalid number of stripes
+invalid 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
+# Reject an invalid stripe size
+invalid lvcreate -L 64m -n $lv -i2 --stripesize 3 $vg 2>err
grep "Invalid stripe size" err
+# Verify that the LV was not created via lvdisplay empty output
test -z "$(lvdisplay $vg)"
# Setting max_lv works. (bz490298)
-lvremove -ff $vg
+check vg_field $vg max_lv "0"
vgchange -l 3 $vg
-lvcreate -l1 -n $lv1 $vg
+check vg_field $vg max_lv "3"
+lvcreate -aey -l1 -n $lv1 $vg
lvcreate -l1 -s -n $lv2 $vg/$lv1
lvcreate -l1 -n $lv3 $vg
-not lvcreate -l1 -n $lv4 $vg
-
+fail lvcreate -l1 -n $lv4 $vg
lvremove -ff $vg/$lv3
+
+# Check snapshot of inactive origin
+lvchange -an $vg/$lv1
lvcreate -l1 -s -n $lv3 $vg/$lv1
-not lvcreate -l1 -n $lv4 $vg
-not lvcreate -l1 -m1 -n $lv4 $vg
+fail lvcreate -l1 -n $lv4 $vg
+fail lvcreate -l1 --type mirror -m1 -n $lv4 $vg
lvremove -ff $vg/$lv3
-lvcreate -l1 -m1 -n $lv3 $vg
-vgs -o +max_lv $vg
+lvcreate -aey -l1 --type mirror -m1 -n $lv3 $vg
not lvcreate -l1 -n $lv4 $vg
-not lvcreate -l1 -m1 -n $lv4 $vg
+not lvcreate -l1 --type mirror -m1 -n $lv4 $vg
lvconvert -m0 $vg/$lv3
-lvconvert -m2 -i 1 $vg/$lv3
+lvconvert -m2 --type mirror -i 1 $vg/$lv3
lvconvert -m1 $vg/$lv3
-not vgchange -l 2
+fail vgchange -l 2
+check vg_field $vg max_lv "3"
vgchange -l 4
-vgs $vg
+check vg_field $vg max_lv "4"
lvremove -ff $vg
vgchange -l 0 $vg
+check vg_field $vg max_lv "0"
-# 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
+# Rejects invalid chunksize, accepts between 4K and 512K
+# and validate origin_size
+lvcreate -aey -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
@@ -98,53 +122,110 @@ 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
+lvremove -f $vg
-# regionsize must be
+# Mirror 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
+invalid lvcreate --type mirror -m 1 -L 32m -n $lv -R 0 $vg 2>err
+grep "may not be zero" err
+invalid lvcreate --type mirror -m 1 -L 32m -n $lv -R 11k $vg
+invalid lvcreate --type mirror -m 1 -L 32m -n $lv -R 1k $vg
+lvcreate -aey -L 32m -n $lv --regionsize 128m --type mirror -m 1 $vg
check lv_field $vg/$lv regionsize "32.00m"
-lvremove -ff $vg
-lvcreate -L 32m -n $lv --regionsize 4m -m 1 $vg
+lvremove -f $vg
+lvcreate -aey -L 32m -n $lv --regionsize 4m --type mirror -m 1 $vg
check lv_field $vg/$lv regionsize "4.00m"
+
+# -m0 is creating non-mirrored segment and give info about redundant option
+lvcreate -m 0 -l1 -n $lv1 $vg 2>&1 | tee err
+grep "Redundant" err
+check lv_field $vg/$lv1 segtype "linear"
lvremove -ff $vg
-# snapshot with virtual origin works
+if test -n "$LVM_TEST_LVMLOCKD"; then
+echo "skip snapshot without origin"
+else
+
+# Old --type snapshot works with -s
+lvcreate --type snapshot -s -V64 -L32 -n $lv1 $vg
+check lv_field $vg/$lv1 segtype "linear"
+lvcreate --type snapshot -V64 -L32 -n $lv2 $vg
+check lv_field $vg/$lv2 segtype "linear"
+lvremove -ff $vg
+
+# --virtualoriginsize always makes old snapshot
lvcreate -s --virtualoriginsize 64m -L 32m -n $lv1 $vg
+check lv_field $vg/$lv1 segtype "linear"
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
+fi
+
# 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"
+lvcreate -L 8 -n $lv1 $vg
+check lv_field $vg/$lv1 lv_read_ahead "auto"
+lvcreate -L 8 -n $lv2 --readahead none $vg
+check lv_field $vg/$lv2 lv_read_ahead "0"
+check lv_field $vg/$lv2 lv_kernel_read_ahead "0"
+lvcreate -L 8 -n $lv3 --readahead 8k $vg
+check lv_field $vg/$lv3 lv_read_ahead "8.00k"
+check lv_field $vg/$lv3 lv_kernel_read_ahead "8.00k"
+lvcreate -L 8 -n $lv4 --readahead auto $vg "$dev1"
+check lv_field $vg/$lv4 lv_read_ahead "auto"
+# figure RA value of a PV origin device
+DEVICE=$(dmsetup deps -o blkdevname "$dev1" | sed -e "s,.*:\ (\(.*\)),/dev/\1,")
+RASZ=$(( $(blockdev --getra "$DEVICE" ) / 2 ))
+test "$RASZ" -ge 128 || RASZ="128"
+check lv_field $vg/$lv4 lv_kernel_read_ahead "${RASZ}.00k" --units k
+lvcreate -vvvvv -L 8 -n $lv5 -i2 --stripesize 16k --readahead auto $vg
+check lv_field $vg/$lv5 lv_read_ahead "auto"
+# For 16k stripe we set '128k' as the is the minimum size we get when creating DM device
+check lv_field $vg/$lv5 lv_kernel_read_ahead "128.00k" --units k
+lvcreate -L 8 -n $lv6 -i2 --stripesize 128k --readahead auto $vg
+check lv_field $vg/$lv6 lv_read_ahead "auto"
+# For striped device we set double of strip size unrelated to underlaying dev RA size
+check lv_field $vg/$lv6 lv_kernel_read_ahead "512.00k" --units k
lvremove -ff $vg
+
+#
+# Validate --major --minor, we need to know VG, thus failing
+#
+fail lvcreate -My --major 234 -l1 $vg
+# cannot specify --major or --minor with -Mn
+fail lvcreate -Mn --major 234 -l1 $vg
+fail lvcreate --persistent n --minor 234 -l1 $vg
+# out-of-range minor value
+fail lvcreate --minor 9999999 -l1 $vg
+if aux kernel_at_least 2 4 0; then
+# On >2.4 we ignore --major
+lvcreate --major 234 -l1 $vg 2>&1 | tee err;
+grep "Ignoring" err
+# Try some bigger possibly unused minor
+if test ! -d /sys/block/dm-2345; then
+ lvcreate --minor 2345 -l1 -n $lv1 $vg
+ check lv_field $vg/$lv1 lv_kernel_minor "2345"
+fi
+if test ! -d /sys/block/dm-23456; then
+ lvcreate -My --minor 23456 -j 122 -l1 -n $lv2 $vg
+ check lv_field $vg/$lv2 lv_kernel_minor "23456"
+fi
+fi # 2.4
+lvremove -f $vg
+
+# prohibited names
+for i in pvmove snapshot ; do
+ invalid lvcreate -l1 -n ${i}1 $vg
+done
+for i in _cdata _cmeta _cpool _cvol _mimage _mlog _pmspare _tdata _tmeta _vorigin ; do
+ invalid lvcreate -l1 -n s_${i}_1 $vg
+done
+
+# Check invalid error for pool-only options
+invalid lvcreate --poolmetadataspare y -l1 $vg
+invalid lvcreate --poolmetadatasize 10 -l1 $vg
+invalid lvcreate --discards passdown -l1 $vg
diff --git a/test/shell/lvcreate-vdo-cache.sh b/test/shell/lvcreate-vdo-cache.sh
new file mode 100644
index 0000000..6cf8437
--- /dev/null
+++ b/test/shell/lvcreate-vdo-cache.sh
@@ -0,0 +1,58 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2017 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+# Exercise caching vdo and vdo-pool's data LV
+
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+#
+# Main
+#
+
+#
+# FIXME: tempororarily disable this test until fixed VDO driver is relased
+# should really be 6.2.2 - currently goes with vdo-6.2.2.18
+aux have_vdo 6 2 1 || skip
+aux have_cache 1 3 0 || skip
+
+which mkfs.ext4 || skip
+export MKE2FS_CONFIG="$TESTDIR/lib/mke2fs.conf"
+
+aux prepare_vg 1 9000
+
+lvcreate --vdo -L4G -V2G --name $lv1 $vg/vpool
+# Test caching VDOPoolLV
+lvcreate -H -L10 $vg/vpool
+
+mkfs.ext4 -E nodiscard "$DM_DEV_DIR/$vg/$lv1"
+
+lvconvert --uncache $vg/vpool
+fsck -n "$DM_DEV_DIR/$vg/$lv1"
+
+lvcreate -H -L10 $vg/vpool_vdata
+fsck -n "$DM_DEV_DIR/$vg/$lv1"
+lvs -a $vg
+lvconvert --uncache $vg/vpool_vdata
+
+
+# Test caching VDOLV
+lvcreate -H -L10 $vg/$lv1
+
+lvconvert --uncache $vg/$lv1
+fsck -n "$DM_DEV_DIR/$vg/$lv1"
+
+lvs -a $vg
+
+vgremove -ff $vg
diff --git a/test/shell/lvcreate-vdo.sh b/test/shell/lvcreate-vdo.sh
new file mode 100644
index 0000000..3e807ac
--- /dev/null
+++ b/test/shell/lvcreate-vdo.sh
@@ -0,0 +1,91 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2018 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+
+SKIP_WITH_LVMPOLLD=1
+
+
+. lib/inittest
+
+#
+# Main
+#
+aux have_vdo 6 2 0 || skip
+which mkfs.ext4 || skip
+
+aux prepare_pvs 2 6400
+get_devs
+
+#aux lvmconf 'allocation/vdo_use_read_cache = 1' 'allocation/vdo_read_cache_size_mb = 64'
+
+#aux lvmconf 'allocation/vdo_use_compression = 0' 'allocation/vdo_use_deduplication = 0'
+
+#aux lvmconf 'allocation/vdo_hash_zone_threads = 0' \
+# 'allocation/vdo_logical_threads = 0' \
+# 'allocation/vdo_physical_threads = 0' \
+# 'allocation/vdo_cpu_threads = 1'
+
+vgcreate $SHARED -s 64K "$vg" "${DEVICES[@]}"
+
+# Create VDO device (vdo-pool is ATM internal volume type)
+lvcreate --type vdo -L4G -n $lv1 $vg/$lv2 >out 2>&1
+# new vdoformat prints some more info
+if grep "data slabs" out ; then
+ # check we have match vdo_slab_size_mb == 128MB (aux.sh)
+ grep "each 128 MB" out
+fi
+
+check lv_field $vg/$lv1 size "<1.24g"
+check lv_field $vg/${lv2} size "4.00g"
+check lv_field $vg/${lv2}_vdata size "4.00g"
+check lv_field $vg/${lv1} data_percent "0.00"
+lvremove -ff $vg
+
+
+lvcreate --vdo -L4G -V8G -n $lv1 $vg/$lv2
+check lv_field $vg/$lv1 size "8.00g"
+check lv_field $vg/${lv2} size "4.00g"
+check lv_field $vg/${lv2}_vdata size "4.00g"
+lvs -a $vg
+
+dmsetup table | grep $vg
+dmsetup status | grep $vg
+
+# Resize not yet supported
+not lvresize -y $vg/$lv1
+not lvresize -y $vg/${lv2}
+not lvresize -y $vg/${lv2}_vdata
+
+# Discard is very slow with VDO ATM so try to avoid it
+#time blkdiscard "$DM_DEV_DIR/$vg/$lv1"
+time mkfs.ext4 -E nodiscard "$DM_DEV_DIR/$vg/$lv1"
+#time mkfs.ext4 "$DM_DEV_DIR/$vg/$lv1"
+fsck -n "$DM_DEV_DIR/$vg/$lv1"
+
+# vpool itself is NOT usable filesystem
+not fsck -n "$DM_DEV_DIR/mapper/$vg-${lv2}"
+# not usable even when there is no linear mapping on top of it
+dmsetup remove ${vg}-$lv1
+not fsck -n "$DM_DEV_DIR/mapper/$vg-${lv2}"
+
+lvremove -ff $vg
+
+# Unknown settings does not pass
+# TODO: try to catch this in parser and 'fail'
+not lvcreate --type vdo --vdosettings 'ack_Xthreads=4' -L10G -V1T -ky -n $lv1 $vg
+
+lvcreate --type vdo --vdosettings 'ack_threads=4' -L10G -V1T -ky -n $lv1 $vg
+check lv_field $vg/$lv1 vdo_ack_threads "4"
+lvs -a $vg
+lvremove -ff $vg
+
+vgremove -ff $vg
diff --git a/test/shell/lvdisplay-raid.sh b/test/shell/lvdisplay-raid.sh
new file mode 100644
index 0000000..32c3f34
--- /dev/null
+++ b/test/shell/lvdisplay-raid.sh
@@ -0,0 +1,80 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2021 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+#
+# tests functionality lvdisplay tool for RAID
+#
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+aux have_raid 1 7 0 || skip
+
+aux prepare_vg 6
+
+# raid0 loosing a leg
+lvcreate -aey --type raid0 -i5 -l5 -n $lv $vg
+lvdisplay $vg/$lv|grep "LV Status *available"
+aux disable_dev "$dev1"
+lvdisplay $vg/$lv|grep "LV Status *NOT available (partial)"
+aux enable_dev "$dev1"
+lvremove -y $vg/$lv
+
+# raid1 loosing a leg/all legs
+lvcreate -aey --type raid1 -m1 -l5 -n $lv $vg "$dev1" "$dev2"
+lvdisplay $vg/$lv|grep "LV Status *available"
+aux disable_dev "$dev1"
+lvdisplay $vg/$lv|grep "LV Status *available (partial)"
+aux disable_dev "$dev2"
+lvdisplay $vg/$lv|grep "LV Status *NOT available (partial)"
+aux enable_dev "$dev1" "$dev2"
+lvremove -y $vg/$lv
+
+# raid5 loosing a leg/2 legs
+lvcreate -aey --type raid5 -i3 -l5 -n $lv $vg
+lvdisplay $vg/$lv|grep "LV Status *available"
+aux disable_dev "$dev1"
+lvdisplay $vg/$lv|grep "LV Status *available (partial)"
+aux disable_dev "$dev2"
+lvdisplay $vg/$lv|grep "LV Status *NOT available (partial)"
+aux enable_dev "$dev1" "$dev2"
+lvremove -y $vg/$lv
+
+# raid6 loosing a leg/2 legs/3 legs
+lvcreate -aey --type raid6 -i3 -l5 -n $lv $vg
+lvdisplay $vg/$lv|grep "LV Status *available"
+aux disable_dev "$dev1"
+lvdisplay $vg/$lv|grep "LV Status *available (partial)"
+aux disable_dev "$dev2"
+lvdisplay $vg/$lv|grep "LV Status *available (partial)"
+aux disable_dev "$dev3"
+lvdisplay $vg/$lv|grep "LV Status *NOT available (partial)"
+aux enable_dev "$dev1" "$dev2" "$dev3"
+lvremove -y $vg/$lv
+
+# raid10 loosing a leg per mirror group / a complete mirror group
+lvcreate -aey --type raid10 -i3 -l3 -n $lv $vg
+lvdisplay $vg/$lv|grep "LV Status *available"
+aux disable_dev "$dev1"
+lvdisplay $vg/$lv|grep "LV Status *available (partial)"
+aux disable_dev "$dev3"
+lvdisplay $vg/$lv|grep "LV Status *available (partial)"
+aux disable_dev "$dev6"
+lvdisplay $vg/$lv|grep "LV Status *available (partial)"
+aux enable_dev "$dev1" "$dev3" "$dev6"
+lvdisplay $vg/$lv|grep "LV Status *available"
+aux disable_dev "$dev1" "$dev2"
+lvdisplay $vg/$lv|grep "LV Status *NOT available (partial)"
+aux enable_dev "$dev1" "$dev2"
+
+vgremove -y -f $vg
diff --git a/test/shell/lvextend-caches-on-thindata.sh b/test/shell/lvextend-caches-on-thindata.sh
new file mode 100644
index 0000000..2000c00
--- /dev/null
+++ b/test/shell/lvextend-caches-on-thindata.sh
@@ -0,0 +1,178 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2017-2020 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+SKIP_WITH_LVMPOLLD=1
+
+# lvextend thin pool data that has cache|writecache attached
+
+. lib/inittest
+
+do_test()
+{
+ local tp=$1
+ local lvt=$2
+
+ # create some initial data
+ lvchange -ay $vg/$lvt
+ mkfs.xfs -f -s size=4096 "$DM_DEV_DIR/$vg/$lvt"
+ mount "$DM_DEV_DIR/$vg/$lvt" "$mount_dir"
+ cp pattern "$mount_dir/pattern1"
+ dd if=/dev/urandom of="$mount_dir/rand100M" bs=1M count=100 conv=fdatasync
+ cp pattern "$mount_dir/pattern2"
+
+ # extend while mounted
+ lvextend -L+64M $vg/${tp}_tdata "$dev4"
+ lvs -a $vg -o+devices
+
+ # verify initial data
+ diff pattern "$mount_dir/pattern1"
+ diff pattern "$mount_dir/pattern2"
+ dd of=/dev/null if="$mount_dir/rand100M" bs=1M count=100
+
+ # add more data
+ cp pattern "$mount_dir/pattern3"
+ dd if=/dev/urandom of="$mount_dir/rand8M" bs=1M count=8 conv=fdatasync
+
+ # restart the LV
+ umount "$mount_dir"
+ lvchange -an $vg/$lvt
+ lvchange -an $vg/$tp
+ lvchange -ay $vg/$lvt
+ mount "$DM_DEV_DIR/$vg/$lvt" "$mount_dir"
+
+ # verify all data
+ diff pattern "$mount_dir/pattern1"
+ diff pattern "$mount_dir/pattern2"
+ diff pattern "$mount_dir/pattern3"
+ dd of=/dev/null if="$mount_dir/rand100M" bs=1M count=100
+ dd of=/dev/null if="$mount_dir/rand8M" bs=1M count=8
+
+ # extend again while inactive
+ umount "$mount_dir"
+ lvchange -an $vg/$lvt
+ lvchange -an $vg/$tp
+ lvextend -L+64M $vg/${tp}_tdata "$dev5"
+ lvs -a $vg -o+devices
+ lvchange -ay $vg/$lvt
+ mount "$DM_DEV_DIR/$vg/$lvt" "$mount_dir"
+
+ # verify all data
+ diff pattern "$mount_dir/pattern1"
+ diff pattern "$mount_dir/pattern2"
+ diff pattern "$mount_dir/pattern3"
+ dd of=/dev/null if="$mount_dir/rand100M" bs=1M count=100
+ dd of=/dev/null if="$mount_dir/rand8M" bs=1M count=8
+
+ # add more data
+ cp pattern "$mount_dir/pattern4"
+
+ # remove the cache
+ lvconvert --splitcache $vg/${tp}_tdata
+
+ # verify all data
+ diff pattern "$mount_dir/pattern1"
+ diff pattern "$mount_dir/pattern2"
+ diff pattern "$mount_dir/pattern3"
+ diff pattern "$mount_dir/pattern4"
+ dd of=/dev/null if="$mount_dir/rand100M" bs=1M count=100
+ dd of=/dev/null if="$mount_dir/rand8M" bs=1M count=8
+
+ umount "$mount_dir"
+ lvchange -an $vg/$lvt
+ lvchange -an $vg/$tp
+ lvchange -ay $vg/$lvt
+ mount "$DM_DEV_DIR/$vg/$lvt" "$mount_dir"
+
+ # verify all data
+ diff pattern "$mount_dir/pattern1"
+ diff pattern "$mount_dir/pattern2"
+ diff pattern "$mount_dir/pattern3"
+ diff pattern "$mount_dir/pattern4"
+ dd of=/dev/null if="$mount_dir/rand100M" bs=1M count=100
+ dd of=/dev/null if="$mount_dir/rand8M" bs=1M count=8
+
+ umount "$mount_dir"
+ lvchange -an $vg/$lvt
+ lvchange -an $vg/$tp
+ lvremove $vg/$lvt
+ lvremove $vg/$tp
+ lvremove -y $vg
+}
+
+
+aux have_cache 1 10 0 || skip
+aux have_writecache 1 0 0 || skip
+which mkfs.xfs || skip
+
+mount_dir="mnt"
+mkdir -p "$mount_dir"
+
+aux prepare_devs 6 400 # want 400M of usable space from each dev
+
+# Tests with fs block sizes require a libblkid version that shows BLOCK_SIZE
+vgcreate $vg "$dev1"
+lvcreate -n $lv1 -L300 $vg
+mkfs.xfs -f "$DM_DEV_DIR/$vg/$lv1"
+blkid -p "$DM_DEV_DIR/$vg/$lv1" | grep BLOCK_SIZE || skip
+lvchange -an $vg
+vgremove -ff $vg
+
+# generate random data
+dd if=/dev/urandom of=pattern bs=512K count=1
+
+vgcreate $SHARED $vg "$dev1" "$dev2" "$dev3" "$dev4" "$dev5" "$dev6"
+
+# test extending cache|writecache on thin pool data
+# test type cache|writecache
+# cache with cachepool|cachevol
+# cache with writeback|writethrough
+
+# lv1 is thinpool LV: 128M
+# lv2 is fast LV: 64M
+# lv3 is thin LV: 1G
+
+# attach writecache to thinpool data
+lvcreate --type thin-pool -n $lv1 -L228M --poolmetadataspare n $vg "$dev1" "$dev2"
+lvcreate --type thin -n $lv3 -V1G --thinpool $lv1 $vg
+lvcreate -n $lv2 -L64M -an $vg "$dev3"
+lvconvert -y --type writecache --cachevol $lv2 $vg/$lv1
+lvs -a $vg -o+devices
+do_test $lv1 $lv3
+
+# attach cache/writeback (cachevol) to thinpool data
+lvcreate --type thin-pool -n $lv1 -L228M --poolmetadataspare n $vg "$dev1" "$dev2"
+lvcreate --type thin -n $lv3 -V1G --thinpool $lv1 $vg
+lvcreate -n $lv2 -L64M -an $vg "$dev3"
+lvconvert -y --type cache --cachevol $lv2 --cachemode writeback $vg/$lv1
+lvs -a $vg -o+devices
+do_test $lv1 $lv3
+
+# attach cache/writethrough (cachevol) to thinpool data
+lvcreate --type thin-pool -n $lv1 -L228M --poolmetadataspare n $vg "$dev1" "$dev2"
+lvcreate --type thin -n $lv3 -V1G --thinpool $lv1 $vg
+lvcreate -n $lv2 -L64M -an $vg "$dev3"
+lvconvert -y --type cache --cachevol $lv2 --cachemode writethrough $vg/$lv1
+lvs -a $vg -o+devices
+do_test $lv1 $lv3
+
+# attach cache (cachepool) to thinpool data
+lvcreate --type thin-pool -n $lv1 -L228M --poolmetadataspare n $vg "$dev1" "$dev2"
+lvcreate --type thin -n $lv3 -V1G --thinpool $lv1 $vg
+lvcreate -y --type cache-pool -n $lv2 -L64M --poolmetadataspare n $vg "$dev3" "$dev6"
+lvconvert -y --type cache --cachepool $lv2 --poolmetadataspare n $vg/$lv1
+lvs -a $vg -o+devices
+do_test $lv1 $lv3
+
+# FIXME: test these thin pool data extensions done by dmeventd
+
+vgremove -f $vg
+
diff --git a/test/shell/lvextend-caches.sh b/test/shell/lvextend-caches.sh
new file mode 100644
index 0000000..4228a61
--- /dev/null
+++ b/test/shell/lvextend-caches.sh
@@ -0,0 +1,154 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2017-2020 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+SKIP_WITH_LVMPOLLD=1
+
+# lvextend LV with cache|writecache
+
+. lib/inittest
+
+case "$(uname -r)" in
+6.[0123]*|5.19*) skip "Skippen test that kills this kernel" ;;
+esac
+
+do_test()
+{
+ # create some initial data
+ lvchange -ay $vg/$lv1
+ mkfs.xfs -f -s size=4096 "$DM_DEV_DIR/$vg/$lv1"
+ mount "$DM_DEV_DIR/$vg/$lv1" "$mount_dir"
+ cp pattern "$mount_dir/pattern1"
+ dd if=/dev/urandom of="$mount_dir/rand100M" bs=1M count=100 conv=fdatasync
+ cp pattern "$mount_dir/pattern2"
+
+ # extend while mounted
+ lvextend -L+64M $vg/$lv1 "$dev4"
+ lvs -a $vg -o+devices
+
+ # verify initial data
+ diff pattern "$mount_dir/pattern1"
+ diff pattern "$mount_dir/pattern2"
+ dd of=/dev/null if="$mount_dir/rand100M" bs=1M count=100
+
+ # add more data
+ cp pattern "$mount_dir/pattern3"
+ dd if=/dev/urandom of="$mount_dir/rand8M" bs=1M count=8 conv=fdatasync
+
+ # restart the LV
+ umount "$mount_dir"
+ lvchange -an $vg/$lv1
+ lvchange -ay $vg/$lv1
+ mount "$DM_DEV_DIR/$vg/$lv1" "$mount_dir"
+
+ # verify all data
+ diff pattern "$mount_dir/pattern1"
+ diff pattern "$mount_dir/pattern2"
+ diff pattern "$mount_dir/pattern3"
+ dd of=/dev/null if="$mount_dir/rand100M" bs=1M count=100
+ dd of=/dev/null if="$mount_dir/rand8M" bs=1M count=8
+
+ # extend again while inactive
+ umount "$mount_dir"
+ lvchange -an $vg/$lv1
+ lvextend -L+64M $vg/$lv1 "$dev5"
+ lvs -a $vg -o+devices
+ lvchange -ay $vg/$lv1
+ mount "$DM_DEV_DIR/$vg/$lv1" "$mount_dir"
+
+ # verify all data
+ diff pattern "$mount_dir/pattern1"
+ diff pattern "$mount_dir/pattern2"
+ diff pattern "$mount_dir/pattern3"
+ dd of=/dev/null if="$mount_dir/rand100M" bs=1M count=100
+ dd of=/dev/null if="$mount_dir/rand8M" bs=1M count=8
+
+ # add more data
+ cp pattern "$mount_dir/pattern4"
+
+ # remove the cache
+ lvconvert --splitcache $vg/$lv1
+
+ # verify all data
+ diff pattern "$mount_dir/pattern1"
+ diff pattern "$mount_dir/pattern2"
+ diff pattern "$mount_dir/pattern3"
+ diff pattern "$mount_dir/pattern4"
+ dd of=/dev/null if="$mount_dir/rand100M" bs=1M count=100
+ dd of=/dev/null if="$mount_dir/rand8M" bs=1M count=8
+
+ umount "$mount_dir"
+ lvchange -an $vg/$lv1
+ lvchange -ay $vg/$lv1
+ mount "$DM_DEV_DIR/$vg/$lv1" "$mount_dir"
+
+ # verify all data
+ diff pattern "$mount_dir/pattern1"
+ diff pattern "$mount_dir/pattern2"
+ diff pattern "$mount_dir/pattern3"
+ diff pattern "$mount_dir/pattern4"
+ dd of=/dev/null if="$mount_dir/rand100M" bs=1M count=100
+ dd of=/dev/null if="$mount_dir/rand8M" bs=1M count=8
+
+ umount "$mount_dir"
+ lvchange -an $vg/$lv1
+ lvremove $vg/$lv1
+ lvremove -y $vg
+}
+
+
+aux have_cache 1 10 0 || skip
+aux have_writecache 1 0 0 || skip
+which mkfs.xfs || skip
+
+mount_dir="mnt"
+mkdir -p "$mount_dir"
+
+aux prepare_devs 6 200 # want 200M of usable space from each dev
+
+# generate random data
+dd if=/dev/urandom of=pattern bs=512K count=1
+
+vgcreate $SHARED $vg "$dev1" "$dev2" "$dev3" "$dev4" "$dev5" "$dev6"
+
+# test type cache|writecache
+# cache with cachepool|cachevol
+# cache with writeback|writethrough
+
+# lv1 is main LV: 300M
+# lv2 is fast LV: 64M
+
+lvcreate -n $lv1 -L300M -an $vg "$dev1" "$dev2"
+lvcreate -n $lv2 -L64M -an $vg "$dev3"
+lvconvert -y --type writecache --cachevol $lv2 $vg/$lv1
+lvs -a $vg -o+devices
+do_test
+
+lvcreate -n $lv1 -L300M -an $vg "$dev1" "$dev2"
+lvcreate -n $lv2 -L64M -an $vg "$dev3"
+lvconvert -y --type cache --cachevol $lv2 --cachemode writeback $vg/$lv1
+lvs -a $vg -o+devices
+do_test
+
+lvcreate -n $lv1 -L300M -an $vg "$dev1" "$dev2"
+lvcreate -n $lv2 -L64M -an $vg "$dev3"
+lvconvert -y --type cache --cachevol $lv2 --cachemode writethrough $vg/$lv1
+lvs -a $vg -o+devices
+do_test
+
+lvcreate -n $lv1 -L300M -an $vg "$dev1" "$dev2"
+lvcreate -y --type cache-pool -n $lv2 -L64M --poolmetadataspare n $vg "$dev3" "$dev6"
+lvconvert -y --type cache --cachepool $lv2 --poolmetadataspare n $vg/$lv1
+lvs -a $vg -o+devices
+do_test
+
+vgremove -f $vg
+
diff --git a/test/shell/lvextend-percent-extents.sh b/test/shell/lvextend-percent-extents.sh
index 1d59082..5d4946d 100644
--- a/test/shell/lvextend-percent-extents.sh
+++ b/test/shell/lvextend-percent-extents.sh
@@ -1,4 +1,5 @@
-#!/bin/sh
+#!/usr/bin/env bash
+
# Copyright (C) 2008-2011 Red Hat, Inc. All rights reserved.
#
# This copyrighted material is made available to anyone wishing to use,
@@ -7,15 +8,21 @@
#
# 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
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
# 'Check extents percentage arguments'
-. lib/test
-aux prepare_vg 2 128
+SKIP_WITH_LVMPOLLD=1
-lvcreate -L 64m -n $lv $vg
+. lib/inittest
+
+aux prepare_pvs 2 128
+get_devs
+
+aux vgcreate $SHARED "$vg" "${DEVICES[@]}"
+
+lvcreate -L64 -n $lv $vg
# 'lvextend rejects both size and extents without PVs'
not lvextend -l 10 -L 64m $vg/$lv 2>err
@@ -26,8 +33,8 @@ 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
+lvextend $vg/$lv "$dev1" | tee out
+grep "Logical volume $vg/$lv successfully resized" out
check pv_field "$dev1" pv_free "0"
lvremove -f $vg/$lv
@@ -35,7 +42,7 @@ 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
+lvreduce -f -l $(( vgsize / 2 )) $vg/$lv
lvextend -l $vgsize $vg/$lv
# 'Reset LV to original size'
@@ -43,8 +50,8 @@ 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
+lvextend -l +100%PVS $vg/$lv "$dev1" "$dev2" | tee out
+grep "Logical volume $vg/$lv successfully resized" out
check pv_field "$dev1" pv_free "0"
check pv_field "$dev2" pv_free "0"
@@ -69,15 +76,15 @@ check pv_field "$dev2" pv_free "0"
# 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)
+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
+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 | tee out
+grep "Logical volume $vg/$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
@@ -86,17 +93,17 @@ check lv_field $vg/$lv lv_size "72.00m"
# 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 ))
+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
+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
+lvextend -l +$(( pe_count * 1 )) $vg/$lv
check lv_field $vg/$lv seg_count "2"
-lvreduce -f -l -$(( $pe_count * 1 )) $vg/$lv
+lvreduce -f -l -$(( pe_count * 1 )) $vg/$lv
check lv_field $vg/$lv seg_count "1"
# do not reduce to 0 extents
@@ -104,3 +111,5 @@ 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"
+
+vgremove -ff $vg
diff --git a/test/shell/lvextend-raid.sh b/test/shell/lvextend-raid.sh
new file mode 100644
index 0000000..04ba554
--- /dev/null
+++ b/test/shell/lvextend-raid.sh
@@ -0,0 +1,89 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2019 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+aux have_raid 1 3 0 || skip
+PROGRESS=0
+aux have_raid 1 15 0 && PROGRESS=1
+
+# Use smallest regionsize to save VG space
+regionsize=$(getconf PAGESIZE) # in bytes
+pageregions=$(( regionsize * 8 )) # number of regions per MD bitmap page
+
+# in KiB
+regionsize=$(( regionsize / 1024 ))
+
+# in MiB
+lvsz=$(( pageregions * regionsize / 1024 ))
+lvext=$(( lvsz / 8 ))
+
+aux prepare_pvs 2 $(( lvsz + 3 * lvext ))
+get_devs
+vgcreate -s 4k $vg ${DEVICES[@]}
+
+# Keep $dev1 & $dev2 always open via small active LVs.
+# This trick avoids race on system with scanning udev service
+# when device is 'in-use' and we cleared _rimage & _rmeta.
+lvcreate -l1 $vg "$dev1"
+lvcreate -l1 $vg "$dev2"
+
+sector=$(( $(get first_extent_sector "$dev2") + 2048 ))
+aux zero_dev "$dev1" "${sector}:"
+aux delayzero_dev "$dev2" 0 10 "${sector}:"
+
+# Create raid1 LV consuming 1 MD bitmap page
+lvcreate --yes --type raid1 --regionsize ${regionsize}K -L$(( lvsz - lvext ))M -n $lv1 $vg
+
+lvs -a $vg
+
+not check lv_field $vg/$lv1 sync_percent "100.00"
+check lv_field $vg/$lv1 size "$(( lvsz - lvext )).00m" $vg/$lv1
+aux wait_for_sync $vg $lv1
+check lv_field $vg/$lv1 sync_percent "100.00"
+check lv_field $vg/$lv1 region_size "4.00k"
+
+# to slow down extension - slowdown readings
+aux delayzero_dev "$dev1" 50 0 "${sector}:"
+aux delayzero_dev "$dev2" 0 50 "${sector}:"
+
+# Extend so that full MD bitmap page is consumed
+lvextend -y -L+${lvext}M $vg/$lv1
+if [ $PROGRESS -eq 1 ]
+then
+# Even with delayed devices wre are catching races here.
+should not check lv_field $vg/$lv1 sync_percent "100.00"
+check lv_field $vg/$lv1 size "$lvsz.00m" $vg/$lv1
+fi
+aux wait_for_sync $vg $lv1
+check lv_field $vg/$lv1 sync_percent "100.00"
+
+# Extend so that another MD bitmap page is allocated
+lvextend -y -L+${lvext}M $vg/$lv1
+if [ $PROGRESS -eq 1 ]
+then
+ # Even with delayed devices wre are catching races here.
+ should not check lv_field $vg/$lv1 sync_percent "100.00"
+else
+ check lv_field $vg/$lv1 sync_percent "100.00"
+fi
+
+aux enable_dev "$dev1" "$dev2"
+
+aux wait_for_sync $vg $lv1
+check lv_field $vg/$lv1 sync_percent "100.00"
+check lv_field $vg/$lv1 size "$(( lvsz + lvext )).00m" $vg/$lv1
+
+vgremove -ff $vg
diff --git a/test/shell/lvextend-snapshot-dmeventd.sh b/test/shell/lvextend-snapshot-dmeventd.sh
index 98bec19..e7040d3 100644
--- a/test/shell/lvextend-snapshot-dmeventd.sh
+++ b/test/shell/lvextend-snapshot-dmeventd.sh
@@ -1,4 +1,5 @@
-#!/bin/sh
+#!/usr/bin/env bash
+
# Copyright (C) 2010-2012 Red Hat, Inc. All rights reserved.
#
# This copyrighted material is made available to anyone wishing to use,
@@ -7,16 +8,18 @@
#
# 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
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+SKIP_WITH_LVMPOLLD=1
-. lib/test
+. lib/inittest
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
+ dd if=/dev/zero of="$DM_DEV_DIR/$vg/snap" bs=1k count=$2 seek=$1 conv=fdatasync
}
percent_() {
@@ -25,7 +28,7 @@ percent_() {
wait_for_change_() {
# dmeventd only checks every 10 seconds :(
- for i in $(seq 1 15) ; do
+ for i in $(seq 1 25) ; do
test "$(percent_)" != "$1" && return
sleep 1
done
@@ -36,18 +39,22 @@ wait_for_change_() {
aux prepare_dmeventd
aux prepare_vg 2
-lvcreate -L16M -n base $vg
+lvcreate -aey -L16M -n base $vg
lvcreate -s -L4M -n snap $vg/base
write_ 0 1000
-test 24 -eq $(percent_)
+test 24 -eq "$(percent_)"
lvchange --monitor y $vg/snap
write_ 1000 1700
pre=$(percent_)
+# Normally the usage should be ~66% here, however on slower systems
+# dmeventd could be actually 'fast' enough to have COW already resized now
+# so mark test skipped if we are below 50% by now
+test "$pre" -gt 50 || skip
wait_for_change_ $pre
-test $pre -gt $(percent_)
+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
@@ -55,7 +62,9 @@ test $pre -gt $(percent_)
write_ 2700 2000
pre=$(percent_)
+# Mark test as skipped if already resized...
+test "$pre" -gt 70 || skip
wait_for_change_ $pre
-test $pre -gt $(percent_)
+test "$pre" -gt "$(percent_)"
vgremove -f $vg
diff --git a/test/shell/lvextend-snapshot-policy.sh b/test/shell/lvextend-snapshot-policy.sh
index 2f5d84b..c49cbb3 100644
--- a/test/shell/lvextend-snapshot-policy.sh
+++ b/test/shell/lvextend-snapshot-policy.sh
@@ -1,4 +1,5 @@
-#!/bin/sh
+#!/usr/bin/env bash
+
# Copyright (C) 2010 Red Hat, Inc. All rights reserved.
#
# This copyrighted material is made available to anyone wishing to use,
@@ -7,9 +8,12 @@
#
# 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
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+
+SKIP_WITH_LVMPOLLD=1
-. lib/test
+. lib/inittest
which mkfs.ext2 || skip
@@ -27,23 +31,23 @@ percent() {
get lv_field $vg/snap snap_percent | cut -d. -f1
}
-aux prepare_dmeventd
+# no dmeventd running in this test, testing --use-policies
aux prepare_vg 2
-lvcreate -l 8 -n base $vg
+lvcreate -aey -L24 -n base $vg
mkfs.ext2 "$DM_DEV_DIR/$vg/base"
-lvcreate -s -l 4 -n snap $vg/base
+lvcreate -s -L16 -n snap $vg/base
mkdir mnt
write 1 4096
pre=$(percent)
extend 50
-test $pre -eq $(percent)
+test "$pre" -eq "$(percent)"
write 2 4096
pre=$(percent)
extend 50
-test $pre -gt $(percent)
+test "$pre" -gt "$(percent)"
vgremove -f $vg
diff --git a/test/shell/lvextend-thin-adddel.sh b/test/shell/lvextend-thin-adddel.sh
new file mode 100644
index 0000000..59b1bfa
--- /dev/null
+++ b/test/shell/lvextend-thin-adddel.sh
@@ -0,0 +1,78 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2022 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+#
+# Play with thin-pool and thin removal and creation in corner cases
+#
+
+SKIP_WITH_LVMLOCKD=1
+SKIP_WITH_LVMPOLLD=1
+
+export LVM_TEST_THIN_REPAIR_CMD=${LVM_TEST_THIN_REPAIR_CMD-/bin/false}
+
+. lib/inittest
+
+aux have_thin 1 0 0 || skip
+
+test -n "$LVM_TEST_THIN_RESTORE_CMD" || LVM_TEST_THIN_RESTORE_CMD=$(which thin_restore) || skip
+"$LVM_TEST_THIN_RESTORE_CMD" -V || skip
+
+aux have_thin 1 10 0 || skip
+
+aux prepare_vg 2
+
+lvcreate -V10 -n $lv1 -L10 -T $vg/pool
+lvcreate -V10 -n $lv2 $vg/pool
+
+# Forcibly 'error' _tmeta thin-pool metadata device
+not dmsetup remove -f $vg-pool_tmeta
+
+# Now try to schedule removal of thin volume id 1
+# that will fail with errored meta device
+not lvremove -y $vg/$lv1
+
+# Check we have queued 'message'
+vgcfgbackup -f out0 $vg
+grep "message1" out0
+
+vgchange -an $vg || true
+
+not dmsetup table ${vg}-pool-tpool
+
+# Reactivate thin-pool
+vgchange -ay $vg
+
+# Check message is still queued there
+vgcfgbackup -f out1 $vg
+grep "message1" out1
+
+lvchange -an $vg
+
+lvextend -L+10 $vg/pool
+
+# Messages should be now processed and gone
+vgcfgbackup -f out2 $vg
+not grep "message1" out2
+
+lvchange -an $vg
+
+lvchange -y -ay $vg/pool_tmeta
+
+# Kernel metadata must not see dev_id 1 either
+thin_dump $DM_DEV_DIR/$vg/pool_tmeta | tee meta
+not grep 'dev_id="1"' meta
+
+lvremove -ff $vg
+
+lvs -a $vg
+
+vgremove -ff $vg
diff --git a/test/shell/lvextend-thin-cache.sh b/test/shell/lvextend-thin-cache.sh
new file mode 100644
index 0000000..40c213b
--- /dev/null
+++ b/test/shell/lvextend-thin-cache.sh
@@ -0,0 +1,43 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2017-2020 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+# Exercise resize of cached thin pool data volumes
+
+
+SKIP_WITH_LVMPOLLD=1
+
+export LVM_TEST_THIN_REPAIR_CMD=${LVM_TEST_THIN_REPAIR_CMD-/bin/false}
+
+. lib/inittest
+
+aux have_thin 1 0 0 || skip
+aux have_cache 1 3 0 || skip
+
+aux prepare_vg 2 20000
+
+lvcreate -l1 -T $vg/pool
+# Caching of thin-pool's dataLV
+lvcreate -H -L10 $vg/pool
+
+lvextend -l+2 $vg/pool
+
+check lv_first_seg_field $vg/pool seg_size_pe "3"
+
+lvextend -L10G $vg/pool
+
+# Check data are resized and its metadata are matching data size
+check lv_field $vg/pool size "10.00g"
+check lv_field $vg/pool_tdata size "10.00g"
+check lv_field $vg/pool_tdata_corig size "10.00g"
+check lv_field $vg/pool_tmeta size "10.00m"
+
+vgremove -ff $vg
diff --git a/test/shell/lvextend-thin-data-dmeventd.sh b/test/shell/lvextend-thin-data-dmeventd.sh
new file mode 100644
index 0000000..7d37f16
--- /dev/null
+++ b/test/shell/lvextend-thin-data-dmeventd.sh
@@ -0,0 +1,68 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2016 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+# Test autoextension of thin data volume
+
+
+SKIP_WITH_LVMPOLLD=1
+
+export LVM_TEST_THIN_REPAIR_CMD=${LVM_TEST_THIN_REPAIR_CMD-/bin/false}
+
+. lib/inittest
+
+# As we check for 'instant' reaction
+# retry only few times
+test_equal_() {
+ for i in $(seq 1 4) ; do
+ test "$(get lv_field $vg/pool data_percent)" = "$1" || return
+ sleep 1
+ done
+}
+
+aux have_thin 1 10 0 || skip
+
+# set reserved stack size above dmeventd 300KiB stack
+# ATM such value should be simply ignored
+aux lvmconf "activation/thin_pool_autoextend_percent = 10" \
+ "activation/thin_pool_autoextend_threshold = 75" \
+ "activation/reserved_stack = 512"
+
+aux prepare_dmeventd
+
+aux prepare_pvs 3 256
+get_devs
+
+vgcreate $SHARED -s 256K "$vg" "${DEVICES[@]}"
+
+lvcreate -L1M -c 64k -T $vg/pool
+lvcreate -V1M $vg/pool -n $lv1
+
+# Fill exactly 75%
+dd if=/dev/zero of="$DM_DEV_DIR/mapper/$vg-$lv1" bs=786432c count=1 conv=fdatasync
+
+# when everything calcs correctly thin-pool should be exactly 75% full now
+# and the size should not have changed
+pre="75.00"
+test_equal_ $pre || die "Data percentage has changed!"
+
+
+# Now triger allocation of 1 extra pool chunk
+dd if=/dev/zero of="$DM_DEV_DIR/mapper/$vg-$lv1" bs=1c count=1 seek=786433 conv=fdatasync
+
+lvs -a -o+chunksize $vg
+dmsetup table
+dmsetup status
+
+# If the watermark works well - dmeventd should have already resized data LV
+test_equal_ $pre && die "Data percentage has NOT changed!"
+
+vgremove -f $vg
diff --git a/test/shell/lvextend-thin-full.sh b/test/shell/lvextend-thin-full.sh
new file mode 100644
index 0000000..d67591d
--- /dev/null
+++ b/test/shell/lvextend-thin-full.sh
@@ -0,0 +1,68 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2015 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+#
+# play with thin-pool resize in corner cases
+#
+
+SKIP_WITH_LVMPOLLD=1
+
+export LVM_TEST_THIN_REPAIR_CMD=${LVM_TEST_THIN_REPAIR_CMD-/bin/false}
+
+. lib/inittest
+
+aux have_thin 1 0 0 || skip
+
+test -n "$LVM_TEST_THIN_RESTORE_CMD" || LVM_TEST_THIN_RESTORE_CMD=$(which thin_restore) || skip
+"$LVM_TEST_THIN_RESTORE_CMD" -V || skip
+
+aux have_thin 1 10 0 || skip
+
+aux prepare_vg 3 4096
+
+aux lvmconf 'activation/thin_pool_autoextend_percent = 30' \
+ 'activation/thin_pool_autoextend_threshold = 70'
+
+aux prepare_thin_metadata 400 0 | tee data
+lvcreate -L200 -V10 -n $lv2 -T $vg/pool
+lvchange -an $vg
+
+# Prepare full metadata volume
+lvcreate -L2M -n $lv1 $vg
+"$LVM_TEST_THIN_RESTORE_CMD" -i data -o "$DM_DEV_DIR/mapper/$vg-$lv1"
+lvconvert -y --thinpool $vg/pool --poolmetadata $vg/$lv1
+
+# active thin pool is needed to use policy
+not lvextend --use-policies $vg/pool 2>&1 | tee err
+
+lvchange -ay $vg/$lv2
+
+# Cannot resize if set to 0%
+not lvextend --use-policies --config 'activation{thin_pool_autoextend_percent = 0}' $vg/pool 2>&1 | tee err
+grep "0%" err
+
+# Creation of new LV is not allowed when thinpool is over threshold
+not lvcreate -V10 $vg/pool
+
+
+lvextend --use-policies $vg/pool "$dev2" "$dev3"
+#should lvextend -l+100%FREE $vg/pool2
+
+check lv_field $vg/pool_tmeta size "3.00m"
+
+lvextend -L+3G $vg/pool
+
+check lv_field $vg/pool_tmeta size "3.50m"
+
+lvs -a $vg
+
+vgremove -ff $vg
diff --git a/test/shell/lvextend-thin-metadata-dmeventd.sh b/test/shell/lvextend-thin-metadata-dmeventd.sh
new file mode 100644
index 0000000..732f670
--- /dev/null
+++ b/test/shell/lvextend-thin-metadata-dmeventd.sh
@@ -0,0 +1,207 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2014-2020 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+# Test autoextension of thin metadata volume
+
+SKIP_WITH_LVMLOCKD=1
+SKIP_WITH_LVMPOLLD=1
+
+export LVM_TEST_THIN_REPAIR_CMD=${LVM_TEST_THIN_REPAIR_CMD-/bin/false}
+
+. lib/inittest
+
+
+meta_percent_() {
+ get lv_field $vg/pool metadata_percent | cut -d. -f1
+}
+
+wait_for_change_() {
+ # dmeventd only checks every 10 seconds :(
+ for i in $(seq 1 12) ; do
+ test "$(meta_percent_)" -lt "$1" && return
+ sleep 1
+ done
+
+ return 1 # timeout
+}
+
+#
+# Temporary solution to create some occupied thin metadata
+# This heavily depends on thin metadata output format to stay as is.
+# Currently it expects 2MB thin metadata and 200MB data volume size
+# Argument specifies how many devices should be created.
+fake_metadata_() {
+ echo '<superblock uuid="" time="0" transaction="'$2'" data_block_size="128" nr_data_blocks="3200">'
+ echo ' <device dev_id="1" mapped_blocks="0" transaction="0" creation_time="0" snap_time="0">'
+ echo ' </device>'
+ echo ' <device dev_id="2" mapped_blocks="0" transaction="0" creation_time="0" snap_time="0">'
+ echo ' </device>'
+ for i in $(seq 10 $1)
+ do
+ echo ' <device dev_id="'$i'" mapped_blocks="30" transaction="0" creation_time="0" snap_time="0">'
+ echo ' <range_mapping origin_begin="0" data_begin="0" length="30" time="0"/>'
+ echo ' </device>'
+ set +x
+ done
+ echo "</superblock>"
+ set -x
+}
+
+test -n "$LVM_TEST_THIN_RESTORE_CMD" || LVM_TEST_THIN_RESTORE_CMD=$(which thin_restore) || skip
+"$LVM_TEST_THIN_RESTORE_CMD" -V || skip
+aux have_thin 1 10 0 || skip
+
+BIG_DATA=""
+aux thin_restore_needs_more_volumes && BIG_DATA="generate_more_metadata"
+
+aux prepare_dmeventd
+
+aux prepare_pvs 3 256
+get_devs
+
+vgcreate -s 1M "$vg" "${DEVICES[@]}"
+
+# Testing dmeventd does NOT autoresize when default threshold 100% is left
+lvcreate -L200M -V50M -n thin -T $vg/pool
+lvcreate -V2M -n thin2 $vg/pool
+lvcreate -L2M -n $lv1 $vg
+lvcreate -L32M -n $lv2 $vg
+lvcreate -L32M -n $lv3 $vg
+lvchange -an $vg/thin $vg/thin2 $vg/pool
+
+# Filling 2M metadata volume
+# (Test for less than 25% free space in metadata)
+fake_metadata_ 400 2 >data
+"$LVM_TEST_THIN_RESTORE_CMD" -i data -o "$DM_DEV_DIR/mapper/$vg-$lv1"
+
+# Swap volume with restored fake metadata
+lvconvert -y --chunksize 64k --thinpool $vg/pool --poolmetadata $vg/$lv1
+
+# Not alllowed when thin-pool metadata free space is <75% for 2M meta
+fail lvcreate -V20 $vg/pool
+
+
+lvchange -an $vg/pool
+
+# Consume more then (100% - 4MiB) out of 32MiB metadata volume (>87.5%)
+# (Test for less than 4MiB free space in metadata, which is less than 25%)
+DATA=7200 # Newer version of thin-pool have hidden reserve, so use lower value
+test -z "$BIG_DATA" || DATA=7400
+fake_metadata_ "$DATA" 2 >data
+"$LVM_TEST_THIN_RESTORE_CMD" -i data -o "$DM_DEV_DIR/mapper/$vg-$lv2"
+
+# Check tha restored metadata are OK for thin_check
+"$LVM_TEST_THIN_CHECK_CMD" "$DM_DEV_DIR/mapper/$vg-$lv2"
+
+# Swap volume with restored fake metadata
+lvconvert -y --chunksize 64k --thinpool $vg/pool --poolmetadata $vg/$lv2
+lvchange -ay $vg/pool
+# Check generated metadata consume more then 88%
+test "$(meta_percent_)" -gt "88"
+lvchange -an $vg/pool
+
+# Creation of thin LV is prohibited when metadata are above this value
+fail lvcreate -V20 $vg/pool 2>&1 | tee out
+grep "free space" out
+lvs -a $vg
+
+
+# Check that even with 99% threshold policy - metadata will go below 88%
+lvextend --use-policies --config "\
+activation/thin_pool_autoextend_percent=1 \
+activation/thin_pool_autoextend_threshold=99" $vg/pool
+# Originaly wanted to test <88% -
+# however some older kernels consume a bit more space, so be happy
+# when it's <90%
+test "$(meta_percent_)" -lt "90"
+
+# After such operatoin creation of thin LV has to pass
+lvcreate -V20 $vg/pool
+
+# Let's revalidate pool metadata (thin_check upon deactivation/activation)
+lvchange -an $vg
+lvchange -ay $vg/pool
+
+lvremove -f $vg
+
+
+
+#########################################################
+# Test automatic resize with help of dmeventd DOES work #
+#########################################################
+
+aux lvmconf "activation/thin_pool_autoextend_percent = 10" \
+ "activation/thin_pool_autoextend_threshold = 70"
+
+# Testing dmeventd autoresize
+lvcreate -L200M -V500M -n thin -T $vg/pool 2>&1 | tee out
+not grep "WARNING: Sum" out
+lvcreate -V2M -n thin2 $vg/pool
+lvcreate -L2M -n $lv1 $vg
+lvchange -an $vg/thin $vg/thin2 $vg/pool
+
+# Prepare some fake metadata with unmatching id
+# Transaction_id is lower by 1 and there are no messages -> ERROR
+fake_metadata_ 10 0 >data
+"$LVM_TEST_THIN_RESTORE_CMD" -i data -o "$DM_DEV_DIR/mapper/$vg-$lv1"
+lvconvert -y --thinpool $vg/pool --poolmetadata $vg/$lv1
+not vgchange -ay $vg 2>&1 | tee out
+grep expected out
+
+check inactive $vg pool_tmeta
+
+# Transaction_id is higher by 1
+fake_metadata_ 10 3 >data
+"$LVM_TEST_THIN_RESTORE_CMD" -i data -o "$DM_DEV_DIR/mapper/$vg-$lv1"
+lvconvert -y --thinpool $vg/pool --poolmetadata $vg/$lv1
+not vgchange -ay $vg 2>&1 | tee out
+grep expected out
+
+check inactive $vg pool_tmeta
+
+# Prepare some fake metadata prefilled to ~81% (>70%)
+fake_metadata_ 400 2 >data
+"$LVM_TEST_THIN_RESTORE_CMD" -i data -o "$DM_DEV_DIR/mapper/$vg-$lv1"
+
+# Swap volume with restored fake metadata
+lvconvert -y --chunksize 64k --thinpool $vg/pool --poolmetadata $vg/$lv1
+
+vgchange -ay $vg
+
+# Check dmeventd resizes metadata via timeout (nothing is written to pool)
+pre=$(meta_percent_)
+wait_for_change_ $pre
+
+lvchange -an $vg
+
+#
+DATA=300 # Newer version of thin-pool have hidden reserve, so use lower value
+test -z "$BIG_DATA" || DATA=350
+fake_metadata_ $DATA 2 >data
+lvchange -ay $vg/$lv1
+"$LVM_TEST_THIN_RESTORE_CMD" -i data -o "$DM_DEV_DIR/mapper/$vg-$lv1"
+
+lvconvert -y --chunksize 64k --thinpool $vg/pool --poolmetadata $vg/$lv1
+lvchange -ay $vg/pool $vg/$lv1
+lvs -a $vg
+
+lvcreate -s -Ky -n $lv2 $vg/thin
+pre=$(meta_percent_)
+
+# go over thin metadata threshold
+echo 2 >"$DM_DEV_DIR/mapper/$vg-$lv2"
+
+wait_for_change_ $pre
+
+lvs -a $vg
+
+vgremove -f $vg
diff --git a/test/shell/lvextend-thin-raid.sh b/test/shell/lvextend-thin-raid.sh
new file mode 100644
index 0000000..a706887
--- /dev/null
+++ b/test/shell/lvextend-thin-raid.sh
@@ -0,0 +1,63 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2016 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+
+SKIP_WITH_LVMPOLLD=1
+
+export LVM_TEST_THIN_REPAIR_CMD=${LVM_TEST_THIN_REPAIR_CMD-/bin/false}
+
+. lib/inittest
+
+aux have_thin 1 0 0 || skip
+aux have_raid 1 3 0 || skip
+
+aux prepare_vg 6 600
+
+lvcreate --type raid1 -l2 --nosync -n pool $vg
+lvconvert --yes --thinpool $vg/pool "$dev3"
+
+check lv_field $vg/pool seg_size_pe "2"
+check lv_field $vg/pool_tdata seg_size_pe "2" -a
+
+lvextend -l+3 $vg/pool
+
+check lv_field $vg/pool seg_size_pe "5"
+check lv_field $vg/pool_tdata seg_size_pe "5" -a
+
+lvremove -f $vg
+
+# check 'raid10' resize works for pool metadata resize
+# https://bugzilla.redhat.com/1075644
+lvcreate --type raid10 -m1 -L5 -i3 --nosync -n pool $vg
+lvcreate --type raid10 -m1 -L3 -i3 --nosync -n meta $vg
+lvconvert --yes --thinpool $vg/pool --poolmetadata $vg/meta
+
+check lv_field $vg/pool_tdata lv_size "6.00m" -a
+check lv_field $vg/pool_tmeta lv_size "3.00m" -a
+
+lvextend --poolmetadatasize +1 --size +1 $vg/pool
+
+check lv_field $vg/pool_tdata lv_size "7.50m" -a
+check lv_field $vg/pool_tmeta lv_size "4.50m" -a
+
+lvremove -f $vg
+
+# check resize of pool and metadata being a different segtype
+# https://bugzilla.redhat.com/1722666
+lvcreate -L4 -n pool $vg
+lvcreate --type raid1 -m1 -L2 --nosync -n meta $vg
+lvconvert --yes --thinpool $vg/pool --poolmetadata $vg/meta
+# using big enough pool so resize of pool metadata is enforced
+# (and it's using a differnt segtype)
+lvextend -L3G $vg/pool
+
+vgremove -ff $vg
diff --git a/test/shell/lvextend-thin.sh b/test/shell/lvextend-thin.sh
new file mode 100644
index 0000000..d1efd47
--- /dev/null
+++ b/test/shell/lvextend-thin.sh
@@ -0,0 +1,43 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2014 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+
+SKIP_WITH_LVMPOLLD=1
+
+export LVM_TEST_THIN_REPAIR_CMD=${LVM_TEST_THIN_REPAIR_CMD-/bin/false}
+
+. lib/inittest
+
+aux have_thin 1 0 0 || skip
+
+aux prepare_vg 3
+lvcreate -i2 -l2 -T $vg/pool2
+lvextend -l+2 $vg/pool2 "$dev2" "$dev3"
+lvextend -l+100%FREE $vg/pool2
+
+lvremove -f $vg
+
+lvcreate -L1 -n pool $vg
+# Does work only with thin-pools
+not lvextend --poolmetadatasize +1 $vg/pool
+lvconvert -y --thinpool $vg/pool --poolmetadatasize 2
+
+# _tdata cannot be used with --poolmetadata
+not lvextend --poolmetadatasize +1 $vg/pool_tdata
+lvextend --poolmetadatasize +1 $vg/pool_tmeta
+lvextend --poolmetadatasize +1 --size +1 $vg/pool
+check lv_field $vg/pool_tmeta size "4.00m"
+check lv_field $vg/lvol0_pmspare size "4.00m"
+
+not lvresize --poolmetadatasize -1 $vg/pool
+
+vgremove -ff $vg
diff --git a/test/shell/lvextend-vdo-dmeventd.sh b/test/shell/lvextend-vdo-dmeventd.sh
new file mode 100644
index 0000000..6dbe4c4
--- /dev/null
+++ b/test/shell/lvextend-vdo-dmeventd.sh
@@ -0,0 +1,68 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2019 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+# Test autoextension of VDO pool volume
+
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+percent_() {
+ get lv_field $vg/vpool data_percent | cut -d. -f1
+}
+
+wait_for_change_() {
+ # dmeventd only checks every 10 seconds :(
+ for i in $(seq 1 25) ; do
+ test "$(percent_)" != "$1" && return
+ sleep 1
+ done
+
+ return 1 # timeout
+}
+
+aux have_vdo 6 2 0 || skip
+
+aux prepare_dmeventd
+
+aux lvmconf "activation/vdo_pool_autoextend_percent = 20" \
+ "activation/vdo_pool_autoextend_threshold = 70" \
+ "allocation/vdo_slab_size_mb = 128"
+
+aux prepare_vg 1 9000
+lvcreate --vdo -V2G -L4G -n $lv1 $vg/vpool
+
+pre=$(percent_)
+# Check out VDO pool is bellow 70%
+test "$pre" -lt 70
+
+# Fill space to be over 70%
+dd if=/dev/urandom of="$DM_DEV_DIR/mapper/$vg-$lv1" bs=1M count=80 conv=fdatasync
+
+# Should be now over 70%
+pre=$(percent_)
+test "$pre" -ge 70
+
+wait_for_change_ $pre
+
+pre=$(percent_)
+# Check out VDO pool gets again bellow 70%
+test "$pre" -lt 70 || die "Data percentage has not changed bellow 70%!"
+
+# 4G * 1.2 (20%) -> 4.8G
+check lv_field $vg/vpool size "4.80g"
+check lv_field $vg/$lv1 size "2.00g"
+
+lvs -a $vg
+
+vgremove -f $vg
diff --git a/test/shell/lvextend-vdo.sh b/test/shell/lvextend-vdo.sh
new file mode 100644
index 0000000..2e9cee4
--- /dev/null
+++ b/test/shell/lvextend-vdo.sh
@@ -0,0 +1,54 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2019 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+aux have_vdo 6 2 0 || skip
+
+aux lvmconf "activation/vdo_pool_autoextend_percent = 1" \
+ "activation/vdo_pool_autoextend_threshold = 70" \
+ "allocation/vdo_slab_size_mb = 128"
+
+aux prepare_vg 1 7000
+lvcreate --vdo -V3G -L4G -n $lv1 $vg/$lv2
+
+# Resize data volume
+lvextend -L+1G $vg/$lv2
+check lv_field $vg/$lv2 size "5.00g"
+check lv_field $vg/${lv2}_vdata size "5.00g"
+
+# Resize virtual volume on top of VDO
+lvextend -L+1G $vg/$lv1
+check lv_field $vg/$lv1 size "4.00g"
+
+lvremove -f $vg
+
+
+# Resize by policy
+lvcreate --vdo -V3G -L4G -n $lv1 $vg/$lv2
+
+# Fill VDO LV to match configured threshold >= 70%
+dd if=/dev/urandom of="$DM_DEV_DIR/$vg/$lv1" bs=1M count=60 oflag=direct
+PERCENT=$(get lv_field $vg/$lv2 data_percent | cut -d. -f1)
+test "$PERCENT" -ge "70"
+
+lvextend --use-policies "$vg/$lv2"
+
+# although autoextend is only 1%, it needs to extend at least by slab_size
+# this is corner case where min growth requires 128M + 128k
+check lv_field $vg/$lv2 size "<4.13g"
+
+
+vgremove -ff $vg
diff --git a/test/shell/lvm-conf-error.sh b/test/shell/lvm-conf-error.sh
new file mode 100644
index 0000000..590834b
--- /dev/null
+++ b/test/shell/lvm-conf-error.sh
@@ -0,0 +1,62 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2020 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+# Check what happens when reading of lvm.conf fails
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+MKFS=mkfs.ext3
+which $MKFS || skip
+which filefrag || skip
+
+aux prepare_vg 1
+
+mkdir mnt
+
+lvcreate -L5M -n $lv1 $vg
+
+$MKFS "$DM_DEV_DIR/$vg/$lv1"
+mount "$DM_DEV_DIR/$vg/$lv1" mnt
+cp etc/lvm.conf mnt
+
+# Figure where the file is placed in filesystem
+filefrag -e mnt/lvm.conf | tee frags || rm -f frags
+umount mnt
+
+test -s frags || skip
+
+# 1st. sector for filesystem
+first_extent_sector=$(get first_extent_sector "$dev1")
+
+# find 1st. 1k block of file and trim '..' from printed number
+file_block=$(awk '/0:/ { gsub(/\.\.$/, "", $4); print $4}' frags)
+
+# figure sector position on DM device
+file_sector=$(( file_block * 2 + first_extent_sector ))
+
+aux error_dev "$dev1" $file_sector:2
+
+mount "$DM_DEV_DIR/$vg/$lv1" mnt
+
+# force lvm to read lvm.conf from mnt path
+LVM_SYSTEM_DIR=mnt lvs 2>&1 | tee out || true
+
+# shell give nice error message
+grep "Failed to load config file mnt/lvm.conf" out
+
+aux enable_dev "$dev1"
+
+umount mnt
+
+vgremove -ff $vg
diff --git a/test/shell/lvm-init.sh b/test/shell/lvm-init.sh
index 8eb7814..7af3ef9 100644
--- a/test/shell/lvm-init.sh
+++ b/test/shell/lvm-init.sh
@@ -1,4 +1,5 @@
-#!/bin/sh
+#!/usr/bin/env bash
+
# Copyright (C) 2008 Red Hat, Inc. All rights reserved.
#
# This copyrighted material is made available to anyone wishing to use,
@@ -7,13 +8,16 @@
#
# 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
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
#
# tests lvm initialization, and especially negative tests of error paths
#
-. lib/test
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
aux prepare_devs 5
diff --git a/test/shell/lvm-on-md.sh b/test/shell/lvm-on-md.sh
new file mode 100644
index 0000000..6c291b9
--- /dev/null
+++ b/test/shell/lvm-on-md.sh
@@ -0,0 +1,317 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2018-2021 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+SKIP_WITH_LVMPOLLD=1
+SKIP_WITH_LVMLOCKD=1
+
+. lib/inittest
+
+RUNDIR="/run"
+test -d "$RUNDIR" || RUNDIR="/var/run"
+PVS_ONLINE_DIR="$RUNDIR/lvm/pvs_online"
+VGS_ONLINE_DIR="$RUNDIR/lvm/vgs_online"
+HINTS="$RUNDIR/lvm/hints"
+
+DFDIR="$LVM_SYSTEM_DIR/devices"
+DF="$DFDIR/system.devices"
+
+_clear_online_files() {
+ # wait till udev is finished
+ aux udev_wait
+ rm -f "$PVS_ONLINE_DIR"/* "$VGS_ONLINE_DIR"/*
+}
+
+
+# This stops lvm from taking advantage of hints which
+# will have already excluded md components.
+
+# This stops lvm from asking udev if a dev is an md component.
+# LVM will ask udev if a dev is an md component, but we don't
+# want to rely on that ability in this test.
+aux lvmconf "devices/md_component_detection = 1" \
+ "devices/hints = \"none\"" \
+ "devices/obtain_device_list_from_udev = 0" \
+ "devices/search_for_devnames = \"none\""
+
+aux extend_filter_md "a|/dev/md|"
+
+aux prepare_devs 3
+
+for level in 1 0 ; do
+
+# create 2 disk MD raid1 array
+# by default using metadata format 1.0 with data at the end of device
+#
+# When a raid0 md array is stopped, the components will not look like
+# duplicate PVs as they do with raid1.
+# mdadm does not seem to like --chunk=64 with raid1
+case "$level" in
+0) CHUNK="--chunk=64" ;;
+*) CHUNK="" ;;
+esac
+aux mdadm_create --metadata=1.0 --level=$level $CHUNK --raid-devices=2 "$dev1" "$dev2"
+mddev=$(< MD_DEV)
+
+vgcreate $vg "$mddev"
+
+lvmdevices || true
+pvs -o+deviceidtype,deviceid
+
+PVIDMD=$(get pv_field "$mddev" uuid | tr -d - )
+
+lvcreate -n $lv1 -l 2 $vg
+lvcreate -n $lv2 -l 2 -an $vg
+
+lvchange -ay $vg/$lv2
+check lv_field $vg/$lv1 lv_active "active"
+
+# lvm does not show md components as PVs
+pvs "$mddev"
+not pvs "$dev1"
+not pvs "$dev2"
+pvs | tee out
+not grep "$dev1" out
+not grep "$dev2" out
+
+vgchange -an $vg
+
+# When the md device is started, lvm will see that and know to
+# scan for md components, so stop the md device to remove this
+# advantage so we will test the fallback detection.
+mdadm --stop "$mddev"
+aux udev_wait
+
+# The md components should still be detected and excluded.
+not pvs "$dev1"
+not pvs "$dev2"
+pvs | tee out
+not grep "$dev1" out
+not grep "$dev2" out
+
+pvs 2>&1|tee out
+not grep "Not using device" out
+
+# should not activate from the md legs
+not vgchange -ay $vg
+
+# should not show an active lv
+not dmsetup info $vg-$lv1
+
+# should not allow updating vg
+not lvcreate -l1 $vg
+
+# should not activate from the md legs
+_clear_online_files
+pvscan --cache -aay "$dev1"
+pvscan --cache -aay "$dev2"
+
+test ! -f "$RUNDIR/lvm/pvs_online/$PVIDMD"
+test ! -f "$RUNDIR/lvm/vgs_online/$vg"
+
+# should not show an active lv
+not dmsetup info $vg-$lv1
+
+aux mdadm_assemble "$mddev" "$dev1" "$dev2"
+
+not pvs "$dev1"
+not pvs "$dev2"
+pvs | tee out
+not grep "$dev1" out
+not grep "$dev2" out
+
+lvs $vg
+vgchange -an $vg
+
+# should not activate from the md legs
+_clear_online_files
+pvscan --cache -aay "$dev1"
+pvscan --cache -aay "$dev2"
+
+test ! -f "$RUNDIR/lvm/pvs_online/$PVIDMD"
+test ! -f "$RUNDIR/lvm/vgs_online/$vg"
+
+# should not show an active lv
+not dmsetup info $vg-$lv1
+
+vgchange -ay $vg
+
+check lv_field $vg/$lv1 lv_active "active"
+
+vgchange -an $vg
+
+_clear_online_files
+pvscan --cache -aay "$mddev"
+
+test -f "$RUNDIR/lvm/pvs_online/$PVIDMD"
+test -f "$RUNDIR/lvm/vgs_online/$vg"
+
+check active $vg $lv1
+
+vgchange -an $vg
+vgremove -f $vg
+
+aux cleanup_md_dev
+aux wipefs_a "$dev1" "$dev2"
+
+done
+
+
+# Repeat tests using the default config settings
+
+aux lvmconf "devices/hints = \"all\"" \
+ "devices/obtain_device_list_from_udev = 1" \
+ "devices/search_for_devnames = \"none\""
+
+rm $DF || true
+
+# create 2 disk MD raid0 array
+# by default using metadata format 1.0 with data at the end of device
+# When a raid0 md array is stopped, the components will not look like
+# duplicate PVs as they do with raid1.
+
+aux mdadm_create --metadata=1.0 --level=0 --chunk=64 --raid-devices=2 "$dev1" "$dev2"
+mddev=$(< MD_DEV)
+
+# Create an unused PV so that there is at least one PV in the hints
+# when the MD dev is stopped. If there are no PVs, the hints are
+# empty, and the code falls back to scanning all, and we do not end
+# up testing the code with hints actively used.
+pvcreate "$dev3"
+
+vgcreate $vg "$mddev"
+
+PVIDMD=$(get pv_field "$mddev" uuid | tr -d - )
+
+lvcreate -n $lv1 -l 2 $vg
+lvcreate -n $lv2 -l 2 -an $vg
+
+lvchange -ay $vg/$lv2
+check lv_field $vg/$lv1 lv_active "active"
+
+# lvm does not show md components as PVs
+pvs "$mddev"
+not pvs "$dev1"
+not pvs "$dev2"
+pvs > out
+not grep "$dev1" out
+not grep "$dev2" out
+
+grep "$mddev" "$HINTS"
+grep "$dev3" "$HINTS"
+not grep "$dev1" "$HINTS"
+not grep "$dev2" "$HINTS"
+
+vgchange -an $vg
+
+# When the md device is started, lvm will see that and know to
+# scan for md components, so stop the md device to remove this
+# advantage so we will test the fallback detection.
+mdadm --stop "$mddev"
+aux udev_wait
+
+# A WARNING indicating duplicate PVs is printed by 'pvs' in this
+# case. It's printed during the scan, but after the scan, the
+# md component detection is run on the devs and they are dropped
+# when we see they are md components. So, we ignore the warning
+# containing the word duplicate, and look for the "Not using device"
+# message, which shouldn't appear, as it would indicate that
+# we didn't drop the md components.
+# FIXME: we should avoid printing the premature warning indicating
+# duplicate PVs which are eventually recognized as md components
+# and dropped.
+pvs 2>&1|tee out1
+grep -v -e WARNING -e "Devices file PVID" out1 > out2
+not grep "Not using device" out2
+not grep "$mddev" out2
+not grep "$dev1" out2
+not grep "$dev2" out2
+grep "$dev3" out2
+cat "$HINTS"
+
+pvs 2>&1|tee out1
+grep -v -e WARNING -e "Devices file PVID" out1 > out2
+not grep "Not using device" out2
+not grep "$mddev" out2
+not grep "$dev1" out2
+not grep "$dev2" out2
+grep "$dev3" out2
+cat "$HINTS"
+
+# The md components should still be detected and excluded.
+not pvs "$dev1"
+not pvs "$dev2"
+pvs | tee out
+not grep "$dev1" out
+not grep "$dev2" out
+grep "$dev3" out
+
+# should not activate from the md legs
+not vgchange -ay $vg
+
+# should not show an active lv
+not dmsetup info $vg-$lv1
+
+# should not allow updating vg
+not lvcreate -l1 $vg
+
+# should not activate from the md legs
+_clear_online_files
+pvscan --cache -aay "$dev1"
+pvscan --cache -aay "$dev2"
+
+test ! -f "$RUNDIR/lvm/pvs_online/$PVIDMD"
+test ! -f "$RUNDIR/lvm/vgs_online/$vg"
+
+# should not show an active lv
+not dmsetup info $vg-$lv1
+
+# start the md dev
+aux mdadm_assemble "$mddev" "$dev1" "$dev2"
+
+not pvs "$dev1"
+not pvs "$dev2"
+pvs | tee out
+not grep "$dev1" out
+not grep "$dev2" out
+
+lvs $vg
+vgchange -an $vg
+
+# should not activate from the md legs
+_clear_online_files
+pvscan --cache -aay "$dev1"
+pvscan --cache -aay "$dev2"
+
+test ! -f "$RUNDIR/lvm/pvs_online/$PVIDMD"
+test ! -f "$RUNDIR/lvm/vgs_online/$vg"
+
+# should not show an active lv
+not dmsetup info $vg-$lv1
+
+vgchange -ay $vg
+
+check lv_field $vg/$lv1 lv_active "active"
+
+vgchange -an $vg
+
+_clear_online_files
+pvscan --cache -aay "$mddev"
+
+test -f "$RUNDIR/lvm/pvs_online/$PVIDMD"
+test -f "$RUNDIR/lvm/vgs_online/$vg"
+
+check active $vg $lv1
+
+vgchange -an $vg
+vgremove -f $vg
+
+aux cleanup_md_dev
diff --git a/test/shell/lvmcache-exercise.sh b/test/shell/lvmcache-exercise.sh
index b1e2b92..8cfb7f1 100644
--- a/test/shell/lvmcache-exercise.sh
+++ b/test/shell/lvmcache-exercise.sh
@@ -1,5 +1,6 @@
-#!/bin/sh
-# Copyright (C) 2008 Red Hat, Inc. All rights reserved.
+#!/usr/bin/env bash
+
+# Copyright (C) 2008-2013 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
@@ -7,17 +8,56 @@
#
# 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
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+SKIP_WITH_LVMLOCKD=1
+SKIP_WITH_LVMPOLLD=1
-. lib/test
+. lib/inittest
aux prepare_pvs 5
+get_devs
vgcreate $vg1 "$dev1"
-vgcreate $vg2 "$dev3"
+vgcreate $vg2 "$dev3" "$dev4" "$dev5"
+
+UUID1=$(get vg_field $vg1 uuid)
aux disable_dev "$dev1"
pvscan
+# dev1 is missing
+fail pvs "${DEVICES[@]}"
+
+# create a new vg1 on dev2,
+# so dev1 and dev2 have different VGs with the same name
vgcreate $vg1 "$dev2"
+
+UUID2=$(get vg_field $vg1 uuid)
+
+# Once dev1 is visible again, both VGs named "vg1" are visible.
aux enable_dev "$dev1"
-pvs
+
+pvs "$dev1"
+
+# reappearing device (rhbz 995440)
+lvcreate -aey -m2 --type mirror -l4 --alloc anywhere --corelog -n $lv1 $vg2
+
+aux disable_dev "$dev3"
+
+pvs 2>&1| tee out
+grep "is missing PV" out
+
+lvconvert --yes --repair $vg2/$lv1
+
+aux enable_dev "$dev3"
+
+lvs -a $vg2 -o+devices 2>&1 | tee out
+not grep "is missing PV" out
+
+# This removes the first "vg1" using its uuid
+vgremove -ff -S vg_uuid=$UUID1
+
+# This removes the second "vg1" using its name,
+# now that there is only one VG with that name.
+vgremove -ff $vg1 $vg2
+
diff --git a/test/shell/lvmetad-disabled.sh b/test/shell/lvmetad-disabled.sh
deleted file mode 100644
index 41a3a19..0000000
--- a/test/shell/lvmetad-disabled.sh
+++ /dev/null
@@ -1,26 +0,0 @@
-#!/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
deleted file mode 100644
index e49eb68..0000000
--- a/test/shell/lvmetad-dump.sh
+++ /dev/null
@@ -1,38 +0,0 @@
-#!/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-pvs.sh b/test/shell/lvmetad-pvs.sh
deleted file mode 100644
index 80b421c..0000000
--- a/test/shell/lvmetad-pvs.sh
+++ /dev/null
@@ -1,19 +0,0 @@
-#!/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-test.sh b/test/shell/lvmetad-test.sh
deleted file mode 100644
index 7e801f1..0000000
--- a/test/shell/lvmetad-test.sh
+++ /dev/null
@@ -1,34 +0,0 @@
-#!/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
deleted file mode 100644
index 3a97a1b..0000000
--- a/test/shell/lvmetad-warning.sh
+++ /dev/null
@@ -1,27 +0,0 @@
-#!/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/lvmlockd-hello-world.sh b/test/shell/lvmlockd-hello-world.sh
new file mode 100644
index 0000000..2e1d329
--- /dev/null
+++ b/test/shell/lvmlockd-hello-world.sh
@@ -0,0 +1,27 @@
+#!/usr/bin/env bash
+
+# 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+test_description='Hello world for vgcreate $SHARED with lvmlockd and sanlock'
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+[ -z "$LVM_TEST_LVMLOCKD" ] && skip
+
+aux prepare_pvs 1
+
+vgcreate $SHARED $vg "$dev1"
+
+vgs -o+locktype,lockargs $vg
+
+vgremove $vg
diff --git a/test/shell/lvmlockd-lv-types.sh b/test/shell/lvmlockd-lv-types.sh
new file mode 100644
index 0000000..398c964
--- /dev/null
+++ b/test/shell/lvmlockd-lv-types.sh
@@ -0,0 +1,192 @@
+#!/usr/bin/env bash
+
+# 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+test_description='Check lvmlockd lock_args for different LV types'
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+[ -z "$LVM_TEST_LVMLOCKD" ] && skip;
+
+if test -n "$LVM_TEST_LOCK_TYPE_SANLOCK" ; then
+LOCKARGS1="1.0.0:70254592"
+LOCKARGS2="1.0.0:71303168"
+LOCKARGS3="1.0.0:72351744"
+fi
+
+if test -n "$LVM_TEST_LOCK_TYPE_DLM" ; then
+LOCKARGS1="dlm"
+LOCKARGS2="dlm"
+LOCKARGS3="dlm"
+fi
+
+if test -n "$LVM_TEST_LVMLOCKD_TEST" ; then
+LOCKARGS1="dlm"
+LOCKARGS2="dlm"
+LOCKARGS3="dlm"
+fi
+
+if test -n "$LVM_TEST_LOCK_TYPE_IDM" ; then
+LOCKARGS1="idm"
+LOCKARGS2="idm"
+LOCKARGS3="idm"
+fi
+
+aux prepare_devs 5
+
+vgcreate --shared $vg "$dev1" "$dev2" "$dev3" "$dev4" "$dev5"
+
+#
+# pvscan autoactivation ignore shared PVs
+#
+RUNDIR="/run"
+test -d "$RUNDIR" || RUNDIR="/var/run"
+
+PVID1=$(pvs "$dev1" --noheading -o uuid | tr -d - | awk '{print $1}')
+pvscan --cache -aay "$dev1"
+not ls "$RUNDIR/lvm/pvs_online/$PVID1"
+pvscan --cache -aay
+not ls "$RUNDIR/lvm/pvs_online/$PVID1"
+not ls "$RUNDIR/lvm/vgs_online/$vg"
+
+
+#
+# thin pool, thin lv, thin snap
+#
+
+lvcreate -L 8M -n pool1 $vg
+check lva_field $vg/pool1 lockargs $LOCKARGS1
+
+lvcreate -L 8M -n pool1_meta $vg
+check lva_field $vg/pool1_meta lockargs $LOCKARGS2
+
+lvconvert -y --type thin-pool --poolmetadata $vg/pool1_meta $vg/pool1
+check lva_field $vg/pool1 lockargs $LOCKARGS3
+check lva_field $vg/pool1_tdata lockargs ""
+check lva_field $vg/pool1_tmeta lockargs ""
+
+lvcreate -n thin1 -V 1G --thinpool $vg/pool1
+check lva_field $vg/thin1 lockargs ""
+
+lvcreate -s -n snap1 $vg/thin1
+check lva_field $vg/snap1 lockargs ""
+
+lvchange -ay -K $vg/snap1
+
+lvchange -an $vg/snap1
+lvchange -an $vg/thin1
+lvchange -an $vg/pool1
+lvremove $vg/snap1
+lvremove $vg/thin1
+lvremove $vg/pool1
+
+# the first sanlock lock should be found and reused
+lvcreate -L 8M -n lv1 $vg
+check lva_field $vg/lv1 lockargs $LOCKARGS1
+
+lvchange -an $vg/lv1
+lvremove $vg/lv1
+
+
+#
+# with automatic metadata lv
+#
+
+lvcreate -L 8M -n pool2 $vg
+check lva_field $vg/pool2 lockargs $LOCKARGS1
+
+lvconvert -y --type thin-pool $vg/pool2
+check lva_field $vg/pool2 lockargs $LOCKARGS2
+check lva_field $vg/pool2_tdata lockargs ""
+check lva_field $vg/pool2_tmeta lockargs ""
+
+lvcreate -n thin2 -V 1G --thinpool $vg/pool2
+check lva_field $vg/thin2 lockargs ""
+
+lvchange -an $vg/thin2
+lvchange -an $vg/pool2
+lvremove $vg/thin2
+lvremove $vg/pool2
+
+
+#
+# cache pool, cache lv
+#
+
+lvcreate -L 8M -n cache1 $vg
+check lva_field $vg/cache1 lockargs $LOCKARGS1
+
+lvcreate -L 8M -n cache1_meta $vg
+check lva_field $vg/cache1_meta lockargs $LOCKARGS2
+
+lvconvert -y --type cache-pool --poolmetadata $vg/cache1_meta $vg/cache1
+check lva_field $vg/cache1 lockargs ""
+check lva_field $vg/cache1_cdata lockargs ""
+check lva_field $vg/cache1_cmeta lockargs ""
+
+lvcreate -n lv1 -L 8M $vg
+check lva_field $vg/lv1 lockargs $LOCKARGS1
+
+lvconvert -y --type cache --cachepool $vg/cache1 $vg/lv1
+check lva_field $vg/lv1 lockargs $LOCKARGS1
+check lva_field $vg/cache1_cpool lockargs ""
+check lva_field $vg/cache1_cpool_cdata lockargs ""
+check lva_field $vg/cache1_cpool_cmeta lockargs ""
+
+lvconvert --splitcache $vg/lv1
+check lva_field $vg/lv1 lockargs $LOCKARGS1
+check lva_field $vg/cache1 lockargs ""
+check lva_field $vg/cache1_cdata lockargs ""
+check lva_field $vg/cache1_cmeta lockargs ""
+
+lvchange -an $vg/cache1
+lvchange -an $vg/lv1
+lvremove $vg/cache1
+lvremove $vg/lv1
+
+#
+# cow snap
+#
+
+lvcreate -n lv2 -L 8M $vg
+check lva_field $vg/lv2 lockargs $LOCKARGS1
+
+lvcreate -s -n lv2snap -L 8M $vg/lv2
+check lva_field $vg/lv2 lockargs $LOCKARGS1
+check lva_field $vg/lv2snap lockargs ""
+
+lvchange -y -an $vg/lv2
+lvremove $vg/lv2snap
+lvremove $vg/lv2
+
+#
+# mirror
+#
+
+lvcreate --type mirror -m 1 -n lv3 -L 8M $vg
+check lva_field $vg/lv3 lockargs $LOCKARGS1
+
+lvchange -an $vg/lv3
+lvremove $vg/lv3
+
+#
+# raid1
+#
+
+lvcreate --type raid1 -m 1 -n lv4 -L 8M $vg
+check lva_field $vg/lv4 lockargs $LOCKARGS1
+
+lvchange -an $vg/lv4
+lvremove $vg/lv4
+
+vgremove $vg
diff --git a/test/shell/lvmlockd_failure.sh b/test/shell/lvmlockd_failure.sh
new file mode 100644
index 0000000..2825462
--- /dev/null
+++ b/test/shell/lvmlockd_failure.sh
@@ -0,0 +1,38 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2020~2021 Seagate, 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+[ -z "$LVM_TEST_FAILURE" ] && skip
+
+aux prepare_vg 3
+
+# Create new logic volume
+lvcreate -a ey --zero n -l 1 -n $lv1 $vg
+
+# FIXME - test shall NOT kill random processes in the system!
+# Emulate lvmlockd abnormally exiting
+killall -9 lvmlockd
+
+systemctl start lvm2-lvmlockd
+
+vgchange --lock-start $vg
+
+lvchange -a n $vg/$lv1
+lvchange -a sy $vg/$lv1
+
+lvcreate -a ey --zero n -l 1 -n $lv2 $vg
+lvchange -a n $vg/$lv2
+
+vgremove -ff $vg
diff --git a/test/shell/lvremove-thindata-caches.sh b/test/shell/lvremove-thindata-caches.sh
new file mode 100644
index 0000000..ba099c3
--- /dev/null
+++ b/test/shell/lvremove-thindata-caches.sh
@@ -0,0 +1,71 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2017-2020 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+aux have_cache 1 10 0 || skip
+aux have_writecache 1 0 0 || skip
+which mkfs.xfs || skip
+
+aux prepare_devs 6 70 # want 64M of usable space from each dev
+
+vgcreate $SHARED $vg "$dev1" "$dev2" "$dev3" "$dev4" "$dev5" "$dev6"
+
+# lv1 is thinpool LV: 128M
+# lv2 is fast LV: 64M
+# lv3 is thin LV: 1G
+
+#
+# Test lvremove of a thinpool that uses cache|writecache on data
+#
+
+# attach writecache to thinpool data
+lvcreate --type thin-pool -n $lv1 -L128M --poolmetadataspare n $vg "$dev1" "$dev2"
+lvcreate --type thin -n $lv3 -V1G --thinpool $lv1 $vg
+lvcreate -n $lv2 -L64M -an $vg "$dev3"
+lvconvert -y --type writecache --cachevol $lv2 $vg/$lv1
+lvchange -ay $vg/$lv1
+lvs -a $vg
+mkfs.xfs -f -s size=4096 "$DM_DEV_DIR/$vg/$lv3"
+lvremove -y $vg/$lv1
+
+# attach cache/writeback (cachevol) to thinpool data
+lvcreate --type thin-pool -n $lv1 -L128M --poolmetadataspare n $vg "$dev1" "$dev2"
+lvcreate --type thin -n $lv3 -V1G --thinpool $lv1 $vg
+lvcreate -n $lv2 -L64M -an $vg "$dev3"
+lvconvert -y --type cache --cachevol $lv2 --cachemode writeback $vg/$lv1
+lvchange -ay $vg/$lv1
+mkfs.xfs -f -s size=4096 "$DM_DEV_DIR/$vg/$lv3"
+lvremove -y $vg/$lv1
+
+# attach cache/writethrough (cachevol) to thinpool data
+lvcreate --type thin-pool -n $lv1 -L128M --poolmetadataspare n $vg "$dev1" "$dev2"
+lvcreate --type thin -n $lv3 -V1G --thinpool $lv1 $vg
+lvcreate -n $lv2 -L64M -an $vg "$dev3"
+lvconvert -y --type cache --cachevol $lv2 --cachemode writethrough $vg/$lv1
+lvchange -ay $vg/$lv1
+mkfs.xfs -f -s size=4096 "$DM_DEV_DIR/$vg/$lv3"
+lvremove -y $vg/$lv1
+
+# attach cache (cachepool) to thinpool data
+lvcreate --type thin-pool -n $lv1 -L128M --poolmetadataspare n $vg "$dev1" "$dev2"
+lvcreate --type thin -n $lv3 -V1G --thinpool $lv1 $vg
+lvcreate -y --type cache-pool -n $lv2 -L64M --poolmetadataspare n $vg "$dev3" "$dev6"
+lvconvert -y --type cache --cachepool $lv2 --poolmetadataspare n $vg/$lv1
+lvchange -ay $vg/$lv1
+mkfs.xfs -f -s size=4096 "$DM_DEV_DIR/$vg/$lv3"
+lvremove -y $vg/$lv1
+
+vgremove -f $vg
+
diff --git a/test/shell/lvrename-cache-thin.sh b/test/shell/lvrename-cache-thin.sh
new file mode 100644
index 0000000..a77a2c1
--- /dev/null
+++ b/test/shell/lvrename-cache-thin.sh
@@ -0,0 +1,52 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2015 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+# Check rename of stacked thin over cached LV
+
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+aux have_cache 1 3 0 || skip
+aux have_thin 1 0 0 || skip
+
+aux prepare_vg 1 80
+
+lvcreate -L10 -n cpool $vg
+lvcreate -L10 -n tpool $vg
+lvcreate -L10 -n $lv1 $vg
+
+lvconvert --yes --type cache-pool $vg/cpool
+
+lvconvert --yes --cache --cachepool cpool $vg/tpool
+
+# currently the only allowed stacking is cache thin data volume
+lvconvert --yes --type thin-pool $vg/tpool
+
+lvcreate -V10 $vg/tpool
+
+# check cache pool remains same after thin-pool rename
+lvrename $vg/tpool $vg/newpool
+
+check lv_exists $vg newpool cpool_cpool
+check lv_not_exists $vg tpool
+
+# allowing rename of internal cache pool
+lvrename $vg/cpool_cpool $vg/cachepool
+
+check lv_exists $vg cachepool
+check lv_not_exists $vg cpool_cpool
+
+lvs -a $vg
+
+vgremove -f $vg
diff --git a/test/shell/lvrename-vdo.sh b/test/shell/lvrename-vdo.sh
new file mode 100644
index 0000000..1417d9f
--- /dev/null
+++ b/test/shell/lvrename-vdo.sh
@@ -0,0 +1,88 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2021 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+# Check online renaming of VDO devices works
+
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+#
+# Main
+#
+
+aux have_vdo 6 2 1 || skip
+aux have_cache 1 3 0 || skip
+aux have_raid 1 3 0 || skip
+
+aux prepare_vg 2 5000
+
+lvcreate --vdo -L4G -V2G --name $lv1 $vg/vpool1
+lvrename $vg/vpool1 vpool2
+check lv_exists $vg $lv1 vpool2 vpool2_vdata
+
+lvremove -ff $vg
+
+# With version >= 6.2.3 online rename should work
+if aux have_vdo 6 2 3 ; then
+
+### CACHE ####
+lvcreate --vdo -L4G -V2G --name $lv1 $vg/vpool1
+lvcreate -H -L10 $vg/vpool1
+lvrename $vg/vpool1 $vg/vpool2
+check lv_exists $vg vpool2 vpool2_vdata
+lvremove -ff $vg
+
+### RAID ####
+lvcreate --type raid1 -L4G --nosync --name vpool1 $vg
+lvconvert --yes --type vdo-pool $vg/vpool1
+lvrename $vg/vpool1 $vg/vpool2
+check lv_exists $vg vpool2 vpool2_vdata vpool2_vdata_rimage_0
+lvremove -ff $vg
+
+fi # >= 6.2.3
+
+# Check when VDO target does not support online resize
+aux lvmconf "global/vdo_disabled_features = [ \"online_rename\" ]"
+
+
+### CACHE ####
+lvcreate --vdo -L4G -V2G --name $lv1 $vg/vpool1
+lvcreate -H -L10 $vg/vpool1
+
+# VDO target driver cannot handle online rename
+not lvrename $vg/vpool1 $vg/vpool2 2>&1 | tee out
+grep "Cannot rename" out
+
+# Ofline should work
+lvchange -an $vg
+lvrename $vg/vpool1 $vg/vpool2
+lvchange -ay $vg
+check lv_exists $vg $lv1 vpool2 vpool2_vdata
+lvremove -ff $vg
+
+
+### RAID ####
+lvcreate --type raid1 -L4G --nosync --name vpool1 $vg
+lvconvert --yes --type vdo-pool $vg/vpool1
+not lvrename $vg/vpool1 $vg/vpool2 2>&1 | tee out
+grep "Cannot rename" out
+
+# Ofline should work
+lvchange -an $vg
+lvrename $vg/vpool1 $vg/vpool2
+lvchange -ay $vg
+check lv_exists $vg vpool2 vpool2_vdata vpool2_vdata_rimage_0
+lvremove -ff $vg
+
+vgremove -ff $vg
diff --git a/test/shell/lvresize-fs-crypt.sh b/test/shell/lvresize-fs-crypt.sh
new file mode 100644
index 0000000..966870d
--- /dev/null
+++ b/test/shell/lvresize-fs-crypt.sh
@@ -0,0 +1,163 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2007-2016 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+aux prepare_vg 3 256
+
+which mkfs.xfs || skip
+
+# Tests require a libblkid version that shows FSLASTBLOCK
+lvcreate -n $lv1 -L 300 $vg
+mkfs.xfs -f "$DM_DEV_DIR/$vg/$lv1"
+blkid -p "$DM_DEV_DIR/$vg/$lv1" | grep FSLASTBLOCK || skip
+lvremove -f $vg/$lv1
+
+mount_dir="mnt_lvresize_cr"
+mkdir -p "$mount_dir"
+
+# dm-crypt device on lv
+cr="$PREFIX-$lv-cr"
+
+# lvextend ext4 on LUKS1
+lvcreate -n $lv -L 256M $vg
+echo 93R4P4pIqAH8 | cryptsetup luksFormat -i1 --type luks1 "$DM_DEV_DIR/$vg/$lv"
+echo 93R4P4pIqAH8 | cryptsetup luksOpen "$DM_DEV_DIR/$vg/$lv" $cr
+mkfs.ext4 /dev/mapper/$cr
+mount /dev/mapper/$cr "$mount_dir"
+dd if=/dev/zero of="$mount_dir/zeros1" bs=1M count=20 oflag=direct
+df --output=size "$mount_dir" |tee df1
+lvextend -L+200M --fs resize $vg/$lv
+check lv_field $vg/$lv lv_size "456.00m"
+df --output=size "$mount_dir" |tee df2
+not diff df1 df2
+umount "$mount_dir"
+cryptsetup close $cr
+lvremove -f $vg/$lv
+
+# lvreduce ext4 on LUKS1
+lvcreate -n $lv -L 456M $vg
+echo 93R4P4pIqAH8 | cryptsetup luksFormat -i1 --type luks1 "$DM_DEV_DIR/$vg/$lv"
+echo 93R4P4pIqAH8 | cryptsetup luksOpen "$DM_DEV_DIR/$vg/$lv" $cr
+mkfs.ext4 /dev/mapper/$cr
+mount /dev/mapper/$cr "$mount_dir"
+dd if=/dev/zero of="$mount_dir/zeros1" bs=1M count=20 oflag=direct
+df --output=size "$mount_dir" |tee df1
+lvresize -L-100M --yes --fs resize $vg/$lv
+check lv_field $vg/$lv lv_size "356.00m"
+df --output=size "$mount_dir" |tee df2
+not diff df1 df2
+umount "$mount_dir"
+cryptsetup close $cr
+lvremove -f $vg/$lv
+
+# lvextend xfs on LUKS1
+lvcreate -n $lv -L 320M $vg
+echo 93R4P4pIqAH8 | cryptsetup luksFormat -i1 --type luks1 "$DM_DEV_DIR/$vg/$lv"
+echo 93R4P4pIqAH8 | cryptsetup luksOpen "$DM_DEV_DIR/$vg/$lv" $cr
+mkfs.xfs /dev/mapper/$cr
+mount /dev/mapper/$cr "$mount_dir"
+dd if=/dev/zero of="$mount_dir/zeros1" bs=1M count=20 oflag=direct
+df --output=size "$mount_dir" |tee df1
+lvextend -L+136M --fs resize $vg/$lv
+check lv_field $vg/$lv lv_size "456.00m"
+df --output=size "$mount_dir" |tee df2
+not diff df1 df2
+umount "$mount_dir"
+cryptsetup close $cr
+lvremove -f $vg/$lv
+
+# lvreduce xfs on LUKS1
+lvcreate -n $lv -L 456M $vg
+echo 93R4P4pIqAH8 | cryptsetup luksFormat -i1 --type luks1 "$DM_DEV_DIR/$vg/$lv"
+echo 93R4P4pIqAH8 | cryptsetup luksOpen "$DM_DEV_DIR/$vg/$lv" $cr
+mkfs.xfs /dev/mapper/$cr
+mount /dev/mapper/$cr "$mount_dir"
+dd if=/dev/zero of="$mount_dir/zeros1" bs=1M count=20 oflag=direct
+df --output=size "$mount_dir" |tee df1
+# xfs cannot be reduced
+not lvresize -L-100M --yes --fs resize $vg/$lv
+check lv_field $vg/$lv lv_size "456.00m"
+df --output=size "$mount_dir" |tee df2
+diff df1 df2
+umount "$mount_dir"
+cryptsetup close $cr
+lvremove -f $vg/$lv
+
+# lvextend ext4 on plain crypt (no header)
+lvcreate -n $lv -L 256M $vg
+echo 93R4P4pIqAH8 | cryptsetup create $cr "$DM_DEV_DIR/$vg/$lv"
+mkfs.ext4 /dev/mapper/$cr
+mount /dev/mapper/$cr "$mount_dir"
+dd if=/dev/zero of="$mount_dir/zeros1" bs=1M count=20 oflag=direct
+df --output=size "$mount_dir" |tee df1
+# fails when no fs is found for --fs resize
+not lvextend -L+200M --yes --fs resize $vg/$lv
+check lv_field $vg/$lv lv_size "256.00m"
+df --output=size "$mount_dir" |tee df2
+diff df1 df2
+umount "$mount_dir"
+cryptsetup close $cr
+lvremove -f $vg/$lv
+
+# lvreduce ext4 on plain crypt (no header)
+lvcreate -n $lv -L 456M $vg
+echo 93R4P4pIqAH8 | cryptsetup create $cr "$DM_DEV_DIR/$vg/$lv"
+mkfs.ext4 /dev/mapper/$cr
+mount /dev/mapper/$cr "$mount_dir"
+dd if=/dev/zero of="$mount_dir/zeros1" bs=1M count=20 oflag=direct
+df --output=size "$mount_dir" |tee df1
+# fails when no fs is found for --fs resize
+not lvresize -L-100M --yes --fs resize $vg/$lv
+check lv_field $vg/$lv lv_size "456.00m"
+df --output=size "$mount_dir" |tee df2
+diff df1 df2
+umount "$mount_dir"
+cryptsetup close $cr
+lvremove -f $vg/$lv
+
+# lvresize uses helper only for crypt dev resize
+# because the fs was resized separately beforehand
+lvcreate -n $lv -L 456M $vg
+echo 93R4P4pIqAH8 | cryptsetup luksFormat -i1 --type luks1 "$DM_DEV_DIR/$vg/$lv"
+echo 93R4P4pIqAH8 | cryptsetup luksOpen "$DM_DEV_DIR/$vg/$lv" $cr
+mkfs.ext4 /dev/mapper/$cr
+mount /dev/mapper/$cr "$mount_dir"
+dd if=/dev/zero of="$mount_dir/zeros1" bs=1M count=10 oflag=direct
+df --output=size "$mount_dir" |tee df1
+# resize only the fs (to 256M), not the crypt dev or LV
+umount "$mount_dir"
+fsck -n /dev/mapper/$cr
+resize2fs /dev/mapper/$cr 262144k
+mount /dev/mapper/$cr "$mount_dir"
+# this lvresize will not resize the fs (which is already reduced
+# to smaller than the requested LV size), but lvresize will use
+# the helper to resize the crypt dev before resizing the LV.
+# Using --fs resize is required to allow lvresize to look above
+# the lv at crypt&fs layers for potential resizing. Without
+# --fs resize, lvresize fails because it sees that crypt resize
+# is needed and --fs resize is needed to enable that.
+not lvresize -L-100 $vg/$lv
+lvresize -L-100M --fs resize $vg/$lv
+check lv_field $vg/$lv lv_size "356.00m"
+df --output=size "$mount_dir" |tee df2
+not diff df1 df2
+umount "$mount_dir"
+cryptsetup close $cr
+lvremove -f $vg/$lv
+
+# test with LUKS2?
+
+vgremove -ff $vg
diff --git a/test/shell/lvresize-fs.sh b/test/shell/lvresize-fs.sh
new file mode 100644
index 0000000..d2c4ac7
--- /dev/null
+++ b/test/shell/lvresize-fs.sh
@@ -0,0 +1,627 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2007-2023 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+aux prepare_vg 2 100
+
+which mkfs.ext4 || skip
+which resize2fs || skip
+
+#
+# Workaroudn for kernel bug fixed with:
+# a408f33e895e455f16cf964cb5cd4979b658db7b
+# refreshing DM device - using fsfreeze with suspend
+#
+workaround_() {
+ blkid -p "$DM_DEV_DIR/$vg/$lv" >/dev/null || {
+ dmsetup suspend $vg-$lv
+ dmsetup resume $vg-$lv
+ }
+}
+
+mount_dir="mnt_lvresize_fs"
+mkdir -p "$mount_dir"
+
+mount_dir_space="other mnt dir"
+mkdir -p "$mount_dir_space"
+
+mount_dir_2="mnt_lvresize_fs_2"
+mkdir -p "$mount_dir_2"
+
+# Test combinations of the following:
+# lvreduce / lvextend
+# no fs / ext4
+# each --fs opt / no --fs opt / --resizefs
+# active / inactive
+# mounted / unmounted
+# fs size less than, equal to or greater than reduced lv size
+
+
+###################
+#
+# lvextend, no fs
+#
+###################
+
+# lvextend, no fs, active, no --fs
+lvcreate -n $lv -L 10M $vg
+lvextend -L+20M $vg/$lv
+check lv_field $vg/$lv lv_size "30.00m"
+
+# lvextend, no fs, active, --fs resize fails with no fs found
+not lvextend -L+20M --fs resize $vg/$lv
+check lv_field $vg/$lv lv_size "30.00m"
+
+lvchange -an $vg/$lv
+
+# lvextend, no fs, inactive, --fs resize error requires active lv
+not lvextend -L+20M --fs resize $vg/$lv
+check lv_field $vg/$lv lv_size "30.00m"
+
+# lvextend, no fs, inactive, no --fs
+lvextend -L+30M $vg/$lv
+check lv_field $vg/$lv lv_size "60.00m"
+
+lvremove -f $vg
+
+
+###################
+#
+# lvreduce, no fs
+#
+###################
+
+# lvreduce, no fs, active, no --fs setting is same as --fs checksize
+lvcreate -n $lv -L 50M $vg
+lvreduce -L-10M $vg/$lv
+check lv_field $vg/$lv lv_size "40.00m"
+lvchange -an $vg/$lv
+
+# lvreduce, no fs, inactive, no --fs setting is same as --fs checksize
+not lvreduce -L-10M $vg/$lv
+lvreduce --fs checksize -L-10M $vg/$lv
+check lv_field $vg/$lv lv_size "30.00m"
+
+# lvreduce, no fs, inactive, --fs ignore
+lvreduce -L-10M --fs ignore $vg/$lv
+check lv_field $vg/$lv lv_size "20.00m"
+
+# lvreduce, no fs, active, --fs resize requires fs to be found
+lvchange -ay $vg/$lv
+not lvreduce -L-10M --fs resize $vg/$lv
+check lv_field $vg/$lv lv_size "20.00m"
+
+lvremove -f $vg/$lv
+
+
+#################
+#
+# lvextend, ext4
+#
+#################
+
+# Use one instance of ext4 for series of lvextend tests:
+lvcreate -n $lv -L 20M $vg
+mkfs.ext4 "$DM_DEV_DIR/$vg/$lv"
+mount "$DM_DEV_DIR/$vg/$lv" "$mount_dir"
+
+# --fs tests require a libblkid version that shows FSLASTBLOCK
+# so exit 0 test here, if the feature is not present
+blkid -p "$DM_DEV_DIR/$vg/$lv" | grep FSLASTBLOCK || exit 0
+
+
+# lvextend, ext4, active, mounted, no --fs setting is same as --fs ignore
+df --output=size "$mount_dir" |tee df1
+dd if=/dev/zero of="$mount_dir/zeros1" bs=1M count=8 oflag=direct
+lvextend -L+10M $vg/$lv
+check lv_field $vg/$lv lv_size "30.00m"
+# with no --fs used, the fs size should be the same
+df --output=size "$mount_dir" |tee df2
+diff df1 df2
+resize2fs "$DM_DEV_DIR/$vg/$lv"
+df --output=size "$mount_dir" |tee df3
+not diff df2 df3
+dd if=/dev/zero of="$mount_dir/zeros2" bs=1M count=10 oflag=direct
+# keep mounted fs
+
+# lvextend, ext4, active, mounted, --fs ignore
+df --output=size "$mount_dir" |tee df1
+lvextend --fs ignore -L+10M $vg/$lv
+check lv_field $vg/$lv lv_size "40.00m"
+df --output=size "$mount_dir" |tee df2
+diff df1 df2
+# keep mounted fs
+
+# lvextend, ext4, active, mounted, --fs resize
+lvextend --fs resize -L+10M $vg/$lv
+check lv_field $vg/$lv lv_size "50.00m"
+df --output=size "$mount_dir" |tee df2
+not diff df1 df2
+# keep mounted fs
+
+workaround_
+
+# lvextend, ext4, active, mounted, --resizefs (same as --fs resize)
+df --output=size "$mount_dir" |tee df1
+lvextend --resizefs -L+10M $vg/$lv
+check lv_field $vg/$lv lv_size "60.00m"
+df --output=size "$mount_dir" |tee df2
+not diff df1 df2
+# keep mounted fs
+
+workaround_
+
+# lvextend, ext4, active, mounted, --fs resize --fsmode manage (same as --fs resize)
+df --output=size "$mount_dir" |tee df1
+lvextend --fs resize --fsmode manage -L+10M $vg/$lv
+check lv_field $vg/$lv lv_size "70.00m"
+df --output=size "$mount_dir" |tee df2
+not diff df1 df2
+dd if=/dev/zero of="$mount_dir/zeros3" bs=1M count=10 oflag=direct
+# keep mounted fs
+
+workaround_
+
+# lvextend, ext4, active, mounted, --fs resize_fsadm
+df --output=size "$mount_dir" |tee df1
+lvextend --fs resize_fsadm -L+10M $vg/$lv
+check lv_field $vg/$lv lv_size "80.00m"
+df --output=size "$mount_dir" |tee df2
+not diff df1 df2
+# keep mounted fs
+
+workaround_
+
+# lvextend, ext4, active, mounted, --fs resize --fsmode nochange
+df --output=size "$mount_dir" |tee df1
+lvextend --fs resize --fsmode nochange -L+10M $vg/$lv
+check lv_field $vg/$lv lv_size "90.00m"
+df --output=size "$mount_dir" |tee df2
+not diff df1 df2
+# keep mounted fs
+
+# lvextend|lvreduce, ext4, active, mounted, --fs resize, renamed LV
+lvrename $vg/$lv $vg/$lv2
+not lvextend --fs resize -L+32M $vg/$lv2
+not lvreduce --fs resize -L-32M $vg/$lv2
+umount "$mount_dir"
+
+# lvextend|lvreduce, ext4, active, mounted, mount dir with space, --fs resize, renamed LV
+mount "$DM_DEV_DIR/$vg/$lv2" "$mount_dir_space"
+lvrename $vg/$lv2 $vg/$lv3
+not lvextend --fs resize -L+32M $vg/$lv3
+not lvreduce --fs resize -L-32M $vg/$lv3
+umount "$mount_dir_space"
+
+lvremove -f $vg/$lv3
+
+
+#################################
+#
+# lvextend, ext4, multiple mounts
+#
+#################################
+
+# Use one instance of ext4 for series of lvextend tests:
+lvcreate -n $lv -L 32M $vg
+mkfs.ext4 "$DM_DEV_DIR/$vg/$lv"
+mount "$DM_DEV_DIR/$vg/$lv" "$mount_dir"
+mount "$DM_DEV_DIR/$vg/$lv" "$mount_dir_2"
+
+# lvextend, ext4, active, mounted twice, -r
+lvextend -r -L+8M $vg/$lv
+check lv_field $vg/$lv lv_size "40.00m"
+
+workaround_
+
+lvrename $vg/$lv $vg/$lv2
+not lvextend -r -L+8M $vg/$lv2
+not lvreduce -r -L-8M $vg/$lv2
+umount "$mount_dir"
+umount "$mount_dir_2"
+lvextend -r -L+8M $vg/$lv2
+
+mount "$DM_DEV_DIR/$vg/$lv2" "$mount_dir"
+mount --bind "$mount_dir" "$mount_dir_2"
+lvextend -r -L+8M $vg/$lv2
+check lv_field $vg/$lv2 lv_size "56.00m"
+lvrename $vg/$lv2 $vg/$lv3
+not lvextend -r -L+8M $vg/$lv3
+not lvreduce -r -L-8M $vg/$lv3
+umount "$mount_dir"
+umount "$mount_dir_2"
+mount "$DM_DEV_DIR/$vg/$lv3" "$mount_dir"
+lvextend -r -L+8M $vg/$lv3
+lvreduce -r -y -L-8M $vg/$lv3
+umount "$mount_dir"
+
+lvremove -f $vg/$lv3
+
+#####################################
+#
+# Now let do some unmounted tests
+#
+#####################################
+
+# prepare new ext4 setup
+lvcreate -n $lv -L 15M $vg
+mkfs.ext4 "$DM_DEV_DIR/$vg/$lv"
+
+# lvextend, ext4, inactive, --fs ignore
+lvchange -an $vg/$lv
+lvextend --fs ignore -L+5M $vg/$lv
+check lv_field $vg/$lv lv_size "20.00m"
+lvchange -ay $vg/$lv
+
+# lvextend, ext4, active, mounted, --fs resize --fsmode offline
+mount "$DM_DEV_DIR/$vg/$lv" "$mount_dir"
+df --output=size "$mount_dir" |tee df1
+dd if=/dev/zero of="$mount_dir/zeros1" bs=1M count=8 oflag=direct
+lvextend --fs resize --fsmode offline -L+10M $vg/$lv
+check lv_field $vg/$lv lv_size "30.00m"
+# fsmode offline leaves fs unmounted
+df -a | tee dfa
+not grep "$mount_dir" dfa
+mount "$DM_DEV_DIR/$vg/$lv" "$mount_dir"
+df --output=size "$mount_dir" |tee df2
+not diff df1 df2
+dd if=/dev/zero of="$mount_dir/zeros2" bs=1M count=10 oflag=direct
+umount "$mount_dir"
+
+# lvextend, ext4, active, unmounted, --fs resize --fsmode nochange
+df --output=size "$mount_dir" |tee df1
+lvextend --fs resize --fsmode nochange -L+10M $vg/$lv
+check lv_field $vg/$lv lv_size "40.00m"
+mount "$DM_DEV_DIR/$vg/$lv" "$mount_dir"
+df --output=size "$mount_dir" |tee df2
+not diff df1 df2
+umount "$mount_dir"
+
+# lvextend, ext4, active, unmounted, --fs resize
+lvextend --fs resize -L+10M $vg/$lv
+check lv_field $vg/$lv lv_size "50.00m"
+mount "$DM_DEV_DIR/$vg/$lv" "$mount_dir"
+df --output=size "$mount_dir" |tee df2
+not diff df1 df2
+umount "$mount_dir"
+
+# lvextend, ext4, active, unmounted, --fs resize_fsadm
+lvextend --fs resize_fsadm -L+10M $vg/$lv
+check lv_field $vg/$lv lv_size "60.00m"
+mount "$DM_DEV_DIR/$vg/$lv" "$mount_dir"
+df --output=size "$mount_dir" |tee df2
+not diff df1 df2
+umount "$mount_dir"
+
+lvremove -f $vg/$lv
+
+
+####################################################################
+#
+# lvreduce, ext4, no --fs setting and the equivalent --fs checksize
+# i.e. fs is not resized
+#
+####################################################################
+
+# lvreduce, ext4, active, mounted, no --fs setting is same as --fs checksize
+# fs smaller than the reduced size
+lvcreate -n $lv -L 20M $vg
+mkfs.ext4 "$DM_DEV_DIR/$vg/$lv"
+lvextend -L+25M $vg/$lv
+mount "$DM_DEV_DIR/$vg/$lv" "$mount_dir"
+dd if=/dev/zero of="$mount_dir/zeros1" bs=1M count=10 oflag=direct
+df --output=size "$mount_dir" |tee df1
+# fs is 20M, reduced size is 27M, so no fs reduce is needed
+# todo: check that resize2fs was not run?
+lvreduce -L27M $vg/$lv
+check lv_field $vg/$lv lv_size "27.00m"
+df --output=size "$mount_dir" |tee df2
+# fs size unchanged
+diff df1 df2
+# keep fs mounted
+
+# lvreduce, ext4, active, mounted, no --fs setting is same as --fs checksize
+# fs equal to the reduced size
+lvreduce -L20M $vg/$lv
+check lv_field $vg/$lv lv_size "20.00m"
+df --output=size "$mount_dir" |tee df2
+# fs size unchanged
+diff df1 df2
+# keep fs mounted
+
+# lvreduce, ext4, active, mounted, no --fs setting is same as --fs checksize
+# fs larger than the reduced size, fs not using reduced space
+# lvreduce fails because fs needs to be reduced and checksize does not resize
+not lvreduce -L-18M $vg/$lv
+check lv_field $vg/$lv lv_size "20.00m"
+df --output=size "$mount_dir" |tee df2
+# fs size unchanged
+diff df1 df2
+# keep fs mounted
+
+# lvreduce, ext4, active, mounted, no --fs setting is same as --fs checksize
+# fs larger than the reduced size, fs is using reduced space
+not lvreduce -L-5M $vg/$lv
+check lv_field $vg/$lv lv_size "20.00m"
+df --output=size "$mount_dir" |tee df2
+# fs size unchanged
+diff df1 df2
+umount "$mount_dir"
+
+lvremove -f $vg/$lv
+
+
+############################################################
+#
+# repeat lvreduce tests with unmounted instead of mounted fs
+#
+############################################################
+
+# lvreduce, ext4, active, unmounted, no --fs setting is same as --fs checksize
+# fs smaller than the reduced size
+lvcreate -n $lv -L 20M $vg
+mkfs.ext4 "$DM_DEV_DIR/$vg/$lv"
+lvextend -L+25M $vg/$lv
+mount "$DM_DEV_DIR/$vg/$lv" "$mount_dir"
+dd if=/dev/zero of="$mount_dir/zeros1" bs=1M count=10 oflag=direct
+df --output=size "$mount_dir" |tee df1
+umount "$mount_dir"
+# fs is 20M, reduced size is 27M, so no fs reduce is needed
+lvreduce -L27M $vg/$lv
+check lv_field $vg/$lv lv_size "27.00m"
+
+# lvreduce, ext4, active, unmounted, no --fs setting is same as --fs checksize
+# fs equal to the reduced size
+# fs is 20M, reduced size is 20M, so no fs reduce is needed
+lvreduce -L20M $vg/$lv
+check lv_field $vg/$lv lv_size "20.00m"
+mount "$DM_DEV_DIR/$vg/$lv" "$mount_dir"
+df --output=size "$mount_dir" |tee df2
+# fs size unchanged
+diff df1 df2
+umount "$mount_dir"
+
+
+# lvreduce, ext4, active, unmounted, no --fs setting is same as --fs checksize
+# fs larger than the reduced size, fs not using reduced space
+# lvreduce fails because fs needs to be reduced and checksize does not resize
+not lvreduce -L-5M $vg/$lv
+
+# lvreduce, ext4, active, unmounted, no --fs setting is same as --fs checksize
+# fs larger than the reduced size, fs is using reduced space
+# lvreduce fails because fs needs to be reduced and checksize does not resize
+not lvreduce -L-10M $vg/$lv
+
+check lv_field $vg/$lv lv_size "20.00m"
+mount "$DM_DEV_DIR/$vg/$lv" "$mount_dir"
+df --output=size "$mount_dir" |tee df2
+# fs size unchanged
+diff df1 df2
+umount "$mount_dir"
+
+lvremove -f $vg
+
+
+#########################################################################
+#
+# repeat a couple prev lvreduce that had no --fs setting,
+# now using --fs checksize to verify it's the same as using no --fs set
+#
+#########################################################################
+
+# lvreduce, ext4, active, mounted, --fs checksize (same as no --fs set)
+# fs larger than the reduced size, fs not using reduced space
+lvcreate -n $lv -L 100M $vg
+mkfs.ext4 "$DM_DEV_DIR/$vg/$lv"
+mount "$DM_DEV_DIR/$vg/$lv" "$mount_dir"
+dd if=/dev/zero of="$mount_dir/zeros1" bs=1M count=20 oflag=direct
+df --output=size "$mount_dir" |tee df1
+# lvreduce fails because fs needs to be reduced and checksize does not resize
+not lvreduce --fs checksize -L-50M $vg/$lv
+check lv_field $vg/$lv lv_size "100.00m"
+df --output=size "$mount_dir" |tee df2
+# fs size unchanged
+diff df1 df2
+umount "$mount_dir"
+
+# lvreduce, ext4, active, unmounted, --fs checksize (same as no --fs set)
+# fs smaller than the reduced size
+lvextend -L+50M $vg/$lv
+mount "$DM_DEV_DIR/$vg/$lv" "$mount_dir"
+df --output=size "$mount_dir" |tee df1
+umount "$mount_dir"
+
+# fs is 100M, reduced size is 120M, so no fs reduce is needed
+lvreduce --fs checksize -L120M $vg/$lv
+check lv_field $vg/$lv lv_size "120.00m"
+mount "$DM_DEV_DIR/$vg/$lv" "$mount_dir"
+df --output=size "$mount_dir" |tee df2
+# fs size unchanged
+diff df1 df2
+umount "$mount_dir"
+lvchange -an $vg/$lv
+
+# lvreduce with inactive and no --fs setting fails because
+# default behavior is fs checksize which activates the LV
+# and sees the fs
+
+# lvreduce, ext4, inactive, no --fs setting same as --fs checksize
+# fs larger than the reduced size, fs not using reduced space
+# lvreduce fails because default is --fs checksize which sees the fs
+not lvreduce -L-100M $vg/$lv
+check lv_field $vg/$lv lv_size "120.00m"
+
+lvremove -f $vg/$lv
+
+
+#################################
+#
+# lvreduce, ext4, --fs resize*
+#
+#################################
+
+# lvreduce, ext4, active, mounted, --fs resize
+# fs larger than the reduced size, fs not using reduced space
+lvcreate -n $lv -L 50M $vg
+mkfs.ext4 "$DM_DEV_DIR/$vg/$lv"
+mount "$DM_DEV_DIR/$vg/$lv" "$mount_dir"
+dd if=/dev/zero of="$mount_dir/zeros1" bs=1M count=10 oflag=direct
+df --output=size "$mount_dir" |tee df1
+# lvreduce runs resize2fs to shrink the fs
+lvreduce --yes --fs resize -L-20M $vg/$lv
+check lv_field $vg/$lv lv_size "30.00m"
+ls -l $mount_dir/zeros1
+df --output=size "$mount_dir" |tee df2
+# fs size is changed
+not diff df1 df2
+
+# lvreduce, ext4, active, mounted, --fs resize
+# fs larger than the reduced size, fs is using reduced space
+# lvreduce runs resize2fs to shrink the fs but resize2fs fails
+# the fs is not remounted after resize2fs fails because the
+# resize failure might leave the fs in an unknown state
+not lvreduce --yes --fs resize -L-15M $vg/$lv
+check lv_field $vg/$lv lv_size "30.00m"
+mount "$DM_DEV_DIR/$vg/$lv" "$mount_dir"
+ls -l $mount_dir/zeros1
+df --output=size "$mount_dir" |tee df3
+# fs size is unchanged
+diff df2 df3
+umount "$mount_dir"
+
+lvremove -f $vg/$lv
+
+
+############################################
+#
+# repeat with unmounted instead of mounted
+#
+############################################
+
+# lvreduce, ext4, active, unmounted, --fs resize
+# fs larger than the reduced size, fs not using reduced space
+lvcreate -n $lv -L 50M $vg
+mkfs.ext4 "$DM_DEV_DIR/$vg/$lv"
+mount "$DM_DEV_DIR/$vg/$lv" "$mount_dir"
+dd if=/dev/zero of="$mount_dir/zeros1" bs=1M count=10 oflag=direct
+df --output=size "$mount_dir" |tee df1
+umount "$mount_dir"
+# lvreduce runs resize2fs to shrink the fs
+lvreduce --fs resize -L-20M $vg/$lv
+check lv_field $vg/$lv lv_size "30.00m"
+mount "$DM_DEV_DIR/$vg/$lv" "$mount_dir"
+ls -l $mount_dir/zeros1
+df --output=size "$mount_dir" |tee df2
+# fs size is changed
+not diff df1 df2
+umount "$mount_dir"
+
+# lvreduce, ext4, active, unmounted, --fs resize
+# fs larger than the reduced size, fs is using reduced space
+# lvreduce runs resize2fs to shrink the fs but resize2fs fails
+not lvreduce --yes --fs resize -L-10M $vg/$lv
+check lv_field $vg/$lv lv_size "30.00m"
+mount "$DM_DEV_DIR/$vg/$lv" "$mount_dir"
+ls -l $mount_dir/zeros1
+df --output=size "$mount_dir" |tee df3
+# fs size is unchanged
+diff df2 df3
+umount "$mount_dir"
+lvchange -an $vg/$lv
+lvremove $vg/$lv
+
+
+##################################################################
+#
+# repeat resizes that shrink the fs, replacing --fs resize with
+# --fs resize --fsmode nochange|offline, --fs resize_fsadm.
+# while mounted and unmounted
+#
+##################################################################
+
+# lvreduce, ext4, active, mounted, --fs resize --fsmode nochange
+# fs larger than the reduced size, fs not using reduced space
+lvcreate -n $lv -L 90M $vg
+mkfs.ext4 "$DM_DEV_DIR/$vg/$lv"
+mount "$DM_DEV_DIR/$vg/$lv" "$mount_dir"
+dd if=/dev/zero of="$mount_dir/zeros1" bs=1M count=10 oflag=direct
+df --output=size "$mount_dir" |tee df1
+# lvreduce needs to unmount to run resize2fs but fsmode nochange doesn't let it
+not lvreduce --fs resize --fsmode nochange -L-10M $vg/$lv
+check lv_field $vg/$lv lv_size "90.00m"
+df --output=size "$mount_dir" |tee df2
+# fs size is unchanged
+diff df1 df2
+umount "$mount_dir"
+
+# lvreduce, ext4, active, unmounted, --fs resize --fsmode nochange
+# fs larger than the reduced size, fs not using reduced space
+# lvreduce runs resize2fs to shrink the fs
+lvreduce --fs resize --fsmode nochange -L-10M $vg/$lv
+check lv_field $vg/$lv lv_size "80.00m"
+mount "$DM_DEV_DIR/$vg/$lv" "$mount_dir"
+df --output=size "$mount_dir" |tee df3
+# fs size is changed
+not diff df2 df3
+# keep fs mounted
+
+# lvreduce, ext4, active, mounted, --fs resize --fsmode offline
+# fs larger than the reduced size, fs not using reduced space
+# lvreduce runs resize2fs to shrink the fs
+# fsmode offline leaves the fs unmounted
+lvreduce --fs resize --fsmode offline -L-10M $vg/$lv
+check lv_field $vg/$lv lv_size "70.00m"
+mount "$DM_DEV_DIR/$vg/$lv" "$mount_dir"
+df --output=size "$mount_dir" |tee df4
+# fs size is changed
+not diff df3 df4
+umount "$mount_dir"
+
+# lvreduce, ext4, active, unmounted, --fs resize --fsmode offline
+# fs larger than the reduced size, fs not using reduced space
+# lvreduce runs resize2fs to shrink the fs
+lvreduce --fs resize --fsmode offline -L-10M $vg/$lv
+check lv_field $vg/$lv lv_size "60.00m"
+mount "$DM_DEV_DIR/$vg/$lv" "$mount_dir"
+df --output=size "$mount_dir" |tee df5
+# fs size is changed
+not diff df4 df5
+# keep fs mounted
+
+# lvreduce, ext4, active, mounted, --fs resize_fsadm
+# fs larger than the reduced size, fs not using reduced space
+# lvreduce runs resize2fs to shrink the fs
+lvreduce --yes --fs resize_fsadm -L-10M $vg/$lv
+check lv_field $vg/$lv lv_size "50.00m"
+ls -l $mount_dir/zeros1
+df --output=size "$mount_dir" |tee df6
+# fs size is changed
+not diff df5 df6
+umount "$mount_dir"
+
+# lvreduce, ext4, active, unmounted, --fs resize_fsadm
+# fs larger than the reduced size, fs not using reduced space
+# lvreduce runs resize2fs to shrink the fs
+lvreduce --fs resize_fsadm -L-10M $vg/$lv
+check lv_field $vg/$lv lv_size "40.00m"
+mount "$DM_DEV_DIR/$vg/$lv" "$mount_dir"
+df --output=size "$mount_dir" |tee df7
+# fs size is changed
+not diff df6 df7
+umount "$mount_dir"
+
+
+vgremove -ff $vg
diff --git a/test/shell/lvresize-full.sh b/test/shell/lvresize-full.sh
new file mode 100644
index 0000000..fe39f45
--- /dev/null
+++ b/test/shell/lvresize-full.sh
@@ -0,0 +1,78 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2016 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+# Excersize resize of filesystem when size of LV already matches
+# https://bugzilla.redhat.com/1354396
+
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+FSCK=${FSCK-fsck}
+MKFS=${MKFS-mkfs.ext3}
+RESIZEFS=${RESIZEFS-resize2fs}
+
+which $FSCK || skip
+which $MKFS || skip
+which $RESIZEFS || skip
+
+aux prepare_vg 2 20
+
+lvcreate -l100%FREE -n $lv1 $vg
+
+lvdev="$DM_DEV_DIR/$vg/$lv1"
+
+lvs -a $vg
+
+"$MKFS" "$lvdev"
+
+# this should resolve to resize to same actual size
+not lvreduce -l-100%FREE $vg/$lv1
+not lvreduce -r -f -l-100%FREE $vg/$lv1
+"$FSCK" -n "$lvdev"
+
+# size should remain the same
+# lvresize fails with same result with or without -r
+not lvextend -l+100%FREE $vg/$lv1
+not lvextend -r -f -l+100%FREE $vg/$lv1
+"$FSCK" -n "$lvdev"
+
+#lvchange -an $vg/$lv1
+not lvresize -l+100%FREE $vg/$lv1
+not lvresize -r -f -l+100%FREE $vg/$lv1
+"$FSCK" -n "$lvdev"
+
+# Check there is really file system resize happening
+# even when LV itself has still the same size
+"$RESIZEFS" -f "$lvdev" 20000
+"$FSCK" -n "$lvdev" | tee out
+grep "20000 blocks" out
+
+SIZE=$(get lv_field $vg/$lv1 size)
+not lvresize -l-100%FREE $vg/$lv1
+not lvresize -r -f -l-100%FREE $vg/$lv1
+test "$SIZE" = "$(get lv_field $vg/$lv1 size)"
+
+"$FSCK" -n "$lvdev" | tee out
+grep -v "20000 blocks" out
+
+
+# Also check it fails when the user 'resize' volume without
+# resizing fs and then retries with '-r'.
+# The first lvreduce intentionally ignores the fs and intentionally
+# corrupts the fs so that the second lvresize will fail when it runs
+# fsck.
+lvreduce -f --fs ignore -l50%VG $vg/$lv1
+fail lvresize -r -f -l20%VG $vg/$lv1
+
+lvremove -ff $vg
diff --git a/test/shell/lvresize-mirror.sh b/test/shell/lvresize-mirror.sh
index a10f7cd..ee23f7f 100644
--- a/test/shell/lvresize-mirror.sh
+++ b/test/shell/lvresize-mirror.sh
@@ -1,4 +1,5 @@
-#!/bin/sh
+#!/usr/bin/env bash
+
# Copyright (C) 2010 Red Hat, Inc. All rights reserved.
#
# This copyrighted material is made available to anyone wishing to use,
@@ -7,33 +8,42 @@
#
# 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
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+
+SKIP_WITH_LVMPOLLD=1
-. lib/test
+. lib/inittest
-aux prepare_vg 5 80
+aux prepare_vg 5
+
+for deactivate in true false; do
# 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
+ lvcreate -aye -l2 --type mirror -m1 -n $lv1 $vg "$dev1" "$dev2" "$dev3":0-1
+
+ test $deactivate && lvchange -an $vg/$lv1
+
+ lvextend -l+2 $vg/$lv1
+ check mirror $vg $lv1 "$dev3"
+ check mirror_images_contiguous $vg $lv1
# 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
+ lvreduce -f --fs ignore -l-2 $vg/$lv1
+ check mirror $vg $lv1 "$dev3"
# 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
+ lvcreate -aye -l2 --type mirror -m1 -n $lv2 $vg "$dev1" "$dev2" "$dev3":0-1
+ lvcreate -l1 -n $lv3 $vg "$dev1"
+ lvcreate -l1 -n $lv4 $vg "$dev2"
+
+ test $deactivate && lvchange -an $vg/$lv2
+
+ lvextend -l+2 $vg/$lv2
+ check mirror $vg $lv2 "$dev3"
+ check mirror_images_clung $vg $lv2
+
+ lvremove -ff $vg
+done
+
+vgremove -ff $vg
diff --git a/test/shell/lvresize-raid.sh b/test/shell/lvresize-raid.sh
index f999a31..4260de8 100644
--- a/test/shell/lvresize-raid.sh
+++ b/test/shell/lvresize-raid.sh
@@ -1,5 +1,6 @@
-#!/bin/sh
-# Copyright (C) 2012 Red Hat, Inc. All rights reserved.
+#!/usr/bin/env bash
+
+# Copyright (C) 2012,2017 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
@@ -7,74 +8,68 @@
#
# 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
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
-. lib/test
-aux target_at_least dm-raid 1 1 0 || skip
+SKIP_WITH_LVMPOLLD=1
-aux prepare_vg 5 80
+. lib/inittest
-# Extend a 2-way RAID1
-for deactivate in true false; do
- lvcreate --type raid1 -m 1 -l 2 -n $lv1 $vg
+aux have_raid 1 3 0 || skip
- if $deactivate; then
- lvchange -an $vg/$lv1
- fi
+levels="5 6 10"
+aux have_raid4 && levels="4 $levels"
+aux have_raid 1 7 0 && levels="0 0_meta $levels"
- lvresize -l +2 $vg/$lv1
+aux prepare_pvs 6
+get_devs
- #check raid_images_contiguous $vg $lv1
+vgcreate $SHARED -s 256K "$vg" "${DEVICES[@]}"
- 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
+# Extend and reduce a 2-way RAID1
+ lvcreate --type raid1 -m 1 -l 2 -n $lv1 $vg
+
+ test $deactivate && {
+ aux wait_for_sync $vg $lv1
lvchange -an $vg/$lv1
- fi
+ }
+
+ lvresize -l +2 $vg/$lv1
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
+# Extend and reduce 3-striped RAID 4/5/6/10
+ for i in $levels ; do
+ lvcreate --type raid$i -i 3 -l 3 -n $lv2 $vg
+ check lv_field $vg/$lv2 "seg_size" "768.00k"
- if $deactivate; then
- lvchange -an $vg/$lv1
- fi
+ test $deactivate && {
+ aux wait_for_sync $vg $lv2
+ lvchange -an $vg/$lv2
+ }
- lvresize -l +3 $vg/$lv1
+ lvresize -l +3 $vg/$lv2
+ check lv_field $vg/$lv2 "seg_size" "1.50m"
#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
+ should lvresize -y -l -3 $vg/$lv2
+ should check lv_field $vg/$lv2 "seg_size" "768.00k"
#check raid_images_contiguous $vg $lv1
lvremove -ff $vg
done
done
+
+# Bug 1005434
+# Ensure extend is contiguous
+lvcreate --type raid5 -l 2 -i 2 -n $lv1 $vg "$dev4" "$dev5" "$dev6"
+lvextend -l +2 --alloc contiguous $vg/$lv1
+check lv_tree_on $vg $lv1 "$dev4" "$dev5" "$dev6"
+
+vgremove -f $vg
diff --git a/test/shell/lvresize-raid10.sh b/test/shell/lvresize-raid10.sh
index 9b71708..e28b684 100644
--- a/test/shell/lvresize-raid10.sh
+++ b/test/shell/lvresize-raid10.sh
@@ -1,4 +1,5 @@
-#!/bin/sh
+#!/usr/bin/env bash
+
# Copyright (C) 2012 Red Hat, Inc. All rights reserved.
#
# This copyrighted material is made available to anyone wishing to use,
@@ -7,36 +8,28 @@
#
# 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
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
-. lib/test
-aux target_at_least dm-raid 1 3 0 || skip
+SKIP_WITH_LVMPOLLD=1
-aux prepare_vg 5 80
+. lib/inittest
+
+aux have_raid 1 3 0 || skip
+
+aux prepare_vg 5
-# Extend RAID10 (2-stripes, 2-mirror)
for deactivate in true false; do
+# Extend RAID10 (2-stripes, 2-mirror)
lvcreate --type raid10 -m 1 -i 2 -l 2 -n $lv1 $vg
- if $deactivate; then
- lvchange -an $vg/$lv1
- fi
+ test $deactivate && lvchange -an $vg/$lv1
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
diff --git a/test/shell/lvresize-rounding.sh b/test/shell/lvresize-rounding.sh
index ad8d9c0..52bedb4 100644
--- a/test/shell/lvresize-rounding.sh
+++ b/test/shell/lvresize-rounding.sh
@@ -1,4 +1,5 @@
-#!/bin/sh
+#!/usr/bin/env bash
+
# Copyright (C) 2007-2012 Red Hat, Inc. All rights reserved.
#
# This copyrighted material is made available to anyone wishing to use,
@@ -7,59 +8,60 @@
#
# 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
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+
+SKIP_WITH_LVMPOLLD=1
-. lib/test
+. lib/inittest
aux prepare_pvs 3 22
+get_devs
-vgcreate -s 32K $vg "$dev1" "$dev2" "$dev3"
+vgcreate $SHARED -s 32K "$vg" "${DEVICES[@]}"
-lvcreate -l4 -i3 -I64 $vg
+lvcreate -an -Zn -l4 -i3 -I64 $vg
-lvcreate -l8 -i2 -I64 $vg
+lvcreate -an -Zn -l8 -i2 -I64 $vg
-lvcreate -l16 $vg
+lvcreate -an -Zn -l16 $vg
-lvcreate -l32 -i3 -I64 -n $lv1 $vg
+lvcreate -an -Zn -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
+export LVM_TEST_AUX_TRACE=yes
aux prepare_vg 3 22
+unset LVM_TEST_AUX_TRACE
# Block some extents
-lvcreate -l4 -i3 $vg
-lvcreate -l1 $vg
+lvcreate -an -Zn -l4 -i3 $vg
+lvcreate -an -Zn -l1 $vg
-lvcreate -l100%FREE -n $lv1 -i3 $vg
+lvcreate -an -Zn -l100%FREE -n $lv1 -i3 $vg
check vg_field $vg vg_free_count 2
lvremove -f $vg/$lv1
-lvcreate -l1 -n $lv1 -i3 $vg
+lvcreate -an -Zn -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
+lvreduce -f --fs ignore -l50%LV $vg/$lv1
vgremove -f $vg
-
-vgcreate -s 4M $vg "$dev1" "$dev2" "$dev3"
+vgcreate $SHARED -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
+lvcreate -an -Zn -l10 -n lv -i3 $vg
check vg_field $vg vg_free_count 3
# Should want 16 extents
@@ -70,21 +72,21 @@ 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
+lvreduce -f --fs ignore -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
+lvreduce -f --fs ignore -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
+not lvreduce -f --fs ignore -l-10%LV $vg/lv
check vg_field $vg vg_free_count 0
-lvreduce -f -l-20%LV $vg/lv
+lvreduce -f --fs ignore -l-20%LV $vg/lv
check vg_field $vg vg_free_count 3
diff --git a/test/shell/lvresize-thin-external-origin.sh b/test/shell/lvresize-thin-external-origin.sh
new file mode 100644
index 0000000..6dbfe4a
--- /dev/null
+++ b/test/shell/lvresize-thin-external-origin.sh
@@ -0,0 +1,60 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2014 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+# Test resize of thin volume with external origin
+
+SKIP_WITH_LVMLOCKD=1
+SKIP_WITH_LVMPOLLD=1
+
+export LVM_TEST_THIN_REPAIR_CMD=${LVM_TEST_THIN_REPAIR_CMD-/bin/false}
+
+. lib/inittest
+
+aux have_thin 1 2 0 || skip
+
+# Pretend we miss the external_origin_extend feature
+aux lvmconf 'global/thin_disabled_features = [ "external_origin_extend" ]'
+
+aux prepare_vg 2
+
+lvcreate -L10 -n $lv1 $vg
+
+# Prepare thin pool
+lvcreate -L20 -T $vg/pool
+
+# Convert $lv1 into thin LV with external origin
+lvconvert -T $vg/$lv1 --thinpool $vg/pool --originname ext
+
+lvs -a $vg
+
+# Bigger size is not supported without feature external_origin_extend
+not lvresize -L+10 $vg/$lv1
+
+# But reduction works
+lvresize -L-5 -f $vg/$lv1
+check lv_field $vg/$lv1 lv_size "5.00" --units m --nosuffix
+
+# Inactive LV cannot be resized as well
+lvchange -an $vg
+not lvresize -L+15 -y $vg/$lv1
+check lv_field $vg/$lv1 lv_size "5.00" --units m --nosuffix
+lvchange -ay $vg/$lv1
+
+not lvresize -L+15 -y $vg/$lv1
+check lv_field $vg/$lv1 lv_size "5.00" --units m --nosuffix
+
+
+# Try to resize again back up to the size of external origin
+lvresize -L+5 -f $vg/$lv1
+check lv_field $vg/$lv1 lv_size "10.00" --units m --nosuffix
+
+vgremove -ff $vg
diff --git a/test/shell/lvresize-thin-metadata.sh b/test/shell/lvresize-thin-metadata.sh
new file mode 100644
index 0000000..f27934b
--- /dev/null
+++ b/test/shell/lvresize-thin-metadata.sh
@@ -0,0 +1,49 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2013-2014 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+
+SKIP_WITH_LVMPOLLD=1
+
+export LVM_TEST_THIN_REPAIR_CMD=${LVM_TEST_THIN_REPAIR_CMD-/bin/false}
+
+. lib/inittest
+
+aux have_thin 1 10 0 || skip
+
+aux prepare_vg 3 1256
+
+for deactivate in true false; do
+# Create some thin volumes
+ lvcreate -L20 -V30 -n $lv1 -T $vg/pool
+ lvcreate -s $vg/$lv1
+# Confirm we have basic 2M metadata
+ check lv_field $vg/pool_tmeta size "2.00m"
+
+ test $deactivate && lvchange -an $vg
+
+ lvresize --poolmetadatasize +2M $vg/pool
+# Test it's been resized to 4M
+ check lv_field $vg/pool_tmeta size "4.00m"
+
+ lvresize --poolmetadatasize +256M $vg/pool
+ check lv_field $vg/pool_tmeta size "260.00m"
+
+ lvresize --poolmetadatasize +3G $vg/pool
+ check lv_field $vg/pool_tmeta size "3.25g"
+
+ vgchange -an $vg
+ vgchange -ay $vg
+
+# TODO: Add more tests
+
+ lvremove -ff $vg
+done
diff --git a/test/shell/lvresize-usage.sh b/test/shell/lvresize-usage.sh
index 51ef221..a7e1544 100644
--- a/test/shell/lvresize-usage.sh
+++ b/test/shell/lvresize-usage.sh
@@ -1,5 +1,6 @@
-#!/bin/sh
-# Copyright (C) 2007-2008 Red Hat, Inc. All rights reserved.
+#!/usr/bin/env bash
+
+# Copyright (C) 2007-2016 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
@@ -7,15 +8,53 @@
#
# 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
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
-. lib/test
+SKIP_WITH_LVMPOLLD=1
-aux prepare_vg 2
+. lib/inittest
+
+aux prepare_vg 2 80
lvcreate -L 10M -n lv -i2 $vg
lvresize -l +4 $vg/lv
+not lvextend -L+0 $vg/lv
+not lvextend -l+0 $vg/lv
lvremove -ff $vg
lvcreate -L 64M -n $lv -i2 $vg
not lvresize -v -l +4 xxx/$lv
+
+# Check stripe size is reduced to extent size when it's bigger
+ESIZE=$(get vg_field $vg vg_extent_size --units b)
+lvextend -L+64m -i 2 -I$(( ${ESIZE%%B} * 2 ))B $vg/$lv 2>&1 | tee err
+grep "Reducing stripe size" err
+
+lvremove -ff $vg
+
+lvcreate -L 10M -n lv $vg "$dev1"
+lvextend -L +10M $vg/lv "$dev2"
+lvextend --type striped -m0 -L +10M $vg/lv "$dev2"
+
+# Attempt to reduce with lvextend and vice versa:
+not lvextend -L 16M $vg/lv
+not lvreduce -L 32M $vg/lv
+
+lvremove -ff $vg
+
+lvcreate --type mirror -aey -L 4 -n $lv1 $vg
+# Incorrent name for resized LV
+not lvextend --type mirror -L 10 -n $lv1 $vg
+# Same size
+not lvextend --type mirror -L 4 $vg/$lv1
+# Cannot use any '-' or '+' sign for --mirror arg
+not lvextend --type mirror -L+2 -m-1 $vg/$lv1
+not lvextend --type mirror -L+2 -m+1 $vg/$lv1
+
+lvextend --type mirror -L+4 -m1 $vg/$lv1
+
+lvs -a $vg
+check lv_field $vg/$lv1 size "8.00m"
+
+lvremove -ff $vg
diff --git a/test/shell/lvresize-vdo.sh b/test/shell/lvresize-vdo.sh
new file mode 100644
index 0000000..cbe8ce9
--- /dev/null
+++ b/test/shell/lvresize-vdo.sh
@@ -0,0 +1,50 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2019 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+# Test resize of VDO volumes
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+aux have_vdo 6 2 0 || skip
+
+aux lvmconf 'allocation/vdo_slab_size_mb = 128'
+
+aux prepare_vg 1 7000
+lvcreate --vdo -V3G -L4G -n $lv1 $vg/$lv2
+
+# Resize data volume
+lvresize -L6G $vg/$lv2
+check lv_field $vg/$lv2 size "6.00g"
+check lv_field $vg/${lv2}_vdata size "6.00g"
+
+# Resize virtual volume on top of VDO
+lvresize -L6G $vg/$lv1
+check lv_field $vg/$lv1 size "6.00g"
+
+# Check too large size
+not lvresize -L4P $vg/$lv1 2>err
+grep "Volume too large" err
+
+# Can't resize inactive VDO
+lvchange -an $vg
+not lvresize -L10G $vg/$lv1 2>err
+grep "Cannot resize inactive" err
+
+not lvresize -L10G $vg/$lv2 2>err
+grep "Cannot resize inactive" err
+
+not lvresize -L10G $vg/${lv2}_vdata 2>err
+grep "Cannot resize inactive" err
+
+vgremove -ff $vg
diff --git a/test/shell/lvresize-xfs.sh b/test/shell/lvresize-xfs.sh
new file mode 100644
index 0000000..7f31939
--- /dev/null
+++ b/test/shell/lvresize-xfs.sh
@@ -0,0 +1,306 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2023 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+aux prepare_vg 1 500
+
+which mkfs.xfs || skip
+which xfs_growfs || skip
+
+mount_dir="mnt_lvresize_fs"
+mkdir -p "$mount_dir"
+
+mount_dir_space="other mnt dir"
+mkdir -p "$mount_dir_space"
+
+
+# Test combinations of the following:
+# lvreduce / lvextend
+# xfs
+# each --fs opt / no --fs opt / --resizefs
+# active / inactive
+# mounted / unmounted
+# fs size less than, equal to or greater than reduced lv size
+
+#################
+#
+# lvextend, xfs
+#
+#################
+
+# lvextend, xfs, active, mounted, no --fs setting is same as --fs ignore
+lvcreate -n $lv -L 300M $vg
+mkfs.xfs "$DM_DEV_DIR/$vg/$lv"
+mount "$DM_DEV_DIR/$vg/$lv" "$mount_dir"
+
+# --fs tests require a libblkid version that shows FSLASTBLOCK
+# so exit 0 test here, if the feature is not present
+blkid -p "$DM_DEV_DIR/$vg/$lv" | grep FSLASTBLOCK || skip
+
+df --output=size "$mount_dir" |tee df1
+dd if=/dev/zero of="$mount_dir/zeros1" bs=1M count=10 oflag=direct
+lvextend -L+20M $vg/$lv
+check lv_field $vg/$lv lv_size "320.00m"
+# with no --fs used, the fs size should be the same
+df --output=size "$mount_dir" |tee df2
+diff df1 df2
+xfs_growfs "$DM_DEV_DIR/$vg/$lv"
+df --output=size "$mount_dir" |tee df3
+not diff df2 df3
+dd if=/dev/zero of="$mount_dir/zeros2" bs=1M count=20 oflag=direct
+# keep it mounted
+
+# lvextend, xfs, active, mounted, --fs ignore
+df --output=size "$mount_dir" |tee df1
+lvextend --fs ignore -L+20 $vg/$lv
+check lv_field $vg/$lv lv_size "340.00m"
+df --output=size "$mount_dir" |tee df2
+diff df1 df2
+
+# lvextend, xfs, active, mounted, --fs resize
+lvextend --fs resize -L+20M $vg/$lv
+check lv_field $vg/$lv lv_size "360.00m"
+df --output=size "$mount_dir" |tee df3
+not diff df2 df3
+
+# lvextend, xfs, active, mounted, --resizefs (same as --fs resize)
+lvextend --resizefs -L+10M $vg/$lv
+check lv_field $vg/$lv lv_size "370.00m"
+df --output=size "$mount_dir" |tee df4
+not diff df3 df4
+
+# lvextend, xfs, active, mounted, --fs resize --fsmode manage (same as --fs resize)
+lvextend --fs resize --fsmode manage -L+10M $vg/$lv
+check lv_field $vg/$lv lv_size "380.00m"
+df --output=size "$mount_dir" |tee df2
+not diff df1 df2
+
+umount "$mount_dir"
+lvchange -an $vg/$lv
+
+# lvextend, xfs, inactive, --fs ignore
+lvextend --fs ignore -L+20M $vg/$lv
+check lv_field $vg/$lv lv_size "400.00m"
+
+lvremove -f $vg/$lv
+
+####################
+# start with new fs
+####################
+
+# lvextend, xfs, active, mounted, --fs resize --fsmode offline
+lvcreate -n $lv -L 300M $vg
+mkfs.xfs "$DM_DEV_DIR/$vg/$lv"
+mount "$DM_DEV_DIR/$vg/$lv" "$mount_dir_space"
+df --output=size "$mount_dir_space" |tee df1
+dd if=/dev/zero of="$mount_dir_space/zeros1" bs=1M count=20 oflag=direct
+# xfs_growfs requires the fs to be mounted, so extending the lv is
+# succeeds, then the xfs extend fails because it cannot be done unmounted
+not lvextend --fs resize --fsmode offline -L+20M $vg/$lv
+check lv_field $vg/$lv lv_size "320.00m"
+df -a | tee dfa
+grep "$mount_dir_space" dfa
+df --output=size "$mount_dir_space" |tee df2
+# fs not extended so fs size not changed
+diff df1 df2
+
+# lvextend, xfs, active, mounted, --fs resize --fsmode nochange
+lvextend --fs resize --fsmode nochange -L+20M $vg/$lv
+check lv_field $vg/$lv lv_size "340.00m"
+df --output=size "$mount_dir_space" |tee df2
+not diff df1 df2
+
+# lvextend, xfs, active, mounted, --fs resize_fsadm
+lvextend --fs resize_fsadm -L+20M $vg/$lv
+check lv_field $vg/$lv lv_size "360.00m"
+df --output=size "$mount_dir_space" |tee df3
+not diff df2 df3
+umount "$mount_dir_space"
+
+# lvextend, xfs, active, unmounted, --fs resize --fsmode nochange
+# xfs_growfs requires the fs to be mounted to grow, so --fsmode nochange
+# with an unmounted fs fails
+not lvextend --fs resize --fsmode nochange -L+20M $vg/$lv
+check lv_field $vg/$lv lv_size "380.00m"
+mount "$DM_DEV_DIR/$vg/$lv" "$mount_dir_space"
+df --output=size "$mount_dir_space" |tee df4
+# fs not extended so fs size not changed
+diff df3 df4
+umount "$mount_dir_space"
+
+# lvextend, xfs, active, unmounted, --fs resize
+# --yes needed because mount changes are required and plain "resize"
+# fsopt did not specify if the user wants to change mount state
+lvextend --yes --fs resize -L+10M $vg/$lv
+check lv_field $vg/$lv lv_size "390.00m"
+mount "$DM_DEV_DIR/$vg/$lv" "$mount_dir_space"
+df --output=size "$mount_dir_space" |tee df5
+not diff df4 df5
+umount "$mount_dir_space"
+
+# lvextend, xfs, active, unmounted, --fs resize_fsadm
+lvextend --fs resize_fsadm -L+10M $vg/$lv
+check lv_field $vg/$lv lv_size "400.00m"
+mount "$DM_DEV_DIR/$vg/$lv" "$mount_dir_space"
+df --output=size "$mount_dir_space" |tee df6
+not diff df5 df6
+umount "$mount_dir_space"
+lvremove -f $vg/$lv
+
+
+#################################################
+#
+# lvreduce, xfs (xfs does not support shrinking)
+#
+##################################################
+
+# lvreduce, xfs, active, mounted, no --fs setting is same as --fs checksize
+# fs smaller than the reduced size
+lvcreate -n $lv -L 300M $vg
+mkfs.xfs "$DM_DEV_DIR/$vg/$lv"
+lvextend -L+100M $vg/$lv
+mount "$DM_DEV_DIR/$vg/$lv" "$mount_dir"
+dd if=/dev/zero of="$mount_dir/zeros1" bs=1M count=20 oflag=direct
+df --output=size "$mount_dir" |tee df1
+# fs is 300M, reduced size is 326M, so no fs reduce is needed
+lvreduce -L326M $vg/$lv
+check lv_field $vg/$lv lv_size "326.00m"
+df --output=size "$mount_dir" |tee df2
+# fs size unchanged
+diff df1 df2
+umount "$mount_dir"
+lvchange -an $vg/$lv
+
+# lvreduce, xfs, inactive, no fs setting is same as --fs checksize
+# fs smaller than the reduced size
+# fs is 200M, reduced size is 216M, so no fs reduce is needed
+lvreduce --fs checksize -L316M $vg/$lv
+check lv_field $vg/$lv lv_size "316.00m"
+lvchange -ay $vg/$lv
+mount "$DM_DEV_DIR/$vg/$lv" "$mount_dir"
+df --output=size "$mount_dir" |tee df2
+# fs size unchanged
+diff df1 df2
+
+# lvreduce, xfs, active, mounted, no --fs setting is same as --fs checksize
+# fs equal to the reduced size
+# fs is 300M, reduced size is 300M, so no fs reduce is needed
+lvreduce -L300M $vg/$lv
+check lv_field $vg/$lv lv_size "300.00m"
+df --output=size "$mount_dir" |tee df2
+# fs size unchanged
+diff df1 df2
+
+# lvreduce, xfs, active, unmounted, no --fs setting is same as --fs checksize
+# fs smaller than the reduced size
+lvextend -L+100M $vg/$lv
+umount "$mount_dir"
+# fs is 300M, reduced size is 316M, so no fs reduce is needed
+lvreduce -L356M $vg/$lv
+check lv_field $vg/$lv lv_size "356.00m"
+mount "$DM_DEV_DIR/$vg/$lv" "$mount_dir"
+df --output=size "$mount_dir" |tee df2
+# fs size unchanged
+diff df1 df2
+
+# lvreduce, xfs, active, mounted, --fs resize
+# fs smaller than the reduced size
+# fs is 300M, reduced size is 316M, so no fs reduce is needed
+lvreduce -L316M $vg/$lv
+check lv_field $vg/$lv lv_size "316.00m"
+df --output=size "$mount_dir" |tee df2
+# fs size unchanged
+diff df1 df2
+umount "$mount_dir"
+lvchange -an $vg/$lv
+
+
+# lvreduce, xfs, inactive, no --fs setting is same as --fs checksize
+# fs equal to the reduced size
+# fs is 300M, reduced size is 300M, so no fs reduce is needed
+lvreduce --fs checksize -L300M $vg/$lv
+check lv_field $vg/$lv lv_size "300.00m"
+lvchange -ay $vg/$lv
+mount "$DM_DEV_DIR/$vg/$lv" "$mount_dir"
+df --output=size "$mount_dir" |tee df2
+# fs size unchanged
+diff df1 df2
+umount "$mount_dir"
+
+lvremove -f $vg/$lv
+
+
+##########################################################
+#
+# lvreduce bigger xfs size (xfs does not support shrinking)
+#
+##########################################################
+
+# lvreduce, xfs, active, mounted, no --fs setting is same as --fs checksize
+# fs larger than the reduced size, fs not using reduced space
+lvcreate -n $lv -L 400M $vg
+mkfs.xfs "$DM_DEV_DIR/$vg/$lv"
+mount "$DM_DEV_DIR/$vg/$lv" "$mount_dir"
+dd if=/dev/zero of="$mount_dir/zeros1" bs=1M count=20 oflag=direct
+df --output=size "$mount_dir" |tee df1
+# lvreduce fails because fs needs to be reduced
+not lvreduce -L-100M $vg/$lv
+check lv_field $vg/$lv lv_size "400.00m"
+df --output=size "$mount_dir" |tee df2
+# fs size unchanged
+diff df1 df2
+# keep fs mounted
+
+# lvreduce, xfs, active, mounted, --fs resize
+# fs larger than the reduced size, fs not using reduced space
+# lvreduce fails because xfs cannot shrink
+not lvreduce --yes --fs resize -L-100M $vg/$lv
+check lv_field $vg/$lv lv_size "400.00m"
+df --output=size "$mount_dir" |tee df2
+# fs size unchanged
+diff df1 df2
+umount "$mount_dir"
+
+# lvreduce, xfs, active, unmounted, --fs resize*
+# fs larger than the reduced size, fs not using reduced space
+# lvreduce fails because xfs cannot shrink
+not lvreduce --yes --fs resize -L-100M $vg/$lv
+check lv_field $vg/$lv lv_size "400.00m"
+not lvreduce --yes --fs resize --fsmode manage -L-100M $vg/$lv
+check lv_field $vg/$lv lv_size "400.00m"
+not lvreduce --yes --fs resize --fsmode nochange -L-100M $vg/$lv
+check lv_field $vg/$lv lv_size "400.00m"
+not lvreduce --yes --fs resize --fsmode offline -L-100M $vg/$lv
+check lv_field $vg/$lv lv_size "400.00m"
+not lvreduce --yes --fs resize_fsadm -L-100M $vg/$lv
+check lv_field $vg/$lv lv_size "400.00m"
+not lvreduce --yes --resizefs -L-100M $vg/$lv
+check lv_field $vg/$lv lv_size "400.00m"
+
+mount "$DM_DEV_DIR/$vg/$lv" "$mount_dir"
+df --output=size "$mount_dir" |tee df2
+# fs size unchanged
+diff df1 df2
+umount "$mount_dir"
+lvchange -an $vg/$lv
+
+# lvreduce, xfs, inactive, no --fs setting is same as --fs checksize
+# fs larger than the reduced size
+# lvreduce fails because fs needs to be reduced
+not lvreduce -L-100M $vg/$lv
+check lv_field $vg/$lv lv_size "400.00m"
+
+vgremove -f $vg
diff --git a/test/shell/lvs-cache.sh b/test/shell/lvs-cache.sh
new file mode 100644
index 0000000..62d45ac
--- /dev/null
+++ b/test/shell/lvs-cache.sh
@@ -0,0 +1,93 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2014 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+# Exercise creation of cache and cache pool volumes
+
+# Full CLI uses --type
+# Shorthand CLI uses -H | --cache
+
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+aux have_cache 1 3 0 || skip
+aux prepare_vg 5 8000
+
+# Use 10M origin size
+lvcreate -aey -L10 -n $lv1 $vg
+lvcreate -H -L5 $vg/$lv1
+
+# replace 10M size with 5M size of cache device
+NEWCLINE=$(dmsetup table $vg-$lv1 | sed 's/20480/10240/')
+dmsetup reload $vg-$lv1 --table "$NEWCLINE"
+dmsetup resume $vg-$lv1
+
+# Check that mismatching cache target is shown by lvs
+lvs -a $vg 2>&1 | grep "WARNING"
+check lv_attr_bit state $vg/$lv1 "X"
+
+lvs -o+lv_active $vg
+
+lvremove -f $vg
+
+
+
+lvcreate --type cache-pool -L10 $vg/cpool
+lvcreate --type cache -l 1 --cachepool $vg/cpool -n corigin $vg
+lvs -o lv_name,cache_policy
+lvs -o lv_name,cache_settings
+
+lvremove -f $vg
+
+lvcreate --type cache-pool -L10 $vg/cpool
+lvcreate --type cache -l 1 --cachepool $vg/cpool -n corigin $vg --cachepolicy mq \
+ --cachesettings migration_threshold=233
+lvs -o lv_name,cache_policy | grep mq
+lvs -o lv_name,cache_settings | grep migration_threshold=233
+
+lvremove -f $vg
+
+lvcreate --type cache-pool -L10 --cachepolicy mq --cachesettings migration_threshold=233 $vg/cpool
+lvcreate --type cache -l 1 --cachepool $vg/cpool -n corigin $vg
+lvs -o lv_name,cache_policy | grep mq
+lvs -o lv_name,cache_settings | grep migration_threshold=233
+
+lvremove -f $vg
+
+lvcreate --type cache-pool -L10 --cachepolicy mq --cachesettings migration_threshold=233 --cachesettings sequential_threshold=13 $vg/cpool
+lvcreate --type cache -l 1 --cachepool $vg/cpool -n corigin $vg
+lvs -o lv_name,cache_policy | grep mq
+lvs -a -o lv_name,cache_policy -S 'cache_policy=mq' | grep corigin
+lvs -o lv_name,cache_settings | grep migration_threshold=233
+lvs -o lv_name,cache_settings | grep sequential_threshold=13
+
+lvcreate -n foo -l 1 $vg
+lvs -S 'cache_policy=mq' | grep corigin
+lvs -S 'cache_policy=mq' | not grep foo
+lvs -S 'cache_policy=undefined' | not grep corigin
+lvs -S 'cache_policy=undefined' | grep foo
+lvs -o +cache_policy -S 'cache_policy=mq' | grep corigin
+lvs -o +cache_policy -S 'cache_policy=mq' | not grep foo
+lvs -o +cache_policy -S 'cache_policy=undefined' | not grep corigin
+lvs -o +cache_policy -S 'cache_policy=undefined' | grep foo
+lvs -o +cache_policy -O cache_policy
+lvs -o +cache_settings -S 'cache_settings={migration_threshold=233}' | grep corigin
+lvs -o +cache_settings -S 'cache_settings!={migration_threshold=233}' | grep foo
+lvs -o +cache_policy -O cache_settings
+
+lvremove -f $vg
+
+lvcreate -n foo -l 1 $vg
+lvs -a -S 'cache_policy=undefined' | grep foo
+
+vgremove -ff $vg
diff --git a/test/shell/mda-rollback.sh b/test/shell/mda-rollback.sh
new file mode 100644
index 0000000..adfc110
--- /dev/null
+++ b/test/shell/mda-rollback.sh
@@ -0,0 +1,33 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2013 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+aux prepare_devs 3
+
+vgcreate $SHARED --metadatasize 128k $vg1 "$dev1" "$dev2" "$dev3"
+
+vgreduce $vg1 "$dev1"
+dd if="$dev1" of=badmda bs=256K count=1
+vgextend $vg1 "$dev1"
+
+dd if=badmda of="$dev1" bs=256K count=1
+
+# the vg_read in vgck (and other commands) will repair the metadata
+vgck $vg1
+
+# dev1 is part of vg1 (as witnessed by metadata on dev2 and dev3), but its mda
+# was corrupt (written over by a backup from time dev1 was an orphan)
+check pv_field "$dev1" vg_name $vg1
diff --git a/test/shell/mdata-strings.sh b/test/shell/mdata-strings.sh
index 16e9360..c87cd75 100644
--- a/test/shell/mdata-strings.sh
+++ b/test/shell/mdata-strings.sh
@@ -1,5 +1,6 @@
-#!/bin/sh
-# Copyright (C) 2008-2011 Red Hat, Inc. All rights reserved.
+#!/usr/bin/env bash
+
+# Copyright (C) 2008-2013 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
@@ -7,16 +8,23 @@
#
# 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
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
# 'Test for proper escaping of strings in metadata (bz431474)'
-. lib/test
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+# For udev impossible to create
+test "$LVM_TEST_DEVDIR" = "/dev" && skip
aux prepare_devs 2
-aux lvmconf 'devices/global_filter = [ "a|.*LVMTEST.*dev/mapper/.*pv[0-9_]*$|", "r|.*|" ]'
+aux extend_filter_LVMTEST
+
+# Setup mangling to 'none' globaly for all libdm users
+export DM_DEFAULT_NAME_MANGLING_MODE=none
-# for udev impossible to create
pv_ugly="__\"!@#\$%^&*,()|@||'\\\"__pv1"
# 'set up temp files, loopback devices'
@@ -30,9 +38,12 @@ dm_table | grep -F "$pv_ugly"
created="$dev1"
# when used with real udev without fallback, it will fail here
pvcreate "$dev1" || created="$dev2"
-pvdisplay | should grep -F "$pv_ugly"
+pvdisplay 2>&1 | tee err
+should grep -F "$pv_ugly" err
should check pv_field "$dev1" pv_name "$dev1"
-vgcreate $vg "$created"
+vgcreate $SHARED $vg "$created"
# 'no parse errors and VG really exists'
vgs $vg 2>err
not grep "Parse error" err
+
+dmsetup remove "${PREFIX}${pv_ugly}"
diff --git a/test/shell/metadata-bad-mdaheader.sh b/test/shell/metadata-bad-mdaheader.sh
new file mode 100644
index 0000000..ad2bcc4
--- /dev/null
+++ b/test/shell/metadata-bad-mdaheader.sh
@@ -0,0 +1,78 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2008-2013,2018 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+xxd -v || skip
+
+aux prepare_devs 3
+get_devs
+
+#
+# Test corrupted mda_header.version field, which also
+# causes the mda_header checksum to be bad.
+#
+# FIXME: if a VG has only a single PV, this repair
+# doesn't work since there's no good PV to get
+# metadata from. A more advanced repair capability
+# is needed.
+#
+
+dd if=/dev/zero of="$dev1" bs=1M count=1 oflag=direct
+dd if=/dev/zero of="$dev2" bs=1M count=1 oflag=direct
+dd if=/dev/zero of="$dev3" bs=1M count=1 oflag=direct
+
+vgcreate $SHARED $vg "$dev1" "$dev2" "$dev3"
+
+pvs
+
+# read mda_header which is 4k from start of disk
+dd if="$dev1" of=meta1 bs=4k count=1 skip=1
+
+# convert binary to text
+xxd meta1 > meta1.txt
+
+# Corrupt mda_header by changing the version field from 0100 to 0200
+sed 's/0000010:\ 304e\ 2a3e\ 0100\ 0000\ 0010\ 0000\ 0000\ 0000/0000010:\ 304e\ 2a3e\ 0200\ 0000\ 0010\ 0000\ 0000\ 0000/' meta1.txt > meta1-bad.txt
+
+# convert text to binary
+xxd -r meta1-bad.txt > meta1-bad
+
+# write bad mda_header back to disk
+dd if=meta1-bad of="$dev1" bs=4k seek=1
+
+# pvs reports bad metadata header
+pvs 2>&1 | tee out
+grep "bad metadata header" out
+
+pvs "$dev1"
+pvs "$dev2"
+pvs "$dev3"
+
+# bad metadata in one mda doesn't prevent using
+# the VG since other mdas are fine and usable
+lvcreate -l1 $vg
+
+
+vgck --updatemetadata $vg
+
+pvs 2>&1 | tee out
+not grep "bad metadata header" out
+
+pvs "$dev1"
+pvs "$dev2"
+pvs "$dev3"
+
+vgchange -an $vg
+vgremove -ff $vg
diff --git a/test/shell/metadata-bad-text.sh b/test/shell/metadata-bad-text.sh
new file mode 100644
index 0000000..e512688
--- /dev/null
+++ b/test/shell/metadata-bad-text.sh
@@ -0,0 +1,320 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2008-2013,2018 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+SKIP_WITH_LVMPOLLD=1
+
+RUNDIR="/run"
+test -d "$RUNDIR" || RUNDIR="/var/run"
+PVS_ONLINE_DIR="$RUNDIR/lvm/pvs_online"
+VGS_ONLINE_DIR="$RUNDIR/lvm/vgs_online"
+
+_clear_online_files() {
+ # wait till udev is finished
+ aux udev_wait
+ rm -f "$PVS_ONLINE_DIR"/*
+ rm -f "$VGS_ONLINE_DIR"/*
+}
+
+. lib/inittest
+
+aux prepare_devs 3
+get_devs
+
+aux clear_devs "$dev1" "$dev2" "$dev3"
+
+vgcreate $SHARED $vg "$dev1" "$dev2" "$dev3"
+
+pvs
+
+dd if="$dev1" of=meta1 bs=4k count=2
+
+sed 's/flags =/flagx =/' meta1 > meta1.bad
+
+dd if=meta1.bad of="$dev1"
+
+pvs 2>&1 | tee out
+grep "Checksum error" out
+
+pvs "$dev1"
+pvs "$dev2"
+pvs "$dev3"
+
+# bad metadata in one mda doesn't prevent using
+# the VG since other mdas are fine and usable
+lvcreate -l1 $vg
+
+
+vgck --updatemetadata $vg
+
+pvs 2>&1 | tee out
+not grep "Checksum error" out
+
+pvs "$dev1"
+pvs "$dev2"
+pvs "$dev3"
+
+vgchange -an $vg
+vgremove -ff $vg
+
+
+#
+# Same test as above, but corrupt metadata text
+# on two of the three PVs, leaving one good
+# copy of the metadata.
+#
+
+aux clear_devs "$dev1" "$dev2" "$dev3"
+
+vgcreate $SHARED $vg "$dev1" "$dev2" "$dev3"
+
+pvs
+
+dd if="$dev1" of=meta1 bs=4k count=2
+dd if="$dev2" of=meta2 bs=4k count=2
+
+sed 's/READ/RRRR/' meta1 > meta1.bad
+sed 's/seqno =/sss =/' meta2 > meta2.bad
+
+dd if=meta1.bad of="$dev1"
+dd if=meta2.bad of="$dev2"
+
+pvs 2>&1 | tee out
+# FIXME: find a better test than looking for a specific message
+grep "Checksum error" out > out2
+grep "$dev1" out2
+grep "$dev2" out2
+
+pvs "$dev1"
+pvs "$dev2"
+pvs "$dev3"
+
+# bad metadata in one mda doesn't prevent using
+# the VG since other mdas are fine
+lvcreate -l1 $vg
+
+
+vgck --updatemetadata $vg
+
+pvs 2>&1 | tee out
+not grep "Checksum error" out
+
+pvs "$dev1"
+pvs "$dev2"
+pvs "$dev3"
+
+vgchange -an $vg
+vgremove -ff $vg
+
+#
+# Three PVs where two have one mda, and the third
+# has two mdas. The first mda is corrupted on all
+# thee PVs, but the second mda on the third PV
+# makes the VG usable.
+#
+
+aux clear_devs "$dev1" "$dev2" "$dev3"
+
+pvcreate "$dev1"
+pvcreate "$dev2"
+pvcreate --pvmetadatacopies 2 "$dev3"
+
+vgcreate $SHARED $vg "$dev1" "$dev2" "$dev3"
+
+pvs
+
+dd if="$dev1" of=meta1 bs=4k count=2
+dd if="$dev2" of=meta2 bs=4k count=2
+dd if="$dev3" of=meta3 bs=4k count=2
+
+sed 's/READ/RRRR/' meta1 > meta1.bad
+sed 's/seqno =/sss =/' meta2 > meta2.bad
+sed 's/id =/id/' meta3 > meta3.bad
+
+dd if=meta1.bad of="$dev1"
+dd if=meta2.bad of="$dev2"
+dd if=meta3.bad of="$dev3"
+
+pvs 2>&1 | tee out
+grep "Checksum error" out > out2
+grep "$dev1" out2
+grep "$dev2" out2
+grep "$dev3" out2
+
+pvs "$dev1"
+pvs "$dev2"
+pvs "$dev3"
+
+# bad metadata in some mdas doesn't prevent using
+# the VG if there's a good mda found
+lvcreate -l1 $vg
+
+
+vgck --updatemetadata $vg
+
+pvs 2>&1 | tee out
+not grep "Checksum error" out
+
+pvs "$dev1"
+pvs "$dev2"
+pvs "$dev3"
+
+vgchange -an $vg
+vgremove -ff $vg
+
+#
+# Test that vgck --updatemetadata will update old metadata
+# and repair bad metadata text at the same time from different
+# devices.
+#
+
+aux clear_devs "$dev1" "$dev2" "$dev3"
+
+pvcreate "$dev1"
+pvcreate "$dev2"
+pvcreate --pvmetadatacopies 2 "$dev3"
+
+vgcreate $SHARED $vg "$dev1" "$dev2" "$dev3"
+
+# Put bad metadata onto dev1
+dd if="$dev1" of=meta1 bs=4k count=2
+sed 's/READ/RRRR/' meta1 > meta1.bad
+dd if=meta1.bad of="$dev1"
+
+pvs 2>&1 | tee out
+grep "Checksum error" out > out2
+grep "$dev1" out2
+
+# We can still use the VG with other available
+# mdas, skipping the bad mda.
+
+lvcreate -n $lv1 -l1 -an $vg "$dev1"
+lvcreate -n $lv2 -l1 -an $vg "$dev1"
+
+# Put old metadata onto dev2 by updating
+# the VG while dev2 is disabled.
+aux disable_dev "$dev2"
+
+pvs
+pvs "$dev1"
+not pvs "$dev2"
+pvs "$dev3"
+lvs $vg/$lv1
+lvs $vg/$lv2
+
+lvremove $vg/$lv2
+
+aux enable_dev "$dev2"
+
+# Both old and bad metadata are reported.
+pvs 2>&1 | tee out
+grep "ignoring metadata seqno" out
+grep "Checksum error" out
+pvs "$dev1"
+pvs "$dev2"
+pvs "$dev3"
+
+lvs $vg/$lv1
+not lvs $vg/$lv2
+
+# fixes the bad metadata on dev1, and
+# fixes the old metadata on dev2.
+vgck --updatemetadata $vg
+
+pvs 2>&1 | tee out
+not grep "ignoring metadata seqno" out
+not grep "Checksum error" out
+pvs "$dev1"
+pvs "$dev2"
+pvs "$dev3"
+
+lvs $vg/$lv1
+
+vgchange -an $vg
+vgremove -ff $vg
+
+#
+# Test pvscan activation with bad PVs
+#
+
+# autoactivation not done on shared VGs
+if test -n "$LVM_TEST_LVMLOCKD"; then
+exit 0
+fi
+
+aux clear_devs "$dev1" "$dev2" "$dev3"
+
+vgcreate $SHARED $vg "$dev1" "$dev2" "$dev3"
+
+PVID1=$(pvs "$dev1" --noheading -o uuid | tr -d - | awk '{print $1}')
+echo $PVID1
+PVID2=$(pvs "$dev2" --noheading -o uuid | tr -d - | awk '{print $1}')
+echo $PVID2
+PVID3=$(pvs "$dev3" --noheading -o uuid | tr -d - | awk '{print $1}')
+echo $PVID3
+
+pvs
+
+dd if="$dev1" of=meta1 bs=4k count=2
+dd if="$dev2" of=meta2 bs=4k count=2
+
+sed 's/READ/RRRR/' meta1 > meta1.bad
+sed 's/seqno =/sss =/' meta2 > meta2.bad
+
+dd if=meta1.bad of="$dev1"
+dd if=meta2.bad of="$dev2"
+
+pvs 2>&1 | tee out
+grep "Checksum error" out > out2
+grep "$dev1" out2
+grep "$dev2" out2
+
+pvs "$dev1"
+pvs "$dev2"
+pvs "$dev3"
+
+# bad metadata in one mda doesn't prevent using
+# the VG since other mdas are fine
+lvcreate -l1 -n $lv1 $vg
+
+vgchange -an $vg
+
+_clear_online_files
+
+# pvscan of one dev with bad metadata will result
+# in the pvid online file being created but the
+# VG will not be known.
+pvscan --cache -aay "$dev1"
+ls "$RUNDIR/lvm/pvs_online/$PVID1"
+not ls "$RUNDIR/lvm/pvs_online/$PVID2"
+not ls "$RUNDIR/lvm/pvs_online/$PVID3"
+not ls "$RUNDIR/lvm/vgs_online/$vg"
+
+_clear_online_files
+
+# scan the one pv with good metadata, does not scan any others
+pvscan --cache -aay "$dev3"
+not ls "$RUNDIR/lvm/pvs_online/$PVID1"
+not ls "$RUNDIR/lvm/pvs_online/$PVID2"
+ls "$RUNDIR/lvm/pvs_online/$PVID3"
+not ls "$RUNDIR/lvm/vgs_online/$vg"
+
+vgck --updatemetadata $vg
+
+pvs 2>&1 | tee out
+not grep "Checksum error" out
+
+pvs "$dev1"
+pvs "$dev2"
+pvs "$dev3"
+
+vgchange -an $vg
+vgremove -ff $vg
diff --git a/test/shell/metadata-balance.sh b/test/shell/metadata-balance.sh
index 88ac114..5f856a1 100644
--- a/test/shell/metadata-balance.sh
+++ b/test/shell/metadata-balance.sh
@@ -1,4 +1,5 @@
-#!/bin/sh
+#!/usr/bin/env bash
+
# Copyright (C) 2008 Red Hat, Inc. All rights reserved.
#
# This copyrighted material is made available to anyone wishing to use,
@@ -7,9 +8,11 @@
#
# 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
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+SKIP_WITH_LVMPOLLD=1
-. lib/test
+. lib/inittest
aux prepare_devs 6
@@ -19,7 +22,7 @@ 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"
+ vgcreate $SHARED $vg "$dev1" "$dev2" "$dev3"
fi
pvchange --metadataignore y "$dev1"
check pv_field "$dev1" pv_mda_count $mdacp
@@ -27,7 +30,7 @@ for mdacp in 1 2; do
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_count $(( mdacp * 2 ))
check vg_field $vg vg_mda_used_count $mdacp
check vg_field $vg vg_mda_copies unmanaged
fi
@@ -35,8 +38,8 @@ for mdacp in 1 2; do
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_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
@@ -60,7 +63,7 @@ pvunignore_ () {
fi
}
-echo Test of vgmetadatacopies with vgcreate and vgchange
+echo Test of vgmetadatacopies with vgcreate $SHARED and vgchange
for mdacp in 1 2; do
pvcreate --metadatacopies $mdacp "$dev1" "$dev2" "$dev4" "$dev5"
check pv_field "$dev1" pv_mda_used_count $mdacp
@@ -68,55 +71,55 @@ for mdacp in 1 2; do
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"
+ vgcreate $SHARED $vg "$dev1" "$dev2" "$dev3"
check vg_field $vg vg_mda_copies unmanaged
echo ensure both --vgmetadatacopies and --metadatacopies accepted
- vgchange --metadatacopies $(($mdacp * 1)) $vg
+ 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))
+ 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))
+ 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
+ echo vgcreate $SHARED 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"
+ vgcreate $SHARED $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))
+ echo vgcreate $SHARED succeeds with a specific number of metadata copies
+ vgcreate $SHARED --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))
+ vgcreate $SHARED --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))
+ echo vgcreate $SHARED succeeds with a larger value than total metadatacopies
+ vgcreate $SHARED --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"
+ echo vgcreate $SHARED succeeds with --vgmetadatacopies unmanaged
+ vgcreate $SHARED --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"
+ echo vgcreate $SHARED succeds with small value of --metadatacopies, ignores mdas
+ vgcreate $SHARED --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_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
@@ -124,14 +127,14 @@ for mdacp in 1 2; do
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_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
+ check vg_field $vg vg_mda_used_count $(( mdacp * 4 ))
+ echo --vgmetadatacopies 0 should be unmanaged for vgchange and vgcreate $SHARED
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"
+ vgcreate $SHARED --vgmetadatacopies 0 $vg "$dev1" "$dev2" "$dev4" "$dev5"
check vg_field $vg vg_mda_copies unmanaged
vgremove -f $vg
done
@@ -141,8 +144,8 @@ 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))
+ vgcreate $SHARED --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"
@@ -152,8 +155,8 @@ for mdacp in 1 2; do
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))
+ vgcreate $SHARED --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"
@@ -168,65 +171,71 @@ for mdacp in 1 2; do
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))
+ 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 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
+if test -n "$LVM_TEST_LVMLOCKD"; then
+echo skip vgsplit and vgmerge with lvmlockd
+else
+
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"
+ vgcreate $SHARED --vgmetadatacopies 2 $vg1 "$dev1" "$dev2" "$dev3"
+ vgcreate $SHARED --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))
+ check vg_field $vg2 vg_mda_copies $(( mdacp * 1 ))
vgsplit $vg1 $vg2 "$dev1"
- check vg_field $vg2 vg_mda_copies $(($mdacp * 1))
+ 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))
+ 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))
+ 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
+fi
+
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))
+ vgcreate $SHARED --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))
+ 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))
+ 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))
+ 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))
+ 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))
+ 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
deleted file mode 100644
index 852ce35..0000000
--- a/test/shell/metadata-dirs.sh
+++ /dev/null
@@ -1,43 +0,0 @@
-#!/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-full.sh b/test/shell/metadata-full.sh
new file mode 100644
index 0000000..a1b7d02
--- /dev/null
+++ b/test/shell/metadata-full.sh
@@ -0,0 +1,131 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2008-2013 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+test_description='Test full metadata'
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+# this test needs lot of memory
+test "$(aux total_mem)" -gt 524288 || skip
+
+LVM_TEST_PVS=${LVM_TEST_PVS:-64}
+
+# aux prepare_vg $LVM_TEST_PVS
+
+unset LVM_LOG_FILE_MAX_LINES
+
+aux prepare_devs 64 1000
+get_devs
+
+vgcreate $SHARED -s 512K --metadatacopies 8 $vg "${DEVICES[@]}"
+
+
+# Create a large metadata set, that getting close to 1/2MiB in size
+#
+# uses long tags to increase the size of the metadata
+# more quickly
+#
+# the specific number of LVs in these loops isn't great
+# because it doesn't depend specified behavior, but it's
+# based on how much metadata it produces at the time this
+# is written.
+
+vgcfgbackup -f data $vg
+TEST_DEVS=925
+# Generate a lot of LV devices (size of 1 extent)
+awk -v TEST_DEVS=$TEST_DEVS '/^\t\}/ {
+ printf("\t}\n\tlogical_volumes {\n");
+ cnt=0;
+ for (i = 0; i < TEST_DEVS; i++) {
+ printf("\t\tlvol%d {\n", i);
+ printf("\t\t\tid = \"%06d-1111-2222-3333-2222-1111-%06d\"\n", i, i);
+ print "\t\t\tstatus = [\"READ\", \"WRITE\", \"VISIBLE\"]";
+ print "\t\t\ttags = [\"A123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789\"]";
+ print "\t\t\tsegment_count = 1";
+ print "\t\t\tsegment1 {";
+ print "\t\t\t\tstart_extent = 0";
+ print "\t\t\t\textent_count = 1";
+ print "\t\t\t\ttype = \"striped\"";
+ print "\t\t\t\tstripe_count = 1";
+ print "\t\t\t\tstripes = [";
+ print "\t\t\t\t\t\"pv0\", " cnt++;
+ printf("\t\t\t\t]\n\t\t\t}\n\t\t}\n");
+ }
+ }
+ {print}
+' data >data_new
+# Restoring big data set of LVs
+vgcfgrestore -f data_new $vg
+
+
+# should show non-zero
+vgs -o+pv_mda_free
+
+# these addtag's will fail at some point when metadata space is full
+
+for i in $(seq 1 "$TEST_DEVS"); do
+ lvchange --addtag B123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789 $vg/lvol$i || break;
+done
+
+# test we hit 'out-of-metadata-space'
+test "$i" -gt 2
+test "$i" -lt "$TEST_DEVS"
+
+# should show 0
+vgs -o+pv_mda_free
+check vg_field $vg vg_mda_free 0
+
+# remove some of the tags to check that we can reduce the size of the
+# metadata, and continue using the vg
+
+for j in $(seq 1 "$i"); do
+ lvchange --deltag B123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789 $vg/lvol$j;
+done
+
+# should show non-zero
+vgs -o+pv_mda_free
+
+# these will fail at some point when metadata space is full again
+
+for i in $(seq 1 50); do
+ lvcreate -l1 -an --addtag C123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789 $vg || break;
+done
+
+# should show 0
+vgs -o+pv_mda_free
+check vg_field $vg vg_mda_free 0
+
+# as long as we have a lot of LVs around, try to activate them all
+# (filters are already set up that exclude the activated LVs from
+# being scanned)
+
+time vgs
+
+# Avoid activation of large set of volumes - this is tested in vgchange-many.sh
+#vgchange -ay $vg
+#vgchange -an $vg
+
+# see if we can remove LVs to make more metadata space,
+# and then create more LVs
+
+for i in $(seq 1 30); do lvremove -y $vg/lvol$i; done
+
+for i in $(seq 1 10); do lvcreate -l1 $vg; done
+
+# should show non-zero
+vgs -o+pv_mda_free
+
+# FIXME:
+# takes extreme amount of time, despite the fact, there are only few LVs active.
+vgremove -ff $vg
diff --git a/test/shell/metadata-old.sh b/test/shell/metadata-old.sh
new file mode 100644
index 0000000..9a0351c
--- /dev/null
+++ b/test/shell/metadata-old.sh
@@ -0,0 +1,221 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2008-2013,2018 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+aux prepare_devs 3
+get_devs
+
+#
+# Test "old metadata" repair which occurs when the VG is written
+# and one of the PVs in the VG does not get written to, and then
+# the PV reappears with the old metadata. This can happen if
+# a command is killed or crashes after writing new metadata to
+# only some of the PVs in the VG, or if a PV is temporarily
+# inaccessible while a VG is written.
+#
+
+vgcreate $SHARED $vg "$dev1" "$dev2" "$dev3"
+
+#
+# Test that vgck --updatemetadata will update old metadata.
+#
+
+lvcreate -n $lv1 -l1 -an $vg "$dev1"
+lvcreate -n $lv2 -l1 -an $vg "$dev1"
+
+aux disable_dev "$dev2"
+
+pvs
+pvs "$dev1"
+not pvs "$dev2"
+pvs "$dev3"
+lvs $vg/$lv1
+lvs $vg/$lv2
+
+lvremove $vg/$lv2
+
+aux enable_dev "$dev2"
+
+pvs 2>&1 | tee out
+grep "ignoring metadata seqno" out
+pvs "$dev1"
+pvs "$dev2"
+pvs "$dev3"
+
+lvs $vg/$lv1
+not lvs $vg/$lv2
+
+# fixes the old metadata on dev1
+vgck --updatemetadata $vg
+
+pvs 2>&1 | tee out
+not grep "ignoring metadata seqno" out
+pvs "$dev1"
+pvs "$dev2"
+pvs "$dev3"
+
+lvs $vg/$lv1
+not lvs $vg/$lv2
+
+#
+# Test that any writing command will also update the
+# old metadata.
+#
+
+lvcreate -n $lv2 -l1 -an $vg "$dev1"
+
+aux disable_dev "$dev2"
+
+pvs
+pvs "$dev1"
+not pvs "$dev2"
+pvs "$dev3"
+lvs $vg/$lv1
+lvs $vg/$lv2
+
+lvremove $vg/$lv2
+
+aux enable_dev "$dev2"
+
+pvs 2>&1 | tee out
+grep "ignoring metadata seqno" out
+pvs "$dev1"
+pvs "$dev2"
+pvs "$dev3"
+
+lvs $vg/$lv1
+not lvs $vg/$lv2
+
+# fixes the old metadata on dev1
+lvcreate -n $lv3 -l1 -an $vg
+
+pvs 2>&1 | tee out
+not grep "ignoring metadata seqno" out
+pvs "$dev1"
+pvs "$dev2"
+pvs "$dev3"
+
+lvs $vg/$lv1
+not lvs $vg/$lv2
+
+vgremove -ff $vg
+
+#
+# First two PVs with one mda, where both have old metadata.
+# Third PV with two mdas, where the first mda has old
+# metadata, and the second mda has current metadata.
+#
+
+aux clear_devs "$dev1" "$dev2" "$dev3"
+
+pvcreate "$dev1"
+pvcreate "$dev2"
+pvcreate --pvmetadatacopies 2 "$dev3"
+
+vgcreate $SHARED $vg "$dev1" "$dev2" "$dev3"
+
+lvcreate -n $lv1 -l1 -an $vg "$dev3"
+lvcreate -n $lv2 -l1 -an $vg "$dev3"
+
+# Save the metadata at this point...
+dd if="$dev1" of=meta1 bs=4k count=4
+dd if="$dev2" of=meta2 bs=4k count=4
+dd if="$dev3" of=meta3 bs=4k count=4
+
+# and now change metadata so the saved copies are old
+lvcreate -n $lv3 -l1 -an $vg "$dev3"
+
+# Copy the saved metadata back to the three
+# devs first mda, leaving the second mda on
+# dev3 as the only latest copy of the metadata.
+
+dd if=meta1 of="$dev1"
+dd if=meta2 of="$dev2"
+dd if=meta3 of="$dev3"
+
+pvs 2>&1 | tee out
+grep "ignoring metadata seqno" out
+pvs "$dev1"
+pvs "$dev2"
+pvs "$dev3"
+
+# We still see the three LVs since we are using
+# the latest copy of metadata from dev3:mda2
+
+lvs $vg/$lv1
+lvs $vg/$lv2
+lvs $vg/$lv3
+
+# This command which writes the VG should update
+# all of the old copies.
+lvcreate -n $lv4 -l1 -an $vg
+
+pvs 2>&1 | tee out
+not grep "ignoring metadata seqno" out
+pvs "$dev1"
+pvs "$dev2"
+pvs "$dev3"
+
+lvs $vg/$lv1
+lvs $vg/$lv2
+lvs $vg/$lv3
+lvs $vg/$lv4
+
+vgchange -an $vg
+vgremove -ff $vg
+
+# Test when the metadata on two PVs have the same seqno
+# but different checksums.
+
+aux clear_devs "$dev1" "$dev2"
+
+pvcreate "$dev1"
+pvcreate "$dev2"
+
+vgcreate $SHARED $vg "$dev1" "$dev2"
+
+lvcreate -n $lv1 -l1 -an $vg
+
+pvck --dump metadata -f meta "$dev2"
+
+# change an unimportant character so the metadata is effectively
+# the same in content but will have a different checksum
+sed 's/Linux/linux/' meta > meta2
+
+# write out the changed metadata
+pvck --repair -y -f meta2 "$dev2"
+
+# the vg can still be used but will produce warnings
+# the mda on one pv is updated, but not the other,
+# which changes the error from a checksum inconsistency
+# into a seqno inconsistency.
+lvs $vg 2>&1 | tee out
+grep WARNING out
+grep $lv1 out
+lvcreate -n $lv2 -l1 -an $vg 2>&1 |tee out
+grep WARNING out
+lvs $vg 2>&1 | tee out
+grep WARNING out
+grep $lv1 out
+grep $lv2 out
+
+# correct the senqo inconsistency
+vgck --updatemetadata $vg
+lvs $vg 2>&1 | tee out
+not grep WARNING out
+grep $lv1 out
+grep $lv2 out
+
+vgremove -ff $vg
diff --git a/test/shell/metadata-zero-space.sh b/test/shell/metadata-zero-space.sh
new file mode 100644
index 0000000..54fbd8f
--- /dev/null
+++ b/test/shell/metadata-zero-space.sh
@@ -0,0 +1,88 @@
+#!/usr/bin/env 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+xxd -v || skip
+
+aux prepare_devs 1 256
+get_devs
+
+# Fill with random data so if the space between metadata
+# copies are not zeroed the grep for zeros will fail.
+dd if=/dev/urandom of="$dev1" bs=1M count=1 || true
+dd if=/dev/urandom of="$dev1" bs=1M skip=15 count=1 || true
+
+pvcreate --pvmetadatacopies 2 "$dev1"
+
+vgcreate $SHARED "$vg" "$dev1"
+
+for i in $(seq 1 50); do lvcreate -l1 -an $vg; done
+
+# Check metadata copies are separated by zeroes in the first mda
+
+dd if="$dev1" of=meta.raw bs=1M count=1
+
+xxd meta.raw > meta.txt
+
+# to help debug if the next grep fails
+ls -l meta.txt
+head -n 100 meta.txt
+grep -A4 -B4 '01200:' meta.txt
+
+_vg="$vg "
+_vg="${_vg:0:16}"
+grep -B1 "$_vg" meta.txt > meta.vg
+
+cat meta.vg
+
+grep -v "$_vg" meta.vg > meta.zeros
+
+cat meta.zeros
+
+grep '0000 0000 0000 0000 0000 0000 0000 0000' meta.zeros > meta.count
+
+# wc will often equal 51, but some natural variability in
+# metadata locations/content mean that some lines do not
+# require a full line of zero padding, and will not match
+# the grep for a full row of zeros. So, check that more
+# than 20 lines match the full row of zeros (this is a
+# random choice, and this isn't a perfect way to test for
+# zero padding.)
+
+test "$(wc -l < meta.count)" -gt 20
+
+rm meta.raw meta.txt meta.vg meta.zeros meta.count
+
+#
+# Check metadata copies are separated by zeroes in the second mda
+#
+
+dd if="$dev1" of=meta.raw bs=1M seek=15 count=1
+
+xxd meta.raw > meta.txt
+
+grep -B1 "$_vg" meta.txt > meta.vg
+
+cat meta.vg
+
+grep -v "$_vg" meta.vg > meta.zeros
+
+cat meta.zeros
+
+grep '0000 0000 0000 0000 0000 0000 0000 0000' meta.zeros > meta.count
+
+test "$(wc -l < meta.count)" -gt 20
+
+vgremove -ff $vg
diff --git a/test/shell/metadata.sh b/test/shell/metadata.sh
index a9f8640..f5d6483 100644
--- a/test/shell/metadata.sh
+++ b/test/shell/metadata.sh
@@ -1,4 +1,5 @@
-#!/bin/sh
+#!/usr/bin/env bash
+
# Copyright (C) 2008 Red Hat, Inc. All rights reserved.
#
# This copyrighted material is made available to anyone wishing to use,
@@ -7,11 +8,14 @@
#
# 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
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+SKIP_WITH_LVMPOLLD=1
-. lib/test
+. lib/inittest
aux prepare_devs 5
+get_devs
pvcreate "$dev1"
pvcreate --metadatacopies 0 "$dev2"
@@ -19,9 +23,13 @@ pvcreate --metadatacopies 0 "$dev3"
pvcreate "$dev4"
pvcreate --metadatacopies 0 "$dev5"
-vgcreate -c n $vg $(cat DEVICES)
+vgcreate $SHARED "$vg" "${DEVICES[@]}"
lvcreate -n $lv -l 1 -i5 -I256 $vg
+pvck --dump metadata "$dev1" > meta1
+grep "description = " meta1 > desc1
+grep "Write from lvcreate" desc1
+
pvchange -x n "$dev1"
pvchange -x y "$dev1"
vgchange -a n $vg
@@ -31,46 +39,14 @@ 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 --metadatacopies "$mdacp" "${DEVICES[@]}"
pvcreate "$dev1"
- vgcreate -c n $vg $(cat DEVICES)
+ vgcreate $SHARED "$vg" "${DEVICES[@]}"
lvcreate -n $lv1 -l 2 -i5 -I256 $vg
- lvcreate -n $lv2 -m2 -l 2 $vg
+ lvcreate -aey -n $lv2 --type mirror -m2 -l 2 $vg
lvchange -an $vg/$lv1 $vg/$lv2
- vgchange -ay $vg
+ vgchange -aey $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
index d6c67ee..8d525ca 100644
--- a/test/shell/mirror-names.sh
+++ b/test/shell/mirror-names.sh
@@ -1,5 +1,6 @@
-#!/bin/sh
-# Copyright (C) 2007-2012 Red Hat, Inc. All rights reserved.
+#!/usr/bin/env bash
+
+# Copyright (C) 2007-2017 Red Hat, Inc. All rights reserved.
# Copyright (C) 2007-2008 NEC Corporation
#
# This copyrighted material is made available to anyone wishing to use,
@@ -8,36 +9,46 @@
#
# 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
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
test_description="check namings of mirrored LV"
-. lib/test
+
+
+. lib/inittest
# ---------------------------------------------------------------------
# Utilities
lv_devices_() {
local d
+ local i
local lv=$1
shift
- local devices=$@
- local devs=$(get lv_field $lv devices -a | sed 's/([0-9]*)//g; s/ //g; s/,/ /g')
+ local devices=( "$@" )
+ local devs
+
+ devs=$(get lv_devices "$lv")
for d in $devs; do
- (echo $devices | grep $d) || return 1
- devices=$(echo $devices | sed "s/$d//")
+ (echo "${devices[@]}" | grep "$d") || return 1
+ for i in "${!devices[@]}"; do
+ if [ "${devices[i]}" = "$d" ] ; then
+ unset "devices[i]"
+ fi
+ done
done
- test -z "$(echo $devices | sed 's/ //g')"
+ test "${#devices[@]}" -eq 0 ||
+ die "Left devices " "${devices[@]}"
}
lv_mirror_log_() {
- test $(get lv_field $1 mirror_log) = $2
+ get lv_field "$1" mirror_log | tr -d '[]'
}
lv_convert_lv_() {
- get lv_field $1 convert_lv
+ get lv_field "$1" convert_lv | tr -d '[]'
}
# ---------------------------------------------------------------------
@@ -63,18 +74,18 @@ check_and_cleanup_lvs_
#COMM "init: lvcreate"
#COMM "mirror images are ${lv1}_mimage_x"
-lvcreate -l2 -m1 -n $lv1 $vg
+lvcreate -an -Zn -l2 --type mirror -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
+test "$(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
+lvcreate -an -Zn --type mirror -m1 -l2 -n $name $vg
lvs $vg/$name
check_and_cleanup_lvs_
@@ -84,7 +95,7 @@ check_and_cleanup_lvs_
#COMM "init: lvrename"
#COMM "renamed mirror names: $lv1 to $lv2"
-lvcreate -l2 -m1 -n $lv1 $vg
+lvcreate -an -Zn -l2 --type mirror -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
@@ -98,28 +109,48 @@ check_and_cleanup_lvs_
#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
+lvcreate -aey -l2 --type mirror -m1 -n $lv1 $vg
+# Use large enough polling interval so mirror is keeping mimagetmp
+LVM_TEST_TAG="kill_me_$PREFIX" lvconvert -m+1 -i+40 -b $vg/$lv1
+
+#
+# TODO: lvmpolld is not 'preserving' -i interval setting from
+# lvconvert initiating command - so there is not much to test
+# if the lvconvert is already finished at this point
+# and lvmpolld cleaned metadata and refreshed DM table
+#
+# It' unclear if this is undocumented feature of bug.
+#
+if test ! -f LOCAL_LVMPOLLD ; then
+
+for i in $(seq 1 10) ; do
+ # check if background process already started
+ # this is recognized by presence of LV1_mimage_2
+ check lvl $vg/${lv1}_mimage_2 && break
+ sleep .1
+done
convlv=$(lv_convert_lv_ $vg/$lv1)
-test $convlv = ${lv1}_mimagetmp_2
+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
+check lv_exists $vg ${lv1}_mimagetmp_2
-#COMM "mirror log name after re-adding is ${lv1}_mlog" \
-lvconvert --mirrorlog core $vg/$lv1
+#COMM "mirror log name after re-adding is ${lv1}_mlog"
+lvconvert -f --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" \
+#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
+fi # ! -f LOCAL_LVMPOLLD
#COMM "cleanup"
check_and_cleanup_lvs_
diff --git a/test/shell/mirror-vgreduce-removemissing.sh b/test/shell/mirror-vgreduce-removemissing.sh
index 232c2be..ff7eea5 100644
--- a/test/shell/mirror-vgreduce-removemissing.sh
+++ b/test/shell/mirror-vgreduce-removemissing.sh
@@ -1,5 +1,6 @@
-#!/bin/sh
-# Copyright (C) 2008-2012 Red Hat, Inc. All rights reserved.
+#!/usr/bin/env bash
+
+# Copyright (C) 2008-2017 Red Hat, Inc. All rights reserved.
# Copyright (C) 2007 NEC Corporation
#
# This copyrighted material is made available to anyone wishing to use,
@@ -8,24 +9,28 @@
#
# 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
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
test_description="ensure that 'vgreduce --removemissing' works on mirrored LV"
-. lib/test
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+list_pvs=()
lv_is_on_ ()
{
local lv=$vg/$1
shift
- local pvs=$@
+ local list_pvs=( "$@" )
- echo "Check if $lv is exactly on PVs $pvs"
+ echo "Check if $lv is exactly on PVs" "${list_pvs[@]}"
rm -f out1 out2
- echo $pvs | sed 's/ /\n/g' | sort | uniq > out1
+ printf "%s\n" "${list_pvs[@]}" | sort | uniq > out1
lvs -a -o+devices $lv
- get lv_devices $lv | sed 's/ /\n/g' | sort | uniq > out2 || true
+ get lv_devices "$lv" | sort | uniq > out2
diff --ignore-blank-lines out1 out2
}
@@ -34,23 +39,23 @@ mimages_are_on_ ()
{
local lv=$1
shift
- local pvs=$@
- local mimages
+ local list_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
+ echo "Check if mirror images of $lv are on PVs" "${list_pvs[@]}"
+ printf "%s\n" "${list_pvs[@]}" | sort | uniq | tee out1
+
+ get lv_field_lv_ "$vg" lv_name -a | grep "${lv}_mimage_" | tee lvs_log
+ test -s lvs_log || return 1
+
+ while IFS= read -r i ; do
+ mimages+=( "$i" )
+ done < lvs_log
+
+ for i in "${mimages[@]}"; do
+ get lv_devices "$vg/$i"
+ done | sort | uniq | tee out2
diff --ignore-blank-lines out1 out2
}
@@ -65,29 +70,35 @@ mirrorlog_is_on_()
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
+ get lv_field $vg/$1 "stripes,attr" | tee out
+ grep "^1 -" out >/dev/null
}
rest_pvs_()
{
local index=$1
local num=$2
- local rem=
+ local rem=()
local n
+ local dev
- for n in $(seq 1 $(($index - 1))) $(seq $(($index + 1)) $num); do
- eval local dev=$\dev$n
- rem="$rem $dev"
+ for n in $(seq 1 $(( index - 1 )) ) $(seq $(( index + 1 )) $num); do
+ eval "dev=\$dev$n"
+ rem+=( "$dev" )
done
- echo "$rem"
+ printf "%s\n" "${rem[@]}"
}
# ---------------------------------------------------------------------
# Initialize PVs and VGs
-aux prepare_vg 5
+aux prepare_pvs 5 80
+get_devs
+vgcreate $SHARED -s 64k "$vg" "${DEVICES[@]}"
+BLOCKS=0-7
+BLOCKS1=8-15
# ---------------------------------------------------------------------
# Common environment setup/cleanup for each sub testcases
@@ -100,15 +111,23 @@ prepare_lvs_()
check_and_cleanup_lvs_()
{
- lvs -a -o+devices $vg
+ lvs -a -o+lv_uuid,devices $vg
prepare_lvs_
}
recover_vg_()
{
aux enable_dev "$@"
+
+ # clear outdated metadata on PVs so they can be used again
+ vgck --updatemetadata $vg
+
+ pvscan --cache
+
pvcreate -ff "$@"
+ # wipefs -a "$@"
vgextend $vg "$@"
+
check_and_cleanup_lvs_
}
@@ -121,10 +140,9 @@ check_and_cleanup_lvs_
#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
+lvcreate -an -Zn -l2 --type mirror -m1 --nosync -n $lv1 $vg "$dev1" "$dev2" "$dev3":$BLOCKS
+mimages_are_on_ $lv1 "$dev1" "$dev2"
+mirrorlog_is_on_ $lv1 "$dev3"
aux disable_dev "$dev2"
vgreduce --removemissing --force $vg
lv_is_linear_ $lv1
@@ -142,14 +160,17 @@ test_3way_mirror_fail_1_()
{
local index=$1
- lvcreate -l2 -m2 -n $lv1 $vg "$dev1" "$dev2" "$dev3" "$dev4":0
- lvchange -an $vg/$lv1
+ lvcreate -an -Zn -l2 --type mirror -m2 --nosync -n $lv1 $vg "$dev1" "$dev2" "$dev3" "$dev4":$BLOCKS
mimages_are_on_ $lv1 "$dev1" "$dev2" "$dev3"
mirrorlog_is_on_ $lv1 "$dev4"
- eval aux disable_dev \$dev$index
+ eval aux disable_dev "\$dev$index"
vgreduce --removemissing --force $vg
- lvs -a -o+devices $vg
- mimages_are_on_ $lv1 $(rest_pvs_ $index 3)
+
+ list_pvs=(); while IFS= read -r line ; do
+ list_pvs+=( "$line" )
+ done < <( rest_pvs_ "$index" 3 )
+
+ mimages_are_on_ "$lv1" "${list_pvs[@]}"
mirrorlog_is_on_ $lv1 "$dev4"
}
@@ -157,7 +178,7 @@ 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
+ eval recover_vg_ "\$dev$n"
done
# ---------------------------------------------------------------------
@@ -169,23 +190,30 @@ test_3way_mirror_fail_2_()
{
local index=$1
- lvcreate -l2 -m2 -n $lv1 $vg "$dev1" "$dev2" "$dev3" "$dev4":0
- lvchange -an $vg/$lv1
+ lvcreate -an -Zn -l2 --type mirror -m2 --nosync -n $lv1 $vg "$dev1" "$dev2" "$dev3" "$dev4":$BLOCKS
mimages_are_on_ $lv1 "$dev1" "$dev2" "$dev3"
mirrorlog_is_on_ $lv1 "$dev4"
- rest_pvs_ $index 3
- aux disable_dev $(rest_pvs_ $index 3)
+
+ list_pvs=(); while IFS= read -r line ; do
+ list_pvs+=( "$line" )
+ done < <( rest_pvs_ "$index" 3 )
+
+ aux disable_dev "${list_pvs[@]}"
vgreduce --force --removemissing $vg
- lvs -a -o+devices $vg
lv_is_linear_ $lv1
- eval lv_is_on_ $lv1 \$dev$n
+ 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)
+
+ list_pvs=(); while IFS= read -r line ; do
+ list_pvs+=( "$line" )
+ done < <( rest_pvs_ "$n" 3 )
+
+ recover_vg_ "${list_pvs[@]}"
done
# ---------------------------------------------------------------------
@@ -197,16 +225,18 @@ 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
+ lvcreate -an -Zn -l2 --type mirror -m2 -n $lv1 $vg "$dev1" "$dev2" "$dev3" "$dev5":$BLOCKS
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)
+
+ list_pvs=(); while IFS= read -r line ; do
+ list_pvs+=( "$line" )
+ done < <( rest_pvs_ "$index" 4 )
+
+ check mirror_images_on $vg $lv1 "${list_pvs[@]}"
check mirror_log_on $vg $lv1 "$dev5"
}
@@ -225,26 +255,35 @@ done
test_3way_mirror_plus_1_fail_3_()
{
local index=$1
+ local dev
- lvcreate -l2 -m2 -n $lv1 $vg "$dev1" "$dev2" "$dev3" "$dev5":0
- lvchange -an $vg/$lv1
+ lvcreate -an -Zn -l2 --type mirror -m2 -n $lv1 $vg "$dev1" "$dev2" "$dev3" "$dev5":$BLOCKS
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)
+
+ list_pvs=(); while IFS= read -r line ; do
+ list_pvs+=( "$line" )
+ done < <( rest_pvs_ "$index" 4 )
+
+ aux disable_dev "${list_pvs[@]}"
vgreduce --removemissing --force $vg
lvs -a -o+devices $vg
- eval local dev=\$dev$n
+ eval dev=\$dev$n
check linear $vg $lv1
- check lv_on $vg $lv1 $dev
+ 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)
+
+ list_pvs=(); while IFS= read -r line ; do
+ list_pvs+=( "$line" )
+ done < <( rest_pvs_ "$n" 4 )
+
+ recover_vg_ "${list_pvs[@]}"
done
# ---------------------------------------------------------------------
@@ -256,15 +295,18 @@ test_2way_mirror_plus_2_fail_1_()
{
local index=$1
- lvcreate -l2 -m1 -n $lv1 $vg "$dev1" "$dev2" "$dev5":0
- lvchange -an $vg/$lv1
+ lvcreate -an -Zn -l2 --type mirror -m1 -n $lv1 $vg "$dev1" "$dev2" "$dev5":$BLOCKS
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)
+
+ list_pvs=(); while IFS= read -r line ; do
+ list_pvs+=( "$line" )
+ done < <( rest_pvs_ "$index" 4 )
+
+ mimages_are_on_ "$lv1" "${list_pvs[@]}"
mirrorlog_is_on_ $lv1 "$dev5"
}
@@ -272,7 +314,7 @@ 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
+ eval recover_vg_ "\$dev$n"
done
# ---------------------------------------------------------------------
@@ -283,17 +325,23 @@ done
test_2way_mirror_plus_2_fail_3_()
{
local index=$1
+ local dev
- lvcreate -l2 -m1 -n $lv1 $vg "$dev1" "$dev2" "$dev5":0
- lvchange -an $vg/$lv1
+ lvcreate -an -Zn -l2 --type mirror -m1 -n $lv1 $vg "$dev1" "$dev2" "$dev5":$BLOCKS
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)
+
+ list_pvs=(); while IFS= read -r line ; do
+ list_pvs+=( "$line" )
+ done < <( rest_pvs_ "$index" 4 )
+
+ aux disable_dev "${list_pvs[@]}"
vgreduce --removemissing --force $vg
lvs -a -o+devices $vg
- eval local dev=\$dev$n
- mimages_are_on_ $lv1 $dev || lv_is_on_ $lv1 $dev
+ eval dev=\$dev$n
+ not mimages_are_on_ $lv1 "$dev"
+ lv_is_on_ $lv1 "$dev"
not mirrorlog_is_on_ $lv1 "$dev5"
}
@@ -301,7 +349,12 @@ 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)
+
+ list_pvs=(); while IFS= read -r line ; do
+ list_pvs+=( "$line" )
+ done < <( rest_pvs_ "$n" 4 )
+
+ recover_vg_ "${list_pvs[@]}"
done
# ---------------------------------------------------------------------
@@ -309,8 +362,7 @@ done
#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
+lvcreate -aey -l2 --type mirror -m1 -n $lv1 $vg "$dev1" "$dev2" "$dev5":$BLOCKS
mimages_are_on_ $lv1 "$dev1" "$dev2"
mirrorlog_is_on_ $lv1 "$dev5"
aux disable_dev "$dev5"
@@ -321,8 +373,7 @@ 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
+lvcreate -aey -l2 --type mirror -m1 -n $lv1 $vg "$dev1" "$dev2" "$dev5":$BLOCKS
lvconvert -m+1 $vg/$lv1 "$dev3"
mimages_are_on_ $lv1 "$dev1" "$dev2" "$dev3"
mirrorlog_is_on_ $lv1 "$dev5"
@@ -337,8 +388,7 @@ recover_vg_ "$dev5"
#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
+lvcreate -an -Zn -l2 --type mirror -m1 --nosync -n $lv1 $vg "$dev1" "$dev2" "$dev5":$BLOCKS
mimages_are_on_ $lv1 "$dev1" "$dev2"
mirrorlog_is_on_ $lv1 "$dev5"
aux disable_dev "$dev1" "$dev2"
@@ -348,8 +398,7 @@ 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
+lvcreate -an -Zn -l2 --type mirror -m1 -n $lv1 $vg "$dev1" "$dev2" "$dev5":$BLOCKS
lvconvert -m+1 $vg/$lv1 "$dev3"
mimages_are_on_ $lv1 "$dev1" "$dev2" "$dev3"
mirrorlog_is_on_ $lv1 "$dev5"
@@ -363,10 +412,8 @@ recover_vg_ "$dev1" "$dev2" "$dev3"
#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
+lvcreate -an -Zn -l2 --type mirror -m1 --nosync -n $lv1 $vg "$dev1" "$dev2" "$dev5":$BLOCKS
+lvcreate -an -Zn -l2 --type mirror -m1 --nosync -n $lv2 $vg "$dev3" "$dev4" "$dev5":$BLOCKS1
mimages_are_on_ $lv1 "$dev1" "$dev2"
mimages_are_on_ $lv2 "$dev3" "$dev4"
mirrorlog_is_on_ $lv1 "$dev5"
@@ -381,10 +428,8 @@ 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
+lvcreate -an -Zn -l2 --type mirror -m1 --nosync -n $lv1 $vg "$dev1" "$dev2" "$dev5":$BLOCKS
+lvcreate -an -Zn -l2 --type mirror -m1 --nosync -n $lv2 $vg "$dev3" "$dev4" "$dev5":$BLOCKS1
mimages_are_on_ $lv1 "$dev1" "$dev2"
mimages_are_on_ $lv2 "$dev3" "$dev4"
mirrorlog_is_on_ $lv1 "$dev5"
@@ -403,8 +448,7 @@ recover_vg_ "$dev2" "$dev4"
#COMM "no failures"
prepare_lvs_
-lvcreate -l2 -m1 -n $lv1 $vg "$dev1" "$dev2" "$dev5":0
-lvchange -an $vg/$lv1
+lvcreate -an -Zn -l2 --type mirror -m1 --nosync -n $lv1 $vg "$dev1" "$dev2" "$dev5":$BLOCKS
mimages_are_on_ $lv1 "$dev1" "$dev2"
mirrorlog_is_on_ $lv1 "$dev5"
vgreduce --removemissing --force $vg
diff --git a/test/shell/missing-pv-unused.sh b/test/shell/missing-pv-unused.sh
new file mode 100644
index 0000000..d74365f
--- /dev/null
+++ b/test/shell/missing-pv-unused.sh
@@ -0,0 +1,79 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2008-2013,2018 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+aux prepare_vg 3
+
+lvcreate -n $lv1 -L8M $vg "$dev2"
+lvcreate -n $lv2 -L8M $vg "$dev3"
+lvcreate -n $lv3 -L8M $vg "$dev2"
+lvcreate -n $lv4 -L8M $vg "$dev3"
+
+vgchange -an $vg
+
+# Fail device that is not used by any LVs.
+aux disable_dev "$dev1"
+
+pvs
+vgs
+lvs -a -o+devices
+
+# Cannot do normal activation of LVs not using failed PV.
+lvchange -ay $vg/$lv1
+lvchange -ay $vg/$lv2
+
+vgchange -an $vg
+
+# Check that MISSING flag is not set in ondisk metadata.
+pvck --dump metadata "$dev2" > meta
+not grep MISSING meta
+rm meta
+
+pvs
+vgs
+lvs -a -o+devices
+
+# lvremove is one of the few commands that is allowed to run
+# when PVs are missing. The vg_write from this command sets
+# the MISSING flag on the PV in the ondisk metadata.
+# (this could be changed, the MISSING flag wouldn't need
+# to be set in the first place since the PV isn't used.)
+lvremove $vg/$lv1
+
+# Check that MISSING flag is set in ondisk metadata.
+pvck --dump metadata "$dev2" > meta
+grep MISSING meta
+rm meta
+
+# with MISSING flag in metadata, restrictions apply
+not lvcreate -l1 $vg
+
+aux enable_dev "$dev1"
+
+# No LVs are using the PV with MISSING flag, so no restrictions
+# are applied, and the vg_write here clears the MISSING flag on disk.
+lvcreate -l1 $vg
+
+# Check that MISSING flag is not set in ondisk metadata.
+pvck --dump metadata "$dev2" > meta
+not grep MISSING meta
+rm meta
+
+
+pvs
+vgs
+lvs -a -o+devices
+
+vgremove -ff $vg
diff --git a/test/shell/missing-pv.sh b/test/shell/missing-pv.sh
new file mode 100644
index 0000000..e1ff659
--- /dev/null
+++ b/test/shell/missing-pv.sh
@@ -0,0 +1,187 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2008-2013,2018 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+aux prepare_vg 3
+
+lvcreate -n $lv1 -L8M --type mirror -m 1 $vg
+lvcreate -n $lv2 -L8M --type mirror -m 1 $vg
+
+vgchange -an $vg
+
+pvs
+vgs
+lvs -a -o+devices
+
+# Fail one leg of each mirror LV.
+aux disable_dev "$dev1"
+
+pvs -o+missing |tee out
+grep missing out |tee out2
+grep unknown out2
+vgs -o+partial,missing_pv_count
+check vg_field $vg vg_partial "partial"
+check vg_field $vg vg_missing_pv_count 1
+lvs -a -o+devices
+
+# Cannot do normal activate of either LV with a failed leg.
+not lvchange -ay $vg/$lv1
+not lvchange -ay $vg/$lv2
+
+# Can activate with partial option.
+lvchange -ay --activationmode partial $vg/$lv1
+lvchange -ay --activationmode partial $vg/$lv2
+
+pvs -o+missing |tee out
+grep missing out |tee out2
+grep unknown out2
+vgs -o+partial,missing_pv_count
+check vg_field $vg vg_partial "partial"
+check vg_field $vg vg_missing_pv_count 1
+lvs -a -o+devices
+
+# Repair lv1 so it no longer uses failed dev.
+lvconvert --repair --yes $vg/$lv1
+
+# Check that MISSING flag is set in ondisk metadata,
+# it should have been written by the lvconvert since the
+# missing PV is still used by lv2.
+pvck --dump metadata "$dev2" > meta
+grep MISSING meta
+rm meta
+
+pvs -o+missing |tee out
+grep missing out |tee out2
+grep unknown out2
+vgs -o+partial,missing_pv_count
+check vg_field $vg vg_partial "partial"
+check vg_field $vg vg_missing_pv_count 1
+lvs -a -o+devices
+
+# Verify normal activation is possible of lv1 since it's
+# not using any failed devs, and partial activation is
+# required for lv2 since it's still using the failed dev.
+vgchange -an $vg
+lvchange -ay $vg/$lv1
+not lvchange -ay $vg/$lv2
+vgchange -an $vg
+
+aux enable_dev "$dev1"
+
+pvs -o+missing |tee out
+grep missing out |tee out2
+grep "$dev1" out2
+vgs -o+partial,missing_pv_count
+check vg_field $vg vg_partial "partial"
+check vg_field $vg vg_missing_pv_count 1
+lvs -a -o+devices
+
+# TODO: check that lv2 has partial flag, lv1 does not
+# (there's no partial reporting option, only attr p.)
+
+# Check that MISSING flag is still set in ondisk
+# metadata since the previously missing dev is still
+# used by lv2.
+pvck --dump metadata "$dev2" > meta
+grep MISSING meta
+rm meta
+
+# The missing pv restrictions still apply even after
+# the dev has reappeared since it has the MISSING flag.
+not lvchange -ay $vg/$lv2
+not lvcreate -l1 $vg
+
+# Update old metadata on the previously missing PV.
+# This should not clear the MISSING flag because the
+# previously missing PV is still used by lv2.
+# This would be done by any command that writes
+# metadata, e.g. lvcreate, but since we are in a
+# state with a missing pv, most commands that write
+# metadata are restricted, so use a command that
+# explicitly writes/fixes metadata.
+vgck --updatemetadata $vg
+
+pvs -o+missing |tee out
+grep missing out |tee out2
+grep "$dev1" out2
+vgs -o+partial,missing_pv_count
+check vg_field $vg vg_partial "partial"
+check vg_field $vg vg_missing_pv_count 1
+lvs -a -o+devices
+
+# Check that MISSING flag is still set in ondisk metadata since the
+# previously missing dev is still used by lv2.
+pvck --dump metadata "$dev2" > meta
+grep MISSING meta
+rm meta
+
+# The missing pv restrictions still apply since it has the MISSING flag.
+not lvchange -ay $vg/$lv2
+not lvcreate -l1 $vg
+
+lvchange -ay --activationmode partial $vg/$lv2
+
+# Replace the missing leg of LV2 so no LV will be using the dev that was
+# missing. The MISSING_PV flag will not have been cleared from the
+# metadata yet; that will take another metadata update.
+lvconvert --repair --yes $vg/$lv2
+
+lvs -a -o+devices | tee out
+not grep "$dev1" out
+
+# The MISSING_PV flag hasn't been cleared from the metadata yet, but now
+# that the PV is not used by any more LVs, that flag will be cleared from
+# the metadata in the next update.
+pvck --dump metadata "$dev2" > meta
+grep MISSING meta
+rm meta
+
+# Reporting commands run vg_read which sees MISSING_PV in the metadata,
+# but vg_read then sees the dev is no longer used by any LV, so vg_read
+# clears the MISSING_PV flag in the vg struct (not in the metadata) before
+# returning the vg struct to the caller. It's cleared in the vg struct so
+# that the limitations of having a missing PV are not applied to the
+# command. The caller sees/uses/reports the VG as having no missing PV,
+# even though the metadata still contains MISSING_PV. The MISSING_PV flag
+# is no longer needed in the metadata, but there has simply not been a
+# metadata update yet to clear it.
+# The message that's printed in this case is:
+# WARNING: VG %s has unused reappeared PV %s %s
+pvs -o+missing |tee out
+not grep missing out
+vgs -o+partial,missing_pv_count
+check vg_field $vg vg_partial ""
+check vg_field $vg vg_missing_pv_count 0
+
+# Run any command that updates the metadata, and the MISSING_PV flag will
+# be cleared. Here just use lvcreate -l1, or we could use
+# vgck --updatemetadata.
+lvcreate -l1 $vg
+
+# Now the MISSING flag is removed from the ondisk metadata.
+pvck --dump metadata "$dev2" > meta
+not grep MISSING meta
+rm meta
+
+# and commands continue to report no missing PV
+pvs -o+missing |tee out
+not grep missing out
+vgs -o+partial,missing_pv_count
+check vg_field $vg vg_partial ""
+check vg_field $vg vg_missing_pv_count 0
+
+vgchange -an $vg
+
+vgremove -ff $vg
diff --git a/test/shell/multi_hosts_lv_ex_timeout_hosta.sh b/test/shell/multi_hosts_lv_ex_timeout_hosta.sh
new file mode 100644
index 0000000..d78b6d9
--- /dev/null
+++ b/test/shell/multi_hosts_lv_ex_timeout_hosta.sh
@@ -0,0 +1,87 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2021 Seagate, 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 v2.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+# This testing script is for multi-hosts testing.
+#
+# On the host A:
+# make check_lvmlockd_idm \
+# LVM_TEST_BACKING_DEVICE=/dev/sdj3,/dev/sdk3,/dev/sdl3 \
+# LVM_TEST_MULTI_HOST=1 T=multi_hosts_lv_ex_timeout_hosta.sh
+# On the host B:
+# make check_lvmlockd_idm \
+# LVM_TEST_BACKING_DEVICE=/dev/sdj3,/dev/sdk3,/dev/sdl3 \
+# LVM_TEST_MULTI_HOST=1 T=multi_hosts_lv_ex_timeout_hostb.sh
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+[ -z "$LVM_TEST_MULTI_HOST" ] && skip;
+
+IFS=',' read -r -a BLKDEVS <<< "$LVM_TEST_BACKING_DEVICE"
+
+for d in "${BLKDEVS[@]}"; do
+ aux extend_filter_LVMTEST "a|$d|"
+done
+
+aux lvmconf "devices/allow_changes_with_duplicate_pvs = 1"
+
+for d in "${BLKDEVS[@]}"; do
+ dd if=/dev/zero of="$d" bs=32k count=1
+ wipefs -a "$d" 2>/dev/null || true
+
+ sg_dev=$(sg_map26 "$d")
+ if [ -n "$LVM_TEST_LOCK_TYPE_IDM" ]; then
+ echo "Cleanup IDM context for drive ${d} ($sg_dev)"
+ sg_raw -v -r 512 -o idm_tmp_data.bin "$sg_dev" \
+ 88 00 01 00 00 00 00 20 FF 01 00 00 00 01 00 00
+ sg_raw -v -s 512 -i idm_tmp_data.bin "$sg_dev" \
+ 8E 00 FF 00 00 00 00 00 00 00 00 00 00 01 00 00
+ rm idm_tmp_data.bin
+ fi
+done
+
+for i in $(seq 1 ${#BLKDEVS[@]}); do
+ vgcreate $SHARED TESTVG$i ${BLKDEVS[$(( i - 1 ))]}
+ lvcreate -a n --zero n -l 1 -n foo TESTVG$i
+ lvchange -a ey TESTVG$i/foo
+done
+
+for d in "${BLKDEVS[@]}"; do
+ drive_wwn=$(udevadm info "$d" | awk -F= '/E: ID_WWN=/ {print $2}')
+ for dev in /dev/*; do
+ if [ -b "$dev" ] && [[ ! "$dev" =~ [0-9] ]]; then
+ wwn=$(udevadm info "$dev" | awk -F= '/E: ID_WWN=/ {print $2}')
+ if [ "$wwn" = "$drive_wwn" ]; then
+ base_name="$(basename -- ${dev})"
+ drive_list+=("$base_name")
+ host_list+=( $(readlink "/sys/block/$base_name" | awk -F'/' '{print $6}') )
+ fi
+ fi
+ done
+done
+
+for d in "${drive_list[@]}"; do
+ [ -f /sys/block/$d/device/delete ] && echo 1 > /sys/block/$d/device/delete
+done
+
+sleep 100
+
+for i in $(seq 1 ${#BLKDEVS[@]}); do
+ check grep_lvmlockd_dump "S lvm_TESTVG$i kill_vg"
+ lvmlockctl --drop TESTVG$i
+done
+
+# Rescan drives so can probe the deleted drives and join back them
+for h in "${host_list[@]}"; do
+ [ -f /sys/class/scsi_host/${h}/scan ] && echo "- - -" > /sys/class/scsi_host/${h}/scan
+done
diff --git a/test/shell/multi_hosts_lv_ex_timeout_hostb.sh b/test/shell/multi_hosts_lv_ex_timeout_hostb.sh
new file mode 100644
index 0000000..f0273fa
--- /dev/null
+++ b/test/shell/multi_hosts_lv_ex_timeout_hostb.sh
@@ -0,0 +1,56 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2021 Seagate, 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 v2.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+# This testing script is for multi-hosts testing.
+#
+# On the host A:
+# make check_lvmlockd_idm \
+# LVM_TEST_BACKING_DEVICE=/dev/sdj3,/dev/sdk3,/dev/sdl3 \
+# LVM_TEST_MULTI_HOST=1 T=multi_hosts_lv_ex_timeout_hosta.sh
+# On the host B:
+# make check_lvmlockd_idm \
+# LVM_TEST_BACKING_DEVICE=/dev/sdj3,/dev/sdk3,/dev/sdl3 \
+# LVM_TEST_MULTI_HOST=1 T=multi_hosts_lv_ex_timeout_hostb.sh
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+[ -z "$LVM_TEST_MULTI_HOST" ] && skip;
+
+IFS=',' read -r -a BLKDEVS <<< "$LVM_TEST_BACKING_DEVICE"
+
+for d in "${BLKDEVS[@]}"; do
+ aux extend_filter_LVMTEST "a|$d|"
+done
+
+aux lvmconf "devices/allow_changes_with_duplicate_pvs = 1"
+
+vgchange --lock-start
+
+vgdisplay
+
+for i in $(seq 1 ${#BLKDEVS[@]}); do
+ not lvchange -a ey TESTVG$i/foo
+done
+
+# Sleep for 70 seconds so the previous lease is expired
+sleep 70
+
+for i in $(seq 1 ${#BLKDEVS[@]}); do
+ lvchange -a ey TESTVG$i/foo
+ lvchange -a n TESTVG$i/foo
+done
+
+for i in $(seq 1 ${#BLKDEVS[@]}); do
+ vgremove -f TESTVG$i
+done
diff --git a/test/shell/multi_hosts_lv_hosta.sh b/test/shell/multi_hosts_lv_hosta.sh
new file mode 100644
index 0000000..2ae2989
--- /dev/null
+++ b/test/shell/multi_hosts_lv_hosta.sh
@@ -0,0 +1,78 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2020 Seagate, 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 v2.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+# This testing script is for multi-hosts testing, the paired scripts
+# are: multi_hosts_lv_hosta.sh / multi_hosts_lv_hostb.sh
+#
+# On the host A:
+# make check_lvmlockd_idm \
+# LVM_TEST_BACKING_DEVICE=/dev/sdj3,/dev/sdk3,/dev/sdl3 \
+# LVM_TEST_MULTI_HOST=1 T=multi_hosts_lv_hosta.sh
+# On the host B:
+# make check_lvmlockd_idm \
+# LVM_TEST_BACKING_DEVICE=/dev/sdj3,/dev/sdk3,/dev/sdl3 \
+# LVM_TEST_MULTI_HOST=1 T=multi_hosts_lv_hostb.sh
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+[ -z "$LVM_TEST_MULTI_HOST" ] && skip;
+
+IFS=',' read -r -a BLKDEVS <<< "$LVM_TEST_BACKING_DEVICE"
+
+for d in "${BLKDEVS[@]}"; do
+ aux extend_filter_LVMTEST "a|$d|"
+done
+
+aux lvmconf "devices/allow_changes_with_duplicate_pvs = 1"
+
+BLKDEVS_NUM=${#BLKDEVS[@]}
+
+for d in "${BLKDEVS[@]}"; do
+ dd if=/dev/zero of="$d" bs=32k count=1
+ wipefs -a "$d" 2>/dev/null || true
+
+ sg_dev=$(sg_map26 "$d")
+ if [ -n "$LVM_TEST_LOCK_TYPE_IDM" ]; then
+ echo "Cleanup IDM context for drive ${d} ($sg_dev)"
+ sg_raw -v -r 512 -o idm_tmp_data.bin "$sg_dev" \
+ 88 00 01 00 00 00 00 20 FF 01 00 00 00 01 00 00
+ sg_raw -v -s 512 -i idm_tmp_data.bin "$sg_dev" \
+ 8E 00 FF 00 00 00 00 00 00 00 00 00 00 01 00 00
+ rm idm_tmp_data.bin
+ fi
+done
+
+#aux prepare_pvs $BLKDEVS_NUM 6400
+
+for i in $(seq 1 ${#BLKDEVS[@]}); do
+ echo $i
+ d="dev$i"
+ vgcreate $SHARED TESTVG$i ${BLKDEVS[$(( i - 1 ))]}
+
+ for j in {1..20}; do
+ lvcreate -a n --zero n -l 1 -n foo$j TESTVG$i
+ done
+done
+
+for i in $(seq 1 ${#BLKDEVS[@]}); do
+ for j in {1..20}; do
+ lvchange -a ey TESTVG$i/foo$j
+ done
+done
+
+for i in $(seq 1 ${#BLKDEVS[@]}); do
+ for j in {1..20}; do
+ lvchange -a n TESTVG$i/foo$j
+ done
+done
diff --git a/test/shell/multi_hosts_lv_hostb.sh b/test/shell/multi_hosts_lv_hostb.sh
new file mode 100644
index 0000000..13efd1a
--- /dev/null
+++ b/test/shell/multi_hosts_lv_hostb.sh
@@ -0,0 +1,61 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2020 Seagate, 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 v2.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+# This testing script is for multi-hosts testing, the paired scripts
+# are: multi_hosts_lv_hosta.sh / multi_hosts_lv_hostb.sh
+#
+# On the host A:
+# make check_lvmlockd_idm \
+# LVM_TEST_BACKING_DEVICE=/dev/sdj3,/dev/sdk3,/dev/sdl3 \
+# LVM_TEST_MULTI_HOST=1 T=multi_hosts_lv_hosta.sh
+# On the host B:
+# make check_lvmlockd_idm \
+# LVM_TEST_BACKING_DEVICE=/dev/sdj3,/dev/sdk3,/dev/sdl3 \
+# LVM_TEST_MULTI_HOST=1 T=multi_hosts_lv_hostb.sh
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+[ -z "$LVM_TEST_MULTI_HOST" ] && skip;
+
+IFS=',' read -r -a BLKDEVS <<< "$LVM_TEST_BACKING_DEVICE"
+
+for d in "${BLKDEVS[@]}"; do
+ aux extend_filter_LVMTEST "a|$d|"
+done
+
+aux lvmconf "devices/allow_changes_with_duplicate_pvs = 1"
+
+vgchange --lock-start
+
+for i in $(seq 1 ${#BLKDEVS[@]}); do
+ for j in {1..20}; do
+ lvchange -a sy TESTVG$i/foo$j
+ done
+done
+
+for i in $(seq 1 ${#BLKDEVS[@]}); do
+ for j in {1..20}; do
+ lvchange -a ey TESTVG$i/foo$j
+ done
+done
+
+for i in $(seq 1 ${#BLKDEVS[@]}); do
+ for j in {1..20}; do
+ lvchange -a n TESTVG$i/foo$j
+ done
+done
+
+for i in $(seq 1 ${#BLKDEVS[@]}); do
+ vgremove -f TESTVG$i
+done
diff --git a/test/shell/multi_hosts_lv_sh_timeout_hosta.sh b/test/shell/multi_hosts_lv_sh_timeout_hosta.sh
new file mode 100644
index 0000000..798f051
--- /dev/null
+++ b/test/shell/multi_hosts_lv_sh_timeout_hosta.sh
@@ -0,0 +1,87 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2021 Seagate, 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 v2.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+# This testing script is for multi-hosts testing.
+#
+# On the host A:
+# make check_lvmlockd_idm \
+# LVM_TEST_BACKING_DEVICE=/dev/sdj3,/dev/sdk3,/dev/sdl3 \
+# LVM_TEST_MULTI_HOST=1 T=multi_hosts_lv_sh_timeout_hosta.sh
+# On the host B:
+# make check_lvmlockd_idm \
+# LVM_TEST_BACKING_DEVICE=/dev/sdj3,/dev/sdk3,/dev/sdl3 \
+# LVM_TEST_MULTI_HOST=1 T=multi_hosts_lv_sh_timeout_hostb.sh
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+[ -z "$LVM_TEST_MULTI_HOST" ] && skip;
+
+IFS=',' read -r -a BLKDEVS <<< "$LVM_TEST_BACKING_DEVICE"
+
+for d in "${BLKDEVS[@]}"; do
+ aux extend_filter_LVMTEST "a|$d|"
+done
+
+aux lvmconf "devices/allow_changes_with_duplicate_pvs = 1"
+
+for d in "${BLKDEVS[@]}"; do
+ dd if=/dev/zero of="$d" bs=32k count=1
+ wipefs -a "$d" 2>/dev/null || true
+
+ sg_dev=$(sg_map26 "$d")
+ if [ -n "$LVM_TEST_LOCK_TYPE_IDM" ]; then
+ echo "Cleanup IDM context for drive ${d} ($sg_dev)"
+ sg_raw -v -r 512 -o idm_tmp_data.bin "$sg_dev" \
+ 88 00 01 00 00 00 00 20 FF 01 00 00 00 01 00 00
+ sg_raw -v -s 512 -i idm_tmp_data.bin "$sg_dev" \
+ 8E 00 FF 00 00 00 00 00 00 00 00 00 00 01 00 00
+ rm idm_tmp_data.bin
+ fi
+done
+
+for i in $(seq 1 ${#BLKDEVS[@]}); do
+ vgcreate $SHARED TESTVG$i ${BLKDEVS[$(( i - 1 ))]}
+ lvcreate -a n --zero n -l 1 -n foo TESTVG$i
+ lvchange -a sy TESTVG$i/foo
+done
+
+for d in "${BLKDEVS[@]}"; do
+ drive_wwn=$(udevadm info "$d" | awk -F= '/E: ID_WWN=/ {print $2}')
+ for dev in /dev/*; do
+ if [ -b "$dev" ] && [[ ! "$dev" =~ [0-9] ]]; then
+ wwn=$(udevadm info "$dev" | awk -F= '/E: ID_WWN=/ {print $2}')
+ if [ "$wwn" = "$drive_wwn" ]; then
+ base_name="$(basename -- ${dev})"
+ drive_list+=("$base_name")
+ host_list+=( $(readlink "/sys/block/$base_name" | awk -F'/' '{print $6}') )
+ fi
+ fi
+ done
+done
+
+for d in "${drive_list[@]}"; do
+ [ -f "/sys/block/$d/device/delete" ] && echo 1 > "/sys/block/$d/device/delete"
+done
+
+sleep 100
+
+for i in $(seq 1 ${#BLKDEVS[@]}); do
+ check grep_lvmlockd_dump "S lvm_TESTVG$i kill_vg"
+ lvmlockctl --drop TESTVG$i
+done
+
+# Rescan drives so can probe the deleted drives and join back them
+for h in "${host_list[@]}"; do
+ [ -f "/sys/class/scsi_host/$h/scan" ] && echo "- - -" > "/sys/class/scsi_host/$h/scan"
+done
diff --git a/test/shell/multi_hosts_lv_sh_timeout_hostb.sh b/test/shell/multi_hosts_lv_sh_timeout_hostb.sh
new file mode 100644
index 0000000..7aea223
--- /dev/null
+++ b/test/shell/multi_hosts_lv_sh_timeout_hostb.sh
@@ -0,0 +1,56 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2021 Seagate, 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 v2.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+# This testing script is for multi-hosts testing.
+#
+# On the host A:
+# make check_lvmlockd_idm \
+# LVM_TEST_BACKING_DEVICE=/dev/sdj3,/dev/sdk3,/dev/sdl3 \
+# LVM_TEST_MULTI_HOST=1 T=multi_hosts_lv_ex_timeout_hosta.sh
+# On the host B:
+# make check_lvmlockd_idm \
+# LVM_TEST_BACKING_DEVICE=/dev/sdj3,/dev/sdk3,/dev/sdl3 \
+# LVM_TEST_MULTI_HOST=1 T=multi_hosts_lv_ex_timeout_hostb.sh
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+[ -z "$LVM_TEST_MULTI_HOST" ] && skip;
+
+IFS=',' read -r -a BLKDEVS <<< "$LVM_TEST_BACKING_DEVICE"
+
+for d in "${BLKDEVS[@]}"; do
+ aux extend_filter_LVMTEST "a|$d|"
+done
+
+aux lvmconf "devices/allow_changes_with_duplicate_pvs = 1"
+
+vgchange --lock-start
+
+vgdisplay
+
+for i in $(seq 1 ${#BLKDEVS[@]}); do
+ lvchange -a sy TESTVG$i/foo
+done
+
+# Sleep for 70 seconds so the previous lease is expired
+sleep 70
+
+for i in $(seq 1 ${#BLKDEVS[@]}); do
+ lvchange -a ey TESTVG$i/foo
+ lvchange -a n TESTVG$i/foo
+done
+
+for i in $(seq 1 ${#BLKDEVS[@]}); do
+ vgremove -f TESTVG$i
+done
diff --git a/test/shell/multi_hosts_vg_hosta.sh b/test/shell/multi_hosts_vg_hosta.sh
new file mode 100644
index 0000000..1534749
--- /dev/null
+++ b/test/shell/multi_hosts_vg_hosta.sh
@@ -0,0 +1,45 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2020 Seagate, 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 v2.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+# This testing script is for multi-hosts testing, the paired scripts
+# are: multi_hosts_vg_hosta.sh / multi_hosts_vg_hostb.sh
+#
+# On the host A:
+# make check_lvmlockd_idm \
+# LVM_TEST_BACKING_DEVICE=/dev/sdj3,/dev/sdk3,/dev/sdl3 \
+# LVM_TEST_MULTI_HOST=1 T=multi_hosts_vg_hosta.sh
+# On the host B:
+# make check_lvmlockd_idm \
+# LVM_TEST_BACKING_DEVICE=/dev/sdj3,/dev/sdk3,/dev/sdl3 \
+# LVM_TEST_MULTI_HOST=1 T=multi_hosts_vg_hostb.sh
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+[ -z "$LVM_TEST_MULTI_HOST" ] && skip;
+
+IFS=',' read -r -a BLKDEVS <<< "$LVM_TEST_BACKING_DEVICE"
+
+for d in "${BLKDEVS[@]}"; do
+ aux extend_filter_LVMTEST "a|$d|"
+done
+
+aux lvmconf "devices/allow_changes_with_duplicate_pvs = 1"
+
+i=0
+for d in "${BLKDEVS[@]}"; do
+ echo $i
+ i=$((i+1))
+ vgcreate $SHARED TESTVG$i $d
+ vgchange -a n TESTVG$i
+done
diff --git a/test/shell/multi_hosts_vg_hostb.sh b/test/shell/multi_hosts_vg_hostb.sh
new file mode 100644
index 0000000..bab65b6
--- /dev/null
+++ b/test/shell/multi_hosts_vg_hostb.sh
@@ -0,0 +1,52 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2020 Seagate, 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 v2.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+# This testing script is for multi-hosts testing, the paired scripts
+# are: multi_hosts_vg_hosta.sh / multi_hosts_vg_hostb.sh
+#
+# On the host A:
+# make check_lvmlockd_idm \
+# LVM_TEST_BACKING_DEVICE=/dev/sdj3,/dev/sdk3,/dev/sdl3 \
+# LVM_TEST_MULTI_HOST=1 T=multi_hosts_vg_hosta.sh
+# On the host B:
+# make check_lvmlockd_idm \
+# LVM_TEST_BACKING_DEVICE=/dev/sdj3,/dev/sdk3,/dev/sdl3 \
+# LVM_TEST_MULTI_HOST=1 T=multi_hosts_vg_hostb.sh
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+[ -z "$LVM_TEST_MULTI_HOST" ] && skip;
+
+IFS=',' read -r -a BLKDEVS <<< "$LVM_TEST_BACKING_DEVICE"
+
+for d in "${BLKDEVS[@]}"; do
+ aux extend_filter_LVMTEST "a|$d|"
+done
+
+aux lvmconf "devices/allow_changes_with_duplicate_pvs = 1"
+
+vgchange --lock-start
+
+i=0
+for d in "${BLKDEVS[@]}"; do
+ i=$((i+1))
+ check vg_field TESTVG$i lv_count 0
+done
+
+i=0
+for d in "${BLKDEVS[@]}"; do
+ i=$((i+1))
+ vgchange -a ey TESTVG$i
+ vgremove -ff TESTVG$i
+done
diff --git a/test/shell/multipath-config.sh b/test/shell/multipath-config.sh
new file mode 100644
index 0000000..ffb7d63
--- /dev/null
+++ b/test/shell/multipath-config.sh
@@ -0,0 +1,171 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2021 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+test_description='using multipath blacklist'
+
+SKIP_WITH_LVMPOLLD=1
+SKIP_WITH_LVMLOCKD=1
+
+. lib/inittest
+
+# FIXME: don't run this test by default because it destroys the
+# local multipath config, the timing of multipath/dm/lvm interactions
+# is fragile, and there's insufficient cleanup after a test fails.
+skip
+
+systemctl stop multipathd
+multipath -F || true
+rm /etc/multipath/wwids || true
+rmmod scsi_debug || true
+rm /etc/multipath/conf.d/lvmtest.conf || true
+
+modprobe --dry-run scsi_debug || skip
+multipath -l || skip
+multipath -l | grep scsi_debug && skip
+ls /etc/multipath/wwids && skip
+
+# Need to use /dev/mapper/mpath
+aux lvmconf 'devices/dir = "/dev"'
+aux lvmconf 'devices/scan = "/dev"'
+# Could set filter to $MP and the component /dev/sd devs
+aux lvmconf "devices/filter = [ \"a|.*|\" ]"
+aux lvmconf "devices/global_filter = [ \"a|.*|\" ]"
+
+modprobe scsi_debug dev_size_mb=16 num_tgts=1
+sleep 2
+
+# Get scsi device name created by scsi_debug.
+# SD = sdh
+# SD_DEV = /dev/sdh
+
+SD=$(grep -H scsi_debug /sys/block/sd*/device/model | cut -f4 -d /);
+echo $SD
+SD_DEV=/dev/$SD
+echo $SD_DEV
+
+# if multipath claimed SD, then io will fail
+#dd if=$SD_DEV of=/dev/null bs=4k count=1 iflag=direct
+#dd if=/dev/zero of=$SD_DEV bs=4k count=1 oflag=direct
+
+# check if multipathd claimed the scsi dev when it appears and create mp dm device
+sleep 2
+multipath -l
+# create the mp dm device
+multipath $SD_DEV
+
+# Get mpath device name created by multipath.
+# MP = mpatha
+# MP_DEV = /dev/maper/mpatha
+
+MP=$(multipath -l | grep scsi_debug | cut -f1 -d ' ')
+echo $MP
+MP_DEV=/dev/mapper/$MP
+echo $MP_DEV
+
+dd if=$MP_DEV of=/dev/null bs=4k count=1 iflag=direct
+dd if=/dev/zero of=$MP_DEV bs=4k count=1 oflag=direct
+
+# Get wwid for the mp and sd dev.
+WWID=$(multipath -l $MP_DEV | head -1 | awk '{print $2}' | tr -d ')' | tr -d '(')
+echo $WWID
+
+grep $WWID /etc/multipath/wwids
+
+pvcreate $MP_DEV
+vgcreate $vg1 $MP_DEV
+
+not pvs $SD_DEV
+pvs $MP_DEV
+
+# remove mpath dm device then check that SD_DEV is
+# filtered based on /etc/multipath/wwids instead of
+# based on sysfs holder
+multipath -f $MP
+sleep 2
+not pvs $SD_DEV
+multipath $SD_DEV
+sleep 2
+multipath -l | grep $SD
+
+#
+# Add the wwid to the blacklist, then restart multipath
+# so the sd dev should no longer be used by multipath,
+# but the sd dev wwid is still in /etc/multipath/wwids.
+#
+
+mkdir /etc/multipath/conf.d/ || true
+rm -f /etc/multipath/conf.d/lvmtest.conf
+
+cat <<EOF > "/etc/multipath/conf.d/lvmtest.conf"
+blacklist {
+ wwid $WWID
+}
+EOF
+
+cat /etc/multipath/conf.d/lvmtest.conf
+
+multipath -r
+sleep 2
+
+grep $WWID /etc/multipath/wwids
+
+multipath -l |tee out
+not grep $SD out
+not grep $MP out
+not grep $WWID out
+
+not pvs $MP_DEV
+pvs $SD_DEV
+vgs $vg1
+
+#
+# Add the wwid to the blacklist_exceptions, in addition
+# to the blacklist, then restart multipath so the
+# sd dev should again be used by multipath.
+#
+
+rm -f /etc/multipath/conf.d/lvmtest.conf
+
+cat <<EOF > "/etc/multipath/conf.d/lvmtest.conf"
+blacklist {
+wwid $WWID
+}
+blacklist_exceptions {
+wwid $WWID
+}
+EOF
+
+cat /etc/multipath/conf.d/lvmtest.conf
+
+multipath -r
+sleep 2
+
+grep $WWID /etc/multipath/wwids
+
+multipath -l |tee out
+grep $SD out
+grep $MP out
+grep $WWID out
+
+pvs $MP_DEV
+not pvs $SD_DEV
+vgs $vg1
+lvs $vg1
+
+sleep 2
+vgremove -ff $vg1
+sleep 2
+multipath -f $MP
+rm /etc/multipath/conf.d/lvmtest.conf
+rm /etc/multipath/wwids
+sleep 1
+rmmod scsi_debug
diff --git a/test/shell/name-mangling.sh b/test/shell/name-mangling.sh
index 5b92e60..4287939 100644
--- a/test/shell/name-mangling.sh
+++ b/test/shell/name-mangling.sh
@@ -1,4 +1,5 @@
-#!/bin/sh
+#!/usr/bin/env bash
+
# Copyright (C) 2012 Red Hat, Inc. All rights reserved.
#
# This copyrighted material is made available to anyone wishing to use,
@@ -7,17 +8,20 @@
#
# 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
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+# This test is not using any lvm command
+# so skip duplicate CLMVD and lvmetad test
-. lib/test
+SKIP_WITH_LVMPOLLD=1
-name_prefix=$RANDOM
+. lib/inittest
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"
+CORRECT_FORM_STR="already in correct form"
RENAMING_STR="renaming to"
function create_dm_dev()
@@ -34,7 +38,7 @@ function create_dm_dev()
verify_udev=""
fi
- dmsetup create "${name_prefix}$name" $verify_udev --manglename $mode --table "0 1 zero"
+ aux dmsetup create "${PREFIX}$name" $verify_udev --manglename $mode --table "0 1 zero"
}
function remove_dm_dev()
@@ -48,7 +52,7 @@ function remove_dm_dev()
verify_udev=""
fi
- dmsetup remove $verify_udev --manglename $mode "${name_prefix}$name"
+ aux dmsetup remove $verify_udev --manglename $mode "${PREFIX}$name"
}
function check_create_and_remove()
@@ -64,19 +68,19 @@ function check_create_and_remove()
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
+ aux dmsetup create "${PREFIX}$input_name" $verify_udev --manglename $mode --table "0 1 zero" 2>err && \
+ test -b "$DM_DEV_DIR/mapper/${PREFIX}$dm_name" && \
+ aux dmsetup remove "${PREFIX}$input_name" $verify_udev --manglename $mode || r=1
- if [ $dm_name = "FAIL_MIXED" ]; then
+ if [ "$dm_name" = "FAIL_MIXED" ]; then
r=0
- grep "$FAILED_MIXED_STR" err || r=1
- elif [ $dm_name = "FAIL_MULTI" ]; then
+ grep "$FAIL_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
+ grep "$FAIL_MULTI_STR" err || r=1
+ elif [ "$dm_name" = "FAIL_BLACK" ]; then
r=0
- grep "$FAILED_BLACK_STR" err || r=1
+ grep "$FAIL_BLACK_STR" err || r=1
fi
return $r
@@ -85,11 +89,11 @@ function check_create_and_remove()
function check_dm_field()
{
local mode=$1
- local dm_name="$2"
+ local dm_name=$2
local field=$3
- local expected="$4"
+ local expected=$4
- value=$(dmsetup info --rows --noheadings --manglename $mode -c -o $field "${DM_DEV_DIR}/mapper/${name_prefix}$dm_name" 2> err || true)
+ value=$(dmsetup info --rows --noheadings --manglename $mode -c -o $field "${DM_DEV_DIR}/mapper/${PREFIX}$dm_name" 2> err || true)
if [ "$expected" = "FAIL_MIXED" ]; then
grep "$FAIL_MIXED_STR" err
@@ -98,19 +102,19 @@ function check_dm_field()
elif [ "$expected" = "FAIL_BLACK" ]; then
grep "$FAIL_BLACK_STR" err
else
- test "$value" = "${name_prefix}$expected"
+ test "$value" = "${PREFIX}$expected"
fi
}
function check_expected_names()
{
local mode=$1
- local dm_name="$2"
+ local dm_name=$2
local r=0
create_dm_dev none "$dm_name"
- test -b "$DM_DEV_DIR/mapper/${name_prefix}$dm_name" && \
+ test -b "$DM_DEV_DIR/mapper/${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" && \
@@ -124,14 +128,14 @@ function check_expected_names()
function check_mangle_cmd()
{
local mode=$1
- local dm_name="$2"
- local expected="$3"
+ 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;
+ dmsetup mangle --manglename $mode --verifyudev "${PREFIX}$dm_name" 1>out 2>err || true;
if [ "$expected" = "OK" ]; then
grep "$CORRECT_FORM_STR" out || r=1
@@ -141,17 +145,40 @@ function check_mangle_cmd()
grep "$FAIL_MULTI_STR" err || r=1
else
rename_expected=1
- grep -F "$RENAMING_STR ${name_prefix}$expected" out || r=1
+ if grep -F "$RENAMING_STR ${PREFIX}$expected" out; then
+ # Check the old node is really renamed.
+ test -b "$DM_DEV_DIR/mapper/${PREFIX}$dm_name" && r=1
+ # FIXME: when renaming to mode=none with udev, udev will
+ # remove the old_node, but fails to properly rename
+ # to new_node. The libdevmapper code tries to call
+ # rename(old_node,new_node), but that won't do anything
+ # since the old node is already removed by udev.
+ # For example renaming 'a\x20b' to 'a b':
+ # - udev removes 'a\x20b'
+ # - udev creates 'a' and 'b' (since it considers the ' ' as a delimiter)
+ # - libdevmapper checks udev has done the rename properly
+ # - libdevmapper calls stat(new_node) and it does not see it
+ # - libdevmapper calls rename(old_node,new_node)
+ # - the rename is a NOP since the old_node does not exist anymore
+ #
+ # Remove this condition once the problem is fixed in libdevmapper.
+ #
+ if [ "$mode" != "none" ]; then
+ test -b "$DM_DEV_DIR/mapper/${PREFIX}$expected" || r=1
+ fi
+ else
+ r=1
+ fi
fi
- if [ $r = 0 -a $rename_expected = 1 ]; then
+ if [ "$r" = 0 ] && [ "$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 "$new_name" || \
remove_dm_dev none "$dm_name" || remove_dm_dev none "$expected"
else
# successfuly done nothing
@@ -164,11 +191,12 @@ function check_mangle_cmd()
# 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
+ln -s "$DM_DEV_DIR/mapper/${PREFIX}abc" "$DM_DEV_DIR/${PREFIX}xyz"
+aux dmsetup status "$DM_DEV_DIR/${PREFIX}xyz" || r=1
+rm -f "$DM_DEV_DIR/${PREFIX}xyz"
remove_dm_dev auto "abc"
-if [ r = 1 ]; then
- exit 1
+if [ "$r" = 1 ]; then
+ return "$r"
fi
### ALL WHITELISTED CHARACTERS ###
diff --git a/test/shell/nomda-missing.sh b/test/shell/nomda-missing.sh
index 2cf759e..1899f03 100644
--- a/test/shell/nomda-missing.sh
+++ b/test/shell/nomda-missing.sh
@@ -1,4 +1,4 @@
-#!/bin/sh
+#!/usr/bin/env bash
# Copyright (C) 2010 Red Hat, Inc. All rights reserved.
#
@@ -8,28 +8,31 @@
#
# 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
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
-. lib/test
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
aux prepare_devs 4
pvcreate "$dev1" "$dev2"
pvcreate --metadatacopies 0 "$dev3" "$dev4"
-vgcreate -c n $vg "$dev1" "$dev2" "$dev3" "$dev4"
+vgcreate $SHARED $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 -aey -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"
+lvcreate -aey -l1 --type mirror -m1 -n mirror12 --mirrorlog core $vg "$dev1" "$dev2"
+lvcreate -aey -l1 --type mirror -m1 -n mirror123 $vg "$dev1" "$dev2" "$dev3"
vgchange -a n $vg
aux disable_dev "$dev1"
-not vgchange -a y $vg
+not vgchange -aey $vg
not vgck $vg
check inactive $vg linear1
@@ -43,7 +46,7 @@ check inactive $vg mirror123
vgchange -a n $vg
aux enable_dev "$dev1"
aux disable_dev "$dev2"
-not vgchange -a y $vg
+not vgchange -aey $vg
not vgck $vg
check active $vg linear1
@@ -57,7 +60,7 @@ check inactive $vg mirror123
vgchange -a n $vg
aux enable_dev "$dev2"
aux disable_dev "$dev3"
-not vgchange -a y $vg
+not vgchange -aey $vg
not vgck $vg
check active $vg origin1
@@ -71,7 +74,9 @@ check active $vg mirror12
vgchange -a n $vg
aux enable_dev "$dev3"
aux disable_dev "$dev4"
-vgchange -a y $vg
+dmsetup table
+dmsetup info -c
+vgchange -aey $vg
not vgck $vg
check active $vg origin1
@@ -81,3 +86,5 @@ check active $vg linear2
check active $vg linear12
check active $vg mirror12
check active $vg mirror123
+
+vgremove -ff $vg
diff --git a/test/shell/nomda-restoremissing.sh b/test/shell/nomda-restoremissing.sh
new file mode 100644
index 0000000..d9c544b
--- /dev/null
+++ b/test/shell/nomda-restoremissing.sh
@@ -0,0 +1,48 @@
+#!/usr/bin/env 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+aux prepare_vg 3
+
+pvchange --metadataignore y "$dev1"
+
+lvcreate -aey --type mirror -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
+not vgck $vg 2>&1 | tee log
+grep "missing 1 physical volume" log
+not lvcreate -aey --type mirror -m 1 -l 1 -n mirror $vg # write operations fail
+aux enable_dev "$dev1"
+# Old versions would automatically clear MISSING_PV on a PV that had no mda,
+# but this made no sense; the existence of an mda means nothing for the
+# validity of the data on the device. I suspect that at some point in the
+# past, the MISSING_PV flag was used to decide if metadata could be used
+# from the device, so the flag could be cleared on a PV with no mda.
+# These days lvm knows when to ignore outdated metadata.
+# MISSING_PV probably has little to no value for determining valid data either,
+# so it's likely that we'll begin to automatically clear MISSING_PV in the
+# future (but it will have nothing to do with having mdas.)
+not lvcreate -aey --type mirror -m 1 -l 1 -n mirror $vg
+vgextend --restoremissing $vg "$dev1"
+lvcreate -aey --type mirror -m 1 -l 1 -n mirror $vg
+vgck $vg
+
+vgremove -ff $vg
diff --git a/test/shell/open-file-limit.sh b/test/shell/open-file-limit.sh
new file mode 100644
index 0000000..8e04705
--- /dev/null
+++ b/test/shell/open-file-limit.sh
@@ -0,0 +1,48 @@
+#!/bin/bash
+# Copyright (C) 2014 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+# Test scan_lvs config setting
+
+SKIP_WITH_LVMPOLLD=1
+SKIP_WITH_LVMLOCKD=1
+
+. lib/inittest
+
+prlimit -h || skip
+
+aux lvmconf 'devices/pv_min_size = 1024'
+
+aux prepare_devs 200 1
+
+for i in $(seq 1 200); do
+ pvcreate "$DM_DEV_DIR/mapper/${PREFIX}pv$i"
+done
+
+pvs > out
+test "$(grep -c pv out)" -eq 200
+
+# Set the soft limit to 100 fd's when 200 PVs need to be open.
+# This requires lvm to increase its soft limit in order to
+# process all the PVs.
+# Test this with and without udev providing device lists.
+
+aux lvmconf 'devices/obtain_device_list_from_udev = 0'
+
+prlimit --nofile=100: pvs > out
+
+test "$(grep -c pv out)" -eq 200
+
+aux lvmconf 'devices/obtain_device_list_from_udev = 1'
+
+prlimit --nofile=100: pvs > out
+
+test "$(grep -c pv out)" -eq 200
+
diff --git a/test/api/vgtest.sh b/test/shell/orphan-ondisk.sh
index 6c0be4e..507b482 100644
--- a/test/api/vgtest.sh
+++ b/test/shell/orphan-ondisk.sh
@@ -1,5 +1,6 @@
-#!/bin/sh
-# Copyright (C) 2008 Red Hat, Inc. All rights reserved.
+#!/usr/bin/env 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
@@ -7,14 +8,12 @@
#
# 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
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
-#
-# tests lvm2app library
-#
-. lib/test
+SKIP_WITH_LVMPOLLD=1
-aux prepare_pvs 2
+. lib/inittest
-aux apitest vgtest $vg1 "$dev1" "$dev2"
+aux prepare_vg 2
+vgreduce $vg "$dev1" 2>&1 | not grep -i 'parse error'
diff --git a/test/shell/outdated-pv.sh b/test/shell/outdated-pv.sh
new file mode 100644
index 0000000..6a361d3
--- /dev/null
+++ b/test/shell/outdated-pv.sh
@@ -0,0 +1,64 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2008-2013,2018 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+aux prepare_vg 3
+
+#
+# Test handling of "outdated PV" which occurs when a PV goes missing
+# from a VG, and while it's missing the PV is removed from the VG.
+# Then the PV reappears with the old VG metadata that shows it is a
+# member. That outdated metadata needs to be cleared.
+#
+
+lvcreate -n $lv1 -l1 -an $vg "$dev1"
+lvcreate -n $lv2 -l1 -an $vg "$dev1"
+
+aux disable_dev "$dev2"
+
+vgreduce --removemissing $vg
+
+pvs
+
+aux enable_dev "$dev2"
+
+pvs 2>&1 | tee out
+grep "outdated" out
+
+not pvs "$dev2"
+
+# The VG can still be used with the outdated PV around
+lvcreate -n $lv3 -l1 $vg
+lvchange -ay $vg
+lvs $vg
+lvchange -an $vg
+
+# Clears the outdated PV
+vgck --updatemetadata $vg
+
+pvs 2>&1 | tee out
+not grep "outdated" out
+
+# The PV is no longer in the VG
+pvs "$dev2" | tee out
+not grep "$vg" out
+
+# The cleared PV can be added back to the VG
+vgextend $vg "$dev2"
+
+pvs "$dev2" | tee out
+grep "$vg" out
+
+vgremove -ff $vg
diff --git a/test/shell/pe-align.sh b/test/shell/pe-align.sh
new file mode 100644
index 0000000..7015108
--- /dev/null
+++ b/test/shell/pe-align.sh
@@ -0,0 +1,142 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2014 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+test_description='Test pe alignment and metadata sizes'
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+aux prepare_devs 1
+
+# values depend on page size 4K
+
+# In order of strength:
+# --dataalignmentoffset (modifies all below)
+# --dataalignment (overrides all below)
+# devices/data_alignment (overrides all below)
+# devices/data_alignment_offset_detection (overrides all below)
+# devices/md_chunk_alignment (overrides all below)
+# devices/default_data_alignment
+
+pvcreate "$dev1"
+check pv_field "$dev1" pe_start 1.00m
+check pv_field "$dev1" mda_size 1020.00k
+pvremove "$dev1"
+
+# default align at 1m is effective even with smaller requested metadata
+pvcreate --metadatasize 100k "$dev1"
+check pv_field "$dev1" pe_start 1.00m
+check pv_field "$dev1" mda_size 1020.00k
+pvremove "$dev1"
+
+# default first pe doesn't depend on on these two settings
+pvcreate --config 'devices {default_data_alignment=0 data_alignment=0}' "$dev1"
+check pv_field "$dev1" pe_start 1.00m
+check pv_field "$dev1" mda_size 1020.00k
+pvremove "$dev1"
+
+# same as previous
+pvcreate --config 'devices {default_data_alignment=1 data_alignment=0}' "$dev1"
+check pv_field "$dev1" pe_start 1.00m
+check pv_field "$dev1" mda_size 1020.00k
+pvremove "$dev1"
+
+# same as previous
+pvcreate --config 'devices {default_data_alignment=0 data_alignment=1024}' "$dev1"
+check pv_field "$dev1" pe_start 1.00m
+check pv_field "$dev1" mda_size 1020.00k
+pvremove "$dev1"
+
+# same as previous
+pvcreate --config 'devices {default_data_alignment=1 data_alignment=1024}' "$dev1"
+check pv_field "$dev1" pe_start 1.00m
+check pv_field "$dev1" mda_size 1020.00k
+pvremove "$dev1"
+
+# combine above
+pvcreate --metadatasize 100k --config 'devices {default_data_alignment=0 data_alignment=0}' "$dev1"
+check pv_field "$dev1" pe_start 1.00m
+check pv_field "$dev1" mda_size 1020.00k
+pvremove "$dev1"
+
+pvcreate --metadatasize 2048k "$dev1"
+check pv_field "$dev1" pe_start 3072.00k --units k
+check pv_field "$dev1" mda_size 3068.00k --units k
+pvremove "$dev1"
+
+pvcreate --metadatasize 2044k "$dev1"
+check pv_field "$dev1" pe_start 2048.00k --units k
+check pv_field "$dev1" mda_size 2044.00k --units k
+pvremove "$dev1"
+
+pvcreate --metadatasize 2048k --config 'devices {default_data_alignment=2}' "$dev1"
+check pv_field "$dev1" pe_start 4.00m
+check pv_field "$dev1" mda_size 4092.00k --units k
+pvremove "$dev1"
+
+pvcreate --metadatasize 100k --config 'devices {default_data_alignment=2}' "$dev1"
+check pv_field "$dev1" pe_start 2048.00k --units k
+check pv_field "$dev1" mda_size 2044.00k --units k
+pvremove "$dev1"
+
+pvcreate --metadatasize 2048k --dataalignment 128k "$dev1"
+check pv_field "$dev1" pe_start 2176.00k --units k
+check pv_field "$dev1" mda_size 2172.00k --units k
+pvremove "$dev1"
+
+pvcreate --metadatasize 2048k --dataalignment 128k --dataalignmentoffset 2k "$dev1"
+check pv_field "$dev1" pe_start 2178.00k --units k
+check pv_field "$dev1" mda_size 2174.00k --units k
+pvremove "$dev1"
+
+pvcreate --metadatasize 2048k --dataalignment 128k --config 'devices {default_data_alignment=0}' "$dev1"
+check pv_field "$dev1" pe_start 2176.00k --units k
+check pv_field "$dev1" mda_size 2172.00k --units k
+pvremove "$dev1"
+
+pvcreate --metadatasize 2048k --dataalignment 128k --config 'devices {default_data_alignment=2}' "$dev1"
+check pv_field "$dev1" pe_start 2176.00k --units k
+check pv_field "$dev1" mda_size 2172.00k --units k
+pvremove "$dev1"
+
+pvcreate --metadatasize 2048k --config 'devices {default_data_alignment=2 data_alignment=128}' "$dev1"
+check pv_field "$dev1" pe_start 2176.00k --units k
+check pv_field "$dev1" mda_size 2172.00k --units k
+pvremove "$dev1"
+
+pvcreate --bootloaderareasize 256k "$dev1"
+check pv_field "$dev1" mda_size 1020.00k --units k
+check pv_field "$dev1" ba_start 1024.00k --units k
+check pv_field "$dev1" ba_size 1024.00k --units k
+check pv_field "$dev1" pe_start 2048.00k --units k
+pvremove "$dev1"
+
+pvcreate --dataalignment 128k --bootloaderareasize 256k "$dev1"
+check pv_field "$dev1" mda_size 1020.00k --units k
+check pv_field "$dev1" ba_start 1024.00k --units k
+check pv_field "$dev1" ba_size 256.00k --units k
+check pv_field "$dev1" pe_start 1280.00k --units k
+pvremove "$dev1"
+
+pvcreate --dataalignment 128k --metadatasize 256k "$dev1"
+check pv_field "$dev1" mda_size 380.00k --units k
+check pv_field "$dev1" ba_start 0k --units k
+check pv_field "$dev1" ba_size 0k --units k
+check pv_field "$dev1" pe_start 384.00k --units k
+pvremove "$dev1"
+
+pvcreate --dataalignment 128k --metadatasize 256k --bootloaderareasize 256k "$dev1"
+check pv_field "$dev1" mda_size 380.00k --units k
+check pv_field "$dev1" ba_start 384.00k --units k
+check pv_field "$dev1" ba_size 256.00k --units k
+check pv_field "$dev1" pe_start 640.00k --units k
+pvremove "$dev1"
diff --git a/test/shell/pool-labels.sh b/test/shell/pool-labels.sh
index 9d3fa03..88978e8 100644
--- a/test/shell/pool-labels.sh
+++ b/test/shell/pool-labels.sh
@@ -1,4 +1,5 @@
-#!/bin/sh
+#!/usr/bin/env bash
+
# Copyright (C) 2007 Red Hat, Inc. All rights reserved.
#
# This copyrighted material is made available to anyone wishing to use,
@@ -7,9 +8,11 @@
#
# 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
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+SKIP_WITH_LVMPOLLD=1
-. lib/test
+. lib/inittest
env printf "" || skip # skip if printf is not available
@@ -21,7 +24,6 @@ create_pool_label_()
# 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"
}
@@ -30,13 +32,10 @@ aux prepare_devs 2
create_pool_label_ 0 "$dev1"
create_pool_label_ 1 "$dev2"
+# verify that lvm will ignore and not use a gfs-pool device
+
+not pvs "$dev1"
+
# 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/process-each-duplicate-pvs.sh b/test/shell/process-each-duplicate-pvs.sh
new file mode 100644
index 0000000..f3063ab
--- /dev/null
+++ b/test/shell/process-each-duplicate-pvs.sh
@@ -0,0 +1,528 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2008-2013 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.
+
+test_description='Test duplicate PVs'
+
+SKIP_WITH_LVMPOLLD=1
+SKIP_WITH_CLVMD=1
+
+# This test should work with real device ids (not devnames).
+# When PVs are being overwritten by the test, the devices file is
+# excluding them since with idtype=devname the devices file falls
+# back to including devs based on PVIDs in the devices file,
+# but the 'dd' is clobbering the PVIDs so those devs aren't included
+# so the 'pvs' commands below don't report them.
+# In general this is better behavior, but needs to be tested
+# with proper device ids.
+SKIP_WITH_DEVICES_FILE=1
+
+. lib/inittest
+
+aux prepare_devs 6 16
+
+# The LV-using-PV tests (DEV_USED_FOR_LV, where a PV is
+# preferred if an active LV is using it) depend on sysfs
+# info that is not available in RHEL5 kernels.
+aux driver_at_least 4 15 || skip
+
+aux lvmconf 'devices/allow_changes_with_duplicate_pvs = 0'
+
+pvcreate "$dev1"
+pvcreate "$dev2"
+vgcreate $SHARED $vg1 "$dev1"
+vgcreate $SHARED $vg2 "$dev2"
+pvresize --setphysicalvolumesize 8m -y "$dev2"
+lvcreate -an -l1 -n $lv1 $vg1
+
+# Both devs are shown and used by the VG
+
+pvs 2>&1 | tee out
+
+grep "$dev1" out
+grep "$dev2" out
+grep "$dev1" out | grep $vg1
+grep "$dev2" out | grep $vg2
+check pv_field "$dev1" pv_allocatable "allocatable"
+check pv_field "$dev2" pv_allocatable "allocatable"
+not grep WARNING out
+
+UUID1=$(get pv_field "$dev1" uuid)
+UUID2=$(get pv_field "$dev2" uuid)
+
+SIZE1=$(get pv_field "$dev1" dev_size)
+SIZE2=$(get pv_field "$dev2" dev_size)
+
+MINOR1=$(get pv_field "$dev1" minor)
+MINOR2=$(get pv_field "$dev2" minor)
+
+check pv_field "$dev1" dev_size "$SIZE1"
+check pv_field "$dev2" dev_size "$SIZE2"
+
+# Copy dev1 over dev2.
+dd if="$dev1" of="$dev2" bs=1M iflag=direct oflag=direct,sync
+#pvscan --cache
+
+# The single preferred dev is shown from 'pvs'.
+pvs -o+uuid,duplicate 2>&1 | tee out
+
+rm warn main || true
+grep WARNING out > warn || true
+grep -v WARNING out > main || true
+
+# Don't know yet if dev1 or dev2 is preferred, so count just one is.
+test "$(grep -c "$vg1" main)" -eq 1
+test "$(grep -c "$UUID1" main)" -eq 1
+not grep duplicate main
+not grep $vg2 main
+not grep $UUID2 main
+
+grep "Not using device" warn
+grep "prefers device" warn
+
+# Find which is the preferred dev and which is the duplicate.
+PV=$(pvs --noheadings -o name -S uuid="$UUID1" | xargs)
+if [ "$PV" = "$dev1" ]; then
+ DUP=$dev2
+else
+ DUP=$dev1
+fi
+
+echo "PV is $PV"
+echo "DUP is $DUP"
+
+grep "$PV" main
+not grep "$DUP" main
+
+# Repeat above checking preferred/dup in output
+pvs 2>&1 | tee out
+
+rm warn main || true
+grep WARNING out > warn || true
+grep -v WARNING out > main || true
+
+grep "$PV" main
+not grep "$DUP" main
+
+# The duplicate dev is included in 'pvs -a'
+pvs -a -o+uuid,duplicate 2>&1 | tee out
+
+rm warn main || true
+grep WARNING out > warn || true
+grep -v WARNING out > main || true
+
+grep "$dev1" main
+grep "$dev2" main
+grep $PV main
+grep $DUP main
+test "$(grep -c duplicate main)" -eq 1
+grep $DUP main | grep duplicate
+not grep $vg2 main
+not grep $UUID2 main
+grep "$dev1" main | grep $vg1
+grep "$dev2" main | grep $vg1
+grep "$dev1" main | grep $UUID1
+grep "$dev2" main | grep $UUID1
+
+grep "Not using device" warn
+grep "prefers device" warn
+
+#
+# Passing a dev name arg always includes that dev.
+#
+
+pvs -o+uuid "$dev1" 2>&1 | tee out
+
+rm warn main || true
+grep WARNING out > warn || true
+grep -v WARNING out > main || true
+
+grep "$dev1" main
+not grep "$dev2" main
+grep "$UUID1" main
+grep "$vg1" main
+grep "Not using device" warn
+grep "prefers device" warn
+
+pvs -o+uuid "$dev2" 2>&1 | tee out
+
+rm warn main || true
+grep WARNING out > warn || true
+grep -v WARNING out > main || true
+
+grep "$dev2" main
+not grep "$dev1" main
+grep "$UUID1" main
+grep "$vg1" main
+grep "Not using device" warn
+grep "prefers device" warn
+
+pvs -o+uuid,duplicate "$dev1" "$dev2" 2>&1 | tee out
+
+rm warn main || true
+grep WARNING out > warn || true
+grep -v WARNING out > main || true
+
+grep "$dev1" main
+grep "$dev2" main
+grep "$dev1" main | grep $vg1
+grep "$dev2" main | grep $vg1
+grep "$dev1" main | grep $UUID1
+grep "$dev2" main | grep $UUID1
+test "$(grep -c duplicate main)" -eq 1
+grep $DUP main | grep duplicate
+
+#
+# Test specific report fields for each dev.
+#
+
+pvs --noheadings -o vg_name,vg_uuid "$dev1" 2>&1 | tee out1
+pvs --noheadings -o vg_name,vg_uuid "$dev2" 2>&1 | tee out2
+
+grep -v WARNING out1 > main1 || true
+grep -v WARNING out2 > main2 || true
+diff main1 main2
+rm out1 out2 main1 main2 || true
+
+check pv_field "$dev1" pv_in_use "used"
+check pv_field "$dev2" pv_in_use "used"
+
+check pv_field "$PV" pv_allocatable "allocatable"
+check pv_field "$DUP" pv_allocatable ""
+
+check pv_field "$PV" pv_duplicate ""
+check pv_field "$DUP" pv_duplicate "duplicate"
+
+pvs --noheadings -o name,pv_allocatable "$dev1" "$dev2" 2>&1 | tee out
+
+rm warn main || true
+grep WARNING out > warn || true
+grep -v WARNING out > main || true
+
+grep "$PV" main
+grep "$DUP" main
+grep "$dev1" main
+grep "$dev2" main
+test "$(grep -c allocatable main)" -eq 1
+
+pvs --noheadings -o name,pv_duplicate "$dev1" "$dev2" 2>&1 | tee out
+
+rm warn main || true
+grep WARNING out > warn || true
+grep -v WARNING out > main || true
+
+grep "$PV" main
+grep "$DUP" main
+grep "$dev1" main
+grep "$dev2" main
+test "$(grep -c duplicate main)" -eq 1
+
+#
+# A filter can be used to show only one.
+#
+
+pvs --config "devices { filter=[ \"a|$dev2|\", \"r|.*|\" ] }" 2>&1 | tee out
+
+rm warn main || true
+grep WARNING out > warn || true
+grep -v WARNING out > main || true
+
+not grep "$dev1" main
+grep "$dev2" main
+
+not grep "Not using device" warn
+not grep "prefers device" warn
+
+
+pvs --config "devices { filter=[ \"a|$dev1|\", \"r|.*|\"] }" 2>&1 | tee out
+
+rm warn main || true
+grep WARNING out > warn || true
+grep -v WARNING out > main || true
+
+grep "$dev1" main
+not grep "$dev2" main
+
+not grep "Not using device" warn
+not grep "prefers device" warn
+
+# PV size and minor is still reported correctly for each.
+
+check pv_field "$dev1" dev_size "$SIZE1"
+check pv_field "$dev2" dev_size "$SIZE2"
+
+check pv_field "$dev1" minor "$MINOR1"
+check pv_field "$dev2" minor "$MINOR2"
+
+# With allow_changes_with_duplicate_pvs=0, a VG with duplicate devs
+# cannot be modified or activated.
+
+not lvcreate -an -l1 -n $lv2 $vg1
+not lvremove $vg1/$lv1
+not lvchange -ay $vg1/$lv1
+not vgremove $vg1
+
+
+# With allow_changes_with_duplicate_pvs=1, changes above are permitted.
+
+aux lvmconf 'devices/allow_changes_with_duplicate_pvs = 1'
+
+lvcreate -an -l1 -n $lv2 $vg1
+lvremove $vg1/$lv1
+lvchange -ay $vg1/$lv2
+lvchange -an $vg1/$lv2
+lvremove $vg1/$lv2
+vgremove -f $vg1
+pvremove -ff -y "$dev1"
+pvremove -ff -y "$dev2"
+
+
+# dev3 and dev4 are copies, orphans
+
+pvcreate "$dev3"
+pvcreate "$dev4"
+pvresize --setphysicalvolumesize 8m -y "$dev4"
+
+UUID3=$(get pv_field "$dev3" uuid)
+UUID4=$(get pv_field "$dev4" uuid)
+
+SIZE3=$(get pv_field "$dev3" dev_size)
+SIZE4=$(get pv_field "$dev4" dev_size)
+
+check pv_field "$dev3" dev_size "$SIZE3"
+check pv_field "$dev4" dev_size "$SIZE4"
+
+pvs 2>&1 | tee out
+
+grep "$dev3" out
+grep "$dev4" out
+
+dd if="$dev3" of="$dev4" bs=1M iflag=direct oflag=direct,sync
+#pvscan --cache
+
+# One appears with 'pvs'
+
+pvs -o+uuid 2>&1 | tee out
+
+rm warn main || true
+grep WARNING out > warn || true
+grep -v WARNING out > main || true
+
+test "$(grep -c "$UUID3" main)" -eq 1
+not grep "$UUID4" main
+
+grep "Not using device" warn
+grep "prefers device" warn
+
+# Both appear with 'pvs -a'
+
+pvs -a -o+uuid 2>&1 | tee out
+
+rm warn main || true
+grep WARNING out > warn || true
+grep -v WARNING out > main || true
+
+test "$(grep -c "$UUID3" main)" -eq 2
+
+grep "$dev3" main
+grep "$dev4" main
+
+grep $UUID3 main
+not grep $UUID4 main
+
+grep "Not using device" warn
+grep "prefers device" warn
+
+# Show each dev individually and both together
+
+pvs -o+uuid "$dev3" 2>&1 | tee out
+
+rm warn main || true
+grep WARNING out > warn || true
+grep -v WARNING out > main || true
+
+grep "$dev3" main
+not grep "$dev4" main
+
+grep "Not using device" warn
+grep "prefers device" warn
+
+pvs -o+uuid "$dev4" 2>&1 | tee out
+
+rm warn main || true
+grep WARNING out > warn || true
+grep -v WARNING out > main || true
+
+not grep "$dev3" main
+grep "$dev4" main
+
+grep "Not using device" warn
+grep "prefers device" warn
+
+pvs -o+uuid "$dev3" "$dev4" 2>&1 | tee out
+
+rm warn main || true
+grep WARNING out > warn || true
+grep -v WARNING out > main || true
+
+grep "$dev3" main
+grep "$dev4" main
+
+grep "Not using device" warn
+grep "prefers device" warn
+
+# Same sizes shown.
+
+check pv_field "$dev3" dev_size "$SIZE3"
+check pv_field "$dev4" dev_size "$SIZE4"
+
+# Verify that devs being used by an active LV are
+# preferred over duplicates that are not used by an LV.
+
+aux clear_devs "$dev3" "$dev4"
+#pvscan --cache
+
+# The previous steps prevent us from nicely cleaning up
+# the vg lockspace in lvmlockd, so just restart it;
+# what follows could also just be split into a separate test.
+if test -n "$LVM_TEST_LVMLOCKD_TEST" ; then
+ killall -9 lvmlockd
+ sleep 2
+ aux prepare_lvmlockd
+fi
+
+vgcreate $SHARED "$vg2" "$dev3" "$dev4"
+lvcreate -l1 -n $lv1 $vg2 "$dev3"
+lvcreate -l1 -n $lv2 $vg2 "$dev4"
+
+dd if="$dev3" of="$dev5" bs=1M iflag=direct oflag=direct,sync
+dd if="$dev4" of="$dev6" bs=1M iflag=direct oflag=direct,sync
+# dev5/dev6 not pvs so dd'ing pv onto them causes invalid hints
+# that won't be detected, so 5/6 won't be scanned unless we
+# force hint recreation
+pvscan --cache
+
+pvs -o+uuid,duplicate 2>&1 | tee out
+
+rm warn main || true
+grep WARNING out > warn || true
+grep -v WARNING out > main || true
+
+grep "$dev3" main
+grep "$dev4" main
+not grep duplicate main
+check pv_field "$dev3" pv_duplicate ""
+check pv_field "$dev4" pv_duplicate ""
+check pv_field "$dev5" pv_duplicate "duplicate"
+check pv_field "$dev6" pv_duplicate "duplicate"
+
+grep "prefers device $dev3" warn
+grep "prefers device $dev4" warn
+not grep "prefers device $dev5" warn
+not grep "prefers device $dev6" warn
+
+pvs -a -o+uuid,duplicate 2>&1 | tee out
+
+rm warn main || true
+grep WARNING out > warn || true
+grep -v WARNING out > main || true
+
+test "$(grep -c duplicate main)" -eq 2
+grep "$dev3" main
+grep "$dev4" main
+grep "$dev5" main
+grep "$dev6" main
+
+grep "prefers device $dev3" warn
+grep "prefers device $dev4" warn
+not grep "prefers device $dev5" warn
+not grep "prefers device $dev6" warn
+
+pvs -o+uuid,duplicate "$dev3" "$dev4" "$dev5" "$dev6" 2>&1 | tee out
+
+rm warn main || true
+grep WARNING out > warn || true
+grep -v WARNING out > main || true
+
+test "$(grep -c duplicate main)" -eq 2
+grep "$dev3" main
+grep "$dev4" main
+grep "$dev5" main
+grep "$dev6" main
+
+grep "prefers device $dev3" warn
+grep "prefers device $dev4" warn
+not grep "prefers device $dev5" warn
+not grep "prefers device $dev6" warn
+
+
+dd if=/dev/zero of="$dev5" bs=1M oflag=direct,sync || true
+dd if=/dev/zero of="$dev6" bs=1M oflag=direct,sync || true
+#pvscan --cache
+
+lvremove -y $vg2/$lv1
+lvremove -y $vg2/$lv2
+vgremove $vg2
+pvremove -ff -y "$dev3"
+pvremove -ff -y "$dev4"
+
+dd if=/dev/zero of="$dev3" bs=1M oflag=direct,sync || true
+dd if=/dev/zero of="$dev4" bs=1M oflag=direct,sync || true
+#pvscan --cache
+
+# Reverse devs in the previous in case dev3/dev4 would be
+# preferred even without an active LV using them.
+
+vgcreate $SHARED $vg2 "$dev5" "$dev6"
+lvcreate -l1 -n $lv1 $vg2 "$dev5"
+lvcreate -l1 -n $lv2 $vg2 "$dev6"
+
+dd if="$dev5" of="$dev3" bs=1M iflag=direct oflag=direct,sync
+dd if="$dev6" of="$dev4" bs=1M iflag=direct oflag=direct,sync
+# dev3/dev4 are not pvs (zeroed above) so dd'ing pv onto them causes
+# invalid hints that won't be detected, so 3/4 won't be scanned
+# unless we force hint recreation
+pvscan --cache
+
+pvs -o+uuid,duplicate 2>&1 | tee out
+
+rm warn main || true
+grep WARNING out > warn || true
+grep -v WARNING out > main || true
+
+grep "$dev5" main
+grep "$dev6" main
+not grep duplicate main
+check pv_field "$dev5" pv_duplicate ""
+check pv_field "$dev6" pv_duplicate ""
+check pv_field "$dev3" pv_duplicate "duplicate"
+check pv_field "$dev4" pv_duplicate "duplicate"
+
+pvs -a -o+uuid,duplicate 2>&1 | tee out
+
+rm warn main || true
+grep WARNING out > warn || true
+grep -v WARNING out > main || true
+
+test "$(grep -c duplicate main)" -eq 2
+grep "$dev3" main
+grep "$dev4" main
+grep "$dev5" main
+grep "$dev6" main
+
+grep "prefers device $dev5" warn
+grep "prefers device $dev6" warn
+not grep "prefers device $dev3" warn
+not grep "prefers device $dev4" warn
+
+dd if=/dev/zero of="$dev3" bs=1M oflag=direct,sync || true
+dd if=/dev/zero of="$dev4" bs=1M oflag=direct,sync || true
+#pvscan --cache
+
+lvremove -y $vg2/$lv1
+lvremove -y $vg2/$lv2
+vgremove $vg2
diff --git a/test/shell/process-each-lv.sh b/test/shell/process-each-lv.sh
new file mode 100644
index 0000000..f28988c
--- /dev/null
+++ b/test/shell/process-each-lv.sh
@@ -0,0 +1,659 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2008-2013 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+test_description='Exercise toollib process_each_lv'
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+
+aux prepare_devs 10
+
+#
+# process_each_lv is used by a number of lv commands:
+# lvconvert lv (none is error)
+# lvchange vg|lv (none is error)
+# lvremove vg|lv (none is error)
+# lvdisplay [vg|lv] (none is all)
+# vgmknodes [vg|lv] (none is all)
+# lvs [vg|lv] (none is all)
+# lvscan (none is all)
+#
+# (lv can also be a tag matching an lv tag, and
+# vg can also be a tag matching a vg tag.)
+#
+# The logic in process_each_vl is mainly related to
+# selecting which vgs/lvs to process.
+#
+
+#
+# test lvremove vg|lv names
+#
+
+prepare_vgs_() {
+ # set up vgs/lvs that we will remove
+ vgcreate $SHARED $vg1 "$dev1" "$dev2"
+ vgcreate $SHARED $vg2 "$dev3" "$dev4"
+ vgcreate $SHARED $vg3 "$dev5" "$dev6"
+ vgcreate $SHARED $vg4 "$dev7" "$dev8"
+ vgcreate $SHARED $vg5 "$dev9" "$dev10"
+ lvcreate -Zn -an -l 2 -n $lv1 $vg1
+ lvcreate -Zn -an -l 2 -n $lv1 $vg2
+ lvcreate -Zn -an -l 2 -n $lv2 $vg2
+ lvcreate -Zn -an -l 2 -n $lv1 $vg3
+ lvcreate -Zn -an -l 2 -n $lv2 $vg3
+ lvcreate -Zn -an -l 2 -n $lv3 $vg3
+ lvcreate -Zn -an -l 2 -n $lv1 $vg5
+ lvcreate -Zn -an -l 2 -n $lv2 $vg5
+ lvcreate -Zn -an -l 2 -n $lv3 $vg5
+ lvcreate -Zn -an -l 2 -n $lv4 $vg5
+ lvcreate -Zn -an -l 2 -n $lv5 $vg5
+}
+
+#
+#
+#
+prepare_vgs_
+
+not lvremove
+not lvremove garbage
+not lvremove $vg1/garbage
+
+lvremove $vg1
+check lv_exists $vg1
+check lv_not_exists $vg1 $lv1
+vgremove $vg1
+
+lvremove $vg2
+check lv_exists $vg2
+check lv_not_exists $vg2 $lv1 $lv2
+vgremove $vg2
+
+lvremove $vg3/$lv1
+lvremove $vg3/$lv2 $vg3/$lv3
+check lv_exists $vg3
+check lv_not_exists $vg3 $lv1 $lv2 $lv3
+vgremove $vg3
+
+lvremove $vg4
+check lv_exists $vg4
+vgremove $vg4
+
+lvremove $vg5/$lv1 $vg5 $vg5/$lv3
+check lv_not_exists $vg5 $lv1 $lv2 $lv3 $lv4 $lv5
+vgremove $vg5
+
+
+#
+# test lvremove vg|lv names from multiple vgs
+#
+prepare_vgs_
+
+lvremove $vg2 $vg3/$lv3 $vg5/$lv1
+check lv_not_exists $vg2 $lv1 $lv2
+check lv_not_exists $vg3 $lv3
+check lv_not_exists $vg5 $lv1
+
+lvremove $vg2 $vg1
+check lv_not_exists $vg1 $lv1
+
+lvremove $vg3/$lv1 $vg3 $vg4 $vg5/$lv2
+check lv_not_exists $vg3 $lv1 $lv2
+check lv_not_exists $vg5 $lv2
+
+lvremove $vg5 $vg1 $vg5/$lv3
+check lv_not_exists $vg5 $lv3 $lv4 $lv5
+
+vgremove $vg1 $vg2 $vg3 $vg4 $vg5
+
+
+#
+# test lvremove @lvtags
+#
+prepare_vgs_
+
+lvchange --addtag V1L1 $vg1/$lv1
+lvchange --addtag V2L1 $vg2/$lv1
+lvchange --addtag V2L2 $vg2/$lv2
+lvchange --addtag V23 $vg2/$lv1
+lvchange --addtag V23 $vg2/$lv2
+lvchange --addtag V23 $vg3/$lv1
+lvchange --addtag V23 $vg3/$lv2
+lvchange --addtag V23 $vg3/$lv3
+lvchange --addtag V3L2 $vg3/$lv2
+lvchange --addtag V3L3A $vg3/$lv3
+lvchange --addtag V3L3B $vg3/$lv3
+lvchange --addtag V5L1 $vg5/$lv1
+lvchange --addtag V5L234 $vg5/$lv2
+lvchange --addtag V5L234 $vg5/$lv3
+lvchange --addtag V5L234 $vg5/$lv4
+lvchange --addtag V5L5 $vg5/$lv5
+vgchange -an $vg1 $vg2 $vg3 $vg4 $vg5
+
+# verify all exist
+check lv_exists $vg1 $lv1
+check lv_exists $vg2 $lv1 $lv2
+check lv_exists $vg3 $lv1 $lv2 $lv3
+check lv_exists $vg5 $lv1 $lv2 $lv3 $lv4 $lv5
+
+lvremove @garbage
+
+lvremove @V3L3A
+check lv_not_exists $vg3 $lv3
+# verify unremoved still exist
+check lv_exists $vg1 $lv1
+check lv_exists $vg2 $lv1 $lv2
+check lv_exists $vg3 $lv1 $lv2
+check lv_exists $vg5 $lv1 $lv2 $lv3 $lv4 $lv5
+
+lvremove @V5L234
+check lv_not_exists $vg5 $lv2 $lv3 $lv4
+# verify unremoved still exist
+check lv_exists $vg1 $lv1
+check lv_exists $vg2 $lv1 $lv2
+check lv_exists $vg3 $lv1 $lv2
+check lv_exists $vg5 $lv1 $lv5
+
+lvremove @V5L1 @V5L5
+check lv_not_exists $vg5 $lv1 $lv5
+# verify unremoved still exist
+check lv_exists $vg1 $lv1
+check lv_exists $vg2 $lv1 $lv2
+check lv_exists $vg3 $lv1 $lv2
+
+lvremove @V23 @V1L1 @V3L2
+check lv_not_exists $vg1 $lv1
+check lv_not_exists $vg2 $lv1 $lv2
+check lv_not_exists $vg3 $lv1 $lv2
+
+vgremove $vg1 $vg2 $vg3 $vg4 $vg5
+
+
+#
+# test lvremove @vgtags
+#
+prepare_vgs_
+
+vgchange --addtag V1 $vg1
+vgchange --addtag V23 $vg2
+vgchange --addtag V23 $vg3
+vgchange --addtag V35 $vg3
+vgchange --addtag V4 $vg4
+vgchange --addtag V35 $vg5
+vgchange --addtag V5 $vg5
+vgchange -an $vg1 $vg2 $vg3 $vg4 $vg5
+
+lvremove @V4
+# verify unremoved exist
+check lv_exists $vg1 $lv1
+check lv_exists $vg2 $lv1 $lv2
+check lv_exists $vg3 $lv1 $lv2 $lv3
+check lv_exists $vg5 $lv1 $lv2 $lv3 $lv4 $lv5
+
+lvremove @V5
+check lv_not_exists $vg5 $lv1 $lv2 $lv3 $lv4 $lv5
+# verify unremoved exist
+check lv_exists $vg1 $lv1
+check lv_exists $vg2 $lv1 $lv2
+check lv_exists $vg3 $lv1 $lv2 $lv3
+
+lvremove @V1 @V23
+check lv_not_exists $vg1 $lv1
+check lv_not_exists $vg2 $lv1 $lv2
+check lv_not_exists $vg3 $lv1 $lv2 $lv3
+
+vgremove $vg1 $vg2 $vg3 $vg4 $vg5
+
+#
+#
+#
+prepare_vgs_
+
+vgchange --addtag V1 $vg1
+vgchange --addtag V23 $vg2
+vgchange --addtag V23 $vg3
+vgchange --addtag V35 $vg3
+vgchange --addtag V4 $vg4
+vgchange --addtag V35 $vg5
+vgchange --addtag V5 $vg5
+
+lvremove @V35 @V5
+check lv_not_exists $vg3 $lv1 $lv2 /$lv3
+check lv_not_exists $vg5 $lv1 $lv2 $lv3 $lv4 $lv5
+# verify unremoved exist
+check lv_exists $vg1 $lv1
+check lv_exists $vg2 $lv1 $lv2
+
+lvremove @V1 @V23
+check lv_not_exists $vg1 $lv1
+check lv_not_exists $vg2 $lv1 $lv2
+
+vgremove $vg1 $vg2 $vg3 $vg4 $vg5
+
+
+#
+# test lvremove vg|lv names and @lvtags
+#
+prepare_vgs_
+
+lvchange --addtag V1L1 $vg1/$lv1
+lvchange --addtag V2L1 $vg2/$lv1
+lvchange --addtag V2L2 $vg2/$lv2
+lvchange --addtag V23 $vg2/$lv1
+lvchange --addtag V23 $vg2/$lv2
+lvchange --addtag V23 $vg3/$lv1
+lvchange --addtag V23 $vg3/$lv2
+lvchange --addtag V23 $vg3/$lv3
+lvchange --addtag V3L2 $vg3/$lv2
+lvchange --addtag V3L3A $vg3/$lv3
+lvchange --addtag V3L3B $vg3/$lv3
+lvchange --addtag V5L1 $vg5/$lv1
+lvchange --addtag V5L234 $vg5/$lv2
+lvchange --addtag V5L234 $vg5/$lv3
+lvchange --addtag V5L234 $vg5/$lv4
+lvchange --addtag V5L5 $vg5/$lv5
+vgchange -an $vg1 $vg2 $vg3 $vg4 $vg5
+
+lvremove $vg1/$lv1 @V3L2 @V5L234
+check lv_not_exists $vg1 $lv1
+check lv_not_exists $vg3 $lv2
+check lv_not_exists $vg5 $lv2 $lv3 $lv4
+# verify unremoved exist
+check lv_exists $vg2 $lv1 $lv2
+check lv_exists $vg3 $lv1 $lv3
+check lv_exists $vg5 $lv1 $lv5
+
+lvremove $vg2/$lv1 @V23 $vg5/$lv1 @V5L5
+
+vgremove $vg1 $vg2 $vg3 $vg4 $vg5
+
+
+#
+# test lvremove vg|lv names and @vgtags
+#
+prepare_vgs_
+
+vgchange --addtag V1 $vg1
+vgchange --addtag V23 $vg2
+vgchange --addtag V23 $vg3
+vgchange --addtag V35 $vg3
+vgchange --addtag V4 $vg4
+vgchange --addtag V35 $vg5
+vgchange --addtag V5 $vg5
+
+lvremove $vg1/$lv1 @V35
+check lv_not_exists $vg1 $lv1
+check lv_not_exists $vg3 $lv1 $lv2 $lv3
+check lv_not_exists $vg5 $lv1 $lv2 $lv3 $lv4 $lv5
+# verify unremoved exist
+check lv_exists $vg2 $lv1 $lv2
+
+lvremove $vg2/$lv1 @V23 $vg2/$lv2
+
+vgremove $vg1 $vg2 $vg3 $vg4 $vg5
+
+
+#
+# test lvremove @lvtags and @vgtags
+#
+prepare_vgs_
+
+lvchange --addtag V1L1 $vg1/$lv1
+lvchange --addtag V2L1 $vg2/$lv1
+lvchange --addtag V2L2 $vg2/$lv2
+lvchange --addtag V23 $vg2/$lv1
+lvchange --addtag V23 $vg2/$lv2
+lvchange --addtag V23 $vg3/$lv1
+lvchange --addtag V23 $vg3/$lv2
+# to check that vg tag @V23 includes this
+# lvchange --addtag V23 $vg3/$lv3
+lvchange --addtag V3L2 $vg3/$lv2
+lvchange --addtag V3L3A $vg3/$lv3
+lvchange --addtag V3L3B $vg3/$lv3
+lvchange --addtag V5L1 $vg5/$lv1
+lvchange --addtag V5L234 $vg5/$lv2
+lvchange --addtag V5L234 $vg5/$lv3
+lvchange --addtag V5L234 $vg5/$lv4
+lvchange --addtag V5L5 $vg5/$lv5
+vgchange --addtag V1 $vg1
+vgchange --addtag V23 $vg2
+vgchange --addtag V23 $vg3
+vgchange --addtag V35 $vg3
+vgchange --addtag V4 $vg4
+vgchange --addtag V35 $vg5
+vgchange --addtag V5 $vg5
+
+lvremove @V23 @V35
+check lv_not_exists $vg2 $lv1 $lv2
+check lv_not_exists $vg3 $lv1 $lv2 $lv3
+check lv_not_exists $vg5 $lv1 $lv2 $lv3 $lv4 $lv5
+# verify unremoved exist
+check lv_exists $vg1 $lv1
+
+lvremove @V1 @V1L1
+check lv_not_exists $vg1 $lv1
+
+vgremove $vg1 $vg2 $vg3 $vg4 $vg5
+
+
+#
+# test lvremove vg|lv names and @lvtags and @vgtags
+#
+prepare_vgs_
+
+lvchange --addtag V1L1 $vg1/$lv1
+lvchange --addtag V2L1 $vg2/$lv1
+lvchange --addtag V2L2 $vg2/$lv2
+lvchange --addtag V23 $vg2/$lv1
+lvchange --addtag V23 $vg2/$lv2
+lvchange --addtag V23 $vg3/$lv1
+lvchange --addtag V23 $vg3/$lv2
+# to check that vg tag @V23 includes this
+# lvchange --addtag V23 $vg3/$lv3
+lvchange --addtag V3L2 $vg3/$lv2
+lvchange --addtag V3L3A $vg3/$lv3
+lvchange --addtag V3L3B $vg3/$lv3
+lvchange --addtag V5L1 $vg5/$lv1
+lvchange --addtag V5L234 $vg5/$lv2
+lvchange --addtag V5L234 $vg5/$lv3
+lvchange --addtag V5L234 $vg5/$lv4
+lvchange --addtag V5L5 $vg5/$lv5
+vgchange --addtag V1 $vg1
+vgchange --addtag V23 $vg2
+vgchange --addtag V23 $vg3
+vgchange --addtag V35 $vg3
+vgchange --addtag V4 $vg4
+vgchange --addtag V35 $vg5
+vgchange --addtag V5 $vg5
+
+lvremove $vg1/$lv1 @V23 @V5L5
+check lv_not_exists $vg1 $lv1
+check lv_not_exists $vg2 $lv1 $lv2
+check lv_not_exists $vg3 $lv1 $lv2 $lv3
+check lv_not_exists $vg5 $lv5
+# verify unremoved exist
+check lv_exists $vg5 $lv1 $lv2 $lv3 $lv4
+
+lvremove $vg5/$lv2 @V5L234 @V5
+check lv_not_exists $vg5 $lv1 $lv2 $lv3 $lv4
+
+vgremove $vg1 $vg2 $vg3 $vg4 $vg5
+
+
+#
+# test lvs: empty, vg(s), lv(s), vgtag(s), lvtag(s), garbage, combinations
+#
+prepare_vgs_
+
+lvchange --addtag V1L1 $vg1/$lv1
+lvchange --addtag V2L1 $vg2/$lv1
+lvchange --addtag V2L2 $vg2/$lv2
+lvchange --addtag V23 $vg2/$lv1
+lvchange --addtag V23 $vg2/$lv2
+lvchange --addtag V23 $vg3/$lv1
+lvchange --addtag V23 $vg3/$lv2
+lvchange --addtag V23 $vg3/$lv3
+lvchange --addtag V3L2 $vg3/$lv2
+lvchange --addtag V3L3A $vg3/$lv3
+lvchange --addtag V3L3B $vg3/$lv3
+lvchange --addtag V5L1 $vg5/$lv1
+lvchange --addtag V5L234 $vg5/$lv2
+lvchange --addtag V5L234 $vg5/$lv3
+lvchange --addtag V5L234 $vg5/$lv4
+lvchange --addtag V5L5 $vg5/$lv5
+vgchange --addtag V1 $vg1
+vgchange --addtag V23 $vg2
+vgchange --addtag V23 $vg3
+vgchange --addtag V35 $vg3
+vgchange --addtag V4 $vg4
+vgchange --addtag V35 $vg5
+vgchange --addtag V5 $vg5
+
+# empty
+lvs -o vg_name,lv_name --separator '-' >err
+grep $vg1-$lv1 err
+grep $vg2-$lv1 err
+grep $vg2-$lv2 err
+grep $vg3-$lv1 err
+grep $vg3-$lv2 err
+grep $vg3-$lv3 err
+grep $vg5-$lv1 err
+grep $vg5-$lv2 err
+grep $vg5-$lv3 err
+grep $vg5-$lv4 err
+grep $vg5-$lv5 err
+
+# vg
+lvs -o vg_name,lv_name --separator '-' $vg1 >err
+grep $vg1-$lv1 err
+not grep $vg2-$lv1 err
+not grep $vg2-$lv2 err
+not grep $vg3-$lv1 err
+not grep $vg3-$lv2 err
+not grep $vg3-$lv3 err
+not grep $vg5-$lv1 err
+not grep $vg5-$lv2 err
+not grep $vg5-$lv3 err
+not grep $vg5-$lv4 err
+not grep $vg5-$lv5 err
+
+# vgs
+lvs -o vg_name,lv_name --separator '-' $vg1 $vg2 >err
+grep $vg1-$lv1 err
+grep $vg2-$lv1 err
+grep $vg2-$lv2 err
+not grep $vg3-$lv1 err
+not grep $vg3-$lv2 err
+not grep $vg3-$lv3 err
+not grep $vg5-$lv1 err
+not grep $vg5-$lv2 err
+not grep $vg5-$lv3 err
+not grep $vg5-$lv4 err
+not grep $vg5-$lv5 err
+
+# lv
+lvs -o vg_name,lv_name --separator '-' $vg1/$lv1 >err
+grep $vg1-$lv1 err
+not grep $vg2-$lv1 err
+not grep $vg2-$lv2 err
+not grep $vg3-$lv1 err
+not grep $vg3-$lv2 err
+not grep $vg3-$lv3 err
+not grep $vg5-$lv1 err
+not grep $vg5-$lv2 err
+not grep $vg5-$lv3 err
+not grep $vg5-$lv4 err
+not grep $vg5-$lv5 err
+
+# lvs
+lvs -o vg_name,lv_name --separator '-' $vg1/$lv1 $vg2/$lv1 $vg2/$lv2 >err
+grep $vg1-$lv1 err
+grep $vg2-$lv1 err
+grep $vg2-$lv2 err
+not grep $vg3-$lv1 err
+not grep $vg3-$lv2 err
+not grep $vg3-$lv3 err
+not grep $vg5-$lv1 err
+not grep $vg5-$lv2 err
+not grep $vg5-$lv3 err
+not grep $vg5-$lv4 err
+not grep $vg5-$lv5 err
+
+# vgtag
+lvs -o vg_name,lv_name --separator '-' @V1 >err
+grep $vg1-$lv1 err
+not grep $vg2-$lv1 err
+not grep $vg2-$lv2 err
+not grep $vg3-$lv1 err
+not grep $vg3-$lv2 err
+not grep $vg3-$lv3 err
+not grep $vg5-$lv1 err
+not grep $vg5-$lv2 err
+not grep $vg5-$lv3 err
+not grep $vg5-$lv4 err
+not grep $vg5-$lv5 err
+
+# vgtags
+lvs -o vg_name,lv_name --separator '-' @V1 @V35 >err
+grep $vg1-$lv1 err
+not grep $vg2-$lv1 err
+not grep $vg2-$lv2 err
+grep $vg3-$lv1 err
+grep $vg3-$lv2 err
+grep $vg3-$lv3 err
+grep $vg5-$lv1 err
+grep $vg5-$lv2 err
+grep $vg5-$lv3 err
+grep $vg5-$lv4 err
+grep $vg5-$lv5 err
+
+# lvtag
+lvs -o vg_name,lv_name --separator '-' @V1L1 >err
+grep $vg1-$lv1 err
+not grep $vg2-$lv1 err
+not grep $vg2-$lv2 err
+not grep $vg3-$lv1 err
+not grep $vg3-$lv2 err
+not grep $vg3-$lv3 err
+not grep $vg5-$lv1 err
+not grep $vg5-$lv2 err
+not grep $vg5-$lv3 err
+not grep $vg5-$lv4 err
+not grep $vg5-$lv5 err
+
+# lvtags
+lvs -o vg_name,lv_name --separator '-' @V1L1 @V5L234 >err
+grep $vg1-$lv1 err
+not grep $vg2-$lv1 err
+not grep $vg2-$lv2 err
+not grep $vg3-$lv1 err
+not grep $vg3-$lv2 err
+not grep $vg3-$lv3 err
+not grep $vg5-$lv1 err
+grep $vg5-$lv2 err
+grep $vg5-$lv3 err
+grep $vg5-$lv4 err
+not grep $vg5-$lv5 err
+
+# vg and lv and vgtag and lvtag
+lvs -o vg_name,lv_name --separator '-' $vg2 $vg5/$lv5 @V1 @V5L234 >err
+grep $vg1-$lv1 err
+grep $vg2-$lv1 err
+grep $vg2-$lv2 err
+not grep $vg3-$lv1 err
+not grep $vg3-$lv2 err
+not grep $vg3-$lv3 err
+not grep $vg5-$lv1 err
+grep $vg5-$lv2 err
+grep $vg5-$lv3 err
+grep $vg5-$lv4 err
+grep $vg5-$lv5 err
+
+# garbage name gives an error if used without a tag
+
+not lvs -o vg_name,lv_name --separator '-' garbage >err
+not grep $vg1-$lv1 err
+not grep $vg2-$lv1 err
+not grep $vg2-$lv2 err
+not grep $vg3-$lv1 err
+not grep $vg3-$lv2 err
+not grep $vg3-$lv3 err
+not grep $vg5-$lv1 err
+not grep $vg5-$lv2 err
+not grep $vg5-$lv3 err
+not grep $vg5-$lv4 err
+not grep $vg5-$lv5 err
+
+not lvs -o vg_name,lv_name --separator '-' $vg1/$lv1 garbage >err
+grep $vg1-$lv1 err
+not grep $vg2-$lv1 err
+not grep $vg2-$lv2 err
+not grep $vg3-$lv1 err
+not grep $vg3-$lv2 err
+not grep $vg3-$lv3 err
+not grep $vg5-$lv1 err
+not grep $vg5-$lv2 err
+not grep $vg5-$lv3 err
+not grep $vg5-$lv4 err
+not grep $vg5-$lv5 err
+
+# garbage name does not give an error if used with a tag
+
+lvs -o vg_name,lv_name --separator '-' @V1 garbage >err
+grep $vg1-$lv1 err
+not grep $vg2-$lv1 err
+not grep $vg2-$lv2 err
+not grep $vg3-$lv1 err
+not grep $vg3-$lv2 err
+not grep $vg3-$lv3 err
+not grep $vg5-$lv1 err
+not grep $vg5-$lv2 err
+not grep $vg5-$lv3 err
+not grep $vg5-$lv4 err
+not grep $vg5-$lv5 err
+
+lvs -o vg_name,lv_name --separator '-' @garbage garbage >err
+not grep $vg1-$lv1 err
+not grep $vg2-$lv1 err
+not grep $vg2-$lv2 err
+not grep $vg3-$lv1 err
+not grep $vg3-$lv2 err
+not grep $vg3-$lv3 err
+not grep $vg5-$lv1 err
+not grep $vg5-$lv2 err
+not grep $vg5-$lv3 err
+not grep $vg5-$lv4 err
+not grep $vg5-$lv5 err
+
+# garbage tag never gives an error
+
+lvs -o vg_name,lv_name --separator '-' @V1 @garbage >err
+grep $vg1-$lv1 err
+not grep $vg2-$lv1 err
+not grep $vg2-$lv2 err
+not grep $vg3-$lv1 err
+not grep $vg3-$lv2 err
+not grep $vg3-$lv3 err
+not grep $vg5-$lv1 err
+not grep $vg5-$lv2 err
+not grep $vg5-$lv3 err
+not grep $vg5-$lv4 err
+not grep $vg5-$lv5 err
+
+lvs -o vg_name,lv_name --separator '-' $vg1/$lv1 @garbage >err
+grep $vg1-$lv1 err
+not grep $vg2-$lv1 err
+not grep $vg2-$lv2 err
+not grep $vg3-$lv1 err
+not grep $vg3-$lv2 err
+not grep $vg3-$lv3 err
+not grep $vg5-$lv1 err
+not grep $vg5-$lv2 err
+not grep $vg5-$lv3 err
+not grep $vg5-$lv4 err
+not grep $vg5-$lv5 err
+
+lvs -o vg_name,lv_name --separator '-' @garbage >err
+not grep $vg1-$lv1 err
+not grep $vg2-$lv1 err
+not grep $vg2-$lv2 err
+not grep $vg3-$lv1 err
+not grep $vg3-$lv2 err
+not grep $vg3-$lv3 err
+not grep $vg5-$lv1 err
+not grep $vg5-$lv2 err
+not grep $vg5-$lv3 err
+not grep $vg5-$lv4 err
+not grep $vg5-$lv5 err
+
+vgremove -f $vg1 $vg2 $vg3 $vg4 $vg5
diff --git a/test/shell/process-each-pv-nomda-all.sh b/test/shell/process-each-pv-nomda-all.sh
new file mode 100644
index 0000000..020f831
--- /dev/null
+++ b/test/shell/process-each-pv-nomda-all.sh
@@ -0,0 +1,63 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2008-2013 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+test_description='Test process_each_pv with zero mda'
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+aux prepare_devs 14
+
+# for vg1
+pvcreate "$dev10"
+
+# for vg2
+pvcreate "$dev2" --metadatacopies 0
+pvcreate "$dev3"
+pvcreate "$dev4"
+pvcreate "$dev5"
+
+# for vg3
+pvcreate "$dev6" --metadatacopies 0
+pvcreate "$dev7" --metadatacopies 0
+pvcreate "$dev8" --metadatacopies 0
+pvcreate "$dev9"
+
+# orphan with mda
+pvcreate "$dev11"
+# orphan without mda
+pvcreate "$dev14" --metadatacopies 0
+
+# non-pv devs
+# dev12
+# dev13
+
+vgcreate $SHARED $vg1 "$dev10"
+vgcreate $SHARED $vg2 "$dev2" "$dev3" "$dev4" "$dev5"
+vgcreate $SHARED $vg3 "$dev6" "$dev7" "$dev8" "$dev9"
+
+pvs -a | tee err
+grep "$dev10" err
+grep "$dev2" err
+grep "$dev3" err
+grep "$dev4" err
+grep "$dev5" err
+grep "$dev6" err
+grep "$dev7" err
+grep "$dev8" err
+grep "$dev9" err
+grep "$dev11" err
+grep "$dev12" err
+grep "$dev13" err
+grep "$dev14" err
+
+vgremove $vg1 $vg2 $vg3
diff --git a/test/shell/process-each-pv-nomda.sh b/test/shell/process-each-pv-nomda.sh
new file mode 100644
index 0000000..2185ce4
--- /dev/null
+++ b/test/shell/process-each-pv-nomda.sh
@@ -0,0 +1,30 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2014 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+test_description='Test process_each_pv with zero mda'
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+aux prepare_devs 2
+
+pvcreate "$dev1" --metadatacopies 0
+pvcreate "$dev2"
+
+vgcreate $SHARED $vg1 "$dev1" "$dev2"
+
+pvdisplay -a -C | tee err
+grep "$dev1" err
+grep "$dev2" err
+
+vgremove $vg1
diff --git a/test/shell/process-each-pv.sh b/test/shell/process-each-pv.sh
new file mode 100644
index 0000000..beb7a6c
--- /dev/null
+++ b/test/shell/process-each-pv.sh
@@ -0,0 +1,1063 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2014 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+test_description='Exercise toollib process_each_pv'
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+aux prepare_devs 14
+
+#
+# process_each_pv is used by a number of pv commands:
+# pvdisplay
+# pvresize
+# pvs
+#
+# process-each-pvresize.sh covers pvresize.
+# process-each-vgreduce.sh covers vgreduce.
+#
+
+
+#
+# set up
+#
+# use use dev10 instead of dev1 because simple grep for
+# dev1 matchines dev10,dev11,etc
+#
+
+vgcreate $SHARED $vg1 "$dev10"
+vgcreate $SHARED $vg2 "$dev2" "$dev3" "$dev4" "$dev5"
+vgcreate $SHARED $vg3 "$dev6" "$dev7" "$dev8" "$dev9"
+
+pvchange --addtag V2D3 "$dev3"
+pvchange --addtag V2D4 "$dev4"
+pvchange --addtag V2D45 "$dev4"
+pvchange --addtag V2D5 "$dev5"
+pvchange --addtag V2D45 "$dev5"
+
+pvchange --addtag V3 "$dev6" "$dev7" "$dev8" "$dev9"
+pvchange --addtag V3D9 "$dev9"
+
+# orphan
+pvcreate "$dev11"
+
+# dev (a non-pv device)
+pvcreate "$dev12"
+pvremove "$dev12"
+
+# dev13 is intentionally untouched so we can
+# test that it is handled appropriately as a non-pv
+
+# orphan
+pvcreate "$dev14"
+
+
+#
+# test pvdisplay
+#
+
+# pv in vg
+pvdisplay -s "$dev10" | tee err
+grep "$dev10" err
+not grep "$dev2" err
+not grep "$dev3" err
+not grep "$dev4" err
+not grep "$dev5" err
+not grep "$dev6" err
+not grep "$dev7" err
+not grep "$dev8" err
+not grep "$dev9" err
+not grep "$dev11" err
+not grep "$dev12" err
+not grep "$dev13" err
+not grep "$dev14" err
+
+# pv not in vg (one orphan)
+pvdisplay -s "$dev11" | tee err
+not grep "$dev10" err
+not grep "$dev2" err
+not grep "$dev3" err
+not grep "$dev4" err
+not grep "$dev5" err
+not grep "$dev6" err
+not grep "$dev7" err
+not grep "$dev8" err
+not grep "$dev9" err
+grep "$dev11" err
+not grep "$dev12" err
+not grep "$dev13" err
+not grep "$dev14" err
+
+# dev is not a pv
+not pvdisplay -s "$dev12" | tee err
+not grep "$dev10" err
+not grep "$dev2" err
+not grep "$dev3" err
+not grep "$dev4" err
+not grep "$dev5" err
+not grep "$dev6" err
+not grep "$dev7" err
+not grep "$dev8" err
+not grep "$dev9" err
+not grep "$dev11" err
+not grep "$dev12" err
+not grep "$dev13" err
+not grep "$dev14" err
+
+# two pvs in different vgs
+pvdisplay -s "$dev10" "$dev2" | tee err
+grep "$dev10" err
+grep "$dev2" err
+not grep "$dev3" err
+not grep "$dev4" err
+not grep "$dev5" err
+not grep "$dev6" err
+not grep "$dev7" err
+not grep "$dev8" err
+not grep "$dev9" err
+not grep "$dev11" err
+not grep "$dev12" err
+not grep "$dev13" err
+not grep "$dev14" err
+
+# -a is invalid when used alone
+not pvdisplay -a | tee err
+not grep "$dev10" err
+not grep "$dev2" err
+not grep "$dev3" err
+not grep "$dev4" err
+not grep "$dev5" err
+not grep "$dev6" err
+not grep "$dev7" err
+not grep "$dev8" err
+not grep "$dev9" err
+not grep "$dev11" err
+not grep "$dev12" err
+not grep "$dev13" err
+not grep "$dev14" err
+
+# one pv and one orphan
+pvdisplay -s "$dev10" "$dev11" | tee err
+grep "$dev10" err
+not grep "$dev2" err
+not grep "$dev3" err
+not grep "$dev4" err
+not grep "$dev5" err
+not grep "$dev6" err
+not grep "$dev7" err
+not grep "$dev8" err
+not grep "$dev9" err
+grep "$dev11" err
+not grep "$dev12" err
+not grep "$dev13" err
+not grep "$dev14" err
+
+# one pv and one dev (dev refers to a non-pv device)
+not pvdisplay -s "$dev10" "$dev12" | tee err
+grep "$dev10" err
+not grep "$dev2" err
+not grep "$dev3" err
+not grep "$dev4" err
+not grep "$dev5" err
+not grep "$dev6" err
+not grep "$dev7" err
+not grep "$dev8" err
+not grep "$dev9" err
+not grep "$dev11" err
+not grep "$dev12" err
+not grep "$dev13" err
+not grep "$dev14" err
+
+# one orphan and one dev
+not pvdisplay -s "$dev11" "$dev12" | tee err
+not grep "$dev10" err
+not grep "$dev2" err
+not grep "$dev3" err
+not grep "$dev4" err
+not grep "$dev5" err
+not grep "$dev6" err
+not grep "$dev7" err
+not grep "$dev8" err
+not grep "$dev9" err
+grep "$dev11" err
+not grep "$dev12" err
+not grep "$dev13" err
+not grep "$dev14" err
+
+# all pvs (pvs in vgs and orphan pvs)
+pvdisplay -s | tee err
+grep "$dev10" err
+grep "$dev2" err
+grep "$dev3" err
+grep "$dev4" err
+grep "$dev5" err
+grep "$dev6" err
+grep "$dev7" err
+grep "$dev8" err
+grep "$dev9" err
+grep "$dev11" err
+not grep "$dev12" err
+not grep "$dev13" err
+grep "$dev14" err
+
+# all devs (pvs in vgs, orphan pvs, and devs)
+pvdisplay -a -C | tee err
+grep "$dev10" err
+grep "$dev2" err
+grep "$dev3" err
+grep "$dev4" err
+grep "$dev5" err
+grep "$dev6" err
+grep "$dev7" err
+grep "$dev8" err
+grep "$dev9" err
+grep "$dev11" err
+grep "$dev12" err
+grep "$dev13" err
+grep "$dev14" err
+
+# pv and orphan and dev
+not pvdisplay -s "$dev9" "$dev11" "$dev12" | tee err
+not grep "$dev10" err
+not grep "$dev2" err
+not grep "$dev3" err
+not grep "$dev4" err
+not grep "$dev5" err
+not grep "$dev6" err
+not grep "$dev7" err
+not grep "$dev8" err
+grep "$dev9" err
+grep "$dev11" err
+not grep "$dev12" err
+not grep "$dev13" err
+not grep "$dev14" err
+
+# -s option not allowed with -a -C
+not pvdisplay -s -a -C | tee err
+not grep "$dev10" err
+not grep "$dev2" err
+not grep "$dev3" err
+not grep "$dev4" err
+not grep "$dev5" err
+not grep "$dev6" err
+not grep "$dev7" err
+not grep "$dev8" err
+not grep "$dev9" err
+not grep "$dev11" err
+not grep "$dev12" err
+not grep "$dev13" err
+not grep "$dev14" err
+
+# pv and all (all ignored)
+pvdisplay -a -C "$dev9" | tee err
+not grep "$dev10" err
+not grep "$dev2" err
+not grep "$dev3" err
+not grep "$dev4" err
+not grep "$dev5" err
+not grep "$dev6" err
+not grep "$dev7" err
+not grep "$dev8" err
+grep "$dev9" err
+not grep "$dev11" err
+not grep "$dev12" err
+not grep "$dev13" err
+not grep "$dev14" err
+
+# orphan and all (all ignored)
+pvdisplay -a -C "$dev11" | tee err
+not grep "$dev10" err
+not grep "$dev2" err
+not grep "$dev3" err
+not grep "$dev4" err
+not grep "$dev5" err
+not grep "$dev6" err
+not grep "$dev7" err
+not grep "$dev8" err
+not grep "$dev9" err
+grep "$dev11" err
+not grep "$dev12" err
+not grep "$dev13" err
+not grep "$dev14" err
+
+# one tag
+pvdisplay -s @V2D3 | tee err
+not grep "$dev10" err
+not grep "$dev2" err
+grep "$dev3" err
+not grep "$dev4" err
+not grep "$dev5" err
+not grep "$dev6" err
+not grep "$dev7" err
+not grep "$dev8" err
+not grep "$dev9" err
+not grep "$dev11" err
+not grep "$dev12" err
+not grep "$dev13" err
+not grep "$dev14" err
+
+# two tags
+pvdisplay -s @V2D3 @V2D45 | tee err
+not grep "$dev10" err
+not grep "$dev2" err
+grep "$dev3" err
+grep "$dev4" err
+grep "$dev5" err
+not grep "$dev6" err
+not grep "$dev7" err
+not grep "$dev8" err
+not grep "$dev9" err
+not grep "$dev11" err
+not grep "$dev12" err
+not grep "$dev13" err
+not grep "$dev14" err
+
+# tag and pv
+pvdisplay -s @V2D3 "$dev4" | tee err
+not grep "$dev10" err
+not grep "$dev2" err
+grep "$dev3" err
+grep "$dev4" err
+not grep "$dev5" err
+not grep "$dev6" err
+not grep "$dev7" err
+not grep "$dev8" err
+not grep "$dev9" err
+not grep "$dev11" err
+not grep "$dev12" err
+not grep "$dev13" err
+not grep "$dev14" err
+
+# tag and orphan
+pvdisplay -s @V2D3 "$dev11" | tee err
+not grep "$dev10" err
+not grep "$dev2" err
+grep "$dev3" err
+not grep "$dev4" err
+not grep "$dev5" err
+not grep "$dev6" err
+not grep "$dev7" err
+not grep "$dev8" err
+not grep "$dev9" err
+grep "$dev11" err
+not grep "$dev12" err
+not grep "$dev13" err
+not grep "$dev14" err
+
+# tag and dev
+not pvdisplay -s @V2D3 "$dev12" | tee err
+not grep "$dev10" err
+not grep "$dev2" err
+grep "$dev3" err
+not grep "$dev4" err
+not grep "$dev5" err
+not grep "$dev6" err
+not grep "$dev7" err
+not grep "$dev8" err
+not grep "$dev9" err
+not grep "$dev11" err
+not grep "$dev12" err
+not grep "$dev13" err
+not grep "$dev14" err
+
+# tag and all (all ignored)
+pvdisplay @V2D3 -a -C | tee err
+not grep "$dev10" err
+not grep "$dev2" err
+grep "$dev3" err
+not grep "$dev4" err
+not grep "$dev5" err
+not grep "$dev6" err
+not grep "$dev7" err
+not grep "$dev8" err
+not grep "$dev9" err
+not grep "$dev11" err
+not grep "$dev12" err
+not grep "$dev13" err
+not grep "$dev14" err
+
+# tag and pv redundant
+pvdisplay -s @V2D3 "$dev3" | tee err
+not grep "$dev10" err
+not grep "$dev2" err
+grep "$dev3" err
+not grep "$dev4" err
+not grep "$dev5" err
+not grep "$dev6" err
+not grep "$dev7" err
+not grep "$dev8" err
+not grep "$dev9" err
+not grep "$dev11" err
+not grep "$dev12" err
+not grep "$dev13" err
+not grep "$dev14" err
+
+
+#
+# test pvs
+#
+
+# pv in vg
+pvs "$dev10" | tee err
+grep "$dev10" err
+not grep "$dev2" err
+not grep "$dev3" err
+not grep "$dev4" err
+not grep "$dev5" err
+not grep "$dev6" err
+not grep "$dev7" err
+not grep "$dev8" err
+not grep "$dev9" err
+not grep "$dev11" err
+not grep "$dev12" err
+not grep "$dev13" err
+not grep "$dev14" err
+
+# pv not in vg (one orphan)
+pvs "$dev11" | tee err
+not grep "$dev10" err
+not grep "$dev2" err
+not grep "$dev3" err
+not grep "$dev4" err
+not grep "$dev5" err
+not grep "$dev6" err
+not grep "$dev7" err
+not grep "$dev8" err
+not grep "$dev9" err
+grep "$dev11" err
+not grep "$dev12" err
+not grep "$dev13" err
+not grep "$dev14" err
+
+# dev is not a pv
+not pvs "$dev12" | tee err
+not grep "$dev10" err
+not grep "$dev2" err
+not grep "$dev3" err
+not grep "$dev4" err
+not grep "$dev5" err
+not grep "$dev6" err
+not grep "$dev7" err
+not grep "$dev8" err
+not grep "$dev9" err
+not grep "$dev11" err
+not grep "$dev12" err
+not grep "$dev13" err
+not grep "$dev14" err
+
+# two pvs in different vgs
+pvs "$dev10" "$dev2" | tee err
+grep "$dev10" err
+grep "$dev2" err
+not grep "$dev3" err
+not grep "$dev4" err
+not grep "$dev5" err
+not grep "$dev6" err
+not grep "$dev7" err
+not grep "$dev8" err
+not grep "$dev9" err
+not grep "$dev11" err
+not grep "$dev12" err
+not grep "$dev13" err
+not grep "$dev14" err
+
+# one pv and one orphan
+pvs "$dev10" "$dev11" | tee err
+grep "$dev10" err
+not grep "$dev2" err
+not grep "$dev3" err
+not grep "$dev4" err
+not grep "$dev5" err
+not grep "$dev6" err
+not grep "$dev7" err
+not grep "$dev8" err
+not grep "$dev9" err
+grep "$dev11" err
+not grep "$dev12" err
+not grep "$dev13" err
+not grep "$dev14" err
+
+# one pv and one dev
+not pvs "$dev10" "$dev12" | tee err
+grep "$dev10" err
+not grep "$dev2" err
+not grep "$dev3" err
+not grep "$dev4" err
+not grep "$dev5" err
+not grep "$dev6" err
+not grep "$dev7" err
+not grep "$dev8" err
+not grep "$dev9" err
+not grep "$dev11" err
+not grep "$dev12" err
+not grep "$dev13" err
+not grep "$dev14" err
+
+# one orphan and one dev
+not pvs "$dev11" "$dev12" | tee err
+not grep "$dev10" err
+not grep "$dev2" err
+not grep "$dev3" err
+not grep "$dev4" err
+not grep "$dev5" err
+not grep "$dev6" err
+not grep "$dev7" err
+not grep "$dev8" err
+not grep "$dev9" err
+grep "$dev11" err
+not grep "$dev12" err
+not grep "$dev13" err
+not grep "$dev14" err
+
+# all pvs (pvs in vgs and orphan pvs)
+pvs | tee err
+grep "$dev10" err
+grep "$dev2" err
+grep "$dev3" err
+grep "$dev4" err
+grep "$dev5" err
+grep "$dev6" err
+grep "$dev7" err
+grep "$dev8" err
+grep "$dev9" err
+grep "$dev11" err
+not grep "$dev12" err
+not grep "$dev13" err
+grep "$dev14" err
+
+# all devs (pvs in vgs, orphan pvs, and devs)
+pvs -a | tee err
+grep "$dev10" err
+grep "$dev2" err
+grep "$dev3" err
+grep "$dev4" err
+grep "$dev5" err
+grep "$dev6" err
+grep "$dev7" err
+grep "$dev8" err
+grep "$dev9" err
+grep "$dev11" err
+grep "$dev12" err
+grep "$dev13" err
+grep "$dev14" err
+
+# pv and orphan and dev
+not pvs "$dev9" "$dev11" "$dev12" | tee err
+not grep "$dev10" err
+not grep "$dev2" err
+not grep "$dev3" err
+not grep "$dev4" err
+not grep "$dev5" err
+not grep "$dev6" err
+not grep "$dev7" err
+not grep "$dev8" err
+grep "$dev9" err
+grep "$dev11" err
+not grep "$dev12" err
+not grep "$dev13" err
+not grep "$dev14" err
+
+# pv and all (all ignored)
+pvs -a "$dev9" | tee err
+not grep "$dev10" err
+not grep "$dev2" err
+not grep "$dev3" err
+not grep "$dev4" err
+not grep "$dev5" err
+not grep "$dev6" err
+not grep "$dev7" err
+not grep "$dev8" err
+grep "$dev9" err
+not grep "$dev11" err
+not grep "$dev12" err
+not grep "$dev13" err
+not grep "$dev14" err
+
+# orphan and all (all ignored)
+pvs -a "$dev11" | tee err
+not grep "$dev10" err
+not grep "$dev2" err
+not grep "$dev3" err
+not grep "$dev4" err
+not grep "$dev5" err
+not grep "$dev6" err
+not grep "$dev7" err
+not grep "$dev8" err
+not grep "$dev9" err
+grep "$dev11" err
+not grep "$dev12" err
+not grep "$dev13" err
+not grep "$dev14" err
+
+# one tag
+pvs @V2D3 | tee err
+not grep "$dev10" err
+not grep "$dev2" err
+grep "$dev3" err
+not grep "$dev4" err
+not grep "$dev5" err
+not grep "$dev6" err
+not grep "$dev7" err
+not grep "$dev8" err
+not grep "$dev9" err
+not grep "$dev11" err
+not grep "$dev12" err
+not grep "$dev13" err
+not grep "$dev14" err
+
+# two tags
+pvs @V2D3 @V2D45 | tee err
+not grep "$dev10" err
+not grep "$dev2" err
+grep "$dev3" err
+grep "$dev4" err
+grep "$dev5" err
+not grep "$dev6" err
+not grep "$dev7" err
+not grep "$dev8" err
+not grep "$dev9" err
+not grep "$dev11" err
+not grep "$dev12" err
+not grep "$dev13" err
+not grep "$dev14" err
+
+# tag and pv
+pvs @V2D3 "$dev4" | tee err
+not grep "$dev10" err
+not grep "$dev2" err
+grep "$dev3" err
+grep "$dev4" err
+not grep "$dev5" err
+not grep "$dev6" err
+not grep "$dev7" err
+not grep "$dev8" err
+not grep "$dev9" err
+not grep "$dev11" err
+not grep "$dev12" err
+not grep "$dev13" err
+not grep "$dev14" err
+
+# tag and orphan
+pvs @V2D3 "$dev11" | tee err
+not grep "$dev10" err
+not grep "$dev2" err
+grep "$dev3" err
+not grep "$dev4" err
+not grep "$dev5" err
+not grep "$dev6" err
+not grep "$dev7" err
+not grep "$dev8" err
+not grep "$dev9" err
+grep "$dev11" err
+not grep "$dev12" err
+not grep "$dev13" err
+not grep "$dev14" err
+
+# tag and dev
+not pvs @V2D3 "$dev12" | tee err
+not grep "$dev10" err
+not grep "$dev2" err
+grep "$dev3" err
+not grep "$dev4" err
+not grep "$dev5" err
+not grep "$dev6" err
+not grep "$dev7" err
+not grep "$dev8" err
+not grep "$dev9" err
+not grep "$dev11" err
+not grep "$dev12" err
+not grep "$dev13" err
+not grep "$dev14" err
+
+# tag and all (all ignored)
+pvs @V2D3 -a | tee err
+not grep "$dev10" err
+not grep "$dev2" err
+grep "$dev3" err
+not grep "$dev4" err
+not grep "$dev5" err
+not grep "$dev6" err
+not grep "$dev7" err
+not grep "$dev8" err
+not grep "$dev9" err
+not grep "$dev11" err
+not grep "$dev12" err
+not grep "$dev13" err
+not grep "$dev14" err
+
+# tag and pv redundant
+pvs @V2D3 "$dev3" | tee err
+not grep "$dev10" err
+not grep "$dev2" err
+grep "$dev3" err
+not grep "$dev4" err
+not grep "$dev5" err
+not grep "$dev6" err
+not grep "$dev7" err
+not grep "$dev8" err
+not grep "$dev9" err
+not grep "$dev11" err
+not grep "$dev12" err
+not grep "$dev13" err
+not grep "$dev14" err
+
+
+#
+# tests including pvs without mdas
+#
+
+# remove old config
+vgremove $vg1
+vgremove $vg2
+vgremove $vg3
+pvremove "$dev11"
+pvremove "$dev14"
+
+# new config with some pvs that have zero mdas
+
+# for vg1
+pvcreate "$dev10"
+
+# for vg2
+pvcreate "$dev2" --metadatacopies 0
+pvcreate "$dev3"
+pvcreate "$dev4"
+pvcreate "$dev5"
+
+# for vg3
+pvcreate "$dev6" --metadatacopies 0
+pvcreate "$dev7" --metadatacopies 0
+pvcreate "$dev8" --metadatacopies 0
+pvcreate "$dev9"
+
+# orphan with mda
+pvcreate "$dev11"
+# orphan without mda
+pvcreate "$dev14" --metadatacopies 0
+
+# non-pv devs
+# dev12
+# dev13
+
+vgcreate $SHARED $vg1 "$dev10"
+vgcreate $SHARED $vg2 "$dev2" "$dev3" "$dev4" "$dev5"
+vgcreate $SHARED $vg3 "$dev6" "$dev7" "$dev8" "$dev9"
+
+pvchange --addtag V2D3 "$dev3"
+pvchange --addtag V2D4 "$dev4"
+pvchange --addtag V2D45 "$dev4"
+pvchange --addtag V2D5 "$dev5"
+pvchange --addtag V2D45 "$dev5"
+
+pvchange --addtag V3 "$dev6" "$dev7" "$dev8" "$dev9"
+pvchange --addtag V3D8 "$dev8"
+pvchange --addtag V3D9 "$dev9"
+
+
+#
+# pvdisplay including pvs without mdas
+#
+
+# pv with mda
+pvdisplay -s "$dev10" | tee err
+grep "$dev10" err
+not grep "$dev2" err
+not grep "$dev3" err
+not grep "$dev4" err
+not grep "$dev5" err
+not grep "$dev6" err
+not grep "$dev7" err
+not grep "$dev8" err
+not grep "$dev9" err
+not grep "$dev11" err
+not grep "$dev12" err
+not grep "$dev13" err
+not grep "$dev14" err
+
+# pv without mda
+pvdisplay -s "$dev2" | tee err
+not grep "$dev10" err
+grep "$dev2" err
+not grep "$dev3" err
+not grep "$dev4" err
+not grep "$dev5" err
+not grep "$dev6" err
+not grep "$dev7" err
+not grep "$dev8" err
+not grep "$dev9" err
+not grep "$dev11" err
+not grep "$dev12" err
+not grep "$dev13" err
+not grep "$dev14" err
+
+# orphan with mda
+pvdisplay -s "$dev11" | tee err
+not grep "$dev10" err
+not grep "$dev2" err
+not grep "$dev3" err
+not grep "$dev4" err
+not grep "$dev5" err
+not grep "$dev6" err
+not grep "$dev7" err
+not grep "$dev8" err
+not grep "$dev9" err
+grep "$dev11" err
+not grep "$dev12" err
+not grep "$dev13" err
+not grep "$dev14" err
+
+# orphan without mda
+pvdisplay -s "$dev14" | tee err
+not grep "$dev10" err
+not grep "$dev2" err
+not grep "$dev3" err
+not grep "$dev4" err
+not grep "$dev5" err
+not grep "$dev6" err
+not grep "$dev7" err
+not grep "$dev8" err
+not grep "$dev9" err
+not grep "$dev11" err
+not grep "$dev12" err
+not grep "$dev13" err
+grep "$dev14" err
+
+# pv with mda, pv without mda, orphan with mda, orphan without mda
+pvdisplay -s "$dev10" "$dev2" "$dev11" "$dev14" | tee err
+grep "$dev10" err
+grep "$dev2" err
+not grep "$dev3" err
+not grep "$dev4" err
+not grep "$dev5" err
+not grep "$dev6" err
+not grep "$dev7" err
+not grep "$dev8" err
+not grep "$dev9" err
+grep "$dev11" err
+not grep "$dev12" err
+not grep "$dev13" err
+grep "$dev14" err
+
+# tag refering to pv with mda and pv without mda
+pvdisplay -s @V3 | tee err
+not grep "$dev10" err
+not grep "$dev2" err
+not grep "$dev3" err
+not grep "$dev4" err
+not grep "$dev5" err
+grep "$dev6" err
+grep "$dev7" err
+grep "$dev8" err
+grep "$dev9" err
+not grep "$dev11" err
+not grep "$dev12" err
+not grep "$dev13" err
+not grep "$dev14" err
+
+# tag refering to one pv without mda
+pvdisplay -s @V3D8 | tee err
+not grep "$dev10" err
+not grep "$dev2" err
+not grep "$dev3" err
+not grep "$dev4" err
+not grep "$dev5" err
+not grep "$dev6" err
+not grep "$dev7" err
+grep "$dev8" err
+not grep "$dev9" err
+not grep "$dev11" err
+not grep "$dev12" err
+not grep "$dev13" err
+not grep "$dev14" err
+
+# all pvs (pvs in vgs and orphan pvs)
+pvdisplay -s | tee err
+grep "$dev10" err
+grep "$dev2" err
+grep "$dev3" err
+grep "$dev4" err
+grep "$dev5" err
+grep "$dev6" err
+grep "$dev7" err
+grep "$dev8" err
+grep "$dev9" err
+grep "$dev11" err
+not grep "$dev12" err
+not grep "$dev13" err
+grep "$dev14" err
+
+# all devs (pvs in vgs, orphan pvs, and devs)
+pvdisplay -a -C | tee err
+grep "$dev10" err
+grep "$dev2" err
+grep "$dev3" err
+grep "$dev4" err
+grep "$dev5" err
+grep "$dev6" err
+grep "$dev7" err
+grep "$dev8" err
+grep "$dev9" err
+grep "$dev11" err
+grep "$dev12" err
+grep "$dev13" err
+grep "$dev14" err
+
+#
+# pvs including pvs without mdas
+#
+
+# pv with mda
+pvs "$dev10" | tee err
+grep "$dev10" err
+not grep "$dev2" err
+not grep "$dev3" err
+not grep "$dev4" err
+not grep "$dev5" err
+not grep "$dev6" err
+not grep "$dev7" err
+not grep "$dev8" err
+not grep "$dev9" err
+not grep "$dev11" err
+not grep "$dev12" err
+not grep "$dev13" err
+not grep "$dev14" err
+
+# pv without mda
+pvs "$dev2" | tee err
+not grep "$dev10" err
+grep "$dev2" err
+not grep "$dev3" err
+not grep "$dev4" err
+not grep "$dev5" err
+not grep "$dev6" err
+not grep "$dev7" err
+not grep "$dev8" err
+not grep "$dev9" err
+not grep "$dev11" err
+not grep "$dev12" err
+not grep "$dev13" err
+not grep "$dev14" err
+
+# orphan with mda
+pvs "$dev11" | tee err
+not grep "$dev10" err
+not grep "$dev2" err
+not grep "$dev3" err
+not grep "$dev4" err
+not grep "$dev5" err
+not grep "$dev6" err
+not grep "$dev7" err
+not grep "$dev8" err
+not grep "$dev9" err
+grep "$dev11" err
+not grep "$dev12" err
+not grep "$dev13" err
+not grep "$dev14" err
+
+# orphan without mda
+pvs "$dev14" | tee err
+not grep "$dev10" err
+not grep "$dev2" err
+not grep "$dev3" err
+not grep "$dev4" err
+not grep "$dev5" err
+not grep "$dev6" err
+not grep "$dev7" err
+not grep "$dev8" err
+not grep "$dev9" err
+not grep "$dev11" err
+not grep "$dev12" err
+not grep "$dev13" err
+grep "$dev14" err
+
+# pv with mda, pv without mda, orphan with mda, orphan without mda
+pvs "$dev10" "$dev2" "$dev11" "$dev14" | tee err
+grep "$dev10" err
+grep "$dev2" err
+not grep "$dev3" err
+not grep "$dev4" err
+not grep "$dev5" err
+not grep "$dev6" err
+not grep "$dev7" err
+not grep "$dev8" err
+not grep "$dev9" err
+grep "$dev11" err
+not grep "$dev12" err
+not grep "$dev13" err
+grep "$dev14" err
+
+# tag refering to pv with mda and pv without mda
+pvs @V3 | tee err
+not grep "$dev10" err
+not grep "$dev2" err
+not grep "$dev3" err
+not grep "$dev4" err
+not grep "$dev5" err
+grep "$dev6" err
+grep "$dev7" err
+grep "$dev8" err
+grep "$dev9" err
+not grep "$dev11" err
+not grep "$dev12" err
+not grep "$dev13" err
+not grep "$dev14" err
+
+# tag refering to one pv without mda
+pvs @V3D8 | tee err
+not grep "$dev10" err
+not grep "$dev2" err
+not grep "$dev3" err
+not grep "$dev4" err
+not grep "$dev5" err
+not grep "$dev6" err
+not grep "$dev7" err
+grep "$dev8" err
+not grep "$dev9" err
+not grep "$dev11" err
+not grep "$dev12" err
+not grep "$dev13" err
+not grep "$dev14" err
+
+# all pvs (pvs in vgs and orphan pvs)
+pvs | tee err
+grep "$dev10" err
+grep "$dev2" err
+grep "$dev3" err
+grep "$dev4" err
+grep "$dev5" err
+grep "$dev6" err
+grep "$dev7" err
+grep "$dev8" err
+grep "$dev9" err
+grep "$dev11" err
+not grep "$dev12" err
+not grep "$dev13" err
+grep "$dev14" err
+
+# all devs (pvs in vgs, orphan pvs, and devs)
+pvs -a | tee err
+grep "$dev10" err
+grep "$dev2" err
+grep "$dev3" err
+grep "$dev4" err
+grep "$dev5" err
+grep "$dev6" err
+grep "$dev7" err
+grep "$dev8" err
+grep "$dev9" err
+grep "$dev11" err
+grep "$dev12" err
+grep "$dev13" err
+grep "$dev14" err
+
+vgremove $vg1 $vg2 $vg3
diff --git a/test/shell/process-each-pvresize.sh b/test/shell/process-each-pvresize.sh
new file mode 100644
index 0000000..b2287b4
--- /dev/null
+++ b/test/shell/process-each-pvresize.sh
@@ -0,0 +1,563 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2008-2014 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+test_description='Exercise toollib process_each_pv'
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+aux prepare_devs 14
+
+#
+# process_each_pv is used by a number of pv commands:
+# pvdisplay
+# pvresize
+# pvs
+# vgreduce
+#
+
+
+#
+# set up
+#
+# use use dev10 instead of dev1 because simple grep for
+# dev1 matchines dev10,dev11,etc
+#
+
+vgcreate $SHARED $vg1 "$dev10"
+vgcreate $SHARED $vg2 "$dev2" "$dev3" "$dev4" "$dev5"
+vgcreate $SHARED $vg3 "$dev6" "$dev7" "$dev8" "$dev9"
+
+pvchange --addtag V2D3 "$dev3"
+pvchange --addtag V2D4 "$dev4"
+pvchange --addtag V2D45 "$dev4"
+pvchange --addtag V2D5 "$dev5"
+pvchange --addtag V2D45 "$dev5"
+
+pvchange --addtag V3 "$dev6" "$dev7" "$dev8" "$dev9"
+pvchange --addtag V3D9 "$dev9"
+
+# orphan
+pvcreate "$dev11"
+
+# dev (a non-pv device)
+pvcreate "$dev12"
+pvremove "$dev12"
+
+# dev13 is intentionally untouched so we can
+# test that it is handled appropriately as a non-pv
+
+# orphan
+pvcreate "$dev14"
+
+#
+# test pvresize without orphans and and without non-pv devs
+#
+
+# For pvs in vgs, pvresize setphysicalvolumesize does not give us
+# the size requested, but reduces the requested size by some the
+# amount for alignment, metadata areas and pv headers. So, when we resize
+# to 30M, the result is 28M, and when we resize to 20M, the result is 16M.
+# For orphans, the resulting size is the same as requested.
+# It suspect that these reduction amounts might be inconsistent, and
+# depend on other changing factors, so it may be that we eventually
+# want to give up checking the exact resulting size, but just check
+# that the result is less than the original size.
+
+old_request="30.00m"
+old_reduced="28.00m"
+new_request="20.00m"
+new_reduced="16.00m"
+
+pvresize --setphysicalvolumesize $old_request -y "$dev10" "$dev2" "$dev3" "$dev4" "$dev5" "$dev6" "$dev7" "$dev8" "$dev9"
+check pv_field "$dev10" pv_size $old_reduced
+check pv_field "$dev2" pv_size $old_reduced
+check pv_field "$dev3" pv_size $old_reduced
+check pv_field "$dev4" pv_size $old_reduced
+check pv_field "$dev5" pv_size $old_reduced
+check pv_field "$dev6" pv_size $old_reduced
+check pv_field "$dev7" pv_size $old_reduced
+check pv_field "$dev8" pv_size $old_reduced
+check pv_field "$dev9" pv_size $old_reduced
+
+# one pv
+pvresize --setphysicalvolumesize $new_request -y "$dev10"
+check pv_field "$dev10" pv_size $new_reduced
+# unchanged
+check pv_field "$dev2" pv_size $old_reduced
+check pv_field "$dev3" pv_size $old_reduced
+check pv_field "$dev4" pv_size $old_reduced
+check pv_field "$dev5" pv_size $old_reduced
+check pv_field "$dev6" pv_size $old_reduced
+check pv_field "$dev7" pv_size $old_reduced
+check pv_field "$dev8" pv_size $old_reduced
+check pv_field "$dev9" pv_size $old_reduced
+# reset back to old size
+pvresize --setphysicalvolumesize $old_request -y "$dev10" "$dev2" "$dev3" "$dev4" "$dev5" "$dev6" "$dev7" "$dev8" "$dev9"
+
+# two pvs in separate vgs
+pvresize --setphysicalvolumesize $new_request -y "$dev2" "$dev6"
+check pv_field "$dev2" pv_size $new_reduced
+check pv_field "$dev6" pv_size $new_reduced
+# unchanged
+check pv_field "$dev10" pv_size $old_reduced
+check pv_field "$dev3" pv_size $old_reduced
+check pv_field "$dev4" pv_size $old_reduced
+check pv_field "$dev5" pv_size $old_reduced
+check pv_field "$dev7" pv_size $old_reduced
+check pv_field "$dev8" pv_size $old_reduced
+check pv_field "$dev9" pv_size $old_reduced
+# reset back to old size
+pvresize --setphysicalvolumesize $old_request -y "$dev10" "$dev2" "$dev3" "$dev4" "$dev5" "$dev6" "$dev7" "$dev8" "$dev9"
+
+# one tag on one pv
+pvresize --setphysicalvolumesize $new_request -y @V2D4
+check pv_field "$dev4" pv_size $new_reduced
+# unchanged
+check pv_field "$dev10" pv_size $old_reduced
+check pv_field "$dev2" pv_size $old_reduced
+check pv_field "$dev3" pv_size $old_reduced
+check pv_field "$dev5" pv_size $old_reduced
+check pv_field "$dev6" pv_size $old_reduced
+check pv_field "$dev7" pv_size $old_reduced
+check pv_field "$dev8" pv_size $old_reduced
+check pv_field "$dev9" pv_size $old_reduced
+# reset back to old size
+pvresize --setphysicalvolumesize $old_request -y "$dev10" "$dev2" "$dev3" "$dev4" "$dev5" "$dev6" "$dev7" "$dev8" "$dev9"
+
+# one tag on all pvs in one vg
+pvresize --setphysicalvolumesize $new_request -y @V3
+check pv_field "$dev6" pv_size $new_reduced
+check pv_field "$dev7" pv_size $new_reduced
+check pv_field "$dev8" pv_size $new_reduced
+check pv_field "$dev9" pv_size $new_reduced
+# unchanged
+check pv_field "$dev10" pv_size $old_reduced
+check pv_field "$dev2" pv_size $old_reduced
+check pv_field "$dev3" pv_size $old_reduced
+check pv_field "$dev4" pv_size $old_reduced
+check pv_field "$dev5" pv_size $old_reduced
+# reset back to old size
+pvresize --setphysicalvolumesize $old_request -y "$dev10" "$dev2" "$dev3" "$dev4" "$dev5" "$dev6" "$dev7" "$dev8" "$dev9"
+
+# one tag on some pvs in one vg
+pvresize --setphysicalvolumesize $new_request -y @V2D45
+check pv_field "$dev4" pv_size $new_reduced
+check pv_field "$dev5" pv_size $new_reduced
+# unchanged
+check pv_field "$dev10" pv_size $old_reduced
+check pv_field "$dev2" pv_size $old_reduced
+check pv_field "$dev3" pv_size $old_reduced
+check pv_field "$dev6" pv_size $old_reduced
+check pv_field "$dev7" pv_size $old_reduced
+check pv_field "$dev8" pv_size $old_reduced
+check pv_field "$dev9" pv_size $old_reduced
+# reset back to old size
+pvresize --setphysicalvolumesize $old_request -y "$dev10" "$dev2" "$dev3" "$dev4" "$dev5" "$dev6" "$dev7" "$dev8" "$dev9"
+
+# one tag on multiple pvs in separate vgs
+pvchange --addtag V12 "$dev10" "$dev2" "$dev3" "$dev4" "$dev5"
+pvresize --setphysicalvolumesize $new_request -y @V12
+check pv_field "$dev10" pv_size $new_reduced
+check pv_field "$dev2" pv_size $new_reduced
+check pv_field "$dev3" pv_size $new_reduced
+check pv_field "$dev4" pv_size $new_reduced
+check pv_field "$dev5" pv_size $new_reduced
+# unchanged
+check pv_field "$dev6" pv_size $old_reduced
+check pv_field "$dev7" pv_size $old_reduced
+check pv_field "$dev8" pv_size $old_reduced
+check pv_field "$dev9" pv_size $old_reduced
+# reset back to old size
+pvresize --setphysicalvolumesize $old_request -y "$dev10" "$dev2" "$dev3" "$dev4" "$dev5" "$dev6" "$dev7" "$dev8" "$dev9"
+
+# one pv and one tag on different pv
+pvresize --setphysicalvolumesize $new_request -y "$dev10" @V3D9
+check pv_field "$dev10" pv_size $new_reduced
+check pv_field "$dev9" pv_size $new_reduced
+# unchanged
+check pv_field "$dev2" pv_size $old_reduced
+check pv_field "$dev3" pv_size $old_reduced
+check pv_field "$dev4" pv_size $old_reduced
+check pv_field "$dev5" pv_size $old_reduced
+check pv_field "$dev6" pv_size $old_reduced
+check pv_field "$dev7" pv_size $old_reduced
+check pv_field "$dev8" pv_size $old_reduced
+# reset back to old size
+pvresize --setphysicalvolumesize $old_request -y "$dev10" "$dev2" "$dev3" "$dev4" "$dev5" "$dev6" "$dev7" "$dev8" "$dev9"
+
+# redundant pv and tag
+pvresize --setphysicalvolumesize $new_request -y "$dev9" @V3D9
+check pv_field "$dev9" pv_size $new_reduced
+# unchanged
+check pv_field "$dev10" pv_size $old_reduced
+check pv_field "$dev2" pv_size $old_reduced
+check pv_field "$dev3" pv_size $old_reduced
+check pv_field "$dev4" pv_size $old_reduced
+check pv_field "$dev5" pv_size $old_reduced
+check pv_field "$dev6" pv_size $old_reduced
+check pv_field "$dev7" pv_size $old_reduced
+check pv_field "$dev8" pv_size $old_reduced
+# reset back to old size
+pvresize --setphysicalvolumesize $old_request -y "$dev10" "$dev2" "$dev3" "$dev4" "$dev5" "$dev6" "$dev7" "$dev8" "$dev9"
+
+# two tags on pvs in separate vgs
+pvresize --setphysicalvolumesize $new_request -y @V3D9 @V2D3
+check pv_field "$dev9" pv_size $new_reduced
+check pv_field "$dev3" pv_size $new_reduced
+# unchanged
+check pv_field "$dev10" pv_size $old_reduced
+check pv_field "$dev2" pv_size $old_reduced
+check pv_field "$dev4" pv_size $old_reduced
+check pv_field "$dev5" pv_size $old_reduced
+check pv_field "$dev6" pv_size $old_reduced
+check pv_field "$dev7" pv_size $old_reduced
+check pv_field "$dev8" pv_size $old_reduced
+# reset back to old size
+pvresize --setphysicalvolumesize $old_request -y "$dev10" "$dev2" "$dev3" "$dev4" "$dev5" "$dev6" "$dev7" "$dev8" "$dev9"
+
+
+#
+# test pvresize with orphans
+#
+
+old_request="30.00m"
+old_reduced="28.00m"
+old_orphan="30.00m"
+new_request="20.00m"
+new_reduced="16.00m"
+new_orphan="20.00m"
+
+pvresize --setphysicalvolumesize $old_request -y "$dev10" "$dev2" "$dev3" "$dev4" "$dev5" "$dev6" "$dev7" "$dev8" "$dev9"
+pvresize --setphysicalvolumesize $old_request -y "$dev11" "$dev14"
+check pv_field "$dev10" pv_size $old_reduced
+check pv_field "$dev2" pv_size $old_reduced
+check pv_field "$dev3" pv_size $old_reduced
+check pv_field "$dev4" pv_size $old_reduced
+check pv_field "$dev5" pv_size $old_reduced
+check pv_field "$dev6" pv_size $old_reduced
+check pv_field "$dev7" pv_size $old_reduced
+check pv_field "$dev8" pv_size $old_reduced
+check pv_field "$dev9" pv_size $old_reduced
+check pv_field "$dev11" pv_size $old_orphan
+check pv_field "$dev14" pv_size $old_orphan
+
+# one orphan
+pvresize --setphysicalvolumesize $new_request -y "$dev11"
+check pv_field "$dev11" pv_size $new_orphan
+# unchanged
+check pv_field "$dev10" pv_size $old_reduced
+check pv_field "$dev2" pv_size $old_reduced
+check pv_field "$dev3" pv_size $old_reduced
+check pv_field "$dev4" pv_size $old_reduced
+check pv_field "$dev5" pv_size $old_reduced
+check pv_field "$dev6" pv_size $old_reduced
+check pv_field "$dev7" pv_size $old_reduced
+check pv_field "$dev8" pv_size $old_reduced
+check pv_field "$dev9" pv_size $old_reduced
+check pv_field "$dev14" pv_size $old_orphan
+# reset back to old size
+pvresize --setphysicalvolumesize $old_request -y "$dev10" "$dev2" "$dev3" "$dev4" "$dev5" "$dev6" "$dev7" "$dev8" "$dev9"
+pvresize --setphysicalvolumesize $old_request -y "$dev11" "$dev14"
+
+# two orphans
+pvresize --setphysicalvolumesize $new_request -y "$dev11" "$dev14"
+check pv_field "$dev11" pv_size $new_orphan
+check pv_field "$dev14" pv_size $new_orphan
+# unchanged
+check pv_field "$dev10" pv_size $old_reduced
+check pv_field "$dev2" pv_size $old_reduced
+check pv_field "$dev3" pv_size $old_reduced
+check pv_field "$dev4" pv_size $old_reduced
+check pv_field "$dev5" pv_size $old_reduced
+check pv_field "$dev6" pv_size $old_reduced
+check pv_field "$dev7" pv_size $old_reduced
+check pv_field "$dev8" pv_size $old_reduced
+check pv_field "$dev9" pv_size $old_reduced
+# reset back to old size
+pvresize --setphysicalvolumesize $old_request -y "$dev10" "$dev2" "$dev3" "$dev4" "$dev5" "$dev6" "$dev7" "$dev8" "$dev9"
+pvresize --setphysicalvolumesize $old_request -y "$dev11" "$dev14"
+
+# one orphan, one tag
+pvresize --setphysicalvolumesize $new_request -y @V3D9 "$dev14"
+check pv_field "$dev9" pv_size $new_reduced
+check pv_field "$dev14" pv_size $new_orphan
+# unchanged
+check pv_field "$dev10" pv_size $old_reduced
+check pv_field "$dev2" pv_size $old_reduced
+check pv_field "$dev3" pv_size $old_reduced
+check pv_field "$dev4" pv_size $old_reduced
+check pv_field "$dev5" pv_size $old_reduced
+check pv_field "$dev6" pv_size $old_reduced
+check pv_field "$dev7" pv_size $old_reduced
+check pv_field "$dev8" pv_size $old_reduced
+check pv_field "$dev11" pv_size $old_orphan
+# reset back to old size
+pvresize --setphysicalvolumesize $old_request -y "$dev10" "$dev2" "$dev3" "$dev4" "$dev5" "$dev6" "$dev7" "$dev8" "$dev9"
+pvresize --setphysicalvolumesize $old_request -y "$dev11" "$dev14"
+
+# one pv, one orphan, one tag
+pvresize --setphysicalvolumesize $new_request -y @V3D9 "$dev14" "$dev10"
+check pv_field "$dev9" pv_size $new_reduced
+check pv_field "$dev10" pv_size $new_reduced
+check pv_field "$dev14" pv_size $new_orphan
+# unchanged
+check pv_field "$dev2" pv_size $old_reduced
+check pv_field "$dev3" pv_size $old_reduced
+check pv_field "$dev4" pv_size $old_reduced
+check pv_field "$dev5" pv_size $old_reduced
+check pv_field "$dev6" pv_size $old_reduced
+check pv_field "$dev7" pv_size $old_reduced
+check pv_field "$dev8" pv_size $old_reduced
+check pv_field "$dev11" pv_size $old_orphan
+# reset back to old size
+pvresize --setphysicalvolumesize $old_request -y "$dev10" "$dev2" "$dev3" "$dev4" "$dev5" "$dev6" "$dev7" "$dev8" "$dev9"
+pvresize --setphysicalvolumesize $old_request -y "$dev11" "$dev14"
+
+
+#
+# test pvresize with non-pv devs
+#
+
+# one dev (non-pv)
+not pvresize --setphysicalvolumesize $new_request -y "$dev13"
+# unchanged
+check pv_field "$dev10" pv_size $old_reduced
+check pv_field "$dev2" pv_size $old_reduced
+check pv_field "$dev3" pv_size $old_reduced
+check pv_field "$dev4" pv_size $old_reduced
+check pv_field "$dev5" pv_size $old_reduced
+check pv_field "$dev6" pv_size $old_reduced
+check pv_field "$dev7" pv_size $old_reduced
+check pv_field "$dev8" pv_size $old_reduced
+check pv_field "$dev9" pv_size $old_reduced
+check pv_field "$dev11" pv_size $old_orphan
+check pv_field "$dev14" pv_size $old_orphan
+
+# one orphan and one dev (non-pv)
+not pvresize --setphysicalvolumesize $new_request -y "$dev14" "$dev13"
+check pv_field "$dev14" pv_size $new_orphan
+# unchanged
+check pv_field "$dev10" pv_size $old_reduced
+check pv_field "$dev2" pv_size $old_reduced
+check pv_field "$dev3" pv_size $old_reduced
+check pv_field "$dev4" pv_size $old_reduced
+check pv_field "$dev5" pv_size $old_reduced
+check pv_field "$dev6" pv_size $old_reduced
+check pv_field "$dev7" pv_size $old_reduced
+check pv_field "$dev8" pv_size $old_reduced
+check pv_field "$dev9" pv_size $old_reduced
+check pv_field "$dev11" pv_size $old_orphan
+# reset back to old size
+pvresize --setphysicalvolumesize $old_request -y "$dev10" "$dev2" "$dev3" "$dev4" "$dev5" "$dev6" "$dev7" "$dev8" "$dev9"
+pvresize --setphysicalvolumesize $old_request -y "$dev11" "$dev14"
+
+# one pv and one dev (non-pv)
+not pvresize --setphysicalvolumesize $new_request -y "$dev9" "$dev13"
+check pv_field "$dev9" pv_size $new_reduced
+# unchanged
+check pv_field "$dev10" pv_size $old_reduced
+check pv_field "$dev2" pv_size $old_reduced
+check pv_field "$dev3" pv_size $old_reduced
+check pv_field "$dev4" pv_size $old_reduced
+check pv_field "$dev5" pv_size $old_reduced
+check pv_field "$dev6" pv_size $old_reduced
+check pv_field "$dev7" pv_size $old_reduced
+check pv_field "$dev8" pv_size $old_reduced
+check pv_field "$dev11" pv_size $old_orphan
+check pv_field "$dev14" pv_size $old_orphan
+# reset back to old size
+pvresize --setphysicalvolumesize $old_request -y "$dev10" "$dev2" "$dev3" "$dev4" "$dev5" "$dev6" "$dev7" "$dev8" "$dev9"
+pvresize --setphysicalvolumesize $old_request -y "$dev11" "$dev14"
+
+# one tag and one dev (non-pv)
+not pvresize --setphysicalvolumesize $new_request -y @V3D9 "$dev13"
+check pv_field "$dev9" pv_size $new_reduced
+# unchanged
+check pv_field "$dev10" pv_size $old_reduced
+check pv_field "$dev2" pv_size $old_reduced
+check pv_field "$dev3" pv_size $old_reduced
+check pv_field "$dev4" pv_size $old_reduced
+check pv_field "$dev5" pv_size $old_reduced
+check pv_field "$dev6" pv_size $old_reduced
+check pv_field "$dev7" pv_size $old_reduced
+check pv_field "$dev8" pv_size $old_reduced
+check pv_field "$dev11" pv_size $old_orphan
+check pv_field "$dev14" pv_size $old_orphan
+# reset back to old size
+pvresize --setphysicalvolumesize $old_request -y "$dev10" "$dev2" "$dev3" "$dev4" "$dev5" "$dev6" "$dev7" "$dev8" "$dev9"
+pvresize --setphysicalvolumesize $old_request -y "$dev11" "$dev14"
+
+# one pv, one orphan, one tag, one dev
+not pvresize --setphysicalvolumesize $new_request -y @V3D9 "$dev13" "$dev14" "$dev10"
+check pv_field "$dev9" pv_size $new_reduced
+check pv_field "$dev10" pv_size $new_reduced
+check pv_field "$dev14" pv_size $new_orphan
+# unchanged
+check pv_field "$dev2" pv_size $old_reduced
+check pv_field "$dev3" pv_size $old_reduced
+check pv_field "$dev4" pv_size $old_reduced
+check pv_field "$dev5" pv_size $old_reduced
+check pv_field "$dev6" pv_size $old_reduced
+check pv_field "$dev7" pv_size $old_reduced
+check pv_field "$dev8" pv_size $old_reduced
+check pv_field "$dev11" pv_size $old_orphan
+# reset back to old size
+pvresize --setphysicalvolumesize $old_request -y "$dev10" "$dev2" "$dev3" "$dev4" "$dev5" "$dev6" "$dev7" "$dev8" "$dev9"
+pvresize --setphysicalvolumesize $old_request -y "$dev11" "$dev14"
+
+
+#
+# pvresize including pvs without mdas
+#
+
+pvresize --setphysicalvolumesize $old_request -y "$dev10" "$dev2" "$dev3" "$dev4" "$dev5" "$dev6" "$dev7" "$dev8" "$dev9"
+pvresize --setphysicalvolumesize $old_request -y "$dev11" "$dev14"
+check pv_field "$dev10" pv_size $old_reduced
+check pv_field "$dev2" pv_size $old_reduced
+check pv_field "$dev3" pv_size $old_reduced
+check pv_field "$dev4" pv_size $old_reduced
+check pv_field "$dev5" pv_size $old_reduced
+check pv_field "$dev6" pv_size $old_reduced
+check pv_field "$dev7" pv_size $old_reduced
+check pv_field "$dev8" pv_size $old_reduced
+check pv_field "$dev9" pv_size $old_reduced
+check pv_field "$dev11" pv_size $old_orphan
+check pv_field "$dev14" pv_size $old_orphan
+
+# one pv without mda
+pvresize --setphysicalvolumesize $new_request -y "$dev2"
+check pv_field "$dev2" pv_size $new_reduced
+# unchanged
+check pv_field "$dev10" pv_size $old_reduced
+check pv_field "$dev3" pv_size $old_reduced
+check pv_field "$dev4" pv_size $old_reduced
+check pv_field "$dev5" pv_size $old_reduced
+check pv_field "$dev6" pv_size $old_reduced
+check pv_field "$dev7" pv_size $old_reduced
+check pv_field "$dev8" pv_size $old_reduced
+check pv_field "$dev9" pv_size $old_reduced
+check pv_field "$dev11" pv_size $old_orphan
+check pv_field "$dev14" pv_size $old_orphan
+# reset back to old size
+pvresize --setphysicalvolumesize $old_request -y "$dev10" "$dev2" "$dev3" "$dev4" "$dev5" "$dev6" "$dev7" "$dev8" "$dev9"
+pvresize --setphysicalvolumesize $old_request -y "$dev11" "$dev14"
+
+# two pvs without mdas
+pvresize --setphysicalvolumesize $new_request -y "$dev6" "$dev7"
+check pv_field "$dev6" pv_size $new_reduced
+check pv_field "$dev7" pv_size $new_reduced
+# unchanged
+check pv_field "$dev10" pv_size $old_reduced
+check pv_field "$dev2" pv_size $old_reduced
+check pv_field "$dev3" pv_size $old_reduced
+check pv_field "$dev4" pv_size $old_reduced
+check pv_field "$dev5" pv_size $old_reduced
+check pv_field "$dev8" pv_size $old_reduced
+check pv_field "$dev9" pv_size $old_reduced
+check pv_field "$dev11" pv_size $old_orphan
+check pv_field "$dev14" pv_size $old_orphan
+# reset back to old size
+pvresize --setphysicalvolumesize $old_request -y "$dev10" "$dev2" "$dev3" "$dev4" "$dev5" "$dev6" "$dev7" "$dev8" "$dev9"
+pvresize --setphysicalvolumesize $old_request -y "$dev11" "$dev14"
+
+# one pv with mda and one pv without mda
+pvresize --setphysicalvolumesize $new_request -y "$dev8" "$dev9"
+check pv_field "$dev8" pv_size $new_reduced
+check pv_field "$dev9" pv_size $new_reduced
+# unchanged
+check pv_field "$dev10" pv_size $old_reduced
+check pv_field "$dev2" pv_size $old_reduced
+check pv_field "$dev3" pv_size $old_reduced
+check pv_field "$dev4" pv_size $old_reduced
+check pv_field "$dev5" pv_size $old_reduced
+check pv_field "$dev6" pv_size $old_reduced
+check pv_field "$dev7" pv_size $old_reduced
+check pv_field "$dev11" pv_size $old_orphan
+check pv_field "$dev14" pv_size $old_orphan
+# reset back to old size
+pvresize --setphysicalvolumesize $old_request -y "$dev10" "$dev2" "$dev3" "$dev4" "$dev5" "$dev6" "$dev7" "$dev8" "$dev9"
+pvresize --setphysicalvolumesize $old_request -y "$dev11" "$dev14"
+
+# one orphan with mda
+pvresize --setphysicalvolumesize $new_request -y "$dev11"
+check pv_field "$dev11" pv_size $new_orphan
+# unchanged
+check pv_field "$dev10" pv_size $old_reduced
+check pv_field "$dev2" pv_size $old_reduced
+check pv_field "$dev3" pv_size $old_reduced
+check pv_field "$dev4" pv_size $old_reduced
+check pv_field "$dev5" pv_size $old_reduced
+check pv_field "$dev6" pv_size $old_reduced
+check pv_field "$dev7" pv_size $old_reduced
+check pv_field "$dev8" pv_size $old_reduced
+check pv_field "$dev9" pv_size $old_reduced
+check pv_field "$dev14" pv_size $old_orphan
+# reset back to old size
+pvresize --setphysicalvolumesize $old_request -y "$dev10" "$dev2" "$dev3" "$dev4" "$dev5" "$dev6" "$dev7" "$dev8" "$dev9"
+pvresize --setphysicalvolumesize $old_request -y "$dev11" "$dev14"
+
+# one orphan without mda
+pvresize --setphysicalvolumesize $new_request -y "$dev14"
+check pv_field "$dev14" pv_size $new_orphan
+# unchanged
+check pv_field "$dev10" pv_size $old_reduced
+check pv_field "$dev2" pv_size $old_reduced
+check pv_field "$dev3" pv_size $old_reduced
+check pv_field "$dev4" pv_size $old_reduced
+check pv_field "$dev5" pv_size $old_reduced
+check pv_field "$dev6" pv_size $old_reduced
+check pv_field "$dev7" pv_size $old_reduced
+check pv_field "$dev8" pv_size $old_reduced
+check pv_field "$dev9" pv_size $old_reduced
+check pv_field "$dev11" pv_size $old_orphan
+# reset back to old size
+pvresize --setphysicalvolumesize $old_request -y "$dev10" "$dev2" "$dev3" "$dev4" "$dev5" "$dev6" "$dev7" "$dev8" "$dev9"
+pvresize --setphysicalvolumesize $old_request -y "$dev11" "$dev14"
+
+# one orphan with mda and one orphan without mda
+pvresize --setphysicalvolumesize $new_request -y "$dev14" "$dev11"
+check pv_field "$dev11" pv_size $new_orphan
+check pv_field "$dev14" pv_size $new_orphan
+# unchanged
+check pv_field "$dev10" pv_size $old_reduced
+check pv_field "$dev2" pv_size $old_reduced
+check pv_field "$dev3" pv_size $old_reduced
+check pv_field "$dev4" pv_size $old_reduced
+check pv_field "$dev5" pv_size $old_reduced
+check pv_field "$dev6" pv_size $old_reduced
+check pv_field "$dev7" pv_size $old_reduced
+check pv_field "$dev8" pv_size $old_reduced
+check pv_field "$dev9" pv_size $old_reduced
+# reset back to old size
+pvresize --setphysicalvolumesize $old_request -y "$dev10" "$dev2" "$dev3" "$dev4" "$dev5" "$dev6" "$dev7" "$dev8" "$dev9"
+pvresize --setphysicalvolumesize $old_request -y "$dev11" "$dev14"
+
+# one pv with mda and one pv without mda, and
+# one orphan with mda and one orphan without mda
+pvresize --setphysicalvolumesize $new_request -y "$dev8" "$dev9" "$dev14" "$dev11"
+check pv_field "$dev8" pv_size $new_reduced
+check pv_field "$dev9" pv_size $new_reduced
+check pv_field "$dev11" pv_size $new_orphan
+check pv_field "$dev14" pv_size $new_orphan
+# unchanged
+check pv_field "$dev10" pv_size $old_reduced
+check pv_field "$dev2" pv_size $old_reduced
+check pv_field "$dev3" pv_size $old_reduced
+check pv_field "$dev4" pv_size $old_reduced
+check pv_field "$dev5" pv_size $old_reduced
+check pv_field "$dev6" pv_size $old_reduced
+check pv_field "$dev7" pv_size $old_reduced
+# reset back to old size
+pvresize --setphysicalvolumesize $old_request -y "$dev10" "$dev2" "$dev3" "$dev4" "$dev5" "$dev6" "$dev7" "$dev8" "$dev9"
+pvresize --setphysicalvolumesize $old_request -y "$dev11" "$dev14"
diff --git a/test/shell/process-each-vg.sh b/test/shell/process-each-vg.sh
new file mode 100644
index 0000000..569cf08
--- /dev/null
+++ b/test/shell/process-each-vg.sh
@@ -0,0 +1,269 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2008-2013 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+test_description='Exercise toollib process_each_vg'
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+aux prepare_devs 6
+
+#
+# process_each_vg is used by a number of vg commands;
+# use 'vgremove' and 'vgs' to test it.
+#
+# The logic in process_each_vg is mainly related to
+# selecting which vg's to process.
+#
+
+#
+# set up four vgs that we will remove
+#
+vgcreate $SHARED $vg1 "$dev1"
+vgcreate $SHARED $vg2 "$dev2"
+vgcreate $SHARED $vg3 "$dev3"
+vgcreate $SHARED $vg4 "$dev4"
+
+# these two vgs will not be removed
+vgcreate $SHARED $vg5 "$dev5"
+vgchange --addtag tagvg5 $vg5
+lvcreate -l 4 -n $lv1 $vg5
+vgcreate $SHARED $vg6 "$dev6"
+lvcreate -l 4 -n $lv2 $vg6
+
+# should fail without any arg
+not vgremove
+
+# should succeed
+vgremove $vg1
+vgremove $vg2 $vg3 $vg4
+
+# these should fail because they are already removed
+not vgremove $vg1
+not vgremove $vg2
+not vgremove $vg3
+not vgremove $vg4
+
+# these should fail because they have lvs in them
+not vgremove $vg5
+not vgremove $vg6
+
+# check that the vgs we removed are gone
+not vgs $vg1
+not vgs $vg2
+not vgs $vg3
+not vgs $vg4
+
+
+#
+# set up four vgs that we will remove
+#
+vgcreate $SHARED --addtag tagfoo $vg1 "$dev1"
+vgcreate $SHARED --addtag tagfoo $vg2 "$dev2"
+vgcreate $SHARED --addtag tagfoo2 $vg3 "$dev3"
+vgcreate $SHARED --addtag tagbar $vg4 "$dev4"
+vgchange --addtag foo $vg4
+
+# should do nothing and fail
+not vgremove garbage
+
+# should find nothing to remove
+vgremove @garbage
+
+# should find nothing to remove
+vgremove @$vg1
+
+# should succeed
+vgremove $vg1
+not vgs $vg1
+
+vgremove $vg2 $vg3 $vg4
+not vgs $vg2
+not vgs $vg3
+not vgs $vg4
+
+
+#
+# set up four vgs that we will remove
+#
+vgcreate $SHARED --addtag tagfoo $vg1 "$dev1"
+vgcreate $SHARED --addtag tagfoo $vg2 "$dev2"
+vgcreate $SHARED --addtag tagfoo2 $vg3 "$dev3"
+vgcreate $SHARED --addtag tagbar $vg4 "$dev4"
+vgchange --addtag foo $vg4
+
+vgremove @tagfoo
+not vgs $vg1
+not vgs $vg2
+
+vgremove @tagfoo2 @tagbar
+not vgs $vg3
+not vgs $vg4
+
+
+#
+# set up four vgs that we will remove
+#
+vgcreate $SHARED --addtag tagfoo $vg1 "$dev1"
+vgcreate $SHARED --addtag tagfoo $vg2 "$dev2"
+vgcreate $SHARED --addtag tagfoo2 $vg3 "$dev3"
+vgcreate $SHARED --addtag tagbar $vg4 "$dev4"
+vgchange --addtag foo $vg4
+
+vgremove $vg1 @tagfoo2
+not vgs $vg1
+not vgs $vg3
+
+vgremove @tagbar $vg2
+not vgs $vg2
+not vgs $vg4
+
+
+#
+# set up four vgs that we will remove
+#
+vgcreate $SHARED --addtag tagfoo $vg1 "$dev1"
+vgcreate $SHARED --addtag tagfoo $vg2 "$dev2"
+vgcreate $SHARED --addtag tagfoo2 $vg3 "$dev3"
+vgcreate $SHARED --addtag tagbar $vg4 "$dev4"
+vgchange --addtag foo $vg4
+
+vgremove @foo @tagfoo2 $vg1 $vg2
+not vgs $vg1
+not vgs $vg2
+not vgs $vg3
+not vgs $vg4
+
+
+#
+# set up four vgs that we will remove
+#
+vgcreate $SHARED --addtag tagfoo $vg1 "$dev1"
+vgcreate $SHARED --addtag tagfoo $vg2 "$dev2"
+vgcreate $SHARED --addtag tagfoo2 $vg3 "$dev3"
+vgcreate $SHARED --addtag tagbar $vg4 "$dev4"
+vgchange --addtag foo $vg4
+
+vgremove @tagfoo $vg1 @tagfoo @tagfoo2 $vg3 @tagbar
+not vgs $vg1
+not vgs $vg2
+not vgs $vg3
+not vgs $vg4
+
+
+#
+# set up four vgs that we will remove
+#
+vgcreate $SHARED --addtag tagfoo $vg1 "$dev1"
+vgcreate $SHARED --addtag tagfoo $vg2 "$dev2"
+vgcreate $SHARED --addtag tagfoo2 $vg3 "$dev3"
+vgcreate $SHARED --addtag tagbar $vg4 "$dev4"
+vgchange --addtag foo $vg4
+
+not vgremove garbage $vg1
+not vgs $vg1
+
+not vgremove $vg2 garbage
+not vgs $vg2
+
+vgremove $vg3 @garbage
+not vgs $vg3
+
+vgremove @garbage $vg4
+not vgs $vg4
+
+
+#
+# end vgremove tests
+# check that the two vgs we did not intend to remove
+# are still there, and then remove them
+#
+vgs $vg5
+vgs $vg6
+vgremove -f $vg5
+vgremove -f $vg6
+not vgs $vg5
+not vgs $vg6
+
+
+#
+# set up four vgs that we will report
+#
+vgcreate $SHARED --addtag tagfoo $vg1 "$dev1"
+vgcreate $SHARED --addtag tagfoo $vg2 "$dev2"
+vgcreate $SHARED --addtag tagfoo2 $vg3 "$dev3"
+vgcreate $SHARED --addtag tagbar $vg4 "$dev4"
+vgchange --addtag foo $vg4
+
+vgs >err
+grep $vg1 err
+grep $vg2 err
+grep $vg3 err
+grep $vg4 err
+
+vgs $vg1 $vg2 >err
+grep $vg1 err
+grep $vg2 err
+not grep $vg3 err
+not grep $vg4 err
+
+vgs @tagfoo >err
+grep $vg1 err
+grep $vg2 err
+not grep $vg3 err
+not grep $vg4 err
+
+vgs @tagfoo2 >err
+grep $vg3 err
+not grep $vg1 err
+not grep $vg2 err
+not grep $vg4 err
+
+vgs @tagfoo2 @tagbar >err
+grep $vg3 err
+grep $vg4 err
+not grep $vg1 err
+not grep $vg2 err
+
+vgs $vg1 @tagbar >err
+grep $vg1 err
+grep $vg4 err
+not grep $vg2 err
+not grep $vg3 err
+
+vgs $vg1 @tagfoo >err
+grep $vg1 err
+grep $vg2 err
+not grep $vg3 err
+not grep $vg4 err
+
+not vgs garbage >err
+not grep $vg1 err
+not grep $vg2 err
+not grep $vg3 err
+not grep $vg4 err
+
+not vgs garbage $vg1 >err
+grep $vg1 err
+not grep $vg2 err
+not grep $vg3 err
+not grep $vg4 err
+
+vgs @garbage @foo >err
+grep $vg4 err
+not grep $vg1 err
+not grep $vg2 err
+not grep $vg3 err
+
+vgremove -f $vg1 $vg2 $vg3 $vg4
+
diff --git a/test/shell/process-each-vgreduce.sh b/test/shell/process-each-vgreduce.sh
new file mode 100644
index 0000000..23584bf
--- /dev/null
+++ b/test/shell/process-each-vgreduce.sh
@@ -0,0 +1,331 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2014 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+test_description='Exercise toollib process_each_pv with vgreduce'
+
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+aux prepare_devs 14
+
+#
+# set up
+#
+# FIXME: some of the setup may not be used by the tests
+# since this was split out from process-each-pv, where
+# some of the setup was used by other tests that only
+# remain in process-each-pv.
+#
+# use use dev10 instead of dev1 because simple grep for
+# dev1 matchines dev10,dev11,etc
+#
+
+vgcreate $SHARED $vg1 "$dev10"
+vgcreate $SHARED $vg2 "$dev2" "$dev3" "$dev4" "$dev5"
+vgcreate $SHARED $vg3 "$dev6" "$dev7" "$dev8" "$dev9"
+
+pvchange --addtag V2D3 "$dev3"
+pvchange --addtag V2D4 "$dev4"
+pvchange --addtag V2D45 "$dev4"
+pvchange --addtag V2D5 "$dev5"
+pvchange --addtag V2D45 "$dev5"
+
+pvchange --addtag V3 "$dev6" "$dev7" "$dev8" "$dev9"
+pvchange --addtag V3D9 "$dev9"
+
+# orphan
+pvcreate "$dev11"
+
+# dev (a non-pv device)
+pvcreate "$dev12"
+pvremove "$dev12"
+
+# dev13 is intentionally untouched so we can
+# test that it is handled appropriately as a non-pv
+
+# orphan
+pvcreate "$dev14"
+
+
+# fail without dev
+not vgreduce $vg2
+
+
+# fail with dev and -a
+not vgreduce $vg2 "$dev2" -a
+check pv_field "$dev2" vg_name $vg2
+check pv_field "$dev3" vg_name $vg2
+check pv_field "$dev4" vg_name $vg2
+check pv_field "$dev5" vg_name $vg2
+check pv_field "$dev6" vg_name $vg3
+check pv_field "$dev7" vg_name $vg3
+check pv_field "$dev8" vg_name $vg3
+check pv_field "$dev9" vg_name $vg3
+
+
+# remove one pv
+vgreduce $vg2 "$dev2"
+not check pv_field "$dev2" vg_name $vg2
+check pv_field "$dev3" vg_name $vg2
+check pv_field "$dev4" vg_name $vg2
+check pv_field "$dev5" vg_name $vg2
+check pv_field "$dev6" vg_name $vg3
+check pv_field "$dev7" vg_name $vg3
+check pv_field "$dev8" vg_name $vg3
+check pv_field "$dev9" vg_name $vg3
+# reset
+vgextend $vg2 "$dev2"
+
+
+# remove two pvs
+vgreduce $vg2 "$dev2" "$dev3"
+not check pv_field "$dev2" vg_name $vg2
+not check pv_field "$dev3" vg_name $vg2
+check pv_field "$dev4" vg_name $vg2
+check pv_field "$dev5" vg_name $vg2
+check pv_field "$dev6" vg_name $vg3
+check pv_field "$dev7" vg_name $vg3
+check pv_field "$dev8" vg_name $vg3
+check pv_field "$dev9" vg_name $vg3
+# reset
+vgextend $vg2 "$dev2" "$dev3"
+pvchange --addtag V2D3 "$dev3"
+
+
+# remove one pv with tag
+vgreduce $vg2 @V2D3
+check pv_field "$dev2" vg_name $vg2
+not check pv_field "$dev3" vg_name $vg2
+check pv_field "$dev4" vg_name $vg2
+check pv_field "$dev5" vg_name $vg2
+check pv_field "$dev6" vg_name $vg3
+check pv_field "$dev7" vg_name $vg3
+check pv_field "$dev8" vg_name $vg3
+check pv_field "$dev9" vg_name $vg3
+# reset
+vgextend $vg2 "$dev3"
+pvchange --addtag V2D3 "$dev3"
+
+
+# remove two pvs, each with different tag
+vgreduce $vg2 @V2D3 @V2D4
+check pv_field "$dev2" vg_name $vg2
+not check pv_field "$dev3" vg_name $vg2
+not check pv_field "$dev4" vg_name $vg2
+check pv_field "$dev5" vg_name $vg2
+check pv_field "$dev6" vg_name $vg3
+check pv_field "$dev7" vg_name $vg3
+check pv_field "$dev8" vg_name $vg3
+check pv_field "$dev9" vg_name $vg3
+# reset
+vgextend $vg2 "$dev3" "$dev4"
+pvchange --addtag V2D3 "$dev3"
+pvchange --addtag V2D4 "$dev4"
+pvchange --addtag V2D45 "$dev4"
+
+
+# remove two pvs, both with same tag
+vgreduce $vg2 @V2D45
+check pv_field "$dev2" vg_name $vg2
+check pv_field "$dev3" vg_name $vg2
+not check pv_field "$dev4" vg_name $vg2
+not check pv_field "$dev5" vg_name $vg2
+check pv_field "$dev6" vg_name $vg3
+check pv_field "$dev7" vg_name $vg3
+check pv_field "$dev8" vg_name $vg3
+check pv_field "$dev9" vg_name $vg3
+# reset
+vgextend $vg2 "$dev4" "$dev5"
+pvchange --addtag V2D4 "$dev4"
+pvchange --addtag V2D45 "$dev4"
+pvchange --addtag V2D5 "$dev5"
+pvchange --addtag V2D45 "$dev5"
+
+
+# remove two pvs, one by name, one by tag
+vgreduce $vg2 "$dev2" @V2D3
+not check pv_field "$dev2" vg_name $vg2
+not check pv_field "$dev3" vg_name $vg2
+check pv_field "$dev4" vg_name $vg2
+check pv_field "$dev5" vg_name $vg2
+check pv_field "$dev6" vg_name $vg3
+check pv_field "$dev7" vg_name $vg3
+check pv_field "$dev8" vg_name $vg3
+check pv_field "$dev9" vg_name $vg3
+# reset
+vgextend $vg2 "$dev2" "$dev3"
+pvchange --addtag V2D3 "$dev3"
+
+
+# remove one pv by tag, where another vg has a pv with same tag
+pvchange --addtag V2D5V3D9 "$dev5"
+pvchange --addtag V2D5V3D9 "$dev9"
+vgreduce $vg2 @V2D5V3D9
+check pv_field "$dev2" vg_name $vg2
+check pv_field "$dev3" vg_name $vg2
+check pv_field "$dev4" vg_name $vg2
+not check pv_field "$dev5" vg_name $vg2
+check pv_field "$dev6" vg_name $vg3
+check pv_field "$dev7" vg_name $vg3
+check pv_field "$dev8" vg_name $vg3
+check pv_field "$dev9" vg_name $vg3
+# reset
+vgextend $vg2 "$dev5"
+pvchange --addtag V2D5 "$dev5"
+pvchange --addtag V2D45 "$dev5"
+
+
+# fail to remove last pv (don't know which will be last)
+not vgreduce -a $vg2
+# reset
+vgremove $vg2
+vgcreate $SHARED $vg2 "$dev2" "$dev3" "$dev4" "$dev5"
+pvchange --addtag V2D3 "$dev3"
+pvchange --addtag V2D4 "$dev4"
+pvchange --addtag V2D45 "$dev4"
+pvchange --addtag V2D5 "$dev5"
+pvchange --addtag V2D45 "$dev5"
+
+
+# lvcreate on one pv to make it used
+# remove all unused pvs
+lvcreate -n $lv1 -l 2 $vg2 "$dev2"
+not vgreduce -a $vg2
+check pv_field "$dev2" vg_name $vg2
+not check pv_field "$dev3" vg_name $vg2
+not check pv_field "$dev4" vg_name $vg2
+not check pv_field "$dev5" vg_name $vg2
+check pv_field "$dev6" vg_name $vg3
+check pv_field "$dev7" vg_name $vg3
+check pv_field "$dev8" vg_name $vg3
+check pv_field "$dev9" vg_name $vg3
+# reset
+vgextend $vg2 "$dev3" "$dev4" "$dev5"
+pvchange --addtag V2D3 "$dev3"
+pvchange --addtag V2D4 "$dev4"
+pvchange --addtag V2D45 "$dev4"
+pvchange --addtag V2D5 "$dev5"
+pvchange --addtag V2D45 "$dev5"
+lvchange -an $vg2/$lv1
+lvremove $vg2/$lv1
+
+
+#
+# tests including pvs without mdas
+#
+
+# remove old config
+vgremove $vg1
+vgremove $vg2
+vgremove $vg3
+pvremove "$dev11"
+pvremove "$dev14"
+
+# new config with some pvs that have zero mdas
+
+# for vg1
+pvcreate "$dev10"
+
+# for vg2
+pvcreate "$dev2" --metadatacopies 0
+pvcreate "$dev3"
+pvcreate "$dev4"
+pvcreate "$dev5"
+
+# for vg3
+pvcreate "$dev6" --metadatacopies 0
+pvcreate "$dev7" --metadatacopies 0
+pvcreate "$dev8" --metadatacopies 0
+pvcreate "$dev9"
+
+# orphan with mda
+pvcreate "$dev11"
+# orphan without mda
+pvcreate "$dev14" --metadatacopies 0
+
+# non-pv devs
+# dev12
+# dev13
+
+vgcreate $SHARED $vg1 "$dev10"
+vgcreate $SHARED $vg2 "$dev2" "$dev3" "$dev4" "$dev5"
+vgcreate $SHARED $vg3 "$dev6" "$dev7" "$dev8" "$dev9"
+
+pvchange --addtag V2D3 "$dev3"
+pvchange --addtag V2D4 "$dev4"
+pvchange --addtag V2D45 "$dev4"
+pvchange --addtag V2D5 "$dev5"
+pvchange --addtag V2D45 "$dev5"
+
+pvchange --addtag V3 "$dev6" "$dev7" "$dev8" "$dev9"
+pvchange --addtag V3D8 "$dev8"
+pvchange --addtag V3D9 "$dev9"
+
+
+#
+# vgreduce including pvs without mdas
+#
+
+# remove pv without mda
+vgreduce $vg2 "$dev2"
+not check pv_field "$dev2" vg_name $vg2
+check pv_field "$dev3" vg_name $vg2
+check pv_field "$dev4" vg_name $vg2
+check pv_field "$dev5" vg_name $vg2
+check pv_field "$dev6" vg_name $vg3
+check pv_field "$dev7" vg_name $vg3
+check pv_field "$dev8" vg_name $vg3
+check pv_field "$dev9" vg_name $vg3
+# reset
+vgextend $vg2 "$dev2"
+
+# remove pv with mda and pv without mda
+vgreduce $vg2 "$dev2" "$dev3"
+not check pv_field "$dev2" vg_name $vg2
+not check pv_field "$dev3" vg_name $vg2
+check pv_field "$dev4" vg_name $vg2
+check pv_field "$dev5" vg_name $vg2
+check pv_field "$dev6" vg_name $vg3
+check pv_field "$dev7" vg_name $vg3
+check pv_field "$dev8" vg_name $vg3
+check pv_field "$dev9" vg_name $vg3
+# reset
+vgextend $vg2 "$dev2"
+vgextend $vg2 "$dev3"
+
+# fail to remove only pv with mda
+not vgreduce $vg3 "$dev9"
+check pv_field "$dev6" vg_name $vg3
+check pv_field "$dev7" vg_name $vg3
+check pv_field "$dev8" vg_name $vg3
+check pv_field "$dev9" vg_name $vg3
+check pv_field "$dev2" vg_name $vg2
+check pv_field "$dev3" vg_name $vg2
+check pv_field "$dev4" vg_name $vg2
+check pv_field "$dev5" vg_name $vg2
+
+# remove by tag a pv without mda
+vgreduce $vg3 @V3D8
+check pv_field "$dev6" vg_name $vg3
+check pv_field "$dev7" vg_name $vg3
+not check pv_field "$dev8" vg_name $vg3
+check pv_field "$dev9" vg_name $vg3
+check pv_field "$dev2" vg_name $vg2
+check pv_field "$dev3" vg_name $vg2
+check pv_field "$dev4" vg_name $vg2
+check pv_field "$dev5" vg_name $vg2
+# reset
+vgextend $vg3 "$dev8"
+
+vgremove $vg1 $vg2 $vg3
diff --git a/test/shell/profiles-cache.sh b/test/shell/profiles-cache.sh
new file mode 100644
index 0000000..b408130
--- /dev/null
+++ b/test/shell/profiles-cache.sh
@@ -0,0 +1,153 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2017 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+# Exercise obtaining cache parameter from various sources
+# Either commmand line or metadata profile or implicit default...
+
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+aux have_cache 1 8 0 || skip
+
+PDIR="$LVM_SYSTEM_DIR/profile"
+PFILE="cache-test"
+
+aux prepare_profiles
+
+cat <<EOF > "$PDIR/${PFILE}.profile"
+allocation {
+ cache_pool_chunk_size = 128
+ cache_mode = "writeback"
+ cache_policy = "mq"
+ cache_metadata_format = 1
+
+ cache_settings {
+ smq {
+ sequential_threshold = 300
+ random_threshold = 500
+ }
+ mq {
+ }
+ mq {
+ sequential_threshold = 100
+ random_threshold = 200
+ }
+ writecache {
+ high_watermark = 60
+ }
+ }
+}
+EOF
+
+cat <<EOF > "$PDIR/${PFILE}1.profile"
+allocation {
+ cache_pool_chunk_size = 512
+ cache_mode = "passthrough"
+ cache_policy = "smq"
+ cache_metadata_format = 1
+}
+EOF
+
+aux prepare_vg 2 1000000
+
+# Check writecache read data from profile
+if aux have_writecache 1 0 0 ; then
+lvcreate -n $lv1 -l 4 -an $vg "$dev1"
+lvcreate -y --type writecache -l 4 --cachevol $lv1 -n $lv2 --metadataprofile $PFILE $vg "$dev2"
+check lv_field $vg/$lv2 cachesettings "high_watermark=60"
+lvremove -y $vg
+fi
+
+# Check chunk_size is grabbed from configuration
+lvcreate -L1G --config 'allocation/cache_pool_chunk_size=512' --type cache-pool $vg/cpool
+check lv_field $vg/cpool chunksize "512.00k"
+
+# Check chunk_size can be overruled when caching LV.
+lvcreate -H --chunksize 128K -L10 --cachepool $vg/cpool -n $lv1
+check lv_field $vg/$lv1 chunksize "128.00k"
+
+lvremove -f $vg
+
+
+# Check chunk_size is grabbed from metadata profile
+lvcreate -L1G --metadataprofile $PFILE --type cache-pool $vg/cpool
+#lvcreate -L1G --commandprofile $PFILE --type cache-pool $vg/cpool
+
+# profile name is stored with cache-pool
+check lv_field $vg/cpool profile "$PFILE"
+# cache chunk size is selected and stored on creation time
+check lv_field $vg/cpool chunksize "128.00k"
+# cache metadata format is not stored with cache-pool
+check lv_field $vg/cpool cachemetadataformat ""
+# cache mode is not stored with cache-pool
+check lv_field $vg/cpool cachemode ""
+# cache policy is not stored with cache-pool
+check lv_field $vg/cpool cachepolicy ""
+# cache settings are not stored with cache-pool
+check lv_field $vg/cpool cachesettings ""
+
+
+lvcreate -L10 -n $lv1 $vg
+lvconvert --metadataprofile "${PFILE}1" -y -H --cachepool $vg/cpool $vg/$lv1
+# chunk size 128k is replace with 512k from PFILE1
+check lv_field $vg/$lv1 chunksize "512.00k"
+# cachemode is from PFILE1
+check lv_field $vg/$lv1 cachemode "passthrough"
+lvremove -f $vg
+
+lvcreate -L1G --metadataprofile "$PFILE" --type cache-pool $vg/cpool
+lvcreate -H -L10 -n $lv1 --cachepool $vg/cpool
+# profile name is stored with cache
+check lv_field $vg/$lv1 profile "$PFILE"
+# cache chunk size is selected and stored on creation time
+check lv_field $vg/$lv1 chunksize "128.00k"
+# cache metadata format is stored with cache
+check lv_field $vg/$lv1 cachemetadataformat "1"
+# cache mode is stored with cache
+check lv_field $vg/$lv1 cachemode "writeback"
+# cache policy is stored with cache
+check lv_field $vg/$lv1 cachepolicy "mq"
+# cache settings are stored with cache
+check lv_field $vg/$lv1 cachesettings "sequential_threshold=100,random_threshold=200"
+
+lvremove -f $vg
+
+#####
+
+lvcreate -L1G --metadataprofile "$PFILE" --type cache-pool $vg/cpool
+lvcreate --cachesettings 'sequential_threshold=300' -H -L10 -n $lv1 --cachepool $vg/cpool
+check lv_field $vg/$lv1 profile "$PFILE"
+check lv_field $vg/$lv1 cachesettings "sequential_threshold=300"
+lvremove -f $vg
+
+#####
+
+lvcreate -L1G --metadataprofile "$PFILE" --type cache-pool $vg/cpool
+lvcreate --chunksize 256 -H -L10 -n $lv1 --cachepool $vg/cpool
+check lv_field $vg/$lv1 cachemode "writeback"
+check lv_field $vg/$lv1 chunksize "256.00k"
+lvremove -f $vg
+
+
+#####
+
+lvcreate -L1G --metadataprofile "$PFILE" --type cache-pool $vg/cpool
+lvcreate --metadataprofile "${PFILE}1" -H -L10 -n $lv1 --cachepool $vg/cpool
+check lv_field $vg/$lv1 chunksize "512.00k"
+check lv_field $vg/$lv1 cachemode "passthrough"
+lvremove -f $vg
+
+#lvs -a -o+chunksize,cachemode,cachemetadataformat,cachepolicy,cachesettings $vg
+
+vgremove -ff $vg
diff --git a/test/shell/profiles-thin.sh b/test/shell/profiles-thin.sh
new file mode 100644
index 0000000..c62a5f5
--- /dev/null
+++ b/test/shell/profiles-thin.sh
@@ -0,0 +1,97 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2014 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+#
+# test thin profile functionality
+#
+
+
+SKIP_WITH_LVMPOLLD=1
+
+export LVM_TEST_THIN_REPAIR_CMD=${LVM_TEST_THIN_REPAIR_CMD-/bin/false}
+
+. lib/inittest
+
+DEV_SIZE=32
+
+# check we have thinp support compiled in
+aux have_thin 1 0 0 || skip
+
+aux prepare_profiles "thin-performance"
+
+# Create scsi debug dev with sector size of 4096B and 1MiB optimal_io_size
+aux prepare_scsi_debug_dev $DEV_SIZE sector_size=4096 opt_blks=256 || skip
+EXPECT=1048576
+check sysfs "$(< SCSI_DEBUG_DEV)" queue/optimal_io_size "$EXPECT"
+aux prepare_pvs 1 "$DEV_SIZE"
+
+# Check we are not running on buggy kernel (broken lcm())
+# If so, turn chunk_size test into 'should'
+SHOULD=""
+check sysfs "$dev1" queue/optimal_io_size "$EXPECT" || SHOULD=should
+
+vgcreate $SHARED $vg "$dev1"
+
+# By default, "generic" policy is used to
+# calculate chunk size which is 64KiB by default
+# or minimum_io_size if it's higher. Also, zeroing is used
+# under default operation.
+lvcreate -L8m -T $vg/pool_generic
+check lv_field $vg/pool_generic profile ""
+check lv_field $vg/pool_generic chunk_size 64.00k
+check lv_field $vg/pool_generic zero "zero"
+
+# If "thin-performance" profile is used, the "performance"
+# policy is used to calculate chunk size which is 512KiB
+# or optimal_io_suize if it's higher. Our test device has
+# 1MiB, so that should be used. Also, zeroing is not used
+# under "thin-perforance" profile.
+lvcreate --profile thin-performance -L8m -T $vg/pool_performance
+check lv_field $vg/pool_performance profile "thin-performance"
+$SHOULD check lv_field $vg/pool_performance chunk_size 1.00m
+check lv_field $vg/pool_performance zero ""
+
+lvremove -f $vg
+
+#
+# Repeat same two creations via lvconvert
+#
+lvcreate -L8m --name pool_generic $vg
+lvconvert --yes --type thin-pool $vg/pool_generic
+check lv_field $vg/pool_generic chunk_size 64.00k
+check lv_field $vg/pool_generic zero "zero"
+
+
+lvcreate -L8m --name pool_performance $vg
+lvconvert --yes --type thin-pool --errorwhenfull y --profile thin-performance $vg/pool_performance
+check lv_field $vg/pool_performance profile "thin-performance"
+$SHOULD check lv_field $vg/pool_performance chunk_size 1.00m
+check lv_field $vg/pool_performance zero ""
+check lv_field $vg/pool_performance lv_when_full "error"
+
+vgremove -ff $vg
+
+if test -d "$DM_DEV_DIR/$vg" ; then
+ should not echo "Udev has left \"$DM_DEV_DIR/$vg\"!"
+ rm -rf "${DM_DEV_DIR:?/dev}/$vg"
+fi
+
+# The profile must be also applied if using the profile
+# for the whole VG - any LVs inherit this profile then.
+vgcreate $SHARED --profile thin-performance $vg "$dev1"
+lvcreate -L8m -T $vg/pool_performance_inherited
+# ...the LV does not have the profile attached, but VG does!
+check vg_field $vg profile "thin-performance"
+check lv_field $vg/pool_performance_inherited profile ""
+$SHOULD check lv_field $vg/pool_performance_inherited chunk_size 1.00m
+check lv_field $vg/pool_performance_inherited zero ""
+
+vgremove -ff $vg
diff --git a/test/shell/profiles-vdo.sh b/test/shell/profiles-vdo.sh
new file mode 100644
index 0000000..7b3c343
--- /dev/null
+++ b/test/shell/profiles-vdo.sh
@@ -0,0 +1,54 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2018-2021 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+# Exercise obtaining vdo parameters from various sources
+# Either commmand line or metadata profile or implicit default...
+
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+aux have_vdo 6 2 0 || skip
+
+PDIR="$LVM_SYSTEM_DIR/profile"
+PFILE="vdo-test"
+
+aux prepare_profiles
+
+cat <<EOF > "$PDIR/${PFILE}.profile"
+allocation {
+ vdo_use_compression = 0
+ vdo_use_deduplication = 0
+ vdo_slab_size_mb = 128
+}
+EOF
+
+aux prepare_vg 2 1000000
+
+# Check chunk_size is grabbed from configuration
+lvcreate --vdo -L5G --config 'allocation/vdo_use_compression=0' $vg/vdopool
+lvdisplay -m $vg/vdopool | tee out
+grep "Compression.*no" out
+lvremove -f $vg
+
+# Without profile using 128MB slab it would NOT even pass
+lvcreate --vdo -L4G --metadataprofile "$PFILE" $vg/vdopool
+lvdisplay -m $vg/vdopool | tee out
+grep "Compression.*no" out
+lvremove -f $vg
+
+lvcreate -L4G --name vdopool $vg
+lvconvert --yes --type vdo-pool --metadataprofile "$PFILE" $vg/vdopool
+check lv_field $vg/vdopool vdo_compression ""
+
+vgremove -ff $vg
diff --git a/test/shell/profiles.sh b/test/shell/profiles.sh
new file mode 100644
index 0000000..be720c8
--- /dev/null
+++ b/test/shell/profiles.sh
@@ -0,0 +1,134 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2013 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+#
+# test basic profile functionality
+#
+
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+MSG_FAILED_TO_APPLY_CMD_PROFILE="Failed to apply command profile"
+MSG_IGNORING_INVALID_CMD_PROFILE="Ignoring invalid command profile"
+MSG_FAILED_TO_APPLY_MDA_PROFILE="Failed to apply metadata profile"
+MSG_IGNORING_INVALID_MDA_PROFILE="Ignoring invalid metadata profile"
+MSG_NOT_PROFILABLE="not customizable by a profile"
+MSG_CMD_PROFILABLE_ONLY="customizable by command profile only, not metadata profile"
+MSG_MDA_PROFILABLE_ONLY="customizable by metadata profile only, not command profile"
+
+# fail if the profile requested by --profile cmdline option is not present
+not pvs --profile nonexistent 2>&1 | grep "$MSG_FAILED_TO_APPLY_CMD_PROFILE"
+
+# config/checks=1: warning message about setting not being profilable +
+# summary error message about invalid profile
+# config/checks=0: just summary error message about invalid profile
+aux profileconf invalid 'log/prefix=" "'
+
+aux lvmconf 'config/checks = 0'
+not pvs --profile invalid 2>msg
+not grep "$MSG_NOT_PROFILABLE" msg
+grep "$MSG_IGNORING_INVALID_CMD_PROFILE" msg
+grep "$MSG_FAILED_TO_APPLY_CMD_PROFILE" msg
+
+aux lvmconf 'config/checks = 1'
+not pvs --profile invalid 2>msg
+grep "$MSG_NOT_PROFILABLE" msg
+grep "$MSG_IGNORING_INVALID_CMD_PROFILE" msg
+grep "$MSG_FAILED_TO_APPLY_CMD_PROFILE" msg
+
+aux lvmconf 'allocation/thin_pool_zero = 1'
+
+# all profilable items listed here - should pass
+aux profileconf valid_cmd_profile 'global/units = "h"' \
+ 'global/si_unit_consistency = 1' \
+ 'global/suffix = 1' \
+ 'global/lvdisplay_shows_full_device_path = 0' \
+ 'report/aligned = 1' \
+ 'report/buffered = 1' \
+ 'report/headings = 1' \
+ 'report/separator = " "' \
+ 'report/prefixes = 0' \
+ 'report/quoted = 1' \
+ 'report/columns_as_rows = 0' \
+ 'report/devtypes_sort = "devtype_name"' \
+ 'report/devtypes_cols = "devtype_name,devtype_max_partitions,devtype_description"' \
+ 'report/devtypes_cols_verbose = "devtype_name,devtype_max_partitions,devtype_description"' \
+ 'report/lvs_sort = "vg_name,lv_name"' \
+ 'report/lvs_cols = "lv_name,vg_name,lv_attr,lv_size,pool_lv,origin,data_percent,move_pv,mirror_log,copy_percent,convert_lv"' \
+ 'report/lvs_cols_verbose = "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,lv_profile"' \
+ 'report/vgs_sort = "vg_name"' \
+ 'report/vgs_cols = "vg_name,pv_count,lv_count,snap_count,vg_attr,vg_size,vg_free"' \
+ 'report/vgs_cols_verbose = "vg_name,vg_attr,vg_extent_size,pv_count,lv_count,snap_count,vg_size,vg_free,vg_uuid,vg_profile"' \
+ 'report/pvs_sort = "pv_name"' \
+ 'report/pvs_cols = "pv_name,vg_name,pv_fmt,pv_attr,pv_size,pv_free"' \
+ 'report/pvs_cols_verbose = "pv_name,vg_name,pv_fmt,pv_attr,pv_size,pv_free,dev_size,pv_uuid"' \
+ 'report/segs_sort = "vg_name,lv_name,seg_start"' \
+ 'report/segs_cols = "lv_name,vg_name,lv_attr,stripes,segtype,seg_size"' \
+ 'report/segs_cols_verbose = "lv_name,vg_name,lv_attr,seg_start,seg_size,stripes,segtype,stripesize,chunksize"' \
+ 'report/pvsegs_sort = "pv_name,pvseg_start"' \
+ 'report/pvsegs_cols = "pv_name,vg_name,pv_fmt,pv_attr,pv_size,pv_free,pvseg_start,pvseg_size"' \
+ 'report/pvsegs_cols_verbose = "pv_name,vg_name,pv_fmt,pv_attr,pv_size,pv_free,pvseg_start,pvseg_size,lv_name,seg_start_pe,segtype,seg_pe_ranges"'
+
+aux profileconf valid_mda_profile 'allocation/thin_pool_zero = 0' \
+ 'allocation/thin_pool_discards = "passdown"' \
+ 'allocation/thin_pool_chunk_size = 64' \
+ 'activation/thin_pool_autoextend_threshold = 100' \
+ 'activation/thin_pool_autoextend_percent = 20'
+
+aux profileconf extra_mda_profile 'allocation/thin_pool_chunk_size = 128'
+
+pvs --profile valid_cmd_profile 2>msg
+not grep "$MSG_NOT_PROFILABLE" msg
+not grep "$MSG_IGNORING_INVALID_CMD_PROFILE" msg
+not grep "$MSG_IGNORING_INVALID_MDA_PROFILE" msg
+
+not pvs --profile valid_mda_profile 2>msg
+grep "$MSG_MDA_PROFILABLE_ONLY" msg
+grep "$MSG_IGNORING_INVALID_CMD_PROFILE" msg
+not grep "$MSG_IGNORING_INVALID_MDA_PROFILE" msg
+
+# attaching/detaching profiles to VG/LV
+aux prepare_pvs 1 8
+pvcreate "$dev1"
+vgcreate $SHARED $vg1 "$dev1"
+check vg_field $vg1 vg_profile ""
+lvcreate -l 1 -n $lv1 $vg1
+check lv_field $vg1/$lv1 lv_profile ""
+vgchange --profile valid_mda_profile $vg1
+check vg_field $vg1 vg_profile valid_mda_profile
+check lv_field $vg1/$lv1 lv_profile ""
+lvchange --profile extra_mda_profile $vg1/$lv1
+check vg_field $vg1 vg_profile valid_mda_profile
+check lv_field $vg1/$lv1 lv_profile extra_mda_profile
+vgchange --detachprofile $vg1
+check vg_field $vg1 vg_profile ""
+check lv_field $vg1/$lv1 lv_profile extra_mda_profile
+lvchange --detachprofile $vg1/$lv1
+check vg_field $vg1 vg_profile ""
+check lv_field $vg1/$lv1 lv_profile ""
+
+# dumpconfig and merged lvm.conf + profile
+aux lvmconf 'global/units="m"'
+aux profileconf extra_cmd_profile 'global/units="h"'
+lvm dumpconfig &>out
+grep 'units="m"' out
+lvm dumpconfig --profile extra_cmd_profile --mergedconfig >out
+grep 'units="h"' out
+
+# dumpconfig --profilable output must be usable as a profile
+lvm dumpconfig --type profilable-command --file etc/profile/generated.profile
+pvs --profile generated &> msg
+not grep "$MSG_NOT_PROFILABLE" msg
+not grep "$MSG_IGNORING_INVALID_CMD_PROFILE" msg
+
+vgremove -ff $vg1
diff --git a/test/shell/pv-check-dev-size.sh b/test/shell/pv-check-dev-size.sh
new file mode 100644
index 0000000..f9d31a1
--- /dev/null
+++ b/test/shell/pv-check-dev-size.sh
@@ -0,0 +1,46 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2016 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+aux prepare_pvs 1 8
+
+aux lvmconf 'metadata/check_pv_device_sizes = 1'
+
+CHECK_MSG="smaller than corresponding PV size"
+
+vgcreate $SHARED "$vg" "$dev1" 2>err
+not grep "$CHECK_MSG" err
+pvs 2>err
+not grep "$CHECK_MSG" err
+vgremove -ff $vg
+
+# set PV size to 2x dev size
+pvcreate --yes --setphysicalvolumesize 16m "$dev1"
+vgcreate $SHARED "$vg" "$dev1" 2>err
+grep "$CHECK_MSG" err
+pvs 2>err
+grep "$CHECK_MSG" err
+vgremove -ff $vg
+
+# should be quiet if requested
+aux lvmconf 'metadata/check_pv_device_sizes = 0'
+pvcreate --yes --setphysicalvolumesize 16m "$dev1"
+vgcreate $SHARED "$vg" "$dev1" 2>err
+not grep "$CHECK_MSG" err
+pvs 2>err
+not grep "$CHECK_MSG" err
+
+vgremove -ff $vg
diff --git a/test/shell/pv-corruption.sh b/test/shell/pv-corruption.sh
new file mode 100644
index 0000000..b3c5059
--- /dev/null
+++ b/test/shell/pv-corruption.sh
@@ -0,0 +1,56 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2020 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+# tests, write failer on PV1 is not reporting errors on PV2 or PV3...
+
+SKIP_WITH_LVMLOCKD=1
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+# skip test early if there is no 'delay' target available
+aux target_at_least dm-delay 1 1 0 || skip "missing dm-delay target"
+touch HAVE_DM_DELAY
+
+#
+# Main
+#
+aux prepare_devs 3 20
+
+pvcreate -y --setphysicalvolumesize 10m "$dev1"
+pvcreate "$dev2"
+pvcreate "$dev3"
+
+vgcreate $vg "$dev1" "$dev2" "$dev3"
+
+pvs -o +uuid
+
+# Keep device readable, but any write fails
+aux writeerror_dev "$dev1" 0:100
+
+# Suppose to fail, size PV1 is not writable
+not pvresize "$dev1" 2>&1 | tee out
+
+# Output should not complain about any error on pv2 nor pv3
+not grep pv2 out
+not grep pv3 out
+
+# Restore working PV1 back
+aux enable_dev "$dev1"
+
+# FIXME: Takes a lot of time ATM....
+pvck "$dev2"
+
+pvs -o +uuid
+vgdisplay
+
+vgremove $vg
diff --git a/test/shell/pv-duplicate-uuid.sh b/test/shell/pv-duplicate-uuid.sh
new file mode 100644
index 0000000..ac2b866
--- /dev/null
+++ b/test/shell/pv-duplicate-uuid.sh
@@ -0,0 +1,49 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2014 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+# Test 'Found duplicate' is shown
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+aux prepare_devs 3
+
+pvcreate "$dev1"
+UUID1=$(get pv_field "$dev1" uuid)
+pvcreate --devices "$dev2" -u "$UUID1" --norestorefile "$dev2"
+pvcreate --devices "$dev3" -u "$UUID1" --norestorefile "$dev3"
+
+pvscan --cache 2>&1 | tee out
+
+pvs -o+uuid 2>&1 | tee out
+
+grep WARNING out > warn || true
+grep -v WARNING out > main || true
+
+test "$(grep -c $UUID1 main)" -eq 1
+
+COUNT=$(grep --count "Not using device" warn)
+[ "$COUNT" -eq 2 ]
+
+pvs -o+uuid --devices $dev2 2>&1 | tee out
+
+rm warn main || true
+grep WARNING out > warn || true
+grep -v WARNING out > main || true
+
+not grep "$dev1" main
+grep "$dev2" main
+not grep "$dev3" main
+
+not grep "Not using device" warn
+
diff --git a/test/shell/pv-duplicate.sh b/test/shell/pv-duplicate.sh
deleted file mode 100644
index 6a22cd1..0000000
--- a/test/shell/pv-duplicate.sh
+++ /dev/null
@@ -1,25 +0,0 @@
-#!/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-ext-flags.sh b/test/shell/pv-ext-flags.sh
new file mode 100644
index 0000000..ae4d6b7
--- /dev/null
+++ b/test/shell/pv-ext-flags.sh
@@ -0,0 +1,157 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2016 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+SKIP_WITH_LVMLOCKD=1
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+aux prepare_devs 2
+
+# PV_EXT_USED flag
+MARKED_AS_USED_MSG="is used by a VG but its metadata is missing"
+
+######################################
+### CHECK PV WITH 0 METADATA AREAS ###
+######################################
+
+pvcreate -ff -y --metadatacopies 0 "$dev1"
+pvcreate -ff -y --metadatacopies 1 "$dev2"
+
+# $dev1 and $dev2 not in any VG - pv_in_use field should be blank
+check pv_field "$dev1" pv_in_use ""
+check pv_field "$dev2" pv_in_use ""
+
+# $dev1 and $dev now in a VG - pv_in_use should display "used"
+vgcreate $vg1 "$dev1" "$dev2"
+check pv_field "$dev1" pv_in_use "used"
+check pv_field "$dev2" pv_in_use "used"
+
+# disable $dev2 and dev1 with 0 MDAs remains, but still
+# marked as used, so pvcreate/vgcreate/pvremove should fail
+aux disable_dev "$dev2"
+
+check pv_field "$dev1" pv_in_use "used"
+not pvcreate "$dev1" 2>err
+cat err
+grep "$MARKED_AS_USED_MSG" err
+not pvchange -u "$dev1" 2>err
+grep "$MARKED_AS_USED_MSG" err
+not vgcreate $vg2 "$dev1" 2>err
+grep "$MARKED_AS_USED_MSG" err
+not pvremove "$dev1" 2>err
+grep "$MARKED_AS_USED_MSG" err
+
+# save PV signature from dev1 for reuse later on in this
+# test so we don't need to initialize all the VG stuff again
+dd if="$dev1" of=dev1_backup bs=1M
+
+# pvcreate and pvremove can be forced even if the PV is marked as used
+pvremove -ff -y "$dev1"
+lvmdevices --deldev "$dev1" || true
+dd if=dev1_backup of="$dev1" bs=1M
+pvcreate -ff -y "$dev1"
+dd if=dev1_backup of="$dev1" bs=1M
+lvmdevices --adddev "$dev1" || true
+
+# prepare a VG with $dev1 and $dev both having 1 MDA
+aux enable_dev "$dev2"
+vgremove -ff $vg1
+pvremove -ff -y "$dev1"
+pvcreate --metadatacopies 1 "$dev1"
+vgcreate $vg1 "$dev1" "$dev2"
+
+# disable $dev1, then repair the VG - $dev1 is removed from VG
+aux disable_dev "$dev1"
+vgreduce --removemissing $vg1
+
+# now, enable $dev1 and clear the old metadata from it
+aux enable_dev "$dev1"
+vgck --updatemetadata $vg1
+
+vgck $vg1
+
+# check $dev1 does not contain the PV_EXT_FLAG anymore
+check pv_field "$dev1" pv_in_use ""
+
+#############################################
+### CHECK PV WITH DISABLED METADATA AREAS ###
+#############################################
+
+pvcreate -ff -y --metadatacopies 1 "$dev1"
+pvcreate -ff -y --metadatacopies 1 "$dev2"
+
+# $dev1 and $dev2 not in any VG - pv_in_use field should be blank
+check pv_field "$dev1" pv_in_use ""
+check pv_field "$dev2" pv_in_use ""
+
+# $dev1 and $dev now in a VG - pv_in_use should display "used"
+vgcreate $vg1 "$dev1" "$dev2"
+check pv_field "$dev1" pv_in_use "used"
+check pv_field "$dev2" pv_in_use "used"
+
+pvchange --metadataignore y "$dev1"
+aux disable_dev "$dev2"
+
+check pv_field "$dev1" pv_in_use "used"
+not pvcreate "$dev1" 2>err
+grep "$MARKED_AS_USED_MSG" err
+not pvchange -u "$dev1" 2>err
+grep "$MARKED_AS_USED_MSG" err
+not vgcreate $vg2 "$dev1" 2>err
+grep "$MARKED_AS_USED_MSG" err
+not pvremove "$dev1" 2>err
+grep "$MARKED_AS_USED_MSG" err
+
+# save PV signature from dev1 for reuse later on in this
+# test so we don't need to initialize all the VG stuff again
+dd if="$dev1" of=dev1_backup bs=1M
+
+# pvcreate and pvremove can be forced even if the PV is marked as used
+pvremove -ff -y "$dev1"
+lvmdevices --deldev "$dev1" || true
+dd if=dev1_backup of="$dev1" bs=1M
+pvcreate -ff -y "$dev1"
+dd if=dev1_backup of="$dev1" bs=1M
+lvmdevices --adddev "$dev1" || true
+
+# prepare a VG with $dev1 and $dev both having 1 MDA
+aux enable_dev "$dev2"
+vgremove -ff $vg1
+pvremove -ff -y "$dev1"
+pvcreate --metadatacopies 1 "$dev1"
+vgcreate $vg1 "$dev1" "$dev2"
+
+# disable $dev1, then repair the VG - $dev1 is removed from VG
+aux disable_dev "$dev1"
+vgreduce --removemissing $vg1
+
+# now, enable $dev1 and clear the old metadata from it
+aux enable_dev "$dev1"
+vgck --updatemetadata $vg1
+
+vgck $vg1
+
+# check $dev1 does not contain the PV_EXT_FLAG anymore
+check pv_field "$dev1" pv_in_use ""
+
+###########################
+# OTHER PV-RELATED CHECKS #
+###########################
+
+# vgcfgrestore should also set PV_EXT_FLAG on PVs where VG is restored
+vgcfgbackup -f vg_backup $vg1
+check pv_field "$dev2" pv_in_use "used"
+vgremove -ff $vg1
+check pv_field "$dev2" pv_in_use ""
+vgcfgrestore -f vg_backup $vg1
+check pv_field "$dev2" pv_in_use "used"
diff --git a/test/shell/pv-ext-update.sh b/test/shell/pv-ext-update.sh
new file mode 100644
index 0000000..bd66c02
--- /dev/null
+++ b/test/shell/pv-ext-update.sh
@@ -0,0 +1,185 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2016 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+SKIP_WITH_LVMPOLLD=1
+
+
+. lib/inittest
+
+env printf "" || skip # skip if printf is not available
+
+# create the PV with PV ext vsn 1 and a vg
+create_pv_with_ext_vsn1_and_vg()
+{
+ VG_NAME="LVMTEST12345pvextupdatevg"
+ LV_NAME="lvol0"
+
+ # 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
+
+ # PV header with PV extension version 1
+ env printf \
+"\x4c\x41\x42\x45\x4c\x4f\x4e\x45\x01\x00\x00\x00\x00\x00\x00\x00"\
+"\x78\x1c\x12\x43\x20\x00\x00\x00\x4c\x56\x4d\x32\x20\x30\x30\x31"\
+"\x64\x35\x56\x33\x38\x5a\x57\x49\x63\x7a\x64\x63\x34\x38\x37\x67"\
+"\x4d\x79\x46\x4b\x6c\x6d\x68\x39\x4e\x73\x34\x6f\x78\x61\x6b\x51"\
+"\x00\x00\x80\x00\x00\x00\x00\x00\x00\x00\x10\x00\x00\x00\x00\x00"\
+"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"\
+"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x10\x00\x00\x00\x00\x00\x00"\
+"\x00\xf0\x0f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"\
+"\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00"\
+"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" | dd of="$1" bs=512 seek=1 conv=notrunc
+
+ # MDA header
+ env printf \
+"\xd8\x36\x2c\xf6\x20\x4c\x56\x4d\x32\x20\x78\x5b\x35\x41\x25\x72"\
+"\x30\x4e\x2a\x3e\x01\x00\x00\x00\x00\x10\x00\x00\x00\x00\x00\x00"\
+"\x00\xf0\x0f\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00\x00\x00\x00"\
+"\x06\x04\x00\x00\x00\x00\x00\x00\x07\x3d\x06\x28\x00\x00\x00\x00"\
+"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" | dd of="$1" bs=4096 seek=1 conv=notrunc
+
+ # VG metadata
+ env printf \
+"\x4c\x56\x4d\x54\x45\x53\x54\x31\x32\x33\x34\x35\x70\x76\x65\x78"\
+"\x74\x75\x70\x64\x61\x74\x65\x76\x67\x20\x7b\x0a\x69\x64\x20\x3d"\
+"\x20\x22\x42\x72\x47\x6f\x34\x33\x2d\x36\x35\x62\x48\x2d\x41\x55"\
+"\x6d\x43\x2d\x77\x56\x74\x71\x2d\x51\x53\x63\x66\x2d\x6b\x5a\x51"\
+"\x45\x2d\x58\x51\x6e\x79\x31\x44\x22\x0a\x73\x65\x71\x6e\x6f\x20"\
+"\x3d\x20\x31\x0a\x66\x6f\x72\x6d\x61\x74\x20\x3d\x20\x22\x6c\x76"\
+"\x6d\x32\x22\x0a\x73\x74\x61\x74\x75\x73\x20\x3d\x20\x5b\x22\x52"\
+"\x45\x53\x49\x5a\x45\x41\x42\x4c\x45\x22\x2c\x20\x22\x52\x45\x41"\
+"\x44\x22\x2c\x20\x22\x57\x52\x49\x54\x45\x22\x5d\x0a\x66\x6c\x61"\
+"\x67\x73\x20\x3d\x20\x5b\x5d\x0a\x65\x78\x74\x65\x6e\x74\x5f\x73"\
+"\x69\x7a\x65\x20\x3d\x20\x38\x31\x39\x32\x0a\x6d\x61\x78\x5f\x6c"\
+"\x76\x20\x3d\x20\x30\x0a\x6d\x61\x78\x5f\x70\x76\x20\x3d\x20\x30"\
+"\x0a\x6d\x65\x74\x61\x64\x61\x74\x61\x5f\x63\x6f\x70\x69\x65\x73"\
+"\x20\x3d\x20\x30\x0a\x0a\x70\x68\x79\x73\x69\x63\x61\x6c\x5f\x76"\
+"\x6f\x6c\x75\x6d\x65\x73\x20\x7b\x0a\x0a\x70\x76\x30\x20\x7b\x0a"\
+"\x69\x64\x20\x3d\x20\x22\x64\x35\x56\x33\x38\x5a\x2d\x57\x49\x63"\
+"\x7a\x2d\x64\x63\x34\x38\x2d\x37\x67\x4d\x79\x2d\x46\x4b\x6c\x6d"\
+"\x2d\x68\x39\x4e\x73\x2d\x34\x6f\x78\x61\x6b\x51\x22\x0a\x64\x65"\
+"\x76\x69\x63\x65\x20\x3d\x20\x22\x2f\x64\x65\x76\x2f\x6c\x6f\x6f"\
+"\x70\x30\x22\x0a\x0a\x73\x74\x61\x74\x75\x73\x20\x3d\x20\x5b\x22"\
+"\x41\x4c\x4c\x4f\x43\x41\x54\x41\x42\x4c\x45\x22\x5d\x0a\x66\x6c"\
+"\x61\x67\x73\x20\x3d\x20\x5b\x5d\x0a\x64\x65\x76\x5f\x73\x69\x7a"\
+"\x65\x20\x3d\x20\x31\x36\x33\x38\x34\x0a\x70\x65\x5f\x73\x74\x61"\
+"\x72\x74\x20\x3d\x20\x32\x30\x34\x38\x0a\x70\x65\x5f\x63\x6f\x75"\
+"\x6e\x74\x20\x3d\x20\x31\x0a\x7d\x0a\x7d\x0a\x0a\x7d\x0a\x23\x20"\
+"\x47\x65\x6e\x65\x72\x61\x74\x65\x64\x20\x62\x79\x20\x4c\x56\x4d"\
+"\x32\x20\x76\x65\x72\x73\x69\x6f\x6e\x20\x32\x2e\x30\x32\x2e\x31"\
+"\x34\x32\x28\x32\x29\x2d\x67\x69\x74\x20\x28\x32\x30\x31\x36\x2d"\
+"\x30\x32\x2d\x31\x35\x29\x3a\x20\x57\x65\x64\x20\x4a\x75\x6c\x20"\
+"\x32\x37\x20\x31\x31\x3a\x32\x35\x3a\x30\x37\x20\x32\x30\x31\x36"\
+"\x0a\x0a\x63\x6f\x6e\x74\x65\x6e\x74\x73\x20\x3d\x20\x22\x54\x65"\
+"\x78\x74\x20\x46\x6f\x72\x6d\x61\x74\x20\x56\x6f\x6c\x75\x6d\x65"\
+"\x20\x47\x72\x6f\x75\x70\x22\x0a\x76\x65\x72\x73\x69\x6f\x6e\x20"\
+"\x3d\x20\x31\x0a\x0a\x64\x65\x73\x63\x72\x69\x70\x74\x69\x6f\x6e"\
+"\x20\x3d\x20\x22\x22\x0a\x0a\x63\x72\x65\x61\x74\x69\x6f\x6e\x5f"\
+"\x68\x6f\x73\x74\x20\x3d\x20\x22\x66\x65\x64\x6f\x72\x61\x2e\x76"\
+"\x69\x72\x74\x22\x09\x23\x20\x4c\x69\x6e\x75\x78\x20\x66\x65\x64"\
+"\x6f\x72\x61\x2e\x76\x69\x72\x74\x20\x34\x2e\x36\x2e\x34\x2d\x33"\
+"\x30\x31\x2e\x66\x63\x32\x34\x2e\x78\x38\x36\x5f\x36\x34\x20\x23"\
+"\x31\x20\x53\x4d\x50\x20\x54\x75\x65\x20\x4a\x75\x6c\x20\x31\x32"\
+"\x20\x31\x31\x3a\x35\x30\x3a\x30\x30\x20\x55\x54\x43\x20\x32\x30"\
+"\x31\x36\x20\x78\x38\x36\x5f\x36\x34\x0a\x63\x72\x65\x61\x74\x69"\
+"\x6f\x6e\x5f\x74\x69\x6d\x65\x20\x3d\x20\x31\x34\x36\x39\x36\x31"\
+"\x31\x35\x30\x37\x09\x23\x20\x57\x65\x64\x20\x4a\x75\x6c\x20\x32"\
+"\x37\x20\x31\x31\x3a\x32\x35\x3a\x30\x37\x20\x32\x30\x31\x36\x0a"\
+"\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"\
+"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" | dd of="$1" bs=4608 seek=1 conv=notrunc
+
+ env printf \
+"\x4c\x56\x4d\x54\x45\x53\x54\x31\x32\x33\x34\x35\x70\x76\x65\x78"\
+"\x74\x75\x70\x64\x61\x74\x65\x76\x67\x20\x7b\x0a\x69\x64\x20\x3d"\
+"\x20\x22\x42\x72\x47\x6f\x34\x33\x2d\x36\x35\x62\x48\x2d\x41\x55"\
+"\x6d\x43\x2d\x77\x56\x74\x71\x2d\x51\x53\x63\x66\x2d\x6b\x5a\x51"\
+"\x45\x2d\x58\x51\x6e\x79\x31\x44\x22\x0a\x73\x65\x71\x6e\x6f\x20"\
+"\x3d\x20\x32\x0a\x66\x6f\x72\x6d\x61\x74\x20\x3d\x20\x22\x6c\x76"\
+"\x6d\x32\x22\x0a\x73\x74\x61\x74\x75\x73\x20\x3d\x20\x5b\x22\x52"\
+"\x45\x53\x49\x5a\x45\x41\x42\x4c\x45\x22\x2c\x20\x22\x52\x45\x41"\
+"\x44\x22\x2c\x20\x22\x57\x52\x49\x54\x45\x22\x5d\x0a\x66\x6c\x61"\
+"\x67\x73\x20\x3d\x20\x5b\x5d\x0a\x65\x78\x74\x65\x6e\x74\x5f\x73"\
+"\x69\x7a\x65\x20\x3d\x20\x38\x31\x39\x32\x0a\x6d\x61\x78\x5f\x6c"\
+"\x76\x20\x3d\x20\x30\x0a\x6d\x61\x78\x5f\x70\x76\x20\x3d\x20\x30"\
+"\x0a\x6d\x65\x74\x61\x64\x61\x74\x61\x5f\x63\x6f\x70\x69\x65\x73"\
+"\x20\x3d\x20\x30\x0a\x0a\x70\x68\x79\x73\x69\x63\x61\x6c\x5f\x76"\
+"\x6f\x6c\x75\x6d\x65\x73\x20\x7b\x0a\x0a\x70\x76\x30\x20\x7b\x0a"\
+"\x69\x64\x20\x3d\x20\x22\x64\x35\x56\x33\x38\x5a\x2d\x57\x49\x63"\
+"\x7a\x2d\x64\x63\x34\x38\x2d\x37\x67\x4d\x79\x2d\x46\x4b\x6c\x6d"\
+"\x2d\x68\x39\x4e\x73\x2d\x34\x6f\x78\x61\x6b\x51\x22\x0a\x64\x65"\
+"\x76\x69\x63\x65\x20\x3d\x20\x22\x2f\x64\x65\x76\x2f\x6c\x6f\x6f"\
+"\x70\x30\x22\x0a\x0a\x73\x74\x61\x74\x75\x73\x20\x3d\x20\x5b\x22"\
+"\x41\x4c\x4c\x4f\x43\x41\x54\x41\x42\x4c\x45\x22\x5d\x0a\x66\x6c"\
+"\x61\x67\x73\x20\x3d\x20\x5b\x5d\x0a\x64\x65\x76\x5f\x73\x69\x7a"\
+"\x65\x20\x3d\x20\x31\x36\x33\x38\x34\x0a\x70\x65\x5f\x73\x74\x61"\
+"\x72\x74\x20\x3d\x20\x32\x30\x34\x38\x0a\x70\x65\x5f\x63\x6f\x75"\
+"\x6e\x74\x20\x3d\x20\x31\x0a\x7d\x0a\x7d\x0a\x0a\x6c\x6f\x67\x69"\
+"\x63\x61\x6c\x5f\x76\x6f\x6c\x75\x6d\x65\x73\x20\x7b\x0a\x0a\x6c"\
+"\x76\x6f\x6c\x30\x20\x7b\x0a\x69\x64\x20\x3d\x20\x22\x46\x73\x36"\
+"\x6c\x6a\x6b\x2d\x4a\x65\x5a\x35\x2d\x55\x4e\x75\x37\x2d\x32\x41"\
+"\x33\x50\x2d\x76\x30\x41\x43\x2d\x64\x63\x64\x36\x2d\x32\x33\x38"\
+"\x39\x4d\x76\x22\x0a\x73\x74\x61\x74\x75\x73\x20\x3d\x20\x5b\x22"\
+"\x52\x45\x41\x44\x22\x2c\x20\x22\x57\x52\x49\x54\x45\x22\x2c\x20"\
+"\x22\x56\x49\x53\x49\x42\x4c\x45\x22\x5d\x0a\x66\x6c\x61\x67\x73"\
+"\x20\x3d\x20\x5b\x5d\x0a\x63\x72\x65\x61\x74\x69\x6f\x6e\x5f\x68"\
+"\x6f\x73\x74\x20\x3d\x20\x22\x66\x65\x64\x6f\x72\x61\x2e\x76\x69"\
+"\x72\x74\x22\x0a\x63\x72\x65\x61\x74\x69\x6f\x6e\x5f\x74\x69\x6d"\
+"\x65\x20\x3d\x20\x31\x34\x36\x39\x36\x31\x31\x35\x31\x30\x0a\x73"\
+"\x65\x67\x6d\x65\x6e\x74\x5f\x63\x6f\x75\x6e\x74\x20\x3d\x20\x31"\
+"\x0a\x0a\x73\x65\x67\x6d\x65\x6e\x74\x31\x20\x7b\x0a\x73\x74\x61"\
+"\x72\x74\x5f\x65\x78\x74\x65\x6e\x74\x20\x3d\x20\x30\x0a\x65\x78"\
+"\x74\x65\x6e\x74\x5f\x63\x6f\x75\x6e\x74\x20\x3d\x20\x31\x0a\x0a"\
+"\x74\x79\x70\x65\x20\x3d\x20\x22\x73\x74\x72\x69\x70\x65\x64\x22"\
+"\x0a\x73\x74\x72\x69\x70\x65\x5f\x63\x6f\x75\x6e\x74\x20\x3d\x20"\
+"\x31\x0a\x0a\x73\x74\x72\x69\x70\x65\x73\x20\x3d\x20\x5b\x0a\x22"\
+"\x70\x76\x30\x22\x2c\x20\x30\x0a\x5d\x0a\x7d\x0a\x7d\x0a\x7d\x0a"\
+"\x7d\x0a\x23\x20\x47\x65\x6e\x65\x72\x61\x74\x65\x64\x20\x62\x79"\
+"\x20\x4c\x56\x4d\x32\x20\x76\x65\x72\x73\x69\x6f\x6e\x20\x32\x2e"\
+"\x30\x32\x2e\x31\x34\x32\x28\x32\x29\x2d\x67\x69\x74\x20\x28\x32"\
+"\x30\x31\x36\x2d\x30\x32\x2d\x31\x35\x29\x3a\x20\x57\x65\x64\x20"\
+"\x4a\x75\x6c\x20\x32\x37\x20\x31\x31\x3a\x32\x35\x3a\x31\x30\x20"\
+"\x32\x30\x31\x36\x0a\x0a\x63\x6f\x6e\x74\x65\x6e\x74\x73\x20\x3d"\
+"\x20\x22\x54\x65\x78\x74\x20\x46\x6f\x72\x6d\x61\x74\x20\x56\x6f"\
+"\x6c\x75\x6d\x65\x20\x47\x72\x6f\x75\x70\x22\x0a\x76\x65\x72\x73"\
+"\x69\x6f\x6e\x20\x3d\x20\x31\x0a\x0a\x64\x65\x73\x63\x72\x69\x70"\
+"\x74\x69\x6f\x6e\x20\x3d\x20\x22\x22\x0a\x0a\x63\x72\x65\x61\x74"\
+"\x69\x6f\x6e\x5f\x68\x6f\x73\x74\x20\x3d\x20\x22\x66\x65\x64\x6f"\
+"\x72\x61\x2e\x76\x69\x72\x74\x22\x09\x23\x20\x4c\x69\x6e\x75\x78"\
+"\x20\x66\x65\x64\x6f\x72\x61\x2e\x76\x69\x72\x74\x20\x34\x2e\x36"\
+"\x2e\x34\x2d\x33\x30\x31\x2e\x66\x63\x32\x34\x2e\x78\x38\x36\x5f"\
+"\x36\x34\x20\x23\x31\x20\x53\x4d\x50\x20\x54\x75\x65\x20\x4a\x75"\
+"\x6c\x20\x31\x32\x20\x31\x31\x3a\x35\x30\x3a\x30\x30\x20\x55\x54"\
+"\x43\x20\x32\x30\x31\x36\x20\x78\x38\x36\x5f\x36\x34\x0a\x63\x72"\
+"\x65\x61\x74\x69\x6f\x6e\x5f\x74\x69\x6d\x65\x20\x3d\x20\x31\x34"\
+"\x36\x39\x36\x31\x31\x35\x31\x30\x09\x23\x20\x57\x65\x64\x20\x4a"\
+"\x75\x6c\x20\x32\x37\x20\x31\x31\x3a\x32\x35\x3a\x31\x30\x20\x32"\
+"\x30\x31\x36\x0a\x0a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"\
+"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" | dd of="$1" bs=5632 seek=1 conv=notrunc
+}
+
+aux prepare_devs 1 8
+
+create_pv_with_ext_vsn1_and_vg "$dev1"
+
+# pvs doesn't update PV header because it holds only VG read lock
+check pv_field "$dev1" pv_ext_vsn 1
+check pv_field "$dev1" pv_in_use "used"
+check pv_field "$dev1" vg_name "$VG_NAME"
+lvs "$VG_NAME"/"$LV_NAME"
+
+# an LVM command taking VG write lock will also cause PV header update to recent version
+vgchange --addtag test $VG_NAME
+check pv_field "$dev1" pv_ext_vsn 2
+check pv_field "$dev1" pv_in_use "used"
+check pv_field "$dev1" vg_name "$VG_NAME"
+lvs "$VG_NAME"/"$LV_NAME"
diff --git a/test/shell/pv-min-size.sh b/test/shell/pv-min-size.sh
index 59250cf..574dce7 100644
--- a/test/shell/pv-min-size.sh
+++ b/test/shell/pv-min-size.sh
@@ -1,4 +1,5 @@
-#!/bin/sh
+#!/usr/bin/env bash
+
# Copyright (C) 2011 Red Hat, Inc. All rights reserved.
#
# This copyrighted material is made available to anyone wishing to use,
@@ -7,9 +8,12 @@
#
# 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
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+
+SKIP_WITH_LVMPOLLD=1
-. lib/test
+. lib/inittest
# use small default size - 512KB
aux lvmconf 'devices/pv_min_size = 512'
diff --git a/test/shell/pv-range-overflow.sh b/test/shell/pv-range-overflow.sh
index 0f353dd..ab845a9 100644
--- a/test/shell/pv-range-overflow.sh
+++ b/test/shell/pv-range-overflow.sh
@@ -1,4 +1,5 @@
-#!/bin/sh
+#!/usr/bin/env bash
+
# Copyright (C) 2008-2011 Red Hat, Inc. All rights reserved.
#
# This copyrighted material is made available to anyone wishing to use,
@@ -7,15 +8,18 @@
#
# 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
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
# 'Ensure that pvmove diagnoses PE-range values 2^32 and larger.'
-. lib/test
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
aux prepare_vg 2
-lvcreate -L4 -n"$lv" $vg
+lvcreate -L4 -n $lv $vg
# Test for the bogus diagnostic reported in BZ 284771
# http://bugzilla.redhat.com/284771.
@@ -30,3 +34,4 @@ grep "Logical volume bogus not found." err
# 'run the offending pvmove command'
not pvmove -v -n$lv "$dev1":4294967296 "$dev2"
+vgremove -ff $vg
diff --git a/test/shell/pvchange-usage.sh b/test/shell/pvchange-usage.sh
index d5a2ebb..1f1348d 100644
--- a/test/shell/pvchange-usage.sh
+++ b/test/shell/pvchange-usage.sh
@@ -1,4 +1,5 @@
-#!/bin/sh
+#!/usr/bin/env bash
+
# Copyright (C) 2008 Red Hat, Inc. All rights reserved.
#
# This copyrighted material is made available to anyone wishing to use,
@@ -7,20 +8,40 @@
#
# 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
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
# 'Test pvchange option values'
-. lib/test
-aux prepare_devs 4
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+check_changed_uuid_() {
+ test "$1" != "$(get pv_field "$2" uuid)" || die "UUID has not changed!"
+}
+
+aux prepare_pvs 4
+
+# check 'allocatable' pv attribute
+pvcreate "$dev1"
+check pv_field "$dev1" pv_attr ---
+vgcreate $SHARED $vg1 "$dev1"
+check pv_field "$dev1" pv_attr a--
+pvchange --allocatable n "$dev1"
+check pv_field "$dev1" pv_attr u--
+vgremove -ff $vg1
+not pvchange --allocatable y "$dev1"
+pvremove -ff "$dev1"
for mda in 0 1 2
do
# "setup pv with metadatacopies = $mda"
- pvcreate "$dev4"
pvcreate --metadatacopies $mda "$dev1"
- vgcreate $vg1 "$dev1" "$dev4"
+# cannot change allocatability for orphan PVs
+ fail pvchange "$dev1" -x y
+ fail pvchange "$dev1" -x n
+ vgcreate $SHARED $vg1 "$dev4" "$dev1"
# "pvchange adds/dels tag to pvs with metadatacopies = $mda "
pvchange "$dev1" --addtag test$mda
@@ -30,36 +51,73 @@ do
# "vgchange disable/enable allocation for pvs with metadatacopies = $mda (bz452982)"
pvchange "$dev1" -x n
- check pv_field "$dev1" pv_attr ---
+ pvchange "$dev1" -x n # already disabled
+ check pv_field "$dev1" pv_attr u--
pvchange "$dev1" -x y
+ pvchange "$dev1" -x y # already enabled
check pv_field "$dev1" pv_attr a--
+# check we are able to change number of managed metadata areas
+ if test $mda -gt 0 ; then
+ pvchange --force --metadataignore y "$dev1"
+ else
+ # already ignored
+ fail pvchange --metadataignore y "$dev1"
+ fi
# 'remove pv'
vgremove $vg1
- pvremove "$dev1" "$dev4"
+ pvremove "$dev1"
done
# "pvchange uuid"
pvcreate --metadatacopies 0 "$dev1"
pvcreate --metadatacopies 2 "$dev2"
-vgcreate $vg1 "$dev1" "$dev2"
+vgcreate $SHARED $vg1 "$dev1" "$dev2"
+
+# Checking for different UUID after pvchange
+UUID1=$(get pv_field "$dev1" uuid)
pvchange -u "$dev1"
+check_changed_uuid_ "$UUID1" "$dev1"
+
+UUID2=$(get pv_field "$dev2" uuid)
pvchange -u "$dev2"
-check pvlv_counts $vg1 2 0 0
+check_changed_uuid_ "$UUID2" "$dev2"
+
+UUID1=$(get pv_field "$dev1" uuid)
+UUID2=$(get pv_field "$dev2" uuid)
pvchange -u --all
+check_changed_uuid_ "$UUID1" "$dev1"
+check_changed_uuid_ "$UUID2" "$dev2"
check pvlv_counts $vg1 2 0 0
-# "pvchange rejects uuid change under an active lv"
+# some args are needed
+invalid pvchange
+# some PV needed
+invalid pvchange --addtag tag
+invalid pvchange --deltag tag
+# some --all & PV can go together
+invalid pvchange -a "$dev1" --addtag tag
+# '-a' needs more params
+invalid pvchange -a
+# '-a' is searching for devs, so specifying device is invalid
+invalid pvchange -a "$dev1"
+fail pvchange -u "$dev1-notfound"
+
+# 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
+vgremove -f $vg1
+
+# cannot change PV tag to PV that is not in VG"
+fail pvchange "$dev1" --addtag test
+fail pvchange "$dev1" --deltag test
-# "pvchange reject --addtag to lvm1 pv"
+if test -n "$LVM_TEST_LVM1" ; then
+# cannot add PV tag to lvm1 format
pvcreate -M1 "$dev1"
-not pvchange "$dev1" --addtag test
+vgcreate $SHARED -M1 $vg1 "$dev1"
+fail pvchange "$dev1" --addtag test
+fi
+
diff --git a/test/shell/pvck-dump.sh b/test/shell/pvck-dump.sh
new file mode 100644
index 0000000..39632a4
--- /dev/null
+++ b/test/shell/pvck-dump.sh
@@ -0,0 +1,204 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2008-2013,2018 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+SKIP_WITH_LVMPOLLD=1
+SKIP_WITH_LVMLOCKD=1
+
+. lib/inittest
+
+SIZE_MB=80
+# 4 devs each $SIZE_MB
+aux prepare_devs 4 $SIZE_MB
+get_devs
+
+dd if=/dev/zero of="$dev1" bs=1M count=2 oflag=direct
+dd if=/dev/zero of="$dev2" bs=1M count=2 oflag=direct
+# clear entire dev to cover mda2
+dd if=/dev/zero of="$dev3" bs=1M count=$SIZE_MB oflag=direct
+dd if=/dev/zero of="$dev4" bs=1M count=2 oflag=direct
+
+pvcreate "$dev1"
+pvcreate "$dev2"
+pvcreate --pvmetadatacopies 2 "$dev3"
+pvcreate --pvmetadatacopies 0 "$dev4"
+
+vgcreate $SHARED $vg "$dev1" "$dev2" "$dev3"
+
+pvs
+
+pvck --dump headers "$dev1" > h1
+pvck --dump headers "$dev2" > h2
+pvck --dump headers "$dev3" > h3
+pvck --dump headers "$dev4" > h4
+
+grep "label_header at 512" h1
+grep "label_header at 512" h2
+grep "label_header at 512" h3
+grep "label_header at 512" h4
+
+grep "pv_header at 544" h1
+grep "pv_header at 544" h2
+grep "pv_header at 544" h3
+grep "pv_header at 544" h4
+
+grep "pv_header.disk_locn\[0\].offset 1048576" h1
+grep "pv_header.disk_locn\[0\].offset 1048576" h2
+grep "pv_header.disk_locn\[0\].offset 1048576" h3
+
+grep "pv_header.disk_locn\[2\].offset 4096" h1
+grep "pv_header.disk_locn\[2\].offset 4096" h2
+grep "pv_header.disk_locn\[2\].offset 4096" h3
+
+grep "pv_header.disk_locn\[2\].size 1044480" h1
+grep "pv_header.disk_locn\[2\].size 1044480" h2
+grep "pv_header.disk_locn\[2\].size 1044480" h3
+
+not grep "pv_header.disk_locn\[3\].size" h4
+not grep "pv_header.disk_locn\[4\].size" h4
+not grep "mda_header" h4
+
+grep "mda_header_1 at 4096" h1
+grep "mda_header_1 at 4096" h2
+grep "mda_header_1 at 4096" h3
+
+grep "mda_header_1.start 4096" h1
+grep "mda_header_1.start 4096" h2
+grep "mda_header_1.start 4096" h3
+
+grep "mda_header_1.size 1044480" h1
+grep "mda_header_1.size 1044480" h2
+grep "mda_header_1.size 1044480" h3
+
+grep "mda_header_2 at " h3
+grep "mda_header_2.start " h3
+
+grep "metadata text at " h1
+grep "metadata text at " h2
+grep "metadata text at " h3
+
+not grep CHECK h1
+not grep CHECK h2
+not grep CHECK h3
+
+pvck --dump metadata "$dev1" > m1
+pvck --dump metadata "$dev2" > m2
+pvck --dump metadata "$dev3" > m3
+pvck --dump metadata "$dev4" > m4
+pvck --dump metadata --pvmetadatacopies 2 "$dev3" > m3b
+
+grep "zero metadata copies" m4
+
+diff m1 m2
+diff m1 m3
+
+not diff m1 m3b > out
+grep "metadata text at" out
+
+lvcreate -an -l1 $vg
+
+pvck --dump metadata_all -f all1 "$dev1" > out1
+pvck --dump metadata_all -f all2 "$dev2" > out2
+pvck --dump metadata_all -f all3 "$dev3" > out3
+pvck --dump metadata_all --pvmetadatacopies 2 -f all3b "$dev3" > out3b
+
+diff out1 out2
+diff out1 out3
+
+grep "seqno 1" out1
+grep "seqno 1" out3b
+grep "seqno 2" out1
+grep "seqno 2" out3b
+
+diff all1 all2
+diff all1 all3
+diff all1 all3b
+
+grep "seqno = 1" all1
+grep "seqno = 2" all1
+
+
+pvck --dump metadata_area -f area1 "$dev1"
+pvck --dump metadata_area -f area2 "$dev2"
+pvck --dump metadata_area -f area3 "$dev3"
+pvck --dump metadata_area -f area3b "$dev3"
+
+diff area1 area2
+diff area1 area3
+diff area1 area3b
+
+vgremove -ff $vg
+
+
+# clear entire dev to cover mda2
+dd if=/dev/zero of="$dev1" bs=1M count=$SIZE_MB oflag=direct
+dd if=/dev/zero of="$dev2" bs=1M count=32 oflag=direct
+dd if=/dev/zero of="$dev3" bs=1M count=32 oflag=direct
+dd if=/dev/zero of="$dev4" bs=1M count=32 oflag=direct
+
+pvcreate --pvmetadatacopies 2 --metadatasize 32M "$dev1"
+
+vgcreate $SHARED -s 64K --metadatasize 32M $vg "$dev1" "$dev2" "$dev3" "$dev4"
+
+for i in $(seq 1 500); do echo "lvcreate -an -Zn -n lv$i -l1 $vg"; done | lvm
+rm -f debug.log*
+
+pvck --dump headers "$dev1" > h1
+
+pvck --dump metadata_search "$dev1" > m1
+grep "seqno 500" m1 || {
+ cat m1
+ die "Missing seqno 500"
+}
+
+# When metadatasize is 32M, headers/rounding can mean that
+# we need more than the first 32M of the dev to get all the
+# metadata.
+dd if="$dev1" of=dev1dd bs=1M count=34
+
+# Clear the header so that we force metadata_search to use
+# the settings instead of getting the mda_size/mda_offset
+# from the headers.
+dd if=/dev/zero of="$dev1" bs=4K count=1 oflag=direct
+
+# Warning: these checks are based on copying specific numbers
+# seen when running these commands, but these numbers could
+# change as side effects of other things. That makes this
+# somewhat fragile, and we might want to remove some of the
+# these checks if they are hard to keep working.
+
+# by experimentation, mda_size for mda1 is 34598912
+pvck --dump metadata_search --settings "mda_num=1 mda_size=34598912" "$dev1" > m1b
+# by experimentation, metadata 484 is the last in the mda1 buffer
+grep "seqno 484" m1b
+# by experimentation, metadata 485 is the last in the mda1 buffer
+grep "seqno 485" m1b
+grep "seqno 500" m1b
+
+# same results when using file as on device
+pvck --dump metadata_search --settings "mda_num=1 mda_size=34598912" dev1dd > m1c
+# by experimentation, metadata 484 is the last in the mda1 buffer
+grep "seqno 484" m1b
+# by experimentation, metadata 485 is the last in the mda1 buffer
+grep "seqno 485" m1b
+grep "seqno 500" m1b
+
+# by experimentation, mda_size for mda2 is 33554432
+pvck --dump metadata_search --settings "mda_num=2 mda_size=33554432" "$dev1" > m2
+# by experimentation, metadata 477 is the last in the mda2 buffer
+grep "seqno 477" m1b
+# by experimentation, metadata 478 is the last in the mda2 buffer
+grep "seqno 478" m1b
+grep "seqno 500" m2
+
+dd if=dev1dd of="$dev1" bs=4K count=1 oflag=direct
+
+vgremove -ff $vg
diff --git a/test/shell/pvck-repair.sh b/test/shell/pvck-repair.sh
new file mode 100644
index 0000000..ac26285
--- /dev/null
+++ b/test/shell/pvck-repair.sh
@@ -0,0 +1,421 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2008-2013,2018 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+SKIP_WITH_LVMPOLLD=1
+SKIP_WITH_LVMLOCKD=1
+
+
+. lib/inittest
+
+SIZE=34
+
+_prepare_vg() {
+ rm -f meta debug.log_DEBUG*
+ for i in "$@" ; do
+ dd if=/dev/zero of="$i" bs=1M count=1 oflag=direct
+ done
+ vgcreate $vg "$@"
+}
+
+_clear_devs() {
+ rm -f meta debug.log_DEBUG*
+ for i in "$@" ; do
+ dd if=/dev/zero of="$i" bs=1M count=$SIZE oflag=direct
+ done
+}
+
+_prepare_vg_with_copy() {
+ _clear_devs "$@"
+ vgcreate --pvmetadatacopies 2 $vg "$@"
+}
+
+aux prepare_devs 2 $SIZE
+get_devs
+
+# One PV, one mda, pv_header zeroed
+_prepare_vg "$dev1"
+dd if=/dev/zero of="$dev1" bs=512 count=2
+pvck --dump headers "$dev1" || true
+pvck --dump metadata_search --settings seqno=1 -f meta "$dev1" || true
+pvck --repair -y -f meta "$dev1"
+pvck --dump headers "$dev1" || true
+vgs $vg
+lvcreate -l1 -an $vg
+
+# One PV, one mda, mda_header zeroed
+_prepare_vg "$dev1"
+dd if=/dev/zero of="$dev1" bs=512 count=1 seek=8
+pvck --dump headers "$dev1" || true
+pvck --dump metadata_search --settings seqno=1 -f meta "$dev1" || true
+pvck --repair -y -f meta "$dev1"
+pvck --dump headers "$dev1" || true
+vgs $vg
+lvcreate -l1 -an $vg
+
+# One PV, one mda, pv_header and mda_header zeroed
+_prepare_vg "$dev1"
+dd if=/dev/zero of="$dev1" bs=512 count=2
+dd if=/dev/zero of="$dev1" bs=512 count=1 seek=8
+pvck --dump headers "$dev1" || true
+pvck --dump metadata_search --settings seqno=1 -f meta "$dev1" || true
+pvck --repair -y -f meta "$dev1"
+pvck --dump headers "$dev1" || true
+vgs $vg
+lvcreate -l1 -an $vg
+
+# One PV, one mda, metadata zeroed, use backup
+_prepare_vg "$dev1"
+vgcfgbackup
+dd if=/dev/zero of="$dev1" bs=512 count=2 seek=9
+pvck --dump headers "$dev1" || true
+pvck --dump metadata "$dev1" || true
+pvck --dump metadata_search "$dev1" || true
+pvck --repair -y -f etc/backup/$vg "$dev1"
+pvck --dump headers "$dev1" || true
+vgs $vg
+lvcreate -l1 -an $vg
+
+# One PV, one mda, mda_header and metadata zeroed, use backup
+_prepare_vg "$dev1"
+vgcfgbackup
+dd if=/dev/zero of="$dev1" bs=512 count=3 seek=8
+pvck --dump headers "$dev1" || true
+pvck --dump metadata "$dev1" || true
+pvck --dump metadata_search "$dev1" || true
+pvck --repair -y -f etc/backup/$vg "$dev1"
+pvck --dump headers "$dev1" || true
+vgs $vg
+lvcreate -l1 -an $vg
+
+# One PV, one mda, pv_header, mda_header and metadata zeroed, use backup
+_prepare_vg "$dev1"
+vgcfgbackup
+dd if=/dev/zero of="$dev1" bs=512 count=2
+dd if=/dev/zero of="$dev1" bs=512 count=3 seek=8
+pvck --dump headers "$dev1" || true
+pvck --dump metadata "$dev1" || true
+pvck --dump metadata_search "$dev1" || true
+pvck --repair -y -f etc/backup/$vg "$dev1"
+pvck --dump headers "$dev1" || true
+vgs $vg
+lvcreate -l1 -an $vg
+
+# One PV, two mdas, pv_header zeroed
+_prepare_vg_with_copy "$dev1"
+dd if=/dev/zero of="$dev1" bs=512 count=2
+pvck --dump headers "$dev1" || true
+pvck --dump metadata_search --settings seqno=1 -f meta "$dev1" || true
+pvck --repair -y -f meta "$dev1"
+pvck --dump headers "$dev1" || true
+vgs $vg
+lvcreate -l1 -an $vg
+
+# One PV, two mdas, mda_header1 zeroed
+_prepare_vg_with_copy "$dev1"
+pvck --dump headers "$dev1" || true
+dd if=/dev/zero of="$dev1" bs=512 count=1 seek=8
+pvck --dump headers "$dev1" || true
+pvck --dump metadata_search --settings mda_num=1 "$dev1" || true
+pvck --dump metadata_search --settings mda_num=2 "$dev1" || true
+pvck --dump metadata --settings mda_num=1 "$dev1" || true
+pvck --dump metadata --settings mda_num=2 "$dev1" || true
+pvck --dump metadata --settings mda_num=2 -f meta "$dev1" || true
+pvck --repair -y -f meta "$dev1"
+pvck --dump headers "$dev1" || true
+vgs $vg
+lvcreate -l1 -an $vg
+
+# One PV, two mdas, pv_header and mda_header1 zeroed
+_prepare_vg_with_copy "$dev1"
+pvck --dump headers "$dev1" || true
+dd if=/dev/zero of="$dev1" bs=512 count=2
+dd if=/dev/zero of="$dev1" bs=512 count=1 seek=8
+pvck --dump headers "$dev1" || true
+pvck --dump metadata "$dev1" || true
+pvck --dump metadata --settings mda_num=2 "$dev1" || true
+pvck --dump metadata_search "$dev1" || true
+pvck --dump metadata_search --settings mda_num=2 "$dev1" || true
+pvck --dump metadata_search --settings seqno=1 -f meta "$dev1" || true
+pvck --repair -y -f meta "$dev1"
+pvck --dump headers "$dev1" || true
+vgs $vg
+lvcreate -l1 -an $vg
+
+# One PV, two mdas, metadata1 zeroed, use mda2
+_prepare_vg_with_copy "$dev1"
+pvck --dump headers "$dev1" || true
+dd if=/dev/zero of="$dev1" bs=512 count=2 seek=9
+pvck --dump headers "$dev1" || true
+pvck --dump metadata "$dev1" || true
+pvck --dump metadata --settings mda_num=2 -f meta "$dev1" || true
+pvck --repair -y -f meta "$dev1"
+pvck --dump headers "$dev1" || true
+vgs $vg
+lvcreate -l1 -an $vg
+
+# One PV, two mdas, mda_header1 and metadata1 zeroed, use mda2
+_prepare_vg_with_copy "$dev1"
+pvck --dump headers "$dev1" || true
+dd if=/dev/zero of="$dev1" bs=512 count=3 seek=8
+pvck --dump headers "$dev1" || true
+pvck --dump metadata "$dev1" || true
+pvck --dump metadata --settings mda_num=2 -f meta "$dev1" || true
+pvck --repair -y -f meta "$dev1"
+pvck --dump headers "$dev1" || true
+vgs $vg
+lvcreate -l1 -an $vg
+
+# One PV, two mdas, pv_header, mda_header1 and metadata1 zeroed, use mda2
+_prepare_vg_with_copy "$dev1"
+pvck --dump headers "$dev1" || true
+dd if=/dev/zero of="$dev1" bs=512 count=2
+dd if=/dev/zero of="$dev1" bs=512 count=3 seek=8
+pvck --dump headers "$dev1" || true
+pvck --dump metadata "$dev1" || true
+pvck --dump metadata --settings mda_num=2 "$dev1" || true
+pvck --dump metadata_search "$dev1" || true
+pvck --dump metadata_search --settings mda_num=2 "$dev1" || true
+pvck --dump metadata_search --settings "mda_num=2 seqno=1" -f meta "$dev1" || true
+pvck --repair -y -f meta "$dev1"
+pvck --dump headers "$dev1" || true
+vgs $vg
+lvcreate -l1 -an $vg
+
+# One PV, two mdas, pv_header, both mda_header, and both metadata zeroed, use backup
+# only writes mda1 since there's no evidence that mda2 existed
+_prepare_vg_with_copy "$dev1"
+pvck --dump headers "$dev1" || true
+vgcfgbackup
+dd if=/dev/zero of="$dev1" bs=512 count=2
+dd if=/dev/zero of="$dev1" bs=512 count=3 seek=8
+dd if=/dev/zero of="$dev1" bs=512 count=3 seek=67584
+pvck --dump headers "$dev1" || true
+pvck --dump metadata "$dev1" || true
+pvck --dump metadata --settings mda_num=2 "$dev1" || true
+pvck --dump metadata_search "$dev1" || true
+pvck --dump metadata_search --settings mda_num=2 "$dev1" || true
+pvck --repair -y -f etc/backup/$vg "$dev1"
+pvck --dump headers "$dev1" || true
+vgs $vg
+lvcreate -l1 -an $vg
+
+# One PV, two mdas, pv_header, both mda_header, and both metadata zeroed, use backup
+# writes mda1 and also mda2 because of the mda2 settings passed to repair
+_prepare_vg_with_copy "$dev1"
+pvck --dump headers "$dev1" || true
+vgcfgbackup
+dd if=/dev/zero of="$dev1" bs=512 count=2
+dd if=/dev/zero of="$dev1" bs=512 count=3 seek=8
+dd if=/dev/zero of="$dev1" bs=512 count=3 seek=67584
+pvck --dump headers "$dev1" || true
+pvck --dump metadata "$dev1" || true
+pvck --dump metadata --settings mda_num=2 "$dev1" || true
+pvck --dump metadata_search "$dev1" || true
+pvck --dump metadata_search --settings mda_num=2 "$dev1" || true
+pvck --repair --settings "mda2_offset=34603008 mda2_size=1048576" -y -f etc/backup/$vg "$dev1"
+pvck --dump headers "$dev1" || true
+vgs $vg
+lvcreate -l1 -an $vg
+
+# Two PV, one mda each, pv_header and mda_header zeroed on each
+_prepare_vg "$dev1" "$dev2"
+dd if=/dev/zero of="$dev1" bs=512 count=2
+dd if=/dev/zero of="$dev2" bs=512 count=2
+dd if=/dev/zero of="$dev1" bs=512 count=1 seek=8
+dd if=/dev/zero of="$dev2" bs=512 count=1 seek=8
+pvck --dump headers "$dev1"
+pvck --dump headers "$dev2"
+pvck --dump metadata_search --settings seqno=1 -f meta "$dev1" || true
+pvck --repair -y -f meta "$dev1"
+pvck --repair -y -f meta "$dev2"
+pvck --dump headers "$dev1"
+pvck --dump headers "$dev2"
+vgs $vg
+lvcreate -l1 -an $vg
+
+# Two PV, one mda each, metadata zeroed on each, use backup
+_prepare_vg "$dev1" "$dev2"
+vgcfgbackup
+dd if=/dev/zero of="$dev1" bs=512 count=2 seek=9
+dd if=/dev/zero of="$dev2" bs=512 count=2 seek=9
+pvck --dump headers "$dev1" || true
+pvck --dump headers "$dev2" || true
+pvck --repair -y -f etc/backup/$vg "$dev1"
+pvck --repair -y -f etc/backup/$vg "$dev2"
+pvck --dump headers "$dev1"
+pvck --dump headers "$dev2"
+vgs $vg
+lvcreate -l1 -an $vg
+
+# Two PV, one mda each, pv_header, mda_header and metadata zeroed on each, use backup
+_prepare_vg "$dev1" "$dev2"
+vgcfgbackup
+dd if=/dev/zero of="$dev1" bs=512 count=2
+dd if=/dev/zero of="$dev2" bs=512 count=2
+dd if=/dev/zero of="$dev1" bs=512 count=3 seek=8
+dd if=/dev/zero of="$dev2" bs=512 count=3 seek=8
+pvck --dump headers "$dev1" || true
+pvck --dump headers "$dev2" || true
+pvck --repair -y -f etc/backup/$vg "$dev1"
+pvck --repair -y -f etc/backup/$vg "$dev2"
+pvck --dump headers "$dev1"
+pvck --dump headers "$dev2"
+vgs $vg
+lvcreate -l1 -an $vg
+
+# Two PV, one mda each, pv_header and mda_header zeroed on first
+_prepare_vg "$dev1" "$dev2"
+dd if=/dev/zero of="$dev1" bs=512 count=2
+dd if=/dev/zero of="$dev1" bs=512 count=1 seek=8
+pvck --dump headers "$dev1" || true
+pvck --dump headers "$dev2" || true
+pvck --dump metadata -f meta "$dev2"
+pvck --repair -y -f meta "$dev1"
+pvck --dump headers "$dev1"
+vgs $vg
+lvcreate -l1 -an $vg
+
+# Two PV, one mda each, metadata zeroed on first
+_prepare_vg "$dev1" "$dev2"
+dd if=/dev/zero of="$dev1" bs=512 count=2 seek=9
+pvck --dump headers "$dev1" || true
+pvck --dump headers "$dev2" || true
+pvck --dump metadata -f meta "$dev2"
+pvck --repair -y -f meta "$dev1"
+pvck --dump headers "$dev1"
+vgs $vg
+lvcreate -l1 -an $vg
+
+# Two PV, one mda each, pv_header, mda_header and metadata zeroed on first
+_prepare_vg "$dev1" "$dev2"
+dd if=/dev/zero of="$dev1" bs=512 count=2
+dd if=/dev/zero of="$dev1" bs=512 count=3 seek=8
+pvck --dump headers "$dev1" || true
+pvck --dump headers "$dev2" || true
+pvck --dump metadata -f meta "$dev2"
+pvck --repair -y -f meta "$dev1"
+pvck --dump headers "$dev1"
+vgs $vg
+lvcreate -l1 -an $vg
+
+# Two PV, one mda on first, no mda on second, zero header on first
+_clear_devs "$dev1" "$dev2"
+pvcreate "$dev1"
+pvcreate --pvmetadatacopies 0 "$dev2"
+vgcreate $vg "$dev1" "$dev2"
+dd if=/dev/zero of="$dev1" bs=512 count=2
+pvck --dump headers "$dev1" || true
+pvck --dump headers "$dev2" || true
+pvck --dump metadata_search --settings seqno=1 -f meta "$dev1" || true
+pvck --repair -y -f meta "$dev1"
+pvck --dump headers "$dev1"
+vgs $vg
+lvcreate -l1 -an $vg
+
+# Two PV, one mda on first, no mda on second, zero headers on both
+_clear_devs "$dev1" "$dev2"
+pvcreate "$dev1"
+pvcreate --pvmetadatacopies 0 "$dev2"
+vgcreate $vg "$dev1" "$dev2"
+dd if=/dev/zero of="$dev1" bs=512 count=2
+dd if=/dev/zero of="$dev2" bs=512 count=2
+pvck --dump headers "$dev1" || true
+pvck --dump headers "$dev2" || true
+pvck --dump metadata_search --settings seqno=1 -f meta "$dev1" || true
+pvck --repair -y -f meta "$dev1"
+pvck --repair -y --settings "mda_offset=0 mda_size=0" -f meta "$dev2"
+pvck --dump headers "$dev1"
+pvck --dump headers "$dev2"
+vgs $vg
+lvcreate -l1 -an $vg
+
+# Two PV, one mda on first, no mda on second, zero all on first
+_clear_devs "$dev1" "$dev2"
+pvcreate "$dev1"
+pvcreate --pvmetadatacopies 0 "$dev2"
+vgcreate $vg "$dev1" "$dev2"
+vgcfgbackup
+dd if=/dev/zero of="$dev1" bs=512 count=2
+dd if=/dev/zero of="$dev1" bs=512 count=3 seek=8
+pvck --dump headers "$dev1" || true
+pvck --dump headers "$dev2" || true
+pvck --repair -y -f etc/backup/$vg "$dev1"
+pvck --repair -y --settings "mda_offset=0 mda_size=0" -f etc/backup/$vg "$dev2"
+pvck --dump headers "$dev1"
+pvck --dump headers "$dev2"
+vgs $vg
+lvcreate -l1 -an $vg
+
+# Two PV, two mda on each, pv_header and mda_header1 zeroed on both
+_clear_devs "$dev1" "$dev2"
+pvcreate --pvmetadatacopies 2 "$dev1"
+pvcreate --pvmetadatacopies 2 "$dev2"
+vgcreate $vg "$dev1" "$dev2"
+dd if=/dev/zero of="$dev1" bs=512 count=2
+dd if=/dev/zero of="$dev2" bs=512 count=2
+dd if=/dev/zero of="$dev1" bs=512 count=1 seek=8
+dd if=/dev/zero of="$dev2" bs=512 count=1 seek=8
+pvck --dump headers "$dev1"
+pvck --dump headers "$dev2"
+pvck --dump metadata_search --settings "mda_num=2 seqno=1" -f meta "$dev1" || true
+pvck --repair -y -f meta "$dev1"
+rm meta
+pvck --dump metadata_search --settings "mda_num=2 seqno=1" -f meta "$dev2" || true
+pvck --repair -y -f meta "$dev2"
+rm meta
+pvck --dump headers "$dev1"
+pvck --dump headers "$dev2"
+vgs $vg
+lvcreate -l1 -an $vg
+
+# Two PV, one mda each, pv_header and mda_header zeroed on each,
+# non-standard data_offset/mda_size on first
+_clear_devs "$dev1" "$dev2"
+pvcreate --metadatasize 2048k --dataalignment 128k "$dev1"
+pvcreate "$dev2"
+vgcreate $vg "$dev1" "$dev2"
+dd if=/dev/zero of="$dev1" bs=512 count=2
+dd if=/dev/zero of="$dev1" bs=512 count=1 seek=8
+dd if=/dev/zero of="$dev2" bs=512 count=2
+dd if=/dev/zero of="$dev2" bs=512 count=1 seek=8
+pvck --dump headers "$dev1" || true
+pvck --dump headers "$dev2" || true
+pvck --dump metadata_search --settings seqno=1 -f meta "$dev1" || true
+pvck --repair -y -f meta "$dev1"
+rm meta
+pvck --dump metadata_search --settings seqno=1 -f meta "$dev2" || true
+pvck --repair -y -f meta "$dev2"
+rm meta
+pvck --dump headers "$dev1" || true
+pvck --dump headers "$dev2" || true
+vgs $vg
+lvcreate -l1 -an $vg
+
+# One PV, one mda, pv_header zeroed, unmatching dev name requires specified uuid
+_clear_devs "$dev1" "$dev2"
+vgcreate $vg "$dev1"
+pvck --dump headers "$dev1" || true
+UUID1=$(pvck --dump headers "$dev1" | grep pv_header.pv_uuid | awk '{print $2}')
+echo "$UUID1"
+dd if=/dev/zero of="$dev1" bs=512 count=2
+pvck --dump headers "$dev1" || true
+pvck --dump metadata_search --settings seqno=1 -f meta "$dev1" || true
+sed 's/\/dev\/mapper\/LVMTEST/\/dev\/mapper\/BADTEST/' meta > meta.bad
+grep device meta
+grep device meta.bad
+not pvck --repair -y -f meta.bad "$dev1"
+pvck --repair -y -f meta.bad --settings pv_uuid=$UUID1 "$dev1"
+pvck --dump headers "$dev1" || true
+vgs $vg
+lvcreate -l1 -an $vg
+
+vgremove -f $vg
diff --git a/test/shell/pvcreate-bootloaderarea.sh b/test/shell/pvcreate-bootloaderarea.sh
new file mode 100644
index 0000000..cc31812
--- /dev/null
+++ b/test/shell/pvcreate-bootloaderarea.sh
@@ -0,0 +1,58 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2014 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+test_description='Test pvcreate bootloader area support'
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+aux prepare_devs 1
+aux lvmconf 'global/suffix=0' 'global/units="b"'
+
+#COMM 'pvcreate sets/aligns bootloader area correctly'
+pvcreate --metadatasize 255s --dataalignment 262144b --bootloaderareasize 614400b "$dev1"
+# ba_start must be aligned based on dataalignment
+# pe_start starts at next dataalignment multiple
+# ba_size is the whole space in between ba_start and pe_start
+check pv_field "$dev1" ba_start "262144"
+check pv_field "$dev1" ba_size "786432"
+check pv_field "$dev1" pe_start "1048576"
+
+#COMM 'pvcreate with booloader area size - test corner cases'
+dev_size=$(pvs -o pv_size --noheadings "$dev1")
+pv_size=$(( dev_size - 1048576 )) # device size - 1m pe_start = area for data
+
+# try to use the whole data area for bootloader area, remaining data area is zero then (pe_start = pv_size)
+pvcreate --metadatasize 255s --bootloaderareasize ${pv_size}b --dataalignment 1048576b "$dev1"
+check pv_field "$dev1" pe_start $dev_size
+check pv_field "$dev1" ba_start 1048576
+check pv_field "$dev1" ba_size $pv_size
+
+# try to use the whole data area for bootloader area only and add one more byte - this must error out
+not pvcreate --bootloaderareasize $(( pv_size + 1 )) --dataalignment 1048576b "$dev1" 2>err
+grep "Bootloader area with data-aligned start must not exceed device size" err
+
+# restoring the PV should also restore the bootloader area correctly
+pvremove -ff "$dev1"
+pvcreate --metadatasize 255s --dataalignment 256k --bootloaderareasize 600k "$dev1"
+vgcreate $SHARED $vg "$dev1"
+vgcfgbackup -f "$TESTDIR/vg_with_ba_backup" "$vg"
+pv_uuid=$(get pv_field "$dev1" pv_uuid)
+vgremove -ff $vg
+pvremove -ff "$dev1"
+pvcreate --metadatasize 255s --dataalignment 256k --restorefile "$TESTDIR/vg_with_ba_backup" --uuid "$pv_uuid" "$dev1"
+check pv_field "$dev1" ba_start "262144"
+check pv_field "$dev1" ba_size "786432"
+check pv_field "$dev1" pe_start "1048576"
+
+pvremove -ff "$dev1"
diff --git a/test/shell/lvmetad-lvm1.sh b/test/shell/pvcreate-ff.sh
index 528eec2..13b05fc 100644
--- a/test/shell/lvmetad-lvm1.sh
+++ b/test/shell/pvcreate-ff.sh
@@ -1,5 +1,6 @@
-#!/bin/sh
-# Copyright (C) 2012 Red Hat, Inc. All rights reserved.
+#!/usr/bin/env bash
+
+# Copyright (C) 2014 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
@@ -7,16 +8,16 @@
#
# 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
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+SKIP_WITH_LVMLOCKD=1
+SKIP_WITH_LVMPOLLD=1
-. lib/test
+. lib/inittest
-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
+pvcreate "$dev1"
+vgcreate foo "$dev1"
+pvcreate -ff -y "$dev1"
+vgs
+vgcreate foo "$dev1"
diff --git a/test/shell/pvcreate-md-fake-hdr.sh b/test/shell/pvcreate-md-fake-hdr.sh
new file mode 100644
index 0000000..856b26c
--- /dev/null
+++ b/test/shell/pvcreate-md-fake-hdr.sh
@@ -0,0 +1,102 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2018-2021 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+
+# TODO: once code get fixed, add matching 'check' calls
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+test -f /proc/mdstat && grep -q raid1 /proc/mdstat || \
+ modprobe raid1 || skip
+
+aux lvmconf 'devices/md_component_detection = 1'
+aux extend_filter_LVMTEST "a|/dev/md|"
+
+aux prepare_devs 4
+
+pvcreate "$dev2"
+
+aux mdadm_create --metadata=1.0 --level=0 --chunk=64 --raid-devices=2 "$dev1" "$dev2"
+
+pvs | tee out
+not grep pv2 out
+
+vgcreate $SHARED $vg "$dev3" "$dev4"
+
+# create 2 disk MD raid1 array
+# by default using metadata format 1.0 with data at the end of device
+# passing --chunk=64 makes mdadm non functional
+aux mdadm_create --metadata=1.0 --level=1 --raid-devices=2 "$dev1" "$dev2"
+
+mddev=$(< MD_DEV)
+pvdev=$(< MD_DEV_PV)
+sleep 3
+mdadm --stop "$mddev"
+
+# copy fake PV/VG header PV3 -> PV2 (which is however md raid1 leg)
+dd if="$dev3" of="$dev2" bs=64k count=1 conv=fdatasync
+
+# remove VG on PV3 & PV4
+vgremove -f $vg
+
+aux udev_wait
+# too bad 'dd' wakes up md array reassembling
+mdadm --detail "$mddev" || true
+mdadm --stop "$mddev" || true
+sleep 1
+
+# print what blkid thinks about each PV
+for i in "$dev1" "$dev2" "$dev3" "$dev4"
+do
+ blkid -c /dev/null "$i" || echo "Unknown signature"
+done
+
+# expect open count for each PV to be 0
+dmsetup info -c
+
+pvs "$dev2" "$dev3" || true
+
+# still expect open count for each PV to be 0
+dmsetup info -c
+
+pvs "$dev3" "$dev2" || true
+
+# and again we expect open count for each PV to be 0
+dmsetup info -c
+dmsetup table
+
+# even after 3 second of possible hidden raid array assembling
+sleep 3
+dmsetup info -c
+
+# if for any reason array went up - stop it again
+if mdadm --detail "$mddev" ; then
+ mdadm --stop "$mddev"
+ aux udev_wait
+ should not mdadm --detail "$mddev"
+fi
+
+# now reassemble array from PV1 & PV2
+aux mdadm_assemble --verbose "$mddev" "$dev1" "$dev2"
+
+sleep 1
+
+# and let 'fake hdr' to be fixed from master/primary leg
+# (when mdadm supports repair)
+if mdadm --action=repair "$mddev" ; then
+ sleep 1
+ pvscan -vvvv
+ # should be showing correctly PV3 & PV4
+ pvs "$dev3" "$dev4"
+fi
diff --git a/test/shell/pvcreate-metadata0.sh b/test/shell/pvcreate-metadata0.sh
index 9154e75..c732a2e 100644
--- a/test/shell/pvcreate-metadata0.sh
+++ b/test/shell/pvcreate-metadata0.sh
@@ -1,4 +1,5 @@
-#!/bin/sh
+#!/usr/bin/env bash
+
# Copyright (C) 2008 Red Hat, Inc. All rights reserved.
#
# This copyrighted material is made available to anyone wishing to use,
@@ -7,7 +8,7 @@
#
# 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
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
#
# Testcase for bugzilla #450651
@@ -15,7 +16,10 @@
#
# 'Test pvcreate without metadata on all pvs'
-. lib/test
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
aux prepare_devs 2 128
@@ -24,9 +28,7 @@ pvcreate "$dev1"
pvcreate --metadatacopies 0 "$dev2"
# "check lv snapshot"
-vgcreate -c n $vg "$dev1" "$dev2"
-lvcreate -n $lv -l 60%FREE $vg
+vgcreate $SHARED $vg "$dev1" "$dev2"
+lvcreate -aey -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
index 9bdc4a1..19f2145 100644
--- a/test/shell/pvcreate-operation-md.sh
+++ b/test/shell/pvcreate-operation-md.sh
@@ -1,5 +1,6 @@
-#!/bin/sh
-# Copyright (C) 2009 Red Hat, Inc. All rights reserved.
+#!/usr/bin/env bash
+
+# Copyright (C) 2009-2015 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
@@ -7,143 +8,129 @@
#
# 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
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
-. lib/test
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
# 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
+aux extend_filter_md "a|/dev/md|"
-# 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
-}
+aux prepare_devs 2
# 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
+aux mdadm_create --metadata=1.0 --level=0 --chunk=64 --raid-devices=2 "$dev1" "$dev2"
+mddev=$(< MD_DEV)
+
+pvdev="$mddev"
# 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
+ "$pvdev"
+
+check pv_field "$pvdev" pe_start "1.00m"
# 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
-
+ "$pvdev"
+check pv_field "$pvdev" pe_start "1.00m"
# 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"
+if aux kernel_at_least 2 6 33 ; then
# 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
+ --config 'devices { md_chunk_alignment=0 }' "$pvdev"
+ check pv_field "$pvdev" pe_start "1.00m"
+ pvremove "$pvdev"
fi
# partition MD array directly, depends on blkext in Linux >= 2.6.28
-if kernel_at_least 2 6 28 ; then
+if aux kernel_at_least 2 6 28 ; then
# create one partition
sfdisk "$mddev" <<EOF
,,83
EOF
+ # Wait till all partition links in udev are created
+ aux udev_wait
+
+ # Skip test if udev rule has not created proper links for partitions
+ test -b "${mddev}p1" || { ls -laR /dev ; skip "Missing partition link" ; }
+
+ pvscan
# make sure partition on MD is _not_ removed
# - tests partition -> parent lookup via sysfs paths
- not pvcreate --metadatasize 128k "$mddev"
+ not pvcreate --metadatasize 128k "$pvdev"
# 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"
+ if aux kernel_at_least 2 6 33 ; then
+ # in case the system is running without devtmpfs /dev
+ # wait here for created device node on tmpfs
+ # test "$DM_DEV_DIR" = "/dev" || cp -LR "${mddev}p1" "${pvdev%/*}"
+
+ pvcreate --metadatasize 128k "${pvdev}p1"
+
+ maj=$(($(stat -L --printf=0x%t "${mddev}p1")))
+ min=$(($(stat -L --printf=0x%T "${mddev}p1")))
+
+ ls /sys/dev/block/$maj:$min/
+ ls /sys/dev/block/$maj:$min/holders/
+ cat /sys/dev/block/$maj:$min/dev
+ cat /sys/dev/block/$maj:$min/stat
+ cat /sys/dev/block/$maj:$min/size
+
+ sysfs_alignment_offset="/sys/dev/block/$maj:$min/alignment_offset"
+ [ -f "$sysfs_alignment_offset" ] && \
+ alignment_offset=$(< "$sysfs_alignment_offset") || \
+ alignment_offset=0
+
+ # default alignment is 1M, add alignment_offset
+ pv_align=$(( 1048576 + alignment_offset ))
+ check pv_field "${pvdev}p1" pe_start $pv_align --units b --nosuffix
+
+ pvremove "${pvdev}p1"
+ # test "$DM_DEV_DIR" = "/dev" || rm -f "${pvdev}p1"
fi
fi
+aux cleanup_md_dev
+aux wipefs_a "$dev1" "$dev2"
+
# 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"
+if aux kernel_at_least 2 6 33 ; then
+
+ aux mdadm_create --metadata=1.0 --level 0 --chunk=1024 --raid-devices=2 "$dev1" "$dev2"
+ mddev=$(< MD_DEV)
- # 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
+ pvdev="$mddev"
# 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
+ --config 'devices { md_chunk_alignment=0 }' "$pvdev"
+
+ # to see the processing of scanning
+ pvs -vvvv
+
+ check pv_field "$pvdev" pe_start "2.00m"
# 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
+ --config 'devices { md_chunk_alignment=0 }' "$pvdev"
+ check pv_field "$pvdev" pe_start "192.00k"
+
+ aux cleanup_md_dev
+ aux wipefs_a "$dev1" "$dev2"
fi
diff --git a/test/shell/pvcreate-operation.sh b/test/shell/pvcreate-operation.sh
index 55fff4e..5cf4fd6 100644
--- a/test/shell/pvcreate-operation.sh
+++ b/test/shell/pvcreate-operation.sh
@@ -1,4 +1,6 @@
-# Copyright (C) 2008 Red Hat, Inc. All rights reserved.
+#!/usr/bin/env bash
+
+# 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
@@ -6,23 +8,35 @@
#
# 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
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
-. lib/test
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
aux lvmconf 'devices/md_component_detection = 1'
aux prepare_devs 4
-for mdatype in 1 2
+if test -n "$LVM_TEST_LVM1" ; then
+mdatypes='1 2'
+else
+mdatypes='2'
+fi
+
+for mdatype in $mdatypes
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
+ grep "Can't open $dev1 exclusively. Mounted filesystem?" err
umount "$dev1"
+ # wipe the filesystem signature for next
+ # pvcreate to not issue any prompts
+ dd if=/dev/zero of="$dev1" bs=1K count=2
fi
# pvcreate (lvm$mdatype) succeeds when run repeatedly (pv not in a vg) (bz178216)
@@ -32,7 +46,7 @@ do
# pvcreate (lvm$mdatype) fails when PV belongs to VG
# pvcreate -M$mdatype "$dev1"
- vgcreate -M$mdatype $vg1 "$dev1"
+ vgcreate $SHARED -M$mdatype $vg1 "$dev1"
not pvcreate -M$mdatype "$dev1"
vgremove -f $vg1
@@ -41,7 +55,7 @@ do
# 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"
+ vgcreate $SHARED -M$mdatype $vg1 "$dev1"
# pvcreate a second time on $dev2 and $dev1
not pvcreate -M$mdatype "$dev2" "$dev1"
@@ -63,7 +77,7 @@ 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"
+vgcreate $SHARED $vg1 "$dev1" "$dev2"
not pvcreate "$dev1"
vgremove -f $vg1
pvremove -f "$dev2" "$dev1"
@@ -71,7 +85,7 @@ 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"
+vgcreate $SHARED $vg1 "$dev1" "$dev2"
pvcreate -ff -y "$dev1"
vgreduce --removemissing $vg1
vgremove -ff $vg1
@@ -88,7 +102,7 @@ done
# pvcreate (lvm2) fails writing LVM label at sector 4
not pvcreate --labelsector 4 "$dev1"
-backupfile=$PREFIX.mybackupfile
+backupfile="$PREFIX.mybackupfile"
uuid1=freddy-fred-fred-fred-fred-fred-freddy
uuid2=freddy-fred-fred-fred-fred-fred-fredie
bogusuuid=fred
@@ -104,25 +118,70 @@ 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"
+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"
+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
+size_mb=$(($(blockdev --getsz "$dev1") / 2048))
+pvcreate --metadatasize $size_mb "$dev1"
+vgcreate $SHARED $vg1 "$dev1"
+vgcfgbackup -f "$backupfile"
+vgcfgrestore -f "$backupfile" "$vg1"
vgremove -f $vg1
-pvremove -f $dev1
+pvremove -f "$dev1"
+
+# pvcreate --restorefile should handle --dataalignment and --dataalignmentoffset
+# and check it's compatible with pe_start value being restored
+# X * dataalignment + dataalignmentoffset == pe_start
+pvcreate --norestorefile --uuid "$uuid1" --dataalignment 600k --dataalignmentoffset 32k "$dev1"
+vgcreate $SHARED $vg1 "$dev1"
+vgcfgbackup -f "$backupfile" "$vg1"
+vgremove -ff $vg1
+pvremove -ff "$dev1"
+# the dataalignment and dataalignmentoffset is ignored here since they're incompatible with pe_start
+pvcreate --restorefile "$backupfile" --uuid "$uuid1" --dataalignment 500k --dataalignmentoffset 10k "$dev1" 2> err
+grep "incompatible with restored pe_start value" err
+# 300k is multiple of 600k so this should pass
+pvcreate --restorefile "$backupfile" --uui "$uuid1" --dataalignment 300k --dataalignmentoffset 32k "$dev1" 2> err
+not grep "incompatible with restored pe_start value" err
+
+# pvcreate rejects non-existent uuid given with restorefile
+not pvcreate --uuid "$uuid2" --restorefile "$backupfile" "$dev1" 2> err
+grep "Can't find uuid $uuid2 in backup file $backupfile" err
+
+# pvcreate rejects restorefile without uuid
+not pvcreate --restorefile "$backupfile" "$dev1" 2>err
+grep -- "--uuid is required with --restorefile" err
+
+# pvcreate rejects uuid restore with multiple volumes specified
+not pvcreate --uuid "$uuid1" --restorefile "$backupfile" "$dev1" "$dev2" 2>err
+grep "Can only set uuid on one volume at once" err
+
+# --bootloaderareasize not allowed with pvcreate --restorefile
+not pvcreate --uuid "$uuid1" --restorefile "$backupfile" --bootloaderareasize 1m "$dev1" "$dev2" 2>err
+grep -- "Command does not accept option combination: --bootloaderareasize with --restorefile" err
+
+rm -f "$backupfile"
+
+pvcreate --norestorefile --uuid $uuid1 "$dev1"
+vgcreate $SHARED --physicalextentsize 1m $vg1 "$dev1"
+vgcfgbackup -f "$backupfile" "$vg1"
+vgremove -ff "$vg1"
+pvremove -ff "$dev1"
+
+# when 2nd mda requested on pvcreate --restorefile and not enough space for it, pvcreate fails
+not pvcreate --restorefile "$backupfile" --uuid $uuid1 --metadatacopies 2 "$dev1" 2>err
+grep "Not enough space available for metadata area with index 1 on PV $dev1" err
+
+rm -f "$backupfile"
# pvcreate wipes swap signature when forced
-dd if=/dev/zero of="$dev1" bs=1024 count=64
+dd if=/dev/zero of="$dev1" bs=64k count=1 oflag=direct
mkswap "$dev1"
blkid -c /dev/null "$dev1" | grep "swap"
pvcreate -f "$dev1"
diff --git a/test/shell/pvcreate-restore.sh b/test/shell/pvcreate-restore.sh
new file mode 100644
index 0000000..45c27bf
--- /dev/null
+++ b/test/shell/pvcreate-restore.sh
@@ -0,0 +1,45 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2015 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+SKIP_WITH_LVMLOCKD=1
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+aux prepare_vg 4
+
+lvcreate --type snapshot -s -L10 -n $lv1 $vg --virtualsize 2T
+lvcreate --type snapshot -s -L10 -n $lv2 $vg --virtualsize 4T
+lvcreate --type snapshot -s -L10 -n $lv3 $vg --virtualsize 4194300M
+
+aux extend_filter_LVMTEST
+aux lvmconf "devices/scan_lvs = 1"
+aux extend_devices "$DM_DEV_DIR/$vg/$lv1"
+aux extend_devices "$DM_DEV_DIR/$vg/$lv2"
+aux extend_devices "$DM_DEV_DIR/$vg/$lv3"
+
+vgcreate $vg1 "$DM_DEV_DIR/$vg/$lv2"
+
+vgcfgbackup -f vgback $vg1
+
+UUID=$(get pv_field "$DM_DEV_DIR/$vg/$lv2" uuid)
+pvremove -ff -y "$DM_DEV_DIR/$vg/$lv2"
+
+# too small to fit
+fail pvcreate --restorefile vgback --uuid $UUID "$DM_DEV_DIR/$vg/$lv1"
+
+# still does not fit
+fail pvcreate --restorefile vgback --uuid $UUID "$DM_DEV_DIR/$vg/$lv3"
+
+pvcreate --restorefile vgback --uuid $UUID "$DM_DEV_DIR/$vg/$lv2"
+
+vgremove -ff $vg
diff --git a/test/shell/pvcreate-usage.sh b/test/shell/pvcreate-usage.sh
index 148802f..a61a2c3 100644
--- a/test/shell/pvcreate-usage.sh
+++ b/test/shell/pvcreate-usage.sh
@@ -1,4 +1,5 @@
-#!/bin/sh
+#!/usr/bin/env bash
+
# Copyright (C) 2008 Red Hat, Inc. All rights reserved.
#
# This copyrighted material is made available to anyone wishing to use,
@@ -7,12 +8,16 @@
#
# 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
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
test_description='Test pvcreate option values'
+
+SKIP_WITH_LVMPOLLD=1
PAGESIZE=$(getconf PAGESIZE)
+# MDA_SIZE_MIN defined in lib/format_text/layout.h
+MDA_SIZE_MIN=$(( 8 * PAGESIZE ))
-. lib/test
+. lib/inittest
aux prepare_devs 4
@@ -22,18 +27,18 @@ 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"
+#COMM 'pvcreate rejects metadatasize that is less than minimum size'
+not pvcreate --dataalignment $(( MDA_SIZE_MIN / 2 ))b --metadatasize $(( MDA_SIZE_MIN / 2 ))b "$dev1" 2>err
+grep "Metadata area size too small" err
+
+#COMM 'pvcreate accepts metadatasize that is at least the minimum size'
+pvcreate --dataalignment ${MDA_SIZE_MIN}b --metadatasize ${MDA_SIZE_MIN}b "$dev1"
#Verify vg_mda_size is smaller pv_mda_size
pvcreate --metadatasize 512k "$dev1"
pvcreate --metadatasize 96k "$dev2"
-vgcreate $vg "$dev1" "$dev2"
+vgcreate $SHARED $vg "$dev1" "$dev2"
+pvs -o +pv_mda_size
check compare_fields vgs $vg vg_mda_size pvs "$dev2" pv_mda_size
vgremove $vg
@@ -81,7 +86,6 @@ not pvcreate --labelsector 1000000000000 "$dev1"
#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'
@@ -89,12 +93,12 @@ not pvcreate --dataalignment 1e "$dev1"
# amuse shell experts
#check pv_field "$dev1" pe_start $(($(getconf PAGESIZE)/1024))".00k"
-#COMM 'pvcreate sets data offset directly'
-pvcreate --dataalignment 512k "$dev1"
+#COMM 'pvcreate sets data alignment directly'
+pvcreate --dataalignment 512K --config 'metadata {pvmetadatasize=255}' "$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 }'
+vgcreate $SHARED $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"
@@ -110,6 +114,31 @@ case "$PAGESIZE" in
*) pv_align="133.00k" ;;
esac
+# pe_start is a multiple of dataalignment, leaving enough
+# space between mda_start and pe_end for the specified
+# metadata size.
+#
+# With page size 4k, mda_start is rounded up start at 4k.
+# The chosen multiple of data alignment (3.5k) is 38:
+# 3.5k * 38 = 133k for pe_start
+# Space available for metadata between mda_start and pe_end is:
+# 133k - 4k = 129k mda size, which is large enough for the
+# specified mda size of 128k.
+#
+# With page size 8k, mda_start is rouned up to start at 8k.
+# The chosen multiple of data alignment (3.5k) is 39:
+# 3.5k * 39 = 136.5k for pe_start
+# Space available for metadata between mda_start and pe_end is:
+# 136.5k - 8k = 128.5k mda size, which is large enough for the
+# specified mda size of 128k.
+#
+# With page size 64k, mda_start is rouned up to start at 64k.
+# The chosen multiple of data alignment (3.5k) is 55:
+# 3.5k * 55 = 192.5k for pe_start
+# Space available for metadata between mda_start and pe_end is:
+# 192.5k - 64k = 128.5k mda size, which is large enough for the
+# specified mda size of 128k.
+
pvcreate --metadatasize 128k --dataalignment 3.5k "$dev1"
check pv_field "$dev1" pe_start $pv_align
@@ -128,27 +157,12 @@ 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"
+vgcreate $SHARED $vg "$dev1" "$dev2"
vgcfgbackup -f backup.$$ $vg
sed 's/pe_start = [0-9]*/pe_start = 0/' backup.$$ > backup.$$1
vgcfgrestore -f backup.$$1 $vg
@@ -171,14 +185,14 @@ for ignore in y n; do
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"
+ echo "vgcreate $SHARED 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))"
+ vgcreate $SHARED $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))"
+ check vg_field $vg vg_mda_used_count "$(( mdacp * 2 ))"
fi
check vg_field $vg vg_mda_copies "unmanaged"
vgremove $vg
diff --git a/test/shell/pvmove-abort-all.sh b/test/shell/pvmove-abort-all.sh
new file mode 100644
index 0000000..872db04
--- /dev/null
+++ b/test/shell/pvmove-abort-all.sh
@@ -0,0 +1,85 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2015 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+# Check pvmove --abort behaviour for all VGs and PVs
+
+SKIP_WITH_LVMLOCKD=1
+
+# Ignore known failure when clvmd is processing sequences of commands for two VGs in parallel - 2015/07/17 agk
+# CLVMD: ioctl/libdm-iface.c:1940 Internal error: Performing unsafe table load while 3 device(s) are known to be suspended: (253:19)
+export DM_ABORT_ON_INTERNAL_ERRORS=0
+
+. lib/inittest
+
+aux lvmconf 'activation/raid_region_size = 16'
+
+aux target_at_least dm-mirror 1 10 0 || skip
+# Throttle mirroring
+aux throttle_dm_mirror || skip
+
+aux prepare_pvs 6 60
+
+vgcreate -s 512k $vg "$dev1" "$dev2"
+pvcreate --metadatacopies 0 "$dev3"
+vgextend $vg "$dev3"
+vgcreate -s 512k $vg1 "$dev4" "$dev5"
+pvcreate --metadatacopies 0 "$dev6"
+vgextend $vg1 "$dev6"
+
+for mode in "--atomic" "" ;
+do
+for backgroundarg in "-b" "" ;
+do
+
+# Create multisegment LV
+lvcreate -an -Zn -l30 -n $lv1 $vg "$dev1"
+lvcreate -an -Zn -l30 -n $lv2 $vg "$dev2"
+lvcreate -an -Zn -l30 -n $lv1 $vg1 "$dev4"
+lvextend -l+30 -n $vg1/$lv1 "$dev5"
+
+cmd1=(pvmove -i1 $backgroundarg $mode "$dev1" "$dev3")
+cmd2=(pvmove -i1 $backgroundarg $mode "$dev2" "$dev3")
+cmd3=(pvmove -i1 $backgroundarg $mode -n $vg1/$lv1 "$dev4" "$dev6")
+
+
+if test -z "$backgroundarg" ; then
+ "${cmd1[@]}" &
+ aux wait_pvmove_lv_ready "$vg-pvmove0"
+ "${cmd2[@]}" &
+ "${cmd3[@]}" &
+ aux wait_pvmove_lv_ready "$vg-pvmove1" "$vg1-pvmove0"
+else
+ LVM_TEST_TAG="kill_me_$PREFIX" "${cmd1[@]}"
+ LVM_TEST_TAG="kill_me_$PREFIX" "${cmd2[@]}"
+ LVM_TEST_TAG="kill_me_$PREFIX" "${cmd3[@]}"
+fi
+
+# test removal of all pvmove LVs
+pvmove --abort
+
+# check if proper pvmove was canceled
+get lv_field $vg name -a | tee out
+not grep "^\[pvmove" out
+get lv_field $vg1 name -a | tee out
+not grep "^\[pvmove" out
+
+lvremove -ff $vg $vg1
+
+wait
+aux kill_tagged_processes
+done
+done
+
+# Restore throttling
+aux restore_dm_mirror
+
+vgremove -ff $vg $vg1
diff --git a/test/shell/pvmove-abort.sh b/test/shell/pvmove-abort.sh
new file mode 100644
index 0000000..86f2417
--- /dev/null
+++ b/test/shell/pvmove-abort.sh
@@ -0,0 +1,73 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2015 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+# Check pvmove --abort behaviour when specific device is requested
+
+SKIP_WITH_LVMLOCKD=1
+
+. lib/inittest
+
+aux lvmconf 'activation/raid_region_size = 16'
+
+aux target_at_least dm-mirror 1 10 0 || skip
+# Throttle mirroring
+aux throttle_dm_mirror || skip
+
+aux prepare_pvs 3 90
+
+vgcreate -s 512k $vg "$dev1" "$dev2"
+pvcreate --metadatacopies 0 "$dev3"
+vgextend $vg "$dev3"
+
+for mode in "--atomic" "" ;
+do
+for backgroundarg in "-b" "" ;
+do
+
+# Create multisegment LV
+lvcreate -an -Zn -l60 -n $lv1 $vg "$dev1"
+lvcreate -an -Zn -l80 -n $lv2 $vg "$dev2"
+
+cmd1=(pvmove -i1 $backgroundarg $mode "$dev1" "$dev3")
+cmd2=(pvmove -i1 $backgroundarg $mode "$dev2" "$dev3")
+
+if test -z "$backgroundarg" ; then
+ "${cmd1[@]}" &
+ aux wait_pvmove_lv_ready "$vg-pvmove0"
+ "${cmd2[@]}" &
+ aux wait_pvmove_lv_ready "$vg-pvmove1"
+else
+ LVM_TEST_TAG="kill_me_$PREFIX" "${cmd1[@]}"
+ LVM_TEST_TAG="kill_me_$PREFIX" "${cmd2[@]}"
+fi
+# remove specific device
+pvmove --abort "$dev1"
+
+# check if proper pvmove was canceled
+get lv_field $vg name -a | tee out
+not grep -E "^\[?pvmove0" out
+grep -E "^\[?pvmove1" out
+
+# remove any remaining pvmoves in progress
+pvmove --abort
+
+lvremove -ff $vg
+
+wait
+aux kill_tagged_processes
+done
+done
+
+# Restore throttling
+aux restore_dm_mirror
+
+vgremove -ff $vg
diff --git a/test/shell/pvmove-all-segtypes.sh b/test/shell/pvmove-all-segtypes.sh
new file mode 100644
index 0000000..38b5267
--- /dev/null
+++ b/test/shell/pvmove-all-segtypes.sh
@@ -0,0 +1,111 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2013 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+test_description="ensure pvmove works with all common segment types"
+
+SKIP_WITH_LVMLOCKD=1
+
+. lib/inittest
+
+which md5sum || skip
+
+aux prepare_vg 5 20
+
+# Each of the following tests does:
+# 1) Create two LVs - one linear and one other segment type
+# The two LVs will share a PV.
+# 2) Move both LVs together
+# 3) Move only the second LV by name
+
+# Testing pvmove of linear LV
+lvcreate -aey -l 2 -n ${lv1}_foo $vg "$dev1"
+lvcreate -aey -l 2 -n $lv1 $vg "$dev1"
+lvextend -l+2 $vg/${lv1}_foo "$dev1"
+lvextend -l+2 $vg/${lv1} "$dev1"
+lvextend -l+2 $vg/${lv1}_foo "$dev2"
+lvextend -l+2 $vg/${lv1} "$dev3"
+check lv_tree_on $vg ${lv1}_foo "$dev1" "$dev2"
+check lv_tree_on $vg $lv1 "$dev1" "$dev3"
+check lv_field $vg/${lv1}_foo seg_count 3
+check lv_field $vg/$lv1 seg_count 3
+aux mkdev_md5sum $vg $lv1
+dmsetup table
+pvmove --atomic "$dev1" "$dev5"
+check lv_tree_on $vg ${lv1}_foo "$dev2" "$dev5"
+check lv_tree_on $vg $lv1 "$dev3" "$dev5"
+# Also check 2 segments from $dev1 were merged on $dev5
+check lv_field $vg/${lv1}_foo seg_count 2
+check lv_field $vg/$lv1 seg_count 2
+check dev_md5sum $vg $lv1
+pvmove -n $lv1 "$dev5" "$dev4"
+check lv_tree_on $vg $lv1 "$dev3" "$dev4"
+check lv_tree_on $vg ${lv1}_foo "$dev2" "$dev5"
+check dev_md5sum $vg $lv1
+lvremove -ff $vg
+
+# Testing pvmove of stripe LV
+lvcreate -aey -l 2 -n ${lv1}_foo $vg "$dev1"
+lvcreate -aey -l 4 -i 2 -n $lv1 $vg "$dev1" "$dev2"
+check lv_tree_on $vg ${lv1}_foo "$dev1"
+check lv_tree_on $vg $lv1 "$dev1" "$dev2"
+aux mkdev_md5sum $vg $lv1
+pvmove "$dev1" "$dev5"
+check lv_tree_on $vg ${lv1}_foo "$dev5"
+check lv_tree_on $vg $lv1 "$dev2" "$dev5"
+check dev_md5sum $vg $lv1
+pvmove -n $lv1 "$dev5" "$dev4"
+check lv_tree_on $vg $lv1 "$dev2" "$dev4"
+check lv_tree_on $vg ${lv1}_foo "$dev5"
+check dev_md5sum $vg $lv1
+lvremove -ff $vg
+
+if test -e LOCAL_CLVMD ; then
+#FIXME these tests currently fail end require cmirrord
+echo "$(should false)FIXME!!! pvmove in clustered VG not fully supported!"
+else
+
+# Testing pvmove of mirror LV
+lvcreate -aey -l 2 -n ${lv1}_foo $vg "$dev1"
+lvcreate -aey -l 2 --type mirror -m 1 -n $lv1 $vg "$dev1" "$dev2"
+check lv_tree_on $vg ${lv1}_foo "$dev1"
+check lv_tree_on $vg $lv1 "$dev1" "$dev2"
+aux mkdev_md5sum $vg $lv1
+pvmove "$dev1" "$dev5"
+check lv_tree_on $vg ${lv1}_foo "$dev5"
+check lv_tree_on $vg $lv1 "$dev2" "$dev5"
+check dev_md5sum $vg $lv1
+pvmove -n $lv1 "$dev5" "$dev4"
+check lv_tree_on $vg $lv1 "$dev2" "$dev4"
+check lv_tree_on $vg ${lv1}_foo "$dev5"
+check dev_md5sum $vg $lv1
+lvremove -ff $vg
+
+# Dummy LV and snap share dev1, while origin is on dev2
+# Testing pvmove of snapshot LV
+lvcreate -aey -l 2 -n ${lv1}_foo $vg "$dev1"
+lvcreate -aey -l 2 -n $lv1 $vg "$dev2"
+lvcreate -s $vg/$lv1 -l 2 -n snap "$dev1"
+check lv_tree_on $vg ${lv1}_foo "$dev1"
+check lv_tree_on $vg snap "$dev1"
+aux mkdev_md5sum $vg snap
+pvmove "$dev1" "$dev5"
+check lv_tree_on $vg ${lv1}_foo "$dev5"
+check lv_tree_on $vg snap "$dev5"
+check dev_md5sum $vg snap
+pvmove -n snap "$dev5" "$dev4"
+check lv_tree_on $vg snap "$dev4"
+check lv_tree_on $vg ${lv1}_foo "$dev5"
+check dev_md5sum $vg snap
+lvremove -ff $vg
+fi
+
+vgremove -ff $vg
diff --git a/test/shell/pvmove-background.sh b/test/shell/pvmove-background.sh
new file mode 100644
index 0000000..6a158e4
--- /dev/null
+++ b/test/shell/pvmove-background.sh
@@ -0,0 +1,36 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2014 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+# Check pvmove behavior when it's progress and machine is rebooted
+
+SKIP_WITH_LVMLOCKD=1
+
+. lib/inittest
+
+aux prepare_vg 3
+
+for mode in "--atomic" ""
+do
+lvcreate -aey -l1 -n $lv1 $vg "$dev1"
+
+lvs -o +devices | tee out
+grep "$dev1" out
+
+LVM_TEST_TAG="kill_me_$PREFIX" pvmove $mode -i 1 -b "$dev1" "$dev2"
+sleep 5 # arbitrary...
+lvs -o +devices | tee out
+not grep "pvmove" out
+lvs -o +devices | tee out
+grep "$dev2" out
+
+lvremove -ff $vg
+done
diff --git a/test/shell/pvmove-basic.sh b/test/shell/pvmove-basic.sh
index e95fc36..c02354d 100644
--- a/test/shell/pvmove-basic.sh
+++ b/test/shell/pvmove-basic.sh
@@ -1,5 +1,6 @@
-#!/bin/sh
-# Copyright (C) 2008-2012 Red Hat, Inc. All rights reserved.
+#!/usr/bin/env bash
+
+# Copyright (C) 2008-2013 Red Hat, Inc. All rights reserved.
# Copyright (C) 2007 NEC Corporation
#
# This copyrighted material is made available to anyone wishing to use,
@@ -8,94 +9,84 @@
#
# 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
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
test_description="ensure that pvmove works with basic options"
-. lib/test
+SKIP_WITH_LVMLOCKD=1
+
+. lib/inittest
-which mkfs.ext2 || skip
which md5sum || skip
# ---------------------------------------------------------------------
# Utilities
-lvdev_() {
- echo "$DM_DEV_DIR/$1/$2"
+create_vg_() {
+ vgcreate -s 128k "$vg" "${DEVICES[@]}"
}
-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
+# ---------------------------------------------------------------------
+# Common environment setup/cleanup for each sub testcases
+prepare_lvs_() {
+ lvcreate -aey -l2 -n $lv1 $vg "$dev1"
+ check lv_on $vg $lv1 "$dev1"
+ lvcreate -aey -l9 -i3 -n $lv2 $vg "$dev2" "$dev3" "$dev4"
+ check lv_on $vg $lv2 "$dev2" "$dev3" "$dev4"
+ lvextend -l+2 $vg/$lv1 "$dev2"
+ check lv_on $vg $lv1 "$dev1" "$dev2"
+ lvextend -l+2 $vg/$lv1 "$dev3"
+ lvextend -l+2 $vg/$lv1 "$dev1"
+ check lv_on $vg $lv1 "$dev1" "$dev2" "$dev3"
+ lvcreate -aey -l1 -n $lv3 $vg "$dev2"
+ check lv_on $vg $lv3 "$dev2"
+ aux mkdev_md5sum $vg $lv1
+ aux mkdev_md5sum $vg $lv2
+ aux mkdev_md5sum $vg $lv3
+ get lv_devices "$vg/$lv1" > "${lv1}_devs"
+ get lv_devices "$vg/$lv2" > "${lv2}_devs"
+ get lv_devices "$vg/$lv3" > "${lv3}_devs"
+ lvs -a -o name,size,seg_pe_ranges $vg
+ vgcfgbackup -f bak-$$ $vg
}
-save_dev_sum_() {
- mkfs.ext2 $1 > /dev/null && md5sum $1 > md5.$(basename $1)
+# Restore metadata content, since data are pvmove-ed
+# original content should be preserved
+restore_lvs_() {
+ vgcfgrestore -f bak-$$ $vg
+ vgchange -aey $vg
}
-check_dev_sum_() {
- md5sum -c md5.$(basename $1)
+lvs_not_changed_() {
+ for i in "${@}"; do
+ get lv_devices "$vg/$i" | tee out
+ diff "${i}_devs" out || \
+ (cat "${i}_devs"; die "Devices for LV $vg/$i differs!")
+ done
}
-create_vg_() {
- vgcreate -c n -s 128k $vg $(cat DEVICES)
+check_and_cleanup_lvs_() {
+ check dev_md5sum $vg $lv1
+ check dev_md5sum $vg $lv2
+ check dev_md5sum $vg $lv3
+ get lv_field $vg name -a >out
+ not grep "^\[pvmove" out
+ vgchange -an $vg
+ lvremove -ff $vg
+ (dm_table | not grep $vg) || \
+ die "ERROR: lvremove did leave some mappings in DM behind!"
}
+
# ---------------------------------------------------------------------
# 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=""
+get_devs
-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
-}
+create_vg_
-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!"
-}
+for mode in "--atomic" ""
+do
#COMM "check environment setup/cleanup"
prepare_lvs_
@@ -108,276 +99,265 @@ check_and_cleanup_lvs_
# 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
+restore_lvs_
+pvmove $mode -i1 -n $vg/$lv1 "$dev2" "$dev5"
+check lv_on $vg $lv1 "$dev1" "$dev5" "$dev3"
+lvs_not_changed_ $lv2 $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
+restore_lvs_
+pvmove $mode -i0 -n $vg/$lv1 "$dev1" "$dev4"
+check lv_on $vg $lv1 "$dev4" "$dev2" "$dev3"
+lvs_not_changed_ $lv2 $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
+restore_lvs_
+pvmove $mode -i0 -n $vg/$lv1 "$dev2" "$dev4"
+check lv_on $vg $lv1 "$dev1" "$dev4" "$dev3"
+lvs_not_changed_ $lv2 $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
+restore_lvs_
+pvmove $mode -i0 -n $vg/$lv1 "$dev3" "$dev4"
+check lv_on $vg $lv1 "$dev1" "$dev2" "$dev4"
+lvs_not_changed_ $lv2 $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
+restore_lvs_
+pvmove $mode -i0 "$dev4" "$dev5"
+check lv_on $vg $lv2 "$dev2" "$dev3" "$dev5"
+lvs_not_changed_ $lv1 $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
+restore_lvs_
+pvmove $mode -i0 "$dev3" "$dev5"
+check lv_on $vg $lv1 "$dev1" "$dev2" "$dev5"
+check lv_on $vg $lv2 "$dev2" "$dev5" "$dev4"
+lvs_not_changed_ $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"
+restore_lvs_
+pvmove $mode -i0 "$dev2" "$dev5"
+check lv_on $vg $lv1 "$dev1" "$dev5" "$dev3"
+check lv_on $vg $lv2 "$dev5" "$dev3" "$dev4"
+check lv_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
+restore_lvs_
+pvmove $mode -i0 -n $vg/$lv2 "$dev2" "$dev1"
+check lv_on $vg $lv2 "$dev1" "$dev3" "$dev4"
+lvs_not_changed_ $lv1 $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
+restore_lvs_
+pvmove $mode -i0 -n $vg/$lv2 "$dev3" "$dev1"
+check lv_on $vg $lv2 "$dev2" "$dev1" "$dev4"
+lvs_not_changed_ $lv1 $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
+restore_lvs_
+pvmove $mode -i0 -n $vg/$lv2 "$dev4" "$dev1"
+check lv_on $vg $lv2 "$dev2" "$dev3" "$dev1"
+lvs_not_changed_ $lv1 $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
+restore_lvs_
+pvmove $mode -i0 "$dev2":0-0 "$dev5"
+check lv_on $vg $lv2 "$dev5" "$dev2" "$dev3" "$dev4"
+lvs_not_changed_ $lv1 $lv3
check_and_cleanup_lvs_
-
+#exit 0
#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
+restore_lvs_
+pvmove $mode -i0 "$dev2":1-1 "$dev5"
+check lv_on $vg $lv2 "$dev2" "$dev3" "$dev4" "$dev5"
+lvs_not_changed_ $lv1 $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
+restore_lvs_
+pvmove $mode -i0 "$dev2":2-2 "$dev5"
+check lv_on $vg $lv2 "$dev2" "$dev5" "$dev3" "$dev4"
+lvs_not_changed_ $lv1 $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
+restore_lvs_
+pvmove $mode -i0 "$dev2":0-2 "$dev5"
+check lv_on $vg $lv2 "$dev5" "$dev3" "$dev4"
+lvs_not_changed_ $lv1 $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
+restore_lvs_
+pvmove $mode -i0 --alloc anywhere "$dev2":0-2 "$dev5":5-5 "$dev4":5-6
+check lv_on $vg $lv2 "$dev5" "$dev4" "$dev3"
+lvs_not_changed_ $lv1 $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
+restore_lvs_
+pvmove $mode -i0 --alloc anywhere "$dev2":0-2 "$dev3":5-5 "$dev4":5-5 "$dev5":5-5
+check lv_on $vg $lv2 "$dev3" "$dev4" "$dev5"
+lvs_not_changed_ $lv1 $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
+restore_lvs_
+not pvmove $mode -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
+lvs_not_changed_ $lv1 $lv2 $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
+restore_lvs_
+pvmove $mode -i0 --alloc anywhere "$dev3":0-2 "$dev3":5-7
+check lv_on $vg $lv2 "$dev2" "$dev3" "$dev4"
+lvs_not_changed_ $lv1 $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
+restore_lvs_
+#lvs -a -o name,size,seg_pe_ranges $vg
+#LV2 1.12m @TESTDIR@/dev/mapper/@PREFIX@pv2:0-2 @TESTDIR@/dev/mapper/@PREFIX@pv3:0-2 @TESTDIR@/dev/mapper/@PREFIX@pv4:0-2
+
+pvmove $mode -i0 --alloc anywhere "$dev3":0-2 "$dev3":5-7 "$dev5":5-6 "$dev4":5-5
+
+#lvs -a -o name,size,seg_pe_ranges $vg
+# Hmm is this correct ? - why pv2 is split
+#LV2 1.12m @TESTDIR@/dev/mapper/@PREFIX@pv2:0-1 @TESTDIR@/dev/mapper/@PREFIX@pv5:5-6 @TESTDIR@/dev/mapper/@PREFIX@pv4:0-1
+#LV2 1.12m @TESTDIR@/dev/mapper/@PREFIX@pv2:2-2 @TESTDIR@/dev/mapper/@PREFIX@pv3:5-5 @TESTDIR@/dev/mapper/@PREFIX@pv4:2-2
+check lv_on $vg $lv2 "$dev2" "$dev3" "$dev4" "$dev5"
+lvs_not_changed_ $lv1 $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
+restore_lvs_
+not pvmove $mode -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
+lvs_not_changed_ $lv1 $lv2 $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
+restore_lvs_
+pvmove $mode -i0 --alloc contiguous "$dev2":0-2 "$dev5":0-0 "$dev5":3-5 "$dev4":5-6
+check lv_on $vg $lv2 "$dev5" "$dev3" "$dev4"
+lvs_not_changed_ $lv1 $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
+restore_lvs_
+pvmove $mode -i0 "$dev3" "$dev5"
+check lv_on $vg $lv1 "$dev1" "$dev2" "$dev5"
+check lv_on $vg $lv2 "$dev2" "$dev5" "$dev4"
+lvs_not_changed_ $lv3
check_and_cleanup_lvs_
# ---
# move inactive LV
#COMM "move inactive LV: from pv2 to pv5"
-prepare_lvs_
+restore_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"
+pvmove $mode -i0 "$dev2" "$dev5"
+check lv_on $vg $lv1 "$dev1" "$dev5" "$dev3"
+check lv_on $vg $lv2 "$dev5" "$dev3" "$dev4"
+check lv_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"
+restore_lvs_
+pvmove $mode -i0 "$dev3" "$dev1"
+not pvmove $mode -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 lv_on $vg $lv1 "$dev1" "$dev2" "$dev1"
+check lv_on $vg $lv2 "$dev2" "$dev1" "$dev4"
+lvs_not_changed_ $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
+restore_lvs_
+not pvmove $mode -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
+lvs_not_changed_ $lv1 $lv2 $lv3
check_and_cleanup_lvs_
#COMM 'same source and destination: from pv1 to pv1'
-prepare_lvs_
-not pvmove -i0 "$dev1" "$dev1"
+restore_lvs_
+not pvmove $mode -i0 "$dev1" "$dev1"
#"(cleanup previous test)"
-lv_not_changed_ $vg/$lv1
-lv_not_changed_ $vg/$lv2
-lv_not_changed_ $vg/$lv3
+lvs_not_changed_ $lv1 $lv2 $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
+restore_lvs_
+not pvmove $mode --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
+lvs_not_changed_ $lv1 $lv2 $lv3
check_and_cleanup_lvs_
# ---------------------------------------------------------------------
#COMM "pvmove abort"
-prepare_lvs_
-pvmove -i100 -b "$dev1" "$dev3"
+restore_lvs_
+LVM_TEST_TAG="kill_me_$PREFIX" pvmove $mode -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 "${DEVICES[@]}"
pvcreate --metadatacopies 0 "$dev1" "$dev2"
create_vg_
-lvcreate -l4 -n $lv1 $vg "$dev1"
-pvmove "$dev1"
+lvcreate -aey -l4 -n $lv1 $vg "$dev1"
+pvmove $mode "$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
+not pvmove $mode -i 1 "$dev2"
+dmsetup info --noheadings -c -o suspended $vg-$lv1
+test "$(dmsetup info --noheadings -c -o suspended "$vg-$lv1")" = "Active"
+if dmsetup info $vg-pvmove0_mimage_0 > /dev/null; then
+ dmsetup remove $vg-pvmove0 $vg-pvmove0_mimage_0 $vg-pvmove0_mimage_1
+else
+ dmsetup remove $vg-pvmove0
+fi
+
+lvremove -ff $vg
+done
diff --git a/test/shell/pvmove-cache-segtypes.sh b/test/shell/pvmove-cache-segtypes.sh
new file mode 100644
index 0000000..0cd3a16
--- /dev/null
+++ b/test/shell/pvmove-cache-segtypes.sh
@@ -0,0 +1,177 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2014 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+test_description="ensure pvmove works with the cache segment types"
+SKIP_WITH_LVMLOCKD=1
+
+. lib/inittest
+
+# pvmove fails when a RAID LV is the origin of a cache LV
+# pvmoving cache types is currently disabled in tools/pvmove.c
+# So, for now we set everything up and make sure pvmove /isn't/ allowed.
+# This allows us to ensure that it is disallowed even when there are
+# stacking complications to consider.
+
+which md5sum || skip
+
+aux have_cache 1 3 0 || skip
+# for stacking
+aux have_thin 1 8 0 || skip
+aux have_raid 1 4 2 || skip
+
+aux prepare_vg 5 80
+
+for mode in "--atomic" ""
+do
+# Each of the following tests does:
+# 1) Create two LVs - one linear and one other segment type
+# The two LVs will share a PV.
+# 2) Move both LVs together
+# 3) Move only the second LV by name
+
+# Testing pvmove of cache-pool LV (can't check contents though)
+###############################################################
+lvcreate -aey -l 2 -n ${lv1}_foo $vg "$dev1"
+lvcreate --type cache-pool -n ${lv1}_pool -l 4 $vg "$dev1"
+check lv_tree_on $vg ${lv1}_foo "$dev1"
+check lv_tree_on $vg ${lv1}_pool "$dev1"
+
+pvmove $mode "$dev1" "$dev5" 2>&1 | tee out
+lvs -a -o+devices $vg
+check lv_tree_on $vg ${lv1}_pool "$dev5"
+check lv_tree_on $vg ${lv1}_foo "$dev5"
+
+lvremove -ff $vg
+dmsetup info -c | not grep $vg
+
+# Testing pvmove of origin LV
+#############################
+lvcreate -aey -l 2 -n ${lv1}_foo $vg "$dev1"
+lvcreate --type cache-pool -n ${lv1}_pool -l 4 $vg "$dev5"
+lvcreate --type cache -n $lv1 -l 8 $vg/${lv1}_pool "$dev1"
+
+check lv_tree_on $vg ${lv1}_foo "$dev1"
+check lv_tree_on $vg ${lv1}_pool_cpool "$dev5"
+check lv_tree_on $vg ${lv1} "$dev1"
+
+aux mkdev_md5sum $vg $lv1
+pvmove $mode "$dev1" "$dev3" 2>&1 | tee out
+check lv_tree_on $vg ${lv1}_foo "$dev3"
+#check lv_tree_on $vg ${lv1}_pool "$dev5"
+lvs -a -o name,attr,devices $vg
+check lv_tree_on $vg ${lv1} "$dev3"
+#check dev_md5sum $vg $lv1
+
+#pvmove $mode -n $lv1 "$dev3" "$dev1"
+#check lv_tree_on $vg ${lv1}_foo "$dev3"
+#check lv_tree_on $vg ${lv1}_pool "$dev5"
+#check lv_tree_on $vg ${lv1} "$dev1"
+#check dev_md5sum $vg $lv1
+lvremove -ff $vg
+dmsetup info -c | not grep $vg
+
+# Testing pvmove of a RAID origin LV
+####################################
+lvcreate -aey -l 2 -n ${lv1}_foo $vg "$dev1"
+lvcreate --type raid1 -m 1 -l 8 -n $lv1 $vg "$dev1" "$dev2"
+lvcreate --type cache -l 4 -n ${lv1}_pool $vg/$lv1 "$dev5"
+check lv_tree_on $vg ${lv1}_foo "$dev1"
+check lv_tree_on $vg ${lv1} "$dev1" "$dev2"
+check lv_tree_on $vg ${lv1}_pool_cpool "$dev5"
+
+aux mkdev_md5sum $vg $lv1
+pvmove $mode "$dev1" "$dev3" 2>&1 | tee out
+check lv_tree_on $vg ${lv1}_foo "$dev3"
+lvs -a -o+devices $vg
+not check lv_tree_on $vg ${lv1} "$dev1"
+#check lv_tree_on $vg ${lv1}_pool "$dev5"
+#check dev_md5sum $vg $lv1 -- THIS IS WHERE THINGS FAIL IF PVMOVE NOT DISALLOWED
+
+#pvmove $mode -n $lv1 "$dev3" "$dev1"
+#check lv_tree_on $vg ${lv1}_foo "$dev3"
+#check lv_tree_on $vg ${lv1} "$dev1" "$dev2"
+#check lv_tree_on $vg ${lv1}_pool "$dev5"
+#check dev_md5sum $vg $lv1
+lvremove -ff $vg
+dmsetup info -c | not grep $vg
+
+# Testing pvmove of a RAID cachepool (metadata and data)
+########################################################
+lvcreate -aey -l 2 -n ${lv1}_foo $vg "$dev1"
+lvcreate --type raid1 -L 6M -n meta $vg "$dev1" "$dev2"
+lvcreate --type raid1 -L 4M -n ${lv1}_pool $vg "$dev1" "$dev2"
+lvconvert --yes --type cache-pool $vg/${lv1}_pool --poolmetadata $vg/meta
+lvcreate --type cache -n $lv1 -L 8M $vg/${lv1}_pool "$dev5"
+
+check lv_tree_on $vg ${lv1}_foo "$dev1"
+check lv_tree_on $vg ${lv1}_pool_cpool "$dev1" "$dev2"
+check lv_tree_on $vg ${lv1} "$dev5"
+
+aux mkdev_md5sum $vg $lv1
+# This will move ${lv1}_foo and the cache-pool data & meta
+# LVs, both of which contain a RAID1 _rimage & _rmeta LV - 5 total LVs
+pvmove $mode "$dev1" "$dev3" 2>&1 | tee out
+check lv_tree_on $vg ${lv1}_foo "$dev3"
+not check lv_tree_on $vg ${lv1}_pool_cpool "$dev1"
+#check lv_tree_on $vg ${lv1} "$dev5"
+#check dev_md5sum $vg $lv1
+
+#pvmove $mode -n ${lv1}_pool "$dev3" "$dev1"
+#check lv_tree_on $vg ${lv1}_foo "$dev3"
+#check lv_tree_on $vg ${lv1}_pool "$dev1" "$dev2"
+#check lv_tree_on $vg ${lv1} "$dev5"
+#check dev_md5sum $vg $lv1
+lvremove -ff $vg
+dmsetup info -c | not grep $vg
+
+# Testing pvmove of Thin-pool on cache LV on RAID
+#################################################
+lvcreate -aey -l 2 -n ${lv1}_foo $vg "$dev1"
+# RAID for cachepool
+lvcreate --type raid1 -m 1 -L 6M -n meta $vg "$dev1" "$dev2"
+lvcreate --type raid1 -m 1 -L 4M -n cachepool $vg "$dev1" "$dev2"
+lvconvert --yes --type cache-pool $vg/cachepool --poolmetadata $vg/meta
+# RAID for thin pool data LV
+lvcreate --type raid1 -m 1 -L 8 -n thinpool $vg "$dev3" "$dev4"
+# Convert thin pool data to a cached LV
+lvconvert --type cache -Zy $vg/thinpool --cachepool $vg/cachepool
+# Create simple thin pool meta
+lvcreate -aey -L 2M -n meta $vg "$dev1"
+# Use thin pool data LV to build a thin pool
+lvconvert --yes --thinpool $vg/thinpool --poolmetadata $vg/meta
+# Create a thin lv for fun
+lvcreate -T $vg/thinpool -V 20 -n thin_lv
+
+check lv_tree_on $vg ${lv1}_foo "$dev1"
+check lv_tree_on $vg cachepool_cpool "$dev1" "$dev2"
+check lv_tree_on $vg thinpool "$dev1" "$dev3" "$dev4"
+
+aux mkdev_md5sum $vg thin_lv
+lvs -a -o name,attr,devices $vg
+# Should move ${lv1}_foo and thinpool_tmeta from dev1 to dev5
+pvmove $mode "$dev1" "$dev5" 2>&1 | tee out
+lvs -a -o name,attr,devices $vg
+check lv_tree_on $vg ${lv1}_foo "$dev5"
+not check lv_tree_on $vg cachepool_cpool "$dev1"
+check lv_tree_on $vg thinpool "$dev3" "$dev4" "$dev5" # Move non-cache tmeta
+#check dev_md5sum $vg/thin_lv
+
+#pvmove $mode -n $vg/cachepool "$dev5" "$dev1"
+#check lv_tree_on $vg ${lv1}_foo "$dev5"
+#check lv_tree_on $vg $vg/cachepool "$dev1" "$dev2"
+#check lv_tree_on $vg $vg/thinpool "$dev3" "$dev4"
+#check dev_md5sum $vg/thin_lv
+
+lvremove -ff $vg
+dmsetup info -c | not grep $vg
+
+done
diff --git a/test/shell/pvmove-lvs.sh b/test/shell/pvmove-lvs.sh
new file mode 100644
index 0000000..754f86a
--- /dev/null
+++ b/test/shell/pvmove-lvs.sh
@@ -0,0 +1,35 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2018 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+test_description="ensure pvmove works with lvs"
+SKIP_WITH_LVMLOCKD=1
+
+. lib/inittest
+
+aux throttle_dm_mirror || skip
+
+aux prepare_vg 5 180
+
+lvcreate -aey -L30 -n $lv1 $vg "$dev1"
+lvextend -L+30 $vg/$lv1 "$dev2"
+lvextend -L+30 $vg/$lv1 "$dev1"
+lvextend -L+30 $vg/$lv1 "$dev2"
+lvextend -L+30 $vg/$lv1 "$dev1"
+
+pvmove -b "$dev1" "$dev5" 2>&1 | tee out
+
+#lvchange -an $vg/$lv1
+lvs -a $vg
+
+pvmove --abort
+
+lvremove -ff $vg
diff --git a/test/shell/pvmove-raid-segtypes.sh b/test/shell/pvmove-raid-segtypes.sh
new file mode 100644
index 0000000..6584b74
--- /dev/null
+++ b/test/shell/pvmove-raid-segtypes.sh
@@ -0,0 +1,96 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2013 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+test_description="ensure pvmove works with raid segment types"
+SKIP_WITH_LVMLOCKD=1
+
+. lib/inittest
+
+which md5sum || skip
+
+aux have_raid 1 3 5 || skip
+
+aux prepare_pvs 5 20
+get_devs
+
+vgcreate -s 128k "$vg" "${DEVICES[@]}"
+
+for mode in "--atomic" ""
+do
+# Each of the following tests does:
+# 1) Create two LVs - one linear and one other segment type
+# The two LVs will share a PV.
+# 2) Move both LVs together
+# 3) Move only the second LV by name
+
+# Testing pvmove of RAID1 LV
+lvcreate -aey -l 2 -n ${lv1}_foo $vg "$dev1"
+lvcreate -aey --regionsize 16K -l 2 --type raid1 -m 1 -n $lv1 $vg "$dev1" "$dev2"
+check lv_tree_on $vg ${lv1}_foo "$dev1"
+check lv_tree_on $vg $lv1 "$dev1" "$dev2"
+aux mkdev_md5sum $vg $lv1
+pvmove $mode "$dev1" "$dev5"
+check lv_tree_on $vg ${lv1}_foo "$dev5"
+check lv_tree_on $vg $lv1 "$dev2" "$dev5"
+check dev_md5sum $vg $lv1
+pvmove $mode -n $lv1 "$dev5" "$dev4"
+check lv_tree_on $vg $lv1 "$dev2" "$dev4"
+check lv_tree_on $vg ${lv1}_foo "$dev5"
+check dev_md5sum $vg $lv1
+lvremove -ff $vg
+
+# Testing pvmove of RAID10 LV
+lvcreate -aey -l 2 -n ${lv1}_foo $vg "$dev1"
+lvcreate -aey -l 4 --type raid10 -i 2 -m 1 -n $lv1 $vg \
+ "$dev1" "$dev2" "$dev3" "$dev4"
+check lv_tree_on $vg ${lv1}_foo "$dev1"
+check lv_tree_on $vg $lv1 "$dev1" "$dev2" "$dev3" "$dev4"
+aux mkdev_md5sum $vg $lv1
+
+# Check collocation of SubLVs is prohibited
+not pvmove $mode -n ${lv1}_rimage_0 "$dev1" "$dev2"
+check lv_tree_on $vg $lv1 "$dev1" "$dev2" "$dev3" "$dev4"
+not pvmove $mode -n ${lv1}_rimage_1 "$dev2" "$dev1"
+check lv_tree_on $vg $lv1 "$dev1" "$dev2" "$dev3" "$dev4"
+not pvmove $mode -n ${lv1}_rmeta_0 "$dev1" "$dev3"
+check lv_tree_on $vg $lv1 "$dev1" "$dev2" "$dev3" "$dev4"
+
+pvmove $mode "$dev1" "$dev5"
+check lv_tree_on $vg ${lv1}_foo "$dev5"
+check lv_tree_on $vg $lv1 "$dev2" "$dev3" "$dev4" "$dev5"
+check dev_md5sum $vg $lv1
+pvmove $mode -n $lv1 "$dev5" "$dev1"
+check lv_tree_on $vg $lv1 "$dev1" "$dev2" "$dev3" "$dev4"
+check lv_tree_on $vg ${lv1}_foo "$dev5"
+check dev_md5sum $vg $lv1
+lvremove -ff $vg
+
+# Testing pvmove of RAID5 LV
+lvcreate -aey -l 2 -n ${lv1}_foo $vg "$dev1"
+lvcreate -aey -l 4 --type raid5 -i 2 -n $lv1 $vg \
+ "$dev1" "$dev2" "$dev3"
+check lv_tree_on $vg ${lv1}_foo "$dev1"
+check lv_tree_on $vg $lv1 "$dev1" "$dev2" "$dev3"
+aux mkdev_md5sum $vg $lv1
+pvmove $mode "$dev1" "$dev5"
+check lv_tree_on $vg ${lv1}_foo "$dev5"
+check lv_tree_on $vg $lv1 "$dev2" "$dev3" "$dev5"
+check dev_md5sum $vg $lv1
+pvmove $mode -n $lv1 "$dev5" "$dev4"
+check lv_tree_on $vg $lv1 "$dev2" "$dev3" "$dev4"
+check lv_tree_on $vg ${lv1}_foo "$dev5"
+check dev_md5sum $vg $lv1
+
+lvremove -ff $vg
+done
+
+vgremove -ff $vg
diff --git a/test/shell/pvmove-restart.sh b/test/shell/pvmove-restart.sh
new file mode 100644
index 0000000..1669187
--- /dev/null
+++ b/test/shell/pvmove-restart.sh
@@ -0,0 +1,103 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2013-2015 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+# Check pvmove behavior when it's progress and machine is rebooted
+
+. lib/inittest
+
+aux prepare_pvs 3 60
+
+vgcreate $SHARED -s 128k $vg "$dev1" "$dev2"
+pvcreate --metadatacopies 0 "$dev3"
+vgextend $vg "$dev3"
+
+# Slowdown writes
+# (FIXME: generates interesting race when not used)
+aux delay_dev "$dev3" 0 800 "$(get first_extent_sector "$dev3"):"
+test -e HAVE_DM_DELAY || skip
+
+for mode in "--atomic" ""
+do
+
+# Create multisegment LV
+lvcreate -an -Zn -l5 -n $lv1 $vg "$dev1"
+lvextend -l+10 $vg/$lv1 "$dev2"
+lvextend -l+5 $vg/$lv1 "$dev1"
+lvextend -l+10 $vg/$lv1 "$dev2"
+
+pvmove -i10 -n $vg/$lv1 "$dev1" "$dev3" $mode &
+PVMOVE=$!
+# Let's wait a bit till pvmove starts and kill it
+aux wait_pvmove_lv_ready "$vg-pvmove0"
+kill -9 $PVMOVE
+
+if test -e LOCAL_LVMPOLLD; then
+ aux prepare_lvmpolld
+fi
+
+wait
+
+# Simulate reboot - forcibly remove related devices
+
+# First take down $lv1 then it's pvmove0
+j=0
+for i in $lv1 pvmove0 pvmove0_mimage_0 pvmove0_mimage_1 ; do
+ while dmsetup status "$vg-$i" ; do
+ dmsetup remove "$vg-$i" && break
+ j=$(( j + 1 ))
+ test $j -le 100 || die "Cannot take down devices."
+ sleep .1;
+ done
+done
+dmsetup table | grep $PREFIX
+
+# Check we really have pvmove volume
+check lv_attr_bit type $vg/pvmove0 "p"
+
+if test -e LOCAL_CLVMD ; then
+ # giveup all clvmd locks (faster then restarting clvmd)
+ # no deactivation happen, nodes are already removed
+ #vgchange -an $vg
+ # FIXME: However above solution has one big problem
+ # as clvmd starts to abort on internal errors on various
+ # errors, based on the fact pvmove is killed -9
+ # Restart clvmd
+ kill "$(< LOCAL_CLVMD)"
+ for i in $(seq 1 100) ; do
+ test $i -eq 100 && die "Shutdown of clvmd is too slow."
+ pgrep clvmd || break
+ sleep .1
+ done # wait for the pid removal
+ aux prepare_clvmd
+fi
+
+# Only PVs should be left in table...
+dmsetup table
+
+# Restart pvmove
+# use exclusive activation to have usable pvmove without cmirrord
+LVM_TEST_TAG="kill_me_$PREFIX" vgchange --config 'activation{polling_interval=10}' -aey $vg
+aux wait_pvmove_lv_ready "$vg-pvmove0"
+dmsetup table
+
+pvmove --abort "$dev1"
+
+lvs -a -o+devices $vg
+
+lvremove -ff $vg
+aux kill_tagged_processes
+done
+
+# Restore delayed device back
+aux delay_dev "$dev3"
+
+vgremove -ff $vg
diff --git a/test/shell/pvmove-resume-1.sh b/test/shell/pvmove-resume-1.sh
new file mode 100644
index 0000000..0068ab2
--- /dev/null
+++ b/test/shell/pvmove-resume-1.sh
@@ -0,0 +1,244 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2015 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+# Check whether all available pvmove resume methods works as expected.
+# lvchange is able to resume pvmoves in progress.
+
+# 2 pvmove LVs in 2 VGs (1 per VG)
+
+SKIP_WITH_LVMLOCKD=1
+SKIP_WITH_CLVMD=1
+
+. lib/inittest
+
+aux prepare_pvs 4 30
+
+vgcreate -s 128k $vg "$dev1"
+vgcreate -s 128k $vg1 "$dev2"
+pvcreate --metadatacopies 0 "$dev3"
+pvcreate --metadatacopies 0 "$dev4"
+vgextend $vg "$dev3"
+vgextend $vg1 "$dev4"
+
+# $1 resume fn
+test_pvmove_resume() {
+ lvcreate -an -Zn -l30 -n $lv1 $vg
+ lvcreate -an -Zn -l30 -n $lv1 $vg1
+
+ aux delay_dev "$dev3" 0 30 "$(get first_extent_sector "$dev3"):"
+ test -e HAVE_DM_DELAY || { lvremove -f $vg $vg1; return 0; }
+ aux delay_dev "$dev4" 0 30 "$(get first_extent_sector "$dev4"):"
+
+ pvmove -i5 "$dev1" &
+ PVMOVE=$!
+ aux wait_pvmove_lv_ready "$vg-pvmove0"
+ kill $PVMOVE
+ test -e LOCAL_LVMPOLLD && aux prepare_lvmpolld
+
+ pvmove -i5 "$dev2" &
+ PVMOVE=$!
+ aux wait_pvmove_lv_ready "$vg1-pvmove0"
+ kill $PVMOVE
+ test -e LOCAL_LVMPOLLD && aux prepare_lvmpolld
+ wait
+
+ aux remove_dm_devs "$vg-$lv1" "$vg1-$lv1" "$vg-pvmove0" "$vg1-pvmove0"
+
+ check lv_attr_bit type $vg/pvmove0 "p"
+ check lv_attr_bit type $vg1/pvmove0 "p"
+
+ if test -e LOCAL_CLVMD ; then
+ # giveup all clvmd locks (faster then restarting clvmd)
+ # no deactivation happen, nodes are already removed
+ #vgchange -an $vg
+ # FIXME: However above solution has one big problem
+ # as clvmd starts to abort on internal errors on various
+ # errors, based on the fact pvmove is killed -9
+ # Restart clvmd
+ kill "$(< LOCAL_CLVMD)"
+ for i in $(seq 1 100) ; do
+ test $i -eq 100 && die "Shutdown of clvmd is too slow."
+ test -e "$CLVMD_PIDFILE" || break
+ sleep .1
+ done # wait for the pid removal
+ aux prepare_clvmd
+ fi
+
+ # call resume function (see below)
+ # with expected number of spawned
+ # bg polling as parameter
+ $1 2
+
+ aux enable_dev "$dev3" "$dev4"
+
+ for i in {100..0} ; do
+ lvs -ao name $vg $vg1 | grep "\[pvmove" || break
+ sleep .1
+ done
+ # wait for 10 secs at max
+ test $i -eq 0 && die "Pvmove is too slow or does not progress."
+
+ aux kill_tagged_processes
+
+ lvremove -ff $vg $vg1
+}
+
+lvchange_single() {
+ LVM_TEST_TAG="kill_me_$PREFIX" lvchange -aey $vg/$lv1
+ LVM_TEST_TAG="kill_me_$PREFIX" lvchange -aey $vg1/$lv1
+
+ if test -e LOCAL_LVMPOLLD; then
+ aux lvmpolld_dump | tee lvmpolld_dump.txt
+ aux check_lvmpolld_init_rq_count 1 "$vg/pvmove0"
+ aux check_lvmpolld_init_rq_count 1 "$vg1/pvmove0"
+ else
+ test "$(aux count_processes_with_tag)" -eq $1
+ fi
+}
+
+lvchange_all() {
+ LVM_TEST_TAG="kill_me_$PREFIX" lvchange -aey $vg/$lv1 $vg1/$lv1
+
+ if test -e LOCAL_LVMPOLLD; then
+ aux lvmpolld_dump | tee lvmpolld_dump.txt
+ aux check_lvmpolld_init_rq_count 1 "$vg/pvmove0"
+ aux check_lvmpolld_init_rq_count 1 "$vg1/pvmove0"
+ else
+ test "$(aux count_processes_with_tag)" -eq $1
+ fi
+}
+
+vgchange_single() {
+ LVM_TEST_TAG="kill_me_$PREFIX" vgchange -aey $vg
+ LVM_TEST_TAG="kill_me_$PREFIX" vgchange -aey $vg1
+
+ if test -e LOCAL_LVMPOLLD; then
+ aux lvmpolld_dump | tee lvmpolld_dump.txt
+ aux check_lvmpolld_init_rq_count 1 "$vg/pvmove0"
+ aux check_lvmpolld_init_rq_count 1 "$vg1/pvmove0"
+ else
+ test "$(aux count_processes_with_tag)" -eq "$1"
+ fi
+}
+
+vgchange_all() {
+ LVM_TEST_TAG="kill_me_$PREFIX" vgchange -aey $vg $vg1
+
+ if test -e LOCAL_LVMPOLLD; then
+ aux lvmpolld_dump | tee lvmpolld_dump.txt
+ aux check_lvmpolld_init_rq_count 1 "$vg/pvmove0"
+ aux check_lvmpolld_init_rq_count 1 "$vg1/pvmove0"
+ else
+ test "$(aux count_processes_with_tag)" -eq "$1"
+ fi
+}
+
+pvmove_fg() {
+ # pvmove resume requires LVs active...
+ LVM_TEST_TAG="kill_me_$PREFIX" vgchange --config 'activation{polling_interval=10}' -aey --poll n $vg $vg1
+
+ # ...also vgchange --poll n must not spawn any bg processes...
+ if test -e LOCAL_LVMPOLLD; then
+ aux lvmpolld_dump | tee lvmpolld_dump.txt
+ aux check_lvmpolld_init_rq_count 0 "$vg/pvmove0"
+ aux check_lvmpolld_init_rq_count 0 "$vg1/pvmove0"
+ else
+ test "$(aux count_processes_with_tag)" -eq 0
+ fi
+
+ # ...thus finish polling
+ get lv_field $vg name -a | grep -E "^\[?pvmove0"
+ get lv_field $vg1 name -a | grep -E "^\[?pvmove0"
+
+ # disable delay device
+ # fg pvmove would take ages to complete otherwise
+ aux enable_dev "$dev3" "$dev4"
+
+ pvmove
+}
+
+pvmove_bg() {
+ # pvmove resume requires LVs active...
+ LVM_TEST_TAG="kill_me_$PREFIX" vgchange --config 'activation{polling_interval=10}' -aey --poll n $vg $vg1
+
+ # ...also vgchange --poll n must not spawn any bg processes...
+ if test -e LOCAL_LVMPOLLD; then
+ aux lvmpolld_dump | tee lvmpolld_dump.txt
+ aux check_lvmpolld_init_rq_count 0 "$vg/pvmove0"
+ aux check_lvmpolld_init_rq_count 0 "$vg1/pvmove0"
+ else
+ test "$(aux count_processes_with_tag)" -eq 0
+ fi
+
+ # ...thus finish polling
+ get lv_field $vg name -a | grep -E "^\[?pvmove0"
+ get lv_field $vg1 name -a | grep -E "^\[?pvmove0"
+
+ LVM_TEST_TAG="kill_me_$PREFIX" pvmove -b -i0
+}
+
+pvmove_fg_single() {
+ # pvmove resume requires LVs active...
+ LVM_TEST_TAG="kill_me_$PREFIX" vgchange --config 'activation{polling_interval=10}' -aey --poll n $vg
+
+ # ...also vgchange --poll n must not spawn any bg processes...
+ if test -e LOCAL_LVMPOLLD; then
+ aux lvmpolld_dump | tee lvmpolld_dump.txt
+ aux check_lvmpolld_init_rq_count 0 "$vg/pvmove0"
+ aux check_lvmpolld_init_rq_count 0 "$vg1/pvmove0"
+ else
+ test "$(aux count_processes_with_tag)" -eq 0
+ fi
+
+ # ...thus finish polling
+ get lv_field $vg name -a | grep -E "^\[?pvmove0"
+ get lv_field $vg1 name -a | grep -E "^\[?pvmove0"
+
+ # disable delay device
+ # fg pvmove would take ages to complete otherwise
+ aux enable_dev "$dev3" "$dev4"
+
+ pvmove "$dev1"
+ pvmove "$dev2"
+}
+
+pvmove_bg_single() {
+ # pvmove resume requires LVs active...
+ LVM_TEST_TAG="kill_me_$PREFIX" vgchange --config 'activation{polling_interval=10}' -aey --poll n $vg
+
+ # ...also vgchange --poll n must not spawn any bg processes...
+ if test -e LOCAL_LVMPOLLD; then
+ aux lvmpolld_dump | tee lvmpolld_dump.txt
+ aux check_lvmpolld_init_rq_count 0 "$vg/pvmove0"
+ aux check_lvmpolld_init_rq_count 0 "$vg1/pvmove0"
+ else
+ test "$(aux count_processes_with_tag)" -eq 0
+ fi
+
+ # ...thus finish polling
+ get lv_field $vg name -a | grep -E "^\[?pvmove0"
+ get lv_field $vg1 name -a | grep -E "^\[?pvmove0"
+
+ LVM_TEST_TAG="kill_me_$PREFIX" pvmove -b "$dev1"
+ LVM_TEST_TAG="kill_me_$PREFIX" pvmove -b "$dev2"
+}
+
+test_pvmove_resume lvchange_single
+test_pvmove_resume lvchange_all
+test_pvmove_resume vgchange_single
+test_pvmove_resume vgchange_all
+test_pvmove_resume pvmove_fg
+test_pvmove_resume pvmove_fg_single
+test_pvmove_resume pvmove_bg
+test_pvmove_resume pvmove_bg_single
+
+vgremove -ff $vg $vg1
diff --git a/test/shell/pvmove-resume-2.sh b/test/shell/pvmove-resume-2.sh
new file mode 100644
index 0000000..3dea743
--- /dev/null
+++ b/test/shell/pvmove-resume-2.sh
@@ -0,0 +1,197 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2015 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+# Check whether all available pvmove resume methods works as expected.
+# lvchange is able to resume pvmoves in progress.
+
+# Moving 2 LVs in VG variant
+
+SKIP_WITH_LVMLOCKD=1
+SKIP_WITH_CLVMD=1
+
+. lib/inittest
+
+aux prepare_pvs 2 30
+
+vgcreate -s 128k $vg "$dev1"
+pvcreate --metadatacopies 0 "$dev2"
+vgextend $vg "$dev2"
+
+test_pvmove_resume() {
+ # 2 LVs on same device
+ lvcreate -an -Zn -l15 -n $lv1 $vg "$dev1"
+ lvcreate -an -Zn -l15 -n $lv2 $vg "$dev1"
+
+ aux delay_dev "$dev2" 0 30 "$(get first_extent_sector "$dev2"):"
+
+ pvmove -i5 "$dev1" &
+ PVMOVE=$!
+ aux wait_pvmove_lv_ready "$vg-pvmove0"
+ kill $PVMOVE
+
+ test -e LOCAL_LVMPOLLD && aux prepare_lvmpolld
+ wait
+ aux remove_dm_devs "$vg-$lv1" "$vg-$lv2" "$vg-pvmove0"
+
+ check lv_attr_bit type $vg/pvmove0 "p"
+
+ if test -e LOCAL_CLVMD ; then
+ # giveup all clvmd locks (faster then restarting clvmd)
+ # no deactivation happen, nodes are already removed
+ #vgchange -an $vg
+ # FIXME: However above solution has one big problem
+ # as clvmd starts to abort on internal errors on various
+ # errors, based on the fact pvmove is killed -9
+ # Restart clvmd
+ kill "$(< LOCAL_CLVMD)"
+ for i in {1..100} ; do
+ test $i -eq 100 && die "Shutdown of clvmd is too slow."
+ test -e "$CLVMD_PIDFILE" || break
+ sleep .1
+ done # wait for the pid removal
+ aux prepare_clvmd
+ fi
+
+ # call resume function (see below)
+ # with expected number of spawned
+ # bg polling as parameter
+ $1 1
+
+ aux enable_dev "$dev2"
+
+ for i in {100..0} ; do # wait for 10 secs at max
+ get lv_field $vg name -a | grep -E "^\[?pvmove" || break
+ sleep .1
+ done
+ test $i -gt 0 || die "Pvmove is too slow or does not progress."
+
+ aux kill_tagged_processes
+
+ lvremove -ff $vg
+}
+
+lvchange_single() {
+ LVM_TEST_TAG="kill_me_$PREFIX" lvchange -aey $vg/$lv1
+ LVM_TEST_TAG="kill_me_$PREFIX" lvchange -aey $vg/$lv2
+}
+
+lvchange_all() {
+ LVM_TEST_TAG="kill_me_$PREFIX" lvchange -aey $vg/$lv1 $vg/$lv2
+
+ # we don't want to spawn more than $1 background pollings
+ if test -e LOCAL_LVMPOLLD; then
+ aux lvmpolld_dump | tee lvmpolld_dump.txt
+ aux check_lvmpolld_init_rq_count 1 "$vg/pvmove0" || should false
+ elif test -e HAVE_DM_DELAY; then
+ test "$(aux count_processes_with_tag)" -eq "$1" || {
+ # FIXME: currently lvm2 is spawning polling process for each LV
+ echo "Lvchange spawns pvmove per activated LV"
+ }
+ fi
+}
+
+vgchange_single() {
+ LVM_TEST_TAG="kill_me_$PREFIX" vgchange -aey $vg
+
+ if test -e LOCAL_LVMPOLLD; then
+ aux lvmpolld_dump | tee lvmpolld_dump.txt
+ aux check_lvmpolld_init_rq_count 1 "$vg/pvmove0"
+ elif test -e HAVE_DM_DELAY; then
+ test "$(aux count_processes_with_tag)" -eq "$1"
+ fi
+}
+
+pvmove_fg() {
+ # pvmove resume requires LVs active...
+ LVM_TEST_TAG="kill_me_$PREFIX" vgchange --config 'activation{polling_interval=10}' -aey --poll n $vg
+
+ # ...also vgchange --poll n must not spawn any bg processes
+ if test -e LOCAL_LVMPOLLD; then
+ aux lvmpolld_dump | tee lvmpolld_dump.txt
+ aux check_lvmpolld_init_rq_count 0 "$vg/pvmove0"
+ else
+ test "$(aux count_processes_with_tag)" -eq 0
+ fi
+
+ # ...thus finish polling
+ get lv_field $vg name -a | grep -E "^\[?pvmove0"
+
+ aux enable_dev "$dev2"
+
+ pvmove
+}
+
+pvmove_bg() {
+ # pvmove resume requires LVs active...
+ LVM_TEST_TAG="kill_me_$PREFIX" vgchange --config 'activation{polling_interval=10}' -aey --poll n $vg
+
+ # ...also vgchange --poll n must not spawn any bg processes
+ if test -e LOCAL_LVMPOLLD; then
+ aux lvmpolld_dump | tee lvmpolld_dump.txt
+ aux check_lvmpolld_init_rq_count 0 "$vg/pvmove0"
+ else
+ test "$(aux count_processes_with_tag)" -eq 0
+ fi
+
+ # ...thus finish polling
+ get lv_field $vg name -a | grep -E "^\[?pvmove0"
+
+ LVM_TEST_TAG="kill_me_$PREFIX" pvmove -b
+}
+
+pvmove_fg_single() {
+ # pvmove resume requires LVs active...
+ LVM_TEST_TAG="kill_me_$PREFIX" vgchange --config 'activation{polling_interval=10}' -aey --poll n $vg
+
+ # ...also vgchange --poll n must not spawn any bg processes
+ if test -e LOCAL_LVMPOLLD; then
+ aux lvmpolld_dump | tee lvmpolld_dump.txt
+ aux check_lvmpolld_init_rq_count 0 "$vg/pvmove0"
+ else
+ test "$(aux count_processes_with_tag)" -eq 0
+ fi
+
+ # ...thus finish polling
+ get lv_field $vg name -a | grep -E "^\[?pvmove0"
+
+ aux enable_dev "$dev2"
+
+ pvmove "$dev1"
+}
+
+pvmove_bg_single() {
+ # pvmove resume requires LVs active...
+ LVM_TEST_TAG="kill_me_$PREFIX" vgchange --config 'activation{polling_interval=10}' -aey --poll n $vg
+
+ # ...also vgchange --poll n must not spawn any bg processes...
+ if test -e LOCAL_LVMPOLLD; then
+ aux lvmpolld_dump | tee lvmpolld_dump.txt
+ aux check_lvmpolld_init_rq_count 0 "$vg/pvmove0"
+ else
+ test "$(aux count_processes_with_tag)" -eq 0
+ fi
+
+ # ...thus finish polling
+ get lv_field $vg name -a | grep -E "^\[?pvmove0"
+
+ LVM_TEST_TAG="kill_me_$PREFIX" pvmove -b "$dev1"
+}
+
+test_pvmove_resume lvchange_single
+test_pvmove_resume lvchange_all
+test_pvmove_resume vgchange_single
+test_pvmove_resume pvmove_fg
+test_pvmove_resume pvmove_fg_single
+test_pvmove_resume pvmove_bg
+test_pvmove_resume pvmove_bg_single
+
+vgremove -ff $vg
diff --git a/test/shell/pvmove-resume-multiseg.sh b/test/shell/pvmove-resume-multiseg.sh
new file mode 100644
index 0000000..5cebd99
--- /dev/null
+++ b/test/shell/pvmove-resume-multiseg.sh
@@ -0,0 +1,222 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2015 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+# Check whether all available pvmove resume methods works as expected.
+# lvchange is able to resume pvmoves in progress.
+
+# Multisegment variant w/ 2 pvmoves LVs per VG
+
+SKIP_WITH_LVMLOCKD=1
+
+. lib/inittest
+
+aux prepare_pvs 5 40
+
+vgcreate -s 128k $vg "$dev1" "$dev2" "$dev3"
+pvcreate --metadatacopies 0 "$dev4" "$dev5"
+vgextend $vg "$dev4" "$dev5"
+
+# $1 resume fn
+test_pvmove_resume() {
+ # Create multisegment LV
+ lvcreate -an -Zn -l50 -n $lv1 $vg "$dev1"
+ lvextend -l+50 $vg/$lv1 "$dev2"
+ # next LV on same VG and differetnt PV (we want to test 2 pvmoves per VG)
+ lvcreate -an -Zn -l50 -n $lv2 $vg "$dev3"
+
+ aux delay_dev "$dev4" 0 30 "$(get first_extent_sector "$dev4"):"
+ test -e HAVE_DM_DELAY || { lvremove -f $vg; return 0; }
+ aux delay_dev "$dev5" 0 30 "$(get first_extent_sector "$dev5"):"
+
+ pvmove -i5 "$dev1" "$dev4" &
+ PVMOVE=$!
+ aux wait_pvmove_lv_ready "$vg-pvmove0"
+ kill $PVMOVE
+
+ pvmove -i5 -n $vg/$lv2 "$dev3" "$dev5" &
+ PVMOVE=$!
+ aux wait_pvmove_lv_ready "$vg-pvmove1"
+ kill $PVMOVE
+
+ test -e LOCAL_LVMPOLLD && aux prepare_lvmpolld
+ wait
+ aux remove_dm_devs "$vg-$lv1" "$vg-$lv2" "$vg-pvmove0" "$vg-pvmove1"
+
+ check lv_attr_bit type $vg/pvmove0 "p"
+ check lv_attr_bit type $vg/pvmove1 "p"
+
+ if test -e LOCAL_CLVMD ; then
+ # giveup all clvmd locks (faster then restarting clvmd)
+ # no deactivation happen, nodes are already removed
+ #vgchange -an $vg
+ # FIXME: However above solution has one big problem
+ # as clvmd starts to abort on internal errors on various
+ # errors, based on the fact pvmove is killed -9
+ # Restart clvmd
+ kill "$(< LOCAL_CLVMD)"
+ for i in $(seq 1 100) ; do
+ test $i -eq 100 && die "Shutdown of clvmd is too slow."
+ test -e "$CLVMD_PIDFILE" || break
+ sleep .1
+ done # wait for the pid removal
+ aux prepare_clvmd
+ fi
+
+ # call resume function (see below)
+ # with expected number of spawned
+ # bg polling as parameter
+ $1 2
+
+ aux enable_dev "$dev4" "$dev5"
+
+ for i in {100..0} ; do # wait for 10 secs at max
+ get lv_field $vg name -a | grep -E "^\[?pvmove" || break
+ sleep .1
+ done
+ test $i -gt 0 || die "Pvmove is too slow or does not progress."
+
+ aux kill_tagged_processes
+
+ lvremove -ff $vg
+ # drop debug logs from killed lvm2 commands
+ rm -f debug.log_DEBUG*
+}
+
+lvchange_single() {
+ LVM_TEST_TAG="kill_me_$PREFIX" lvchange -aey $vg/$lv1
+ LVM_TEST_TAG="kill_me_$PREFIX" lvchange -aey $vg/$lv2
+}
+
+lvchange_all() {
+ LVM_TEST_TAG="kill_me_$PREFIX" lvchange -aey $vg/$lv1 $vg/$lv2
+
+ # we don't want to spawn more than $1 background pollings
+ if test -e LOCAL_LVMPOLLD; then
+ aux lvmpolld_dump | tee lvmpolld_dump.txt
+ aux check_lvmpolld_init_rq_count 1 "$vg/pvmove0"
+ aux check_lvmpolld_init_rq_count 1 "$vg/pvmove1"
+ else
+ test "$(aux count_processes_with_tag)" -eq $1
+ fi
+}
+
+vgchange_single() {
+ LVM_TEST_TAG="kill_me_$PREFIX" vgchange -aey $vg
+
+ if test -e LOCAL_LVMPOLLD; then
+ aux lvmpolld_dump | tee lvmpolld_dump.txt
+ aux check_lvmpolld_init_rq_count 1 "$vg/pvmove0"
+ aux check_lvmpolld_init_rq_count 1 "$vg/pvmove1"
+ else
+ test "$(aux count_processes_with_tag)" -eq "$1"
+ fi
+}
+
+pvmove_fg() {
+ # pvmove resume requires LVs active...
+ LVM_TEST_TAG="kill_me_$PREFIX" vgchange --config 'activation{polling_interval=10}' -aey --poll n $vg
+
+ # ...also vgchange --poll n must not spawn any bg processes...
+ if test -e LOCAL_LVMPOLLD; then
+ aux lvmpolld_dump | tee lvmpolld_dump.txt
+ aux check_lvmpolld_init_rq_count 0 "$vg/pvmove0"
+ aux check_lvmpolld_init_rq_count 0 "$vg/pvmove1"
+ else
+ test "$(aux count_processes_with_tag)" -eq 0
+ fi
+
+ # ...thus finish polling
+ get lv_field $vg name -a | grep -E "^\[?pvmove0"
+ get lv_field $vg name -a | grep -E "^\[?pvmove1"
+
+ # disable delay device
+ # fg pvmove would take ages to complete otherwise
+ aux enable_dev "$dev4" "$dev5"
+
+ LVM_TEST_TAG="kill_me_$PREFIX" pvmove
+}
+
+pvmove_bg() {
+ # pvmove resume requires LVs active...
+ LVM_TEST_TAG="kill_me_$PREFIX" vgchange --config 'activation{polling_interval=10}' -aey --poll n $vg
+
+ # ...also vgchange --poll n must not spawn any bg processes...
+ if test -e LOCAL_LVMPOLLD; then
+ aux lvmpolld_dump | tee lvmpolld_dump.txt
+ aux check_lvmpolld_init_rq_count 0 "$vg/pvmove0"
+ aux check_lvmpolld_init_rq_count 0 "$vg/pvmove1"
+ else
+ test "$(aux count_processes_with_tag)" -eq 0
+ fi
+
+ # ...thus finish polling
+ get lv_field $vg name -a | grep -E "^\[?pvmove0"
+ get lv_field $vg name -a | grep -E "^\[?pvmove1"
+
+ LVM_TEST_TAG="kill_me_$PREFIX" pvmove -b
+}
+
+pvmove_fg_single() {
+ # pvmove resume requires LVs active...
+ LVM_TEST_TAG="kill_me_$PREFIX" vgchange --config 'activation{polling_interval=10}' -aey --poll n $vg
+
+ # ...also vgchange --poll n must not spawn any bg processes...
+ if test -e LOCAL_LVMPOLLD; then
+ aux lvmpolld_dump | tee lvmpolld_dump.txt
+ aux check_lvmpolld_init_rq_count 0 "$vg/pvmove0"
+ aux check_lvmpolld_init_rq_count 0 "$vg/pvmove1"
+ else
+ test "$(aux count_processes_with_tag)" -eq 0
+ fi
+
+ # ...thus finish polling
+ get lv_field $vg name -a | grep -E "^\[?pvmove0"
+ get lv_field $vg name -a | grep -E "^\[?pvmove1"
+
+ # disable delay device
+ # fg pvmove would take ages to complete otherwise
+ aux enable_dev "$dev4" "$dev5"
+
+ LVM_TEST_TAG="kill_me_$PREFIX" pvmove "$dev1"
+ LVM_TEST_TAG="kill_me_$PREFIX" pvmove "$dev3"
+}
+
+pvmove_bg_single() {
+ # pvmove resume requires LVs active...
+ LVM_TEST_TAG="kill_me_$PREFIX" vgchange --config 'activation{polling_interval=10}' -aey --poll n $vg
+
+ # ...also vgchange --poll n must not spawn any bg processes...
+ if test -e LOCAL_LVMPOLLD; then
+ aux lvmpolld_dump | tee lvmpolld_dump.txt
+ aux check_lvmpolld_init_rq_count 0 "$vg/pvmove0"
+ aux check_lvmpolld_init_rq_count 0 "$vg/pvmove1"
+ else
+ test "$(aux count_processes_with_tag)" -eq 0
+ fi
+
+ # ...thus finish polling
+ get lv_field $vg name -a | grep -E "^\[?pvmove0"
+ get lv_field $vg name -a | grep -E "^\[?pvmove1"
+
+ LVM_TEST_TAG="kill_me_$PREFIX" pvmove -b "$dev1"
+ LVM_TEST_TAG="kill_me_$PREFIX" pvmove -b "$dev3"
+}
+
+test_pvmove_resume lvchange_single
+test_pvmove_resume lvchange_all
+test_pvmove_resume vgchange_single
+test_pvmove_resume pvmove_fg
+test_pvmove_resume pvmove_fg_single
+test_pvmove_resume pvmove_bg
+test_pvmove_resume pvmove_bg_single
+
+vgremove -ff $vg
diff --git a/test/shell/pvmove-thin-segtypes.sh b/test/shell/pvmove-thin-segtypes.sh
new file mode 100644
index 0000000..f8c65f5
--- /dev/null
+++ b/test/shell/pvmove-thin-segtypes.sh
@@ -0,0 +1,77 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2013 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+test_description="ensure pvmove works with thin segment types"
+SKIP_WITH_LVMLOCKD=1
+
+. lib/inittest
+
+which md5sum || skip
+
+aux have_thin 1 8 0 || skip
+# for stacking
+aux have_raid 1 3 5 || skip
+
+aux prepare_pvs 5 20
+get_devs
+
+vgcreate -s 128k "$vg" "${DEVICES[@]}"
+
+for mode in "--atomic" ""
+do
+
+# Each of the following tests does:
+# 1) Create two LVs - one linear and one other segment type
+# The two LVs will share a PV.
+# 2) Move both LVs together
+# 3) Move only the second LV by name
+
+
+# Testing pvmove of thin LV
+lvcreate -aey -l 2 -n ${lv1}_foo $vg "$dev1"
+lvcreate -aey -T $vg/${lv1}_pool -l8 -V 8 -n $lv1 "$dev1"
+check lv_tree_on $vg ${lv1}_foo "$dev1"
+check lv_tree_on $vg $lv1 "$dev1"
+aux mkdev_md5sum $vg $lv1
+pvmove "$dev1" "$dev5" $mode
+check lv_tree_on $vg ${lv1}_foo "$dev5"
+check lv_tree_on $vg $lv1 "$dev5"
+check dev_md5sum $vg $lv1
+pvmove -n $lv1 "$dev5" "$dev4" $mode
+check lv_tree_on $vg $lv1 "$dev4"
+check lv_tree_on $vg ${lv1}_foo "$dev5"
+check dev_md5sum $vg $lv1
+lvremove -ff $vg
+
+# Testing pvmove of thin LV on RAID
+lvcreate -aey -l 2 -n ${lv1}_foo $vg "$dev1"
+lvcreate -aey --type raid1 -m 1 -l 8 -n ${lv1}_raid1_pool $vg "$dev1" "$dev2"
+lvcreate -aey --type raid1 -m 1 -L 2 -n ${lv1}_raid1_meta $vg "$dev1" "$dev2"
+lvconvert --yes --thinpool $vg/${lv1}_raid1_pool \
+ --poolmetadata ${lv1}_raid1_meta
+lvcreate -aey -T $vg/${lv1}_raid1_pool -V 8 -n $lv1
+check lv_tree_on $vg ${lv1}_foo "$dev1"
+check lv_tree_on $vg $lv1 "$dev1" "$dev2"
+aux mkdev_md5sum $vg $lv1
+pvmove "$dev1" "$dev5" $mode
+check lv_tree_on $vg ${lv1}_foo "$dev5"
+check lv_tree_on $vg $lv1 "$dev2" "$dev5"
+check dev_md5sum $vg $lv1
+pvmove -n $lv1 "$dev5" "$dev4" $mode
+check lv_tree_on $vg $lv1 "$dev2" "$dev4"
+check lv_tree_on $vg ${lv1}_foo "$dev5"
+check dev_md5sum $vg $lv1
+lvremove -ff $vg
+
+done
+
+vgremove -ff $vg
diff --git a/test/shell/pvremove-thin.sh b/test/shell/pvremove-thin.sh
new file mode 100644
index 0000000..4512557
--- /dev/null
+++ b/test/shell/pvremove-thin.sh
@@ -0,0 +1,35 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2014 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+# Checks we are not reading our own devices
+# https://bugzilla.redhat.com/show_bug.cgi?id=1064374
+
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+aux prepare_vg
+
+aux have_thin 1 8 0 || skip
+
+aux extend_filter_LVMTEST
+
+lvcreate -L10 -V10 -n $lv1 -T $vg/pool1
+
+aux extend_devices "$DM_DEV_DIR/$vg/$lv1"
+aux lvmconf "devices/scan_lvs = 1"
+
+pvcreate "$DM_DEV_DIR/$vg/$lv1"
+pvremove "$DM_DEV_DIR/$vg/$lv1"
+
+vgremove -ff $vg
diff --git a/test/shell/pvremove-usage.sh b/test/shell/pvremove-usage.sh
index c6d724b..17d90e6 100644
--- a/test/shell/pvremove-usage.sh
+++ b/test/shell/pvremove-usage.sh
@@ -1,4 +1,5 @@
-#!/bin/sh
+#!/usr/bin/env bash
+
# Copyright (C) 2008 Red Hat, Inc. All rights reserved.
#
# This copyrighted material is made available to anyone wishing to use,
@@ -7,23 +8,33 @@
#
# 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
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+
+SKIP_WITH_LVMPOLLD=1
-. lib/test
+. lib/inittest
aux prepare_devs 3
pvcreate "$dev1"
pvcreate --metadatacopies 0 "$dev2"
pvcreate --metadatacopies 2 "$dev3"
+
+# Fails without give argument
+not pvremove
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"
+pvs -a | grep "$dev2"
+# bz1108394 no crash on nonPV label listing
+pvs -a -o+devices
+
pvcreate --metadatacopies 0 "$dev2"
# check pvremove refuses to remove pv in a vg
-vgcreate -c n $vg "$dev1" "$dev2"
+vgcreate $SHARED $vg "$dev1" "$dev2"
not pvremove "$dev2" "$dev3"
for mdacp in 0 1 2; do
@@ -42,17 +53,20 @@ for mdacp in 0 1 2; do
vgremove -ff $vg
pvcreate --metadatacopies $mdacp "$dev1"
pvcreate "$dev2"
- vgcreate $vg "$dev1" "$dev2"
+ vgcreate $SHARED $vg "$dev1" "$dev2"
# pvremove -f fails when pv in a vg (---metadatacopies $mdacp)
- not pvremove -f "$dev1"
+ not pvremove -f "$dev1" 2>&1 | tee out
+ grep "is used" out
pvs "$dev1"
# pvremove -ff fails without confirmation when pv in a vg (---metadatacopies $mdacp)
- echo n | not pvremove -ff "$dev1"
+ not pvremove -ff "$dev1" 2>&1 | tee out
+ grep "is used" out
# pvremove -ff succeds with confirmation when pv in a vg (---metadatacopies $mdacp)
- pvremove -ffy "$dev1"
+ pvremove -ffy "$dev1" 2>&1 | tee out
+ grep "is used" out
not pvs "$dev1"
vgreduce --removemissing $vg
@@ -66,3 +80,5 @@ for mdacp in 0 1 2; do
pvcreate --metadatacopies $mdacp "$dev1"
vgextend $vg "$dev1"
done
+
+vgremove -ff $vg
diff --git a/test/shell/pvremove-warnings.sh b/test/shell/pvremove-warnings.sh
new file mode 100644
index 0000000..dc3178d
--- /dev/null
+++ b/test/shell/pvremove-warnings.sh
@@ -0,0 +1,26 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2014 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+aux prepare_devs 2
+pvcreate "$dev1" "$dev2"
+pvremove "$dev1" "$dev2" 2>&1 | tee pvremove.txt
+not grep "No physical" pvremove.txt
+
+pvcreate "$dev1" "$dev2"
+vgcreate $SHARED bla "$dev1" "$dev2"
+pvremove -ff -y "$dev1" "$dev2" 2>&1 | tee pvremove.txt
+not grep "device missing" pvremove.txt
diff --git a/test/shell/pvresize-mdas.sh b/test/shell/pvresize-mdas.sh
new file mode 100644
index 0000000..240dfb2
--- /dev/null
+++ b/test/shell/pvresize-mdas.sh
@@ -0,0 +1,38 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2016 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+aux prepare_devs 1 8
+
+pvcreate --setphysicalvolumesize 8m --metadatacopies 2 "$dev1"
+check pv_field "$dev1" pv_size 8.00m
+check pv_field "$dev1" pv_mda_count 2
+pvs "$dev1"
+
+pvresize --setphysicalvolumesize 4m -y "$dev1"
+check pv_field "$dev1" pv_size 4.00m
+check pv_field "$dev1" pv_mda_count 2
+pvs "$dev1"
+
+# Check physical size is checked agains metadatasize
+pvcreate --metadatasize 2m --metadatacopies 1 -y "$dev1"
+not pvresize --setphysicalvolumesize 2m -y "$dev1" |& tee out
+grep "Size must exceed physical extent start of 6144 sectors on" out
+# 3MiB shall pass with 1M default alignment
+pvresize --setphysicalvolumesize 3m -y "$dev1"
+check pv_field "$dev1" pv_size 3.00m
+check pv_field "$dev1" pv_mda_count 1
+pvs "$dev1"
diff --git a/test/shell/pvscan-autoactivate.sh b/test/shell/pvscan-autoactivate.sh
new file mode 100644
index 0000000..f574731
--- /dev/null
+++ b/test/shell/pvscan-autoactivate.sh
@@ -0,0 +1,240 @@
+#!/usr/bin/env 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+SKIP_WITH_LVMPOLLD=1
+
+RUNDIR="/run"
+test -d "$RUNDIR" || RUNDIR="/var/run"
+PVS_ONLINE_DIR="$RUNDIR/lvm/pvs_online"
+VGS_ONLINE_DIR="$RUNDIR/lvm/vgs_online"
+PVS_LOOKUP_DIR="$RUNDIR/lvm/pvs_lookup"
+
+# FIXME: kills logic for running system
+_clear_online_files() {
+ # wait till udev is finished
+ aux udev_wait
+ rm -f "$PVS_ONLINE_DIR"/*
+ rm -f "$VGS_ONLINE_DIR"/*
+ rm -f "$PVS_LOOKUP_DIR"/*
+}
+
+. lib/inittest
+
+aux prepare_devs 8 16
+
+# Check 'pvscan' is ignored when event_activation is 0
+pvscan --cache -aay -v --config 'global/event_activation=0' 2>&1 | tee out
+grep "Ignoring pvscan" out
+
+vgcreate $vg1 "$dev1" "$dev2"
+lvcreate -n $lv1 -l 4 -a n $vg1
+
+test -d "$PVS_ONLINE_DIR" || mkdir -p "$PVS_ONLINE_DIR"
+test -d "$VGS_ONLINE_DIR" || mkdir -p "$VGS_ONLINE_DIR"
+test -d "$PVS_LOOKUP_DIR" || mkdir -p "$PVS_LOOKUP_DIR"
+_clear_online_files
+
+# check pvscan with no args scans and activates all
+pvscan --cache -aay
+check lv_field $vg1/$lv1 lv_active "active"
+lvchange -an $vg1
+
+_clear_online_files
+
+# first dev leaves vg incomplete and inactive,
+# and second dev completes vg and activates
+pvscan --cache -aay "$dev1"
+check lv_field $vg1/$lv1 lv_active ""
+pvscan --cache -aay "$dev2"
+check lv_field $vg1/$lv1 lv_active "active"
+lvchange -an $vg1
+
+_clear_online_files
+
+# check that vg is activated when both devs
+# are scanned together
+pvscan --cache -aay "$dev1" "$dev2"
+check lv_field $vg1/$lv1 lv_active "active"
+lvchange -an $vg1
+
+# check that a cache command without aay will
+# just record online state, and that a following
+# pvscan cache aay that does not record any new
+# online files will activate the vg
+_clear_online_files
+pvscan --cache "$dev1"
+check lv_field $vg1/$lv1 lv_active ""
+pvscan --cache "$dev2"
+check lv_field $vg1/$lv1 lv_active ""
+pvscan --cache -aay
+check lv_field $vg1/$lv1 lv_active "active"
+lvchange -an $vg1
+
+# Set up tests where one dev has no metadata
+
+vgchange -an $vg1
+vgremove -ff $vg1
+pvremove "$dev1"
+pvremove "$dev2"
+pvcreate --metadatacopies 0 "$dev1"
+pvcreate --metadatacopies 1 "$dev2"
+vgcreate $vg1 "$dev1" "$dev2"
+lvcreate -n $lv1 -l 4 -a n $vg1
+
+
+_clear_online_files
+
+# test case where dev with metadata is scanned first
+pvscan --cache -aay "$dev2"
+check lv_field $vg1/$lv1 lv_active ""
+pvscan --cache -aay "$dev1"
+check lv_field $vg1/$lv1 lv_active "active"
+lvchange -an $vg1
+
+_clear_online_files
+pvscan --cache -aay "$dev1"
+check lv_field $vg1/$lv1 lv_active ""
+pvscan --cache -aay "$dev2"
+check lv_field $vg1/$lv1 lv_active "active"
+lvchange -an $vg1
+
+# use the --cache option to record a dev
+# is online without the -aay option to
+# activate until after they are online
+
+_clear_online_files
+
+pvscan --cache "$dev1"
+check lv_field $vg1/$lv1 lv_active ""
+pvscan --cache -aay "$dev2"
+check lv_field $vg1/$lv1 lv_active "active"
+lvchange -an $vg1
+
+vgremove -f $vg1
+
+# pvscan cache ignores pv that's not used
+
+pvcreate "$dev3"
+
+PVID3=$(pvs "$dev3" --noheading -o uuid | tr -d - | awk '{print $1}')
+echo $PVID3
+
+not ls "$RUNDIR/lvm/pvs_online/$PVID3"
+
+pvscan --cache -aay "$dev3"
+
+ls "$RUNDIR/lvm/pvs_online"
+not ls "$RUNDIR/lvm/pvs_online/$PVID3"
+
+
+# pvscan cache ignores pv in a foreign vg
+
+if [ -e "/etc/machine-id" ]; then
+
+aux lvmconf "global/system_id_source = machineid"
+
+_clear_online_files
+
+vgcreate $vg2 "$dev3"
+lvcreate -an -n $lv2 -l1 $vg2
+pvscan --cache -aay "$dev3"
+ls "$RUNDIR/lvm/pvs_online/$PVID3"
+check lv_field $vg2/$lv2 lv_active "active"
+lvchange -an $vg2
+rm "$RUNDIR/lvm/pvs_online/$PVID3"
+
+# a vg without a system id is not foreign, not ignored
+vgchange -y --systemid "" "$vg2"
+
+_clear_online_files
+pvscan --cache -aay "$dev3"
+ls "$RUNDIR/lvm/pvs_online/$PVID3"
+check lv_field $vg2/$lv2 lv_active "active"
+lvchange -an $vg2
+rm "$RUNDIR/lvm/pvs_online/$PVID3"
+
+# make the vg foreign by assigning a system id different from ours
+vgchange -y --systemid "asdf" "$vg2"
+
+_clear_online_files
+
+pvscan --cache -aay "$dev3"
+not ls "$RUNDIR/lvm/pvs_online/$PVID3"
+lvs --foreign $vg2 > out
+cat out
+grep $lv2 out
+check lv_field $vg2/$lv2 lv_active "" --foreign
+
+fi
+
+
+# Test the case where pvscan --cache -aay (with no devs)
+# gets the final PV to complete the VG, where that final PV
+# does not hold VG metadata. In this case it needs to rely
+# on VG metadata that has been saved from a previously
+# scanned PV from the same VG.
+#
+# We can't control which order of devices pvscan will see,
+# so create several PVs without metadata surrounding one
+# PV with metadata, to make it likely that pvscan will
+# get a final PV without metadata.
+
+pvcreate --metadatacopies 0 "$dev4"
+pvcreate --metadatacopies 0 "$dev5"
+pvcreate --metadatacopies 1 "$dev6"
+pvcreate --metadatacopies 0 "$dev7"
+pvcreate --metadatacopies 0 "$dev8"
+vgcreate $vg3 "$dev4" "$dev5" "$dev6" "$dev7" "$dev8"
+lvcreate -n $lv1 -l 4 -a n $vg3
+
+_clear_online_files
+
+check lv_field $vg3/$lv1 lv_active ""
+pvscan --cache "$dev4"
+check lv_field $vg3/$lv1 lv_active ""
+pvscan --cache "$dev5"
+check lv_field $vg3/$lv1 lv_active ""
+pvscan --cache "$dev6"
+check lv_field $vg3/$lv1 lv_active ""
+pvscan --cache "$dev7"
+check lv_field $vg3/$lv1 lv_active ""
+pvscan --cache "$dev8"
+check lv_field $vg3/$lv1 lv_active ""
+pvscan --cache -aay
+check lv_field $vg3/$lv1 lv_active "active"
+lvchange -an $vg3
+
+# Test event activation when PV and dev size don't match
+
+vgremove -ff $vg3
+
+pvremove "$dev8"
+pvcreate -y --setphysicalvolumesize 8M "$dev8"
+
+PVID8=$(pvs "$dev8" --noheading -o uuid | tr -d - | awk '{print $1}')
+echo $PVID8
+
+vgcreate $vg3 "$dev8"
+lvcreate -l1 -n $lv1 $vg3
+check lv_field $vg3/$lv1 lv_active "active"
+vgchange -an $vg3
+check lv_field $vg3/$lv1 lv_active ""
+
+_clear_online_files
+
+pvscan --cache -aay "$dev8"
+check lv_field $vg3/$lv1 lv_active "active"
+ls "$RUNDIR/lvm/pvs_online/$PVID8"
+ls "$RUNDIR/lvm/vgs_online/$vg3"
+vgchange -an $vg3
+
+vgremove -ff $vg3
diff --git a/test/shell/pvscan-autoactivation-polling.sh b/test/shell/pvscan-autoactivation-polling.sh
new file mode 100644
index 0000000..53adf51
--- /dev/null
+++ b/test/shell/pvscan-autoactivation-polling.sh
@@ -0,0 +1,74 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2016 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+SKIP_WITH_LVMLOCKD=1
+
+. lib/inittest
+
+# test if snapshot-merge target is available
+aux target_at_least dm-snapshot-merge 1 0 0 || skip
+
+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
+
+ BASE_SNAP_LV_NAME=$(snap_lv_name_ $LV_NAME)
+
+ lvcreate -aey -n $LV_NAME -l 50%FREE $VG_NAME
+ lvs
+ 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%ORIGIN ${VG_NAME}/${LV_NAME}
+ done
+ fi
+}
+
+aux prepare_pvs 1 50
+
+vgcreate $vg1 "$dev1"
+mkdir test_mnt
+
+setup_merge_ $vg1 $lv1
+mount "$(lvdev_ $vg1 $lv1)" test_mnt
+lvconvert --merge "$vg1/$(snap_lv_name_ "$lv1")"
+umount test_mnt
+vgchange -an $vg1
+
+# check snapshot get removed on autoactivation
+pvscan --cache -aay "$dev1"
+
+check active $vg1 $lv1
+i=100
+while ! check lv_not_exists "$vg1/$(snap_lv_name_ "$lv1")"; do
+ test $i -lt 0 && fail "Background polling failed to remove merged snapshot LV"
+ sleep .1
+ i=$((i-1))
+done
+
+# TODO: add similar simple tests for other interrupted/unfinished polling operation
+
+vgremove -ff $vg1
diff --git a/test/shell/pvscan-cache.sh b/test/shell/pvscan-cache.sh
new file mode 100644
index 0000000..c351885
--- /dev/null
+++ b/test/shell/pvscan-cache.sh
@@ -0,0 +1,80 @@
+#!/usr/bin/env 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+SKIP_WITH_LVMLOCKD=1
+SKIP_WITH_LVMPOLLD=1
+
+RUNDIR="/run"
+test -d "$RUNDIR" || RUNDIR="/var/run"
+PVS_ONLINE_DIR="$RUNDIR/lvm/pvs_online"
+VGS_ONLINE_DIR="$RUNDIR/lvm/vgs_online"
+
+_clear_online_files() {
+ # wait till udev is finished
+ aux udev_wait
+ rm -f "$PVS_ONLINE_DIR"/*
+ rm -f "$VGS_ONLINE_DIR"/*
+}
+
+. lib/inittest
+
+aux prepare_pvs 2
+
+vgcreate $vg1 "$dev1" "$dev2"
+vgs | grep $vg1
+
+pvscan --cache
+
+vgs | grep $vg1
+
+# Check that an LV cannot be activated by lvchange while VG is exported
+lvcreate -n $lv1 -l 4 -a n $vg1
+check lv_exists $vg1
+vgexport $vg1
+fail lvs $vg1
+fail lvchange -ay $vg1/$lv1
+vgimport $vg1
+check lv_exists $vg1
+check lv_field $vg1/$lv1 lv_active ""
+
+# Check that an LV cannot be activated by pvscan while VG is exported
+vgchange -an $vg1
+_clear_online_files
+vgexport $vg1
+pvscan --cache -aay "$dev1" || true
+pvscan --cache -aay "$dev2" || true
+_clear_online_files
+vgimport $vg1
+check lv_exists $vg1
+check lv_field $vg1/$lv1 lv_active ""
+pvscan --cache -aay "$dev1"
+pvscan --cache -aay "$dev2"
+check lv_field $vg1/$lv1 lv_active "active"
+lvchange -an -vvvv $vg1/$lv1
+dmsetup ls
+lvremove $vg1/$lv1
+
+# When MDA is ignored on PV, do not read any VG
+# metadata from such PV as it may contain old
+# metadata which hasn't been updated for some
+# time and also since the MDA is marked as ignored,
+# it should really be *ignored*!
+_clear_online_files
+pvchange --metadataignore y "$dev1"
+aux disable_dev "$dev2"
+pvscan --cache
+check pv_field "$dev1" vg_name "[unknown]"
+aux enable_dev "$dev2"
+pvscan --cache
+check pv_field "$dev1" vg_name "$vg1"
+
+vgremove -ff $vg1
diff --git a/test/shell/pvscan-nomda-bg.sh b/test/shell/pvscan-nomda-bg.sh
new file mode 100644
index 0000000..42bd26f
--- /dev/null
+++ b/test/shell/pvscan-nomda-bg.sh
@@ -0,0 +1,43 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2015 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+SKIP_WITH_LVMLOCKD=1
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+aux prepare_devs 2
+
+pvcreate --metadatacopies 0 "$dev1"
+pvcreate --metadatacopies 1 "$dev2"
+vgcreate $vg1 "$dev1" "$dev2"
+lvcreate -n foo -l 1 -an --zero n $vg1
+
+check inactive $vg1 foo
+
+RUNDIR="/run"
+test -d "$RUNDIR" || RUNDIR="/var/run"
+# create a file in pvs_online to disable the pvscan init
+# case which scans everything when the first dev appears.
+mkdir -p "$RUNDIR/lvm/pvs_online" || true
+touch "$RUNDIR/lvm/pvs_online/foo"
+
+pvscan --cache --background "$dev2" -aay
+
+check inactive $vg1 foo
+
+pvscan --cache --background "$dev1" -aay
+
+check active $vg1 foo
+
+rm "$RUNDIR/lvm/pvs_online/foo"
+vgremove -ff $vg1
diff --git a/test/shell/read-ahead.sh b/test/shell/read-ahead.sh
index 8c8f42c..2f061fa 100644
--- a/test/shell/read-ahead.sh
+++ b/test/shell/read-ahead.sh
@@ -1,4 +1,5 @@
-#!/bin/sh
+#!/usr/bin/env bash
+
# Copyright (C) 2008 Red Hat, Inc. All rights reserved.
#
# This copyrighted material is made available to anyone wishing to use,
@@ -7,7 +8,7 @@
#
# 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
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
#
# tests basic functionality of read-ahead and ra regressions
@@ -15,17 +16,18 @@
test_description='Test read-ahead functionality'
-. lib/test
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
aux prepare_vg 5
#COMM "test various read ahead settings (bz450922)"
-lvcreate -l 100%FREE -i5 -I256 -n $lv $vg
+lvcreate -l 100%FREE -i5 -I512 -n $lv $vg
ra=$(get lv_field $vg/$lv lv_kernel_read_ahead --units s --nosuffix)
-test $(( ( $ra / 5 ) * 5 )) -eq $ra
+test $(( ( ra / 5 ) * 5 )) -le $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
@@ -33,8 +35,11 @@ lvremove -ff $vg
#COMM "read ahead is properly inherited from underlying PV"
blockdev --setra 768 "$dev1"
vgscan
+# is there something in the system changing readahead settings behind the scene...
+RASZ=$(blockdev --getra "$dev1")
+test "$RASZ" -ge 768 || RASZ=768
lvcreate -n $lv -L4m $vg "$dev1"
-test $(blockdev --getra $DM_DEV_DIR/$vg/$lv) -eq 768
+test "$(blockdev --getra "$DM_DEV_DIR/$vg/$lv")" -eq "$RASZ"
lvremove -ff $vg
# Check default, active/inactive values for read_ahead / kernel_read_ahead
@@ -46,4 +51,5 @@ 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
+
+vgremove -ff $vg
diff --git a/test/shell/relative-sign-options.sh b/test/shell/relative-sign-options.sh
new file mode 100644
index 0000000..6be7525
--- /dev/null
+++ b/test/shell/relative-sign-options.sh
@@ -0,0 +1,80 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2017 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+test_description='Exercise toollib process_each_lv'
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+aux prepare_vg 1 256
+
+lvcreate -an -n $lv1 -l4 $vg
+lvcreate -an -n $lv2 -L4 $vg
+lvcreate -an -n $lv3 -l+4 $vg
+lvcreate -an -n $lv4 -L+4 $vg
+not lvcreate -n $lv5 -l-4 $vg
+not lvcreate -n $lv5 -L-4 $vg
+
+lvremove $vg/$lv1
+lvremove $vg/$lv2
+lvremove $vg/$lv3
+lvremove $vg/$lv4
+
+lvcreate -an -n $lv1 -l4 $vg
+lvresize -y -l8 $vg/$lv1
+lvresize -y -L16 $vg/$lv1
+lvresize -y -l+1 $vg/$lv1
+lvresize -y -L+1 $vg/$lv1
+lvresize -y --fs ignore -l-1 $vg/$lv1
+lvresize -y --fs ignore -L-1 $vg/$lv1
+
+lvcreate -an -n $lv2 -l4 $vg
+lvextend -y -l8 $vg/$lv2
+lvextend -y -L16 $vg/$lv2
+lvextend -y -l+1 $vg/$lv2
+lvextend -y -L+1 $vg/$lv2
+not lvextend -y -l-1 $vg/$lv2
+not lvextend -y -L-1 $vg/$lv2
+
+lvcreate -an -n $lv3 -l64 $vg
+lvreduce -y --fs ignore -l32 $vg/$lv3
+lvreduce -y --fs ignore -L8 $vg/$lv3
+lvreduce -y --fs ignore -l-1 $vg/$lv3
+lvreduce -y --fs ignore -L-1 $vg/$lv3
+not lvreduce -y --fs ignore -l+1 $vg/$lv3
+not lvreduce -y --fs ignore -L+1 $vg/$lv3
+
+# relative with percent extents
+
+lvcreate -an -n $lv6 -l+100%FREE $vg
+lvremove $vg/$lv6
+
+lvcreate -an -n $lv6 -l1 $vg
+lvextend -y -l+100%FREE $vg/$lv6
+lvremove $vg/$lv6
+
+lvcreate -an -n $lv6 -l1 $vg
+lvresize -y -l+100%FREE $vg/$lv6
+lvremove $vg/$lv6
+
+if aux have_thin 1 0 0 ; then
+# relative poolmetadatasize
+lvcreate --type thin-pool -L64 --poolmetadatasize 32 -n $lv7 $vg
+lvresize --poolmetadatasize 64 $vg/$lv7
+lvresize --poolmetadatasize +8 $vg/$lv7
+not lvresize -y --poolmetadatasize -8 $vg/$lv7
+
+lvextend --poolmetadatasize +4 $vg/$lv7
+not lvextend -y --poolmetadatasize -8 $vg/$lv7
+fi
+
+vgremove -y $vg
diff --git a/test/shell/report-fields.sh b/test/shell/report-fields.sh
new file mode 100644
index 0000000..eb81afc
--- /dev/null
+++ b/test/shell/report-fields.sh
@@ -0,0 +1,91 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2015 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+SKIP_WITH_LVMLOCKD=1
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+# Test only that there's correct set of fields displayed on output.
+
+aux prepare_pvs 1
+
+OPTS="--nameprefixes --noheadings --rows"
+
+aux lvmconf 'report/pvs_cols="pv_name,pv_size"'
+aux lvmconf 'report/compact_output=0'
+aux lvmconf 'report/compact_output_cols=""'
+
+pvs $OPTS > out
+grep LVM2_PV_NAME out
+grep LVM2_PV_SIZE out
+
+pvs $OPTS -o pv_attr > out
+grep LVM2_PV_ATTR out
+not grep -v LVM2_PV_ATTR out
+
+pvs $OPTS -o+pv_attr > out
+grep LVM2_PV_NAME out
+grep LVM2_PV_SIZE out
+grep LVM2_PV_ATTR out
+
+pvs $OPTS -o-pv_name > out
+not grep LVM2_PV_NAME out
+grep LVM2_PV_SIZE out
+
+pvs $OPTS -o+pv_attr -o-pv_attr > out
+grep LVM2_PV_NAME out
+grep LVM2_PV_SIZE out
+not grep LVM2_PV_ATTR out
+
+pvs $OPTS -o-pv_attr -o+pv_attr > out
+grep LVM2_PV_NAME out
+grep LVM2_PV_SIZE out
+grep LVM2_PV_ATTR out
+
+pvs $OPTS -o+pv_attr -o-pv_attr -o pv_attr > out
+grep LVM2_PV_ATTR out
+not grep -v LVM2_PV_ATTR out
+
+# -o-size is the same as -o-pv_size - the prefix is recognized
+pvs $OPTS -o-size > out
+not grep LVM2_PV_SIZE out
+
+# PV does not have tags nor is it exported if we haven't done that explicitly.
+# Check compaction per field is done correctly.
+pvs $OPTS -o pv_name,pv_exported,pv_tags -o#pv_tags > out
+grep LVM2_PV_NAME out
+grep LVM2_PV_EXPORTED out
+not grep LVM2_PV_TAGS out
+
+aux lvmconf 'report/compact_output_cols="pv_tags"'
+
+pvs $OPTS -o pv_name,pv_exported,pv_tags > out
+grep LVM2_PV_NAME out
+grep LVM2_PV_EXPORTED out
+not grep LVM2_PV_TAGS out
+
+pvs $OPTS -o pv_name,pv_exported,pv_tags -o#pv_exported > out
+grep LVM2_PV_NAME out
+not grep LVM2_PV_EXPORTED out
+grep LVM2_PV_TAGS out
+
+aux lvmconf 'report/compact_output=1'
+pvs $OPTS -o pv_name,pv_exported,pv_tags > out
+grep LVM2_PV_NAME out
+not grep LVM2_PV_EXPORTED out
+not grep LVM2_PV_TAGS out
+
+pvs $OPTS -o pv_name,pv_exported,pv_tags -o#pv_exported > out
+grep LVM2_PV_NAME out
+not grep LVM2_PV_EXPORTED out
+not grep LVM2_PV_TAGS out
diff --git a/test/shell/report-format.sh b/test/shell/report-format.sh
new file mode 100644
index 0000000..e02d61b
--- /dev/null
+++ b/test/shell/report-format.sh
@@ -0,0 +1,77 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2022 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+
+SKIP_WITH_LVMLOCKD=1
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+aux have_thin 1 0 0 || skip
+
+aux prepare_vg 1
+
+OUT_LOG_FILE="out"
+
+lvcreate -l1 -T $vg/$lv1
+lvcreate -l1 -n $lv2 --addtag lv_tag1 -an $vg
+lvcreate -l1 -n $lv3 --addtag lv_tag3 --addtag lv_tag1 --addtag lv_tag2 $vg
+
+aux lvmconf "report/output_format = basic"
+lvs -o name,kernel_major,data_percent,tags | tee "$OUT_LOG_FILE"
+
+#
+# LV KMaj Data% LV Tags
+# lvol1 253 0.00
+# lvol2 -1 lv_tag1
+# lvol3 253 lv_tag1,lv_tag2,lv_tag3
+#
+grep -E "^[[:space:]]*${lv1}[[:space:]]*[[:digit:]]+[[:space:]]*[[:digit:]]+.[[:digit:]]+[[:space:]]*\$" out
+grep -E "^[[:space:]]*${lv2}[[:space:]]*-1[[:space:]]*lv_tag1[[:space:]]*\$" out
+grep -E "^[[:space:]]*${lv3}[[:space:]]*[[:digit:]]+[[:space:]]*lv_tag1,lv_tag2,lv_tag3\$" out
+
+
+aux lvmconf "report/output_format = json"
+lvs -o name,kernel_major,data_percent,tags | tee "$OUT_LOG_FILE"
+# {
+# "report": [
+# {
+# "lv": [
+# {"lv_name":"lvol1", "lv_kernel_major":"253", "data_percent":"0.00", "lv_tags":""},
+# {"lv_name":"lvol2", "lv_kernel_major":"-1", "data_percent":"", "lv_tags":"lv_tag1"},
+# {"lv_name":"lvol3", "lv_kernel_major":"253", "data_percent":"", "lv_tags":"lv_tag1,lv_tag2,lv_tag3"}
+# ]
+# }
+# ]
+# }
+grep -E "^[[:space:]]*{\"lv_name\":\"$lv1\", \"lv_kernel_major\":\"[[:digit:]]+\", \"data_percent\":\"[[:digit:]]+.[[:digit:]]+\", \"lv_tags\":\"\"},\$" out
+grep -E "^[[:space:]]*{\"lv_name\":\"$lv2\", \"lv_kernel_major\":\"-1\", \"data_percent\":\"\", \"lv_tags\":\"lv_tag1\"},\$" out
+grep -E "^[[:space:]]*{\"lv_name\":\"$lv3\", \"lv_kernel_major\":\"[[:digit:]]+\", \"data_percent\":\"\", \"lv_tags\":\"lv_tag1,lv_tag2,lv_tag3\"}\$" out
+
+aux lvmconf "report/output_format = json_std"
+lvs -o name,kernel_major,data_percent,tags | tee "$OUT_LOG_FILE"
+# {
+# "report": [
+# {
+# "lv": [
+# {"lv_name":"lvol1", "lv_kernel_major":253, "data_percent":0.00, "lv_tags":[]},
+# {"lv_name":"lvol2", "lv_kernel_major":-1, "data_percent":null, "lv_tags":["lv_tag1"]},
+# {"lv_name":"lvol3", "lv_kernel_major":253, "data_percent":null, "lv_tags":["lv_tag1","lv_tag2","lv_tag3"]}
+# ]
+# }
+# ]
+# }
+grep -E "^[[:space:]]*{\"lv_name\":\"$lv1\", \"lv_kernel_major\":[[:digit:]]+, \"data_percent\":[[:digit:]]+.[[:digit:]]+, \"lv_tags\":\[\]},\$" out
+grep -E "^[[:space:]]*{\"lv_name\":\"$lv2\", \"lv_kernel_major\":-1, \"data_percent\":null, \"lv_tags\":\[\"lv_tag1\"\]},\$" out
+grep -E "^[[:space:]]*{\"lv_name\":\"$lv3\", \"lv_kernel_major\":[[:digit:]]+, \"data_percent\":null, \"lv_tags\":\[\"lv_tag1\",\"lv_tag2\",\"lv_tag3\"\]}\$" out
+
+vgremove -ff $vg
diff --git a/test/shell/report-hidden.sh b/test/shell/report-hidden.sh
new file mode 100644
index 0000000..f38e048
--- /dev/null
+++ b/test/shell/report-hidden.sh
@@ -0,0 +1,33 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2016 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+SKIP_WITH_LVMLOCKD=1
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+aux prepare_vg 1
+lvcreate --type mirror -m1 -l1 --alloc anywhere -n $lv1 $vg
+
+aux lvmconf 'log/prefix=""'
+
+aux lvmconf "report/mark_hidden_devices = 0"
+lvs --noheadings -a -o name $vg > out
+grep "^${lv1}_mimage_0" out
+not grep "^\[${lv1}_mimage_0\]" out
+
+aux lvmconf "report/mark_hidden_devices = 1"
+lvs --noheadings -a -o name $vg > out
+grep "^\[${lv1}_mimage_0\]" out
+not grep "^${lv1}_mimage_0" out
+
+vgremove -ff $vg
diff --git a/test/shell/scan-lvs.sh b/test/shell/scan-lvs.sh
new file mode 100644
index 0000000..fe11201
--- /dev/null
+++ b/test/shell/scan-lvs.sh
@@ -0,0 +1,46 @@
+#!/bin/bash
+# Copyright (C) 2014 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+# Test scan_lvs config setting
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+aux extend_filter_LVMTEST
+aux lvmconf "devices/scan_lvs = 1"
+
+aux prepare_pvs 1
+
+vgcreate $SHARED $vg1 "$dev1"
+
+lvcreate -l1 -n $lv1 $vg1
+
+aux extend_devices "$DM_DEV_DIR/$vg1/$lv1"
+pvcreate "$DM_DEV_DIR/$vg1/$lv1"
+
+pvs "$DM_DEV_DIR/$vg1/$lv1"
+
+aux lvmconf 'devices/scan_lvs = 0'
+
+not pvs "$DM_DEV_DIR/$vg1/$lv1"
+
+pvs --config devices/scan_lvs=1 "$DM_DEV_DIR/$vg1/$lv1"
+
+not pvremove "$DM_DEV_DIR/$vg1/$lv1"
+
+pvremove --config devices/scan_lvs=1 "$DM_DEV_DIR/$vg1/$lv1"
+
+lvchange -an "$vg1/$lv1"
+
+lvremove "$vg1/$lv1"
+
+vgremove $vg1
diff --git a/test/shell/select-report.sh b/test/shell/select-report.sh
new file mode 100644
index 0000000..f08c4ed
--- /dev/null
+++ b/test/shell/select-report.sh
@@ -0,0 +1,223 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2014-2015 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+aux prepare_pvs 6 16
+
+# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+# MAKE SURE ALL PV, VG AND LV NAMES CREATED IN
+# THIS TEST ARE UNIQUE - THIS SIMPLIFIES TESTING
+# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+# create $VGS with assorted tags
+vgcreate $SHARED $vg1 --vgmetadatacopies 2 --addtag "vg_tag3" --addtag "vg_tag2" -s 4m "$dev1" "$dev2" "$dev3"
+vgcreate $SHARED $vg2 --addtag "vg_tag2" -s 4m "$dev4" "$dev5"
+vgcreate $SHARED $vg3 --addtag "vg_tag1" -s 4m "$dev6"
+
+# add PV assorted tags
+pvchange --addtag "pv_tag3" --addtag "pv_tag1" --addtag "pv_tag2" "$dev1"
+pvchange --addtag "pv_tag1" --addtag "pv_tag4" "$dev6"
+
+# create $LVS with assorted tags and various sizes
+lvcreate --addtag 'lv_tag2.-+/=!:&#' --addtag "lv_tag1" -L8m -n "vol1" $vg1
+lvcreate --addtag "lv_tag1" -L4m -n "vol2" $vg1
+lvcreate --readahead 512 --addtag "lv_tag1" -L16m -n "abc" $vg2
+lvcreate --readahead 512 -My --minor 254 -L4m -n "xyz" $vg3
+lvcreate -L4m -aey -n "orig" $vg3
+lvcreate -L4m -s "$vg3/orig" -n "snap"
+
+OUT_LOG_FILE="out"
+ERR_LOG_FILE="err"
+
+sel() {
+ local items_found
+
+ ${1}s --noheadings -o ${1}_name --select "$2" 2>"$ERR_LOG_FILE" | tee "$OUT_LOG_FILE"
+ shift 2
+
+ test -f "$OUT_LOG_FILE" || {
+ echo " >>> Missing log file to check!"
+ return 1
+ }
+
+ # there shouldn't be any selection syntax error
+ grep "Selection syntax error at" "$ERR_LOG_FILE" >/dev/null && {
+ echo " >>> Selection syntax error hit!"
+ return 1
+ }
+
+ items_found=$(wc -l "$OUT_LOG_FILE" | cut -f 1 -d ' ')
+
+ # the number of lines on output must match
+ test "$items_found" -eq $# || {
+ echo " >>> NUMBER OF ITEMS EXPECTED: $#" "$@"
+ echo " >>> NUMBER OF ITEMS FOUND: $items_found ($(< $OUT_LOG_FILE))"
+ return 1
+ }
+
+ # the names selected must be correct
+ # each pv, vg and lv name is unique so just check
+ # the presence of the names given as arg
+ for name in "$@" ; do
+ grep "$name" "$OUT_LOG_FILE" >/dev/null || {
+ echo " >>> $name not found in the output log"
+ return 1
+ }
+ done
+
+ rm -f "$OUT_LOG_FILE" "$ERR_LOG_FILE"
+}
+
+##########################
+# STRING FIELD SELECTION #
+##########################
+#$LVS 'lv_name="vol1"' && result vol1
+sel lv 'lv_name="vol1"' vol1
+#$LVS 'lv_name!="vol1"' && result vol2 abc xyz
+sel lv 'lv_name!="vol1"' vol2 abc xyz orig snap
+# check string values are accepted without quotes too
+sel lv 'lv_name=vol1' vol1
+# check single quotes are also accepted instead of double quotes
+sel lv "lv_name='vol1'" vol1
+
+###############################
+# STRING LIST FIELD SELECTION #
+###############################
+sel pv 'tags=["pv_tag1"]'
+# for one item, no need to use []
+sel pv 'tags="pv_tag1"' "$dev1" "$dev6"
+# no match
+sel pv 'tags=["pv_tag1" && "pv_tag2"]'
+sel pv 'tags=["pv_tag1" && "pv_tag2" && "pv_tag3"]' "$dev1"
+# check the order has no effect on selection result
+sel pv 'tags=["pv_tag3" && "pv_tag2" && "pv_tag1"]' "$dev1"
+sel pv 'tags=["pv_tag4" || "pv_tag3"]' "$dev1" "$dev6"
+sel pv 'tags!=["pv_tag1"]' "$dev1" "$dev2" "$dev3" "$dev4" "$dev5" "$dev6"
+# check mixture of && and || - this is not allowed
+not sel pv 'tags=["pv_tag1" && "pv_tag2" || "pv_tag3"]'
+# check selection with blank value
+sel lv 'tags=""' xyz orig snap
+sel lv 'tags={}' xyz orig snap
+sel lv 'tags=[]' xyz orig snap
+# check subset selection
+sel pv 'tags={"pv_tag1"}' "$dev1" "$dev6"
+sel pv 'tags={"pv_tag1" && "pv_tag2"}' "$dev1"
+
+##########################
+# NUMBER FIELD SELECTION #
+##########################
+sel vg 'pv_count=3' $vg1
+sel vg 'pv_count!=3' $vg3 $vg2
+sel vg 'pv_count<2' $vg3
+sel vg 'pv_count<=2' $vg3 $vg2
+sel vg 'pv_count>2' $vg1
+sel vg 'pv_count>=2' $vg1 $vg2
+
+########################
+# SIZE FIELD SELECTION #
+########################
+# check size units are accepted as well as floating point numbers for sizes
+sel lv 'size=8388608b' vol1
+sel lv 'size=8192k' vol1
+sel lv 'size=8m' vol1
+sel lv 'size=8.00m' vol1
+sel lv 'size=0.0078125g' vol1
+sel lv 'size=0.00000762939453125t' vol1
+sel lv 'size=0.000000007450580596923828125p' vol1
+sel lv 'size=0.0000000000072759576141834259033203125e' vol1
+
+sel lv 'size>8m' abc
+sel lv 'size>=8m' abc vol1
+sel lv 'size<8m' vol2 xyz orig snap
+sel lv 'size<=8m' vol2 xyz vol1 orig snap
+
+###########################
+# PERCENT FIELD SELECTION #
+###########################
+if aux target_at_least dm-snapshot 1 10 0; then
+ # Test zero percent only if snapshot can be zero.
+ # Before 1.10.0, the snap percent included metadata size.
+ sel lv 'snap_percent=0' snap
+fi
+dd if=/dev/zero of="$DM_DEV_DIR/$vg3/snap" bs=1M count=1 oflag=direct
+sel lv 'snap_percent<50' snap
+sel lv 'snap_percent>50'
+# overflow snapshot -> invalidated, but still showing 100%
+not dd if=/dev/zero of="$DM_DEV_DIR/$vg3/snap" bs=1M count=4 oflag=direct
+sel lv 'snap_percent=100' snap
+# % char is accepted as suffix for percent values
+sel lv 'snap_percent=100%' snap
+# percent values over 100% are not accepted
+not sel lv 'snap_percent=101%'
+
+#########################
+# REGEX FIELD SELECTION #
+#########################
+sel lv 'lv_name=~"^vol[12]"' vol1 vol2
+sel lv 'lv_name!~"^vol[12]"' abc xyz orig snap
+# check regex is accepted without quotes too
+sel lv 'lv_name=~^vol[12]' vol1 vol2
+
+###########
+# GENERIC #
+###########
+# check prefix works for selection too
+sel lv 'lv_name="vol1"' vol1
+sel lv 'name="vol1"' vol1
+
+# check reserved values are accepted for certain fields as well as usual values
+sel vg 'vg_mda_copies=unmanaged' $vg2 $vg3
+sel vg 'vg_mda_copies=2' $vg1
+# also, we must match only vg1, not including vg2 and vg3
+# when comparing ranges - unamanged is mapped onto 2^64 - 1 internally,
+# so we need to skip this internal value if it matches with selection criteria!
+sel vg 'vg_mda_copies>=2' $vg1
+not sel vg 'vg_mda_copies=18446744073709551615'
+
+sel lv 'lv_read_ahead=auto' vol1 vol2 orig snap
+sel lv 'lv_read_ahead=256k' abc xyz
+
+sel lv 'lv_minor=-1' vol1 vol2 abc orig snap
+sel lv 'lv_minor=undefined' vol1 vol2 abc orig snap
+sel lv 'lv_minor=undef' vol1 vol2 abc orig snap
+sel lv 'lv_minor=unknown' vol1 vol2 abc orig snap
+sel lv 'lv_minor=254' xyz
+# also test synonym for string field type
+sel lv 'seg_monitor=undefined' vol1 vol2 abc abc orig xyz
+
+# if size unit not spefied, the 'm' (MiB) unit is used by default
+sel lv 'lv_size=8' vol1
+
+# no need to use quotes for the whole selection string if it does not clash with shell
+sel lv name=vol1 vol1
+
+##########################################
+# FORMING MORE COMPLEX SELECTION CLAUSES #
+##########################################
+# AND clause
+sel lv 'lv_tags=lv_tag1 && lv_size=4m' vol2
+# OR clause
+sel lv 'lv_name=vol1 || lv_name=vol2' vol1 vol2
+# grouping by using ( )
+sel lv '(lv_name=vol1 || lv_name=vol2) || vg_tags=vg_tag1' vol1 vol2 orig snap xyz
+sel lv '(lv_name=vol1 && lv_size=100m) || vg_tags=vg_tag1' xyz orig snap
+sel lv '(lv_name=vol1 || lv_name=vol2) && vg_tags=vg_tag1'
+sel lv '(lv_name=vol1 || lv_name=vol2) && lv_size < 8m' vol2
+sel lv '(lv_name=vol1 && lv_size=8m) && vg_tags=vg_tag2' vol1
+# negation of clause grouped by ( )
+sel lv '!(lv_name=vol1 || lv_name=vol2)' abc xyz orig snap
+
+vgremove -ff $vg1 $vg2 $vg3
diff --git a/test/shell/select-tools-thin.sh b/test/shell/select-tools-thin.sh
new file mode 100644
index 0000000..8fbe1b3
--- /dev/null
+++ b/test/shell/select-tools-thin.sh
@@ -0,0 +1,43 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2015 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+
+SKIP_WITH_LVMPOLLD=1
+
+export LVM_TEST_THIN_REPAIR_CMD=${LVM_TEST_THIN_REPAIR_CMD-/bin/false}
+
+. lib/inittest
+
+aux have_thin 1 0 0 || skip
+
+aux prepare_pvs 1 16
+
+#########################
+# special cases to test #
+#########################
+
+# if calling lvremove and an LV is removed that is related to other LV
+# and we're doing selection based on this relation, check if we're
+# selecting on initial state (here, thin origin LV thin_orig is removed
+# first, but thin snap should be still selectable based on origin=thin_orig
+# condition even though thin_orig has just been removed)
+vgcreate $SHARED -s 4m $vg1 "$dev1"
+lvcreate -l100%FREE -T $vg1/pool
+lvcreate -V4m -T $vg1/pool -n thin_orig
+lvcreate -s $vg1/thin_orig -n thin_snap
+lvremove -ff -S 'lv_name=thin_orig || origin=thin_orig' > out
+grep "Logical volume \"thin_orig\" successfully removed" out
+grep "Logical volume \"thin_snap\" successfully removed" out
+not lvs $vg1/thin_orig
+not lvs $vg1/thin_snap
+
+vgremove -ff $vg1
diff --git a/test/shell/select-tools.sh b/test/shell/select-tools.sh
new file mode 100644
index 0000000..0ca633c
--- /dev/null
+++ b/test/shell/select-tools.sh
@@ -0,0 +1,280 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2015 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+aux prepare_pvs 4 12
+
+vgcreate $SHARED -s 4m $vg1 "$dev1" "$dev2"
+vgcreate $SHARED -s 4m $vg2 "$dev3" "$dev4"
+
+# vg1/lv1 mapped onto dev1
+lvcreate -l1 -n "lv1" $vg1 "$dev1"
+
+# vg1/lv2 mapped onto dev1 and dev2 (2 segments)
+lvcreate -l3 -n "lv2" $vg1 "$dev1" "$dev2"
+
+# vg2/lv3 mapped onto dev3
+lvcreate -l1 -n "lv3" $vg2 "$dev3"
+
+# vg2/lv4 mapped onto dev3
+lvcreate -l1 -n "lv4" $vg2 "$dev3" "$dev4"
+
+# vg2/lv1 mapped onto "$dev4" (same LV name as vg1/lv1)
+lvcreate -l1 -n "lv1" $vg2 "$dev4"
+
+###########################################
+# exercise process_each_vg with selection #
+###########################################
+
+# select contains VGS field
+# direct vg name match
+vgchange --addtag 101 -S "vg_name=$vg1"
+check vg_field $vg1 vg_tags 101
+not check vg_field $vg2 vg_tags 101
+vgchange --deltag 101
+
+# select contains LVS fiels
+vgchange --addtag 102 -S "lv_name=lv2"
+check vg_field $vg1 vg_tags 102
+not check vg_field $vg2 vg_tags 102
+vgchange --deltag 102
+vgchange --addtag 103 -S "lv_name=lv1"
+check vg_field $vg1 vg_tags 103
+check vg_field $vg2 vg_tags 103
+vgchange --deltag 103
+
+# select contains SEGS field
+vgchange --addtag 104 -S 'seg_start=8m'
+check vg_field $vg1 vg_tags 104
+not check vg_field $vg2 vg_tags 104
+vgchange --deltag 104
+vgchange --addtag 105 -S "seg_start=0m"
+check vg_field $vg1 vg_tags 105
+check vg_field $vg2 vg_tags 105
+vgchange --deltag 105
+
+# select contains PVS field
+vgchange --addtag 106 -S pv_name="$dev1"
+check vg_field $vg1 vg_tags 106
+not check vg_field $vg2 vg_tags 106
+vgchange --deltag 106
+vgchange --addtag 107 -S "pv_size>0m"
+check vg_field $vg1 vg_tags 107
+check vg_field $vg2 vg_tags 107
+vgchange --deltag 107
+
+# select contains PVSEGS field
+vgchange --addtag 108 -S "pvseg_size=2"
+check vg_field $vg1 vg_tags 108
+not check vg_field $vg2 vg_tags 108
+vgchange --deltag 108
+vgchange --addtag 109 -S "pvseg_size=1"
+check vg_field $vg1 vg_tags 109
+check vg_field $vg2 vg_tags 109
+vgchange --deltag 109
+
+# if VG name or tag is supplied together with the
+# selection, the result is an intersection of both
+vgchange --addtag 110 -S "vg_name=$vg1" $vg2
+not check vg_field $vg1 vg_tags 110
+not check vg_field $vg2 vg_tags 110
+vgchange --deltag 110
+vgchange --addtag 111 -S "vg_name=$vg1" $vg1
+check vg_field $vg1 vg_tags 111
+not check vg_field $vg2 vg_tags 111
+vgchange --deltag 111
+vgchange --addtag "tag" $vg1
+vgchange --addtag 112 -S "vg_name=$vg2" @tag
+not check vg_field $vg1 vg_tags "tag,112"
+not check vg_field $vg2 vg_tags "tag,112"
+vgchange --deltag 112
+vgchange --addtag 113 -S "vg_name=$vg1" @tag
+check vg_field $vg1 vg_tags "113,tag"
+not check vg_field $vg2 vg_tags "113,tag"
+vgchange --deltag 113 --deltag tag
+
+###########################################
+# exercise process_each_lv with selection #
+###########################################
+
+# select contains VGS field
+lvchange --addtag 201 -S "vg_name=$vg1"
+check lv_field $vg1/lv1 lv_tags 201
+check lv_field $vg1/lv2 lv_tags 201
+not check lv_field $vg2/lv3 lv_tags 201
+not check lv_field $vg2/lv4 lv_tags 201
+not check lv_field $vg2/lv1 lv_tags 201
+lvchange --deltag 201 $vg1 $vg2
+
+# select contains LVS fiels
+lvchange --addtag 202 -S "lv_name=lv2"
+not check lv_field $vg1/lv1 lv_tags 202
+check lv_field $vg1/lv2 lv_tags 202
+not check lv_field $vg2/lv3 lv_tags 202
+not check lv_field $vg2/lv4 lv_tags 202
+not check lv_field $vg2/lv1 lv_tags 202
+lvchange --deltag 202 $vg1 $vg2
+lvchange --addtag 203 -S "lv_name=lv1"
+check lv_field $vg1/lv1 lv_tags 203
+not check lv_field $vg1/lv2 lv_tags 203
+not check lv_field $vg2/lv3 lv_tags 203
+not check lv_field $vg2/lv4 lv_tags 203
+check lv_field $vg2/lv1 lv_tags 203
+lvchange --deltag 203 $vg1 $vg2
+
+# select contains SEGS field
+lvchange --addtag 204 -S "seg_start=8m"
+not check lv_field $vg1/lv1 lv_tags 204
+check lv_field $vg1/lv2 lv_tags 204
+not check lv_field $vg2/lv3 lv_tags 204
+not check lv_field $vg2/lv4 lv_tags 204
+not check lv_field $vg2/lv1 lv_tags 204
+lvchange --deltag 204 $vg1 $vg2
+
+# select contains PVS field - COMBINATION NOT ALLOWED!
+lvchange --addtag 205 -S pv_name="$dev1" 2>err
+grep "Can't report LV and PV fields at the same time" err
+grep "Selection failed for LV" err
+not check lv_field $vg1/lv1 lv_tags 205
+not check lv_field $vg1/lv2 lv_tags 205
+not check lv_field $vg2/lv3 lv_tags 205
+not check lv_field $vg2/lv4 lv_tags 205
+not check lv_field $vg2/lv1 lv_tags 205
+
+# select contains PVSEGS field - COMBINATION NOT ALLOWED!
+lvchange --addtag 206 -S "pvseg_start>=0" 2>err
+grep "Can't report LV and PV fields at the same time" err
+grep "Selection failed for LV" err
+not check lv_field $vg1/lv1 lv_tags 206
+not check lv_field $vg1/lv2 lv_tags 206
+not check lv_field $vg2/lv3 lv_tags 206
+not check lv_field $vg2/lv4 lv_tags 206
+not check lv_field $vg2/lv1 lv_tags 206
+
+# if LV name or tag is supplied together with the
+# selection, the result is an intersection of both
+lvchange --addtag 207 -S "lv_name=lv2" $vg1/lv1
+not check lv_field $vg1/lv1 lv_tags 207
+not check lv_field $vg1/lv2 lv_tags 207
+not check lv_field $vg2/lv3 lv_tags 207
+not check lv_field $vg2/lv4 lv_tags 207
+not check lv_field $vg2/lv1 lv_tags 207
+lvchange --deltag 207 $vg1 $vg2
+lvchange --addtag 208 -S "lv_name=lv2" $vg1/lv2
+not check lv_field $vg1/lv1 lv_tags 208
+check lv_field $vg1/lv2 lv_tags 208
+not check lv_field $vg2/lv3 lv_tags 208
+not check lv_field $vg2/lv4 lv_tags 208
+not check lv_field $vg2/lv1 lv_tags 208
+lvchange --deltag 208 $vg1 $vg2
+lvchange --addtag "tag" $vg1/lv2
+lvchange --addtag 209 -S "lv_name=lv3" @tag
+not check lv_field $vg1/lv1 lv_tags "209,tag"
+not check lv_field $vg1/lv2 lv_tags "209,tag"
+not check lv_field $vg2/lv3 lv_tags "209,tag"
+not check lv_field $vg2/lv4 lv_tags "209,tag"
+not check lv_field $vg2/lv1 lv_tags "209,tag"
+lvchange --deltag 209 $vg1 $vg2
+lvchange --addtag 210 -S "lv_name=lv2" @tag
+not check lv_field $vg1/lv1 lv_tags "210,tag"
+check lv_field $vg1/lv2 lv_tags "210,tag"
+not check lv_field $vg2/lv3 lv_tags "210,tag"
+not check lv_field $vg2/lv4 lv_tags "210,tag"
+not check lv_field $vg2/lv1 lv_tags "210,tag"
+lvchange --deltag 210 --deltag tag $vg1 $vg2
+
+###########################################
+# exercise process_each_pv with selection #
+###########################################
+
+# select contains VGS field
+pvchange --addtag 301 -S "vg_name=$vg1"
+check pv_field "$dev1" pv_tags 301
+check pv_field "$dev2" pv_tags 301
+not check pv_field "$dev3" pv_tags 301
+not check pv_field "$dev4" pv_tags 301
+pvchange -a --deltag 301
+
+# select contains LVS field
+pvchange --addtag 302 -S "lv_name=lv2"
+check pv_field "$dev1" pv_tags 302
+check pv_field "$dev2" pv_tags 302
+not check pv_field "$dev3" pv_tags 302
+not check pv_field "$dev4" pv_tags 302
+pvchange -a --deltag 302
+
+# select contains SEGS field
+pvchange --addtag 303 -S "seg_start=8m"
+check pv_field "$dev1" pv_tags 303
+not check pv_field "$dev2" pv_tags 303
+not check pv_field "$dev3" pv_tags 303
+not check pv_field "$dev4" pv_tags 303
+pvchange -a --deltag 303
+
+# select contains PVS field
+pvchange --addtag 304 -S pv_name="$dev1"
+check pv_field "$dev1" pv_tags 304
+not check pv_field "$dev2" pv_tags 304
+not check pv_field "$dev3" pv_tags 304
+not check pv_field "$dev4" pv_tags 304
+pvchange -a --deltag 304
+
+# select contains PVSEGS field
+pvchange --addtag 305 -S "pvseg_size=2"
+not check pv_field "$dev1" pv_tags 305
+check pv_field "$dev2" pv_tags 305
+not check pv_field "$dev3" pv_tags 305
+not check pv_field "$dev4" pv_tags 305
+pvchange -a --deltag 305
+
+# if PV name or tag is supplied together with the
+# selection, the result is an intersection of both
+pvchange --addtag 306 -S pv_name="$dev1" "$dev2"
+not check pv_field "$dev1" pv_tags 306
+not check pv_field "$dev2" pv_tags 306
+not check pv_field "$dev3" pv_tags 306
+not check pv_field "$dev4" pv_tags 306
+pvchange -a --deltag 306
+pvchange --addtag 307 -S pv_name="$dev1" "$dev1"
+check pv_field "$dev1" pv_tags 307
+not check pv_field "$dev2" pv_tags 307
+not check pv_field "$dev3" pv_tags 307
+not check pv_field "$dev4" pv_tags 307
+pvchange -a --deltag 307
+pvchange --addtag "tag" "$dev1"
+pvchange --addtag 308 -S pv_name="$dev2" @tag
+not check pv_field "$dev1" pv_tags "308,tag"
+not check pv_field "$dev2" pv_tags "308,tag"
+not check pv_field "$dev3" pv_tags "308,tag"
+not check pv_field "$dev4" pv_tags "308,tag"
+pvchange --deltag 308 "$dev1"
+pvchange --addtag 309 -S pv_name="$dev1" @tag
+check pv_field "$dev1" pv_tags "309,tag"
+not check pv_field "$dev2" pv_tags "309,tag"
+not check pv_field "$dev3" pv_tags "309,tag"
+not check pv_field "$dev4" pv_tags "309,tag"
+pvchange -a --deltag 309 --deltag tag
+
+#########################
+# special cases to test #
+#########################
+
+# if calling vgremove, make sure we're doing selection per-VG, not per-LV
+# (vgremove calls process_each_vg with vgremove_single which itself
+# iterates over LVs with process_each_lv_in_vg - so internally it actually
+# operates per-LV, but we still need the selection to be done per-VG)
+vgremove --yes -S 'lv_name=lv2' # should remove whole vg1, not just the lv2
+vgremove --yes $vg2
diff --git a/test/shell/snapshot-autoumount-dmeventd.sh b/test/shell/snapshot-autoumount-dmeventd.sh
index 3b4b711..7967e86 100644
--- a/test/shell/snapshot-autoumount-dmeventd.sh
+++ b/test/shell/snapshot-autoumount-dmeventd.sh
@@ -1,5 +1,6 @@
-#!/bin/bash
-# Copyright (C) 2010-2012 Red Hat, Inc. All rights reserved.
+#!/usr/bin/env bash
+
+# Copyright (C) 2010-2015 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
@@ -7,11 +8,14 @@
#
# 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
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
# no automatic extensions please
-. lib/test
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
which mkfs.ext2 || skip
@@ -22,24 +26,32 @@ aux prepare_dmeventd
aux prepare_vg 2
mntdir="${PREFIX}mnt"
-lvcreate -l 8 -n base $vg
+lvcreate -aey -L8 -n base $vg
mkfs.ext2 "$DM_DEV_DIR/$vg/base"
-lvcreate -s -l 4 -n snap $vg/base
+lvcreate -s -L4 -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
+# Use remount-ro to avoid logging kernel WARNING
+mount -o errors=remount-ro "$DM_DEV_DIR/mapper/$vg-snap" "$mntdir"
+
+test "$(dmsetup info -c --noheadings -o open $vg-snap)" -eq 1
+
+grep "$mntdir" /proc/mounts
+
+# overfill 4M snapshot (with metadata)
+not dd if=/dev/zero of="$mntdir/file" bs=1M count=4 conv=fdatasync
+
+# Should be nearly instant check of dmeventd for invalid snapshot.
+# Wait here for umount and open_count drops to 0 as it may
+# take a while to finalize umount operation (it might be already
+# removed from /proc/mounts, but still opened).
+for i in {1..100}; do
+ sleep .1
+ test "$(dmsetup info -c --noheadings -o open $vg-snap)" -eq 0 && break
done
-cat /proc/mounts | not grep "$mntdir"
+not grep "$mntdir" /proc/mounts
vgremove -f $vg
diff --git a/test/shell/snapshot-cluster.sh b/test/shell/snapshot-cluster.sh
new file mode 100644
index 0000000..e6c9ab3
--- /dev/null
+++ b/test/shell/snapshot-cluster.sh
@@ -0,0 +1,28 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2014 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+# Testing renaming snapshots in cluster
+# https://bugzilla.redhat.com/show_bug.cgi?id=1136925
+
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+aux prepare_vg 1
+
+lvcreate -aey -L1 -n $lv1 $vg
+lvcreate -s -L1 -n $lv2 $vg/$lv1
+lvrename $vg/$lv2 $vg/$lv3
+lvremove -f $vg/$lv1
+
+vgremove -f $vg
diff --git a/test/shell/snapshot-maxsize.sh b/test/shell/snapshot-maxsize.sh
new file mode 100644
index 0000000..43d4db1
--- /dev/null
+++ b/test/shell/snapshot-maxsize.sh
@@ -0,0 +1,35 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2014 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+# Testing calculation of snapshot space
+# https://bugzilla.redhat.com/show_bug.cgi?id=1035871
+
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+aux prepare_pvs 1
+get_devs
+
+vgcreate $SHARED -s 4K "$vg" "${DEVICES[@]}"
+
+lvcreate -aey -L1 -n $lv1 $vg
+# Snapshot should be large enough to handle any writes
+lvcreate -L2 -s $vg/$lv1 -n $lv2
+
+dd if=/dev/zero of="$DM_DEV_DIR/$vg/$lv2" bs=1M count=1 oflag=direct
+
+# Snapshot must not be 'I'nvalid here
+check lv_attr_bit state $vg/$lv2 "a"
+
+vgremove -f $vg
diff --git a/test/shell/snapshot-merge-stack.sh b/test/shell/snapshot-merge-stack.sh
new file mode 100644
index 0000000..b6763ca
--- /dev/null
+++ b/test/shell/snapshot-merge-stack.sh
@@ -0,0 +1,89 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2016 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+# Exercise snapshot merge also when stacked
+
+
+export LVM_TEST_THIN_REPAIR_CMD=${LVM_TEST_THIN_REPAIR_CMD-/bin/false}
+
+. lib/inittest
+
+which mkfs.ext3 || skip
+
+aux target_at_least dm-snapshot-merge 1 0 0 || skip
+
+aux prepare_vg 2 100
+
+snap_and_merge() {
+ lvcreate -s -n $lv2 -L20 $vg/$lv1 "$dev2"
+ #dd if=/dev/zero of="$DM_DEV_DIR/$vg/$lv1" bs=1M count=10 conv=fdatasync
+ aux udev_wait
+ mkfs.ext3 "$DM_DEV_DIR/$vg/$lv2"
+ sync
+ lvs -a $vg
+
+ SLEEP_PID=$(aux hold_device_open $vg $lv1 20)
+
+ # initiate background merge
+ lvconvert -b --merge $vg/$lv2
+
+ lvs -a -o+lv_merging,lv_merge_failed $vg
+ get lv_field $vg/$lv1 lv_attr | grep "Owi-ao"
+ get lv_field $vg/$lv2 lv_attr | grep "Swi-a-s---"
+ kill $SLEEP_PID
+
+ aux delay_dev "$dev1" 0 200 "$(get first_extent_sector "$dev1"):"
+ lvchange --poll n --refresh $vg/$lv1
+ dmsetup table
+ lvs -av -o+lv_merging,lv_merge_failed $vg
+ # Origin is closed and snapshot merge could run
+ get lv_field $vg/$lv1 lv_attr | grep "Owi-a-"
+ sleep 1
+ check lv_attr_bit state $vg/$lv2 "a"
+ aux error_dev "$dev2" "$(get first_extent_sector "$dev2"):"
+ aux enable_dev "$dev1"
+ # delay to let snapshot merge 'discover' failing COW device
+ sleep 1
+ sync
+ dmsetup status
+ lvs -a -o+lv_merging,lv_merge_failed $vg
+ check lv_attr_bit state $vg/$lv1 "m"
+ check lv_attr_bit state $vg/$lv2 "m"
+
+ # device OK and running in full speed
+ aux enable_dev "$dev2"
+
+ # reactivate so merge can finish
+ lvchange -an $vg
+ lvchange -ay $vg
+ sleep 1
+ lvs -a -o+lv_merging,lv_merge_failed $vg
+ check lv_not_exists $vg $lv2
+ fsck -n "$DM_DEV_DIR/$vg/$lv1"
+
+ lvremove -f $vg
+}
+
+
+# First check merge on plain linear LV
+lvcreate -aey -L50 -n $lv1 $vg "$dev1"
+snap_and_merge
+
+# When available check merge of old snapshot with Thin LV being origin
+if aux have_thin 1 0 0 ; then
+ lvcreate -T -L10 -V50 -n $lv1 $vg/pool "$dev1"
+ snap_and_merge
+fi
+
+# TODO snapshot merge with Mirror, Raid, Cache...
+
+vgremove -f $vg
diff --git a/test/shell/snapshot-merge-thin.sh b/test/shell/snapshot-merge-thin.sh
new file mode 100644
index 0000000..a74567b
--- /dev/null
+++ b/test/shell/snapshot-merge-thin.sh
@@ -0,0 +1,78 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2019 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+# Exercise merge of old snapshots over thin
+
+export LVM_TEST_THIN_REPAIR_CMD=${LVM_TEST_THIN_REPAIR_CMD-/bin/false}
+
+. lib/inittest
+
+aux target_at_least dm-snapshot-merge 1 0 0 || skip
+aux have_thin 1 0 0 || skip
+
+aux prepare_vg 2
+
+lvcreate -T -L1 -V1 -n $lv1 $vg/pool "$dev1"
+lvcreate -s -n $lv2 $vg/$lv1
+
+# Take also thick snapshot of thin snapshot
+lvcreate -s -L1 -n $lv3 $vg/$lv2
+
+sleep 10 < "$DM_DEV_DIR/$vg/$lv1" >/dev/null 2>&1 &
+PID_SLEEP=$!
+
+# initiated merge that cannot proceed, but there is no need to retry
+lvconvert --config 'activation/retry_deactivation=0' --merge $vg/$lv2
+
+kill $PID_SLEEP
+wait
+
+# Remove everything
+lvremove --yes $vg
+
+# No LV left in VG
+check vg_field $vg lv_count "0"
+
+
+# Create again pool with thin and thick snapshot
+lvcreate -T -L1 -V1 -n $lv1 $vg/pool "$dev1"
+lvcreate -s -n $lv2 -L2 $vg/$lv1 "$dev2"
+dd if=/dev/zero of="$DM_DEV_DIR/$vg/$lv2" bs=1M count=1 oflag=direct
+
+lvs -a -o+lv_merging,lv_merge_failed $vg
+aux delay_dev "$dev1" 0 400 "$(get first_extent_sector "$dev1"):"
+
+# Initiate background merge
+lvconvert -b --merge $vg/$lv2
+
+# Query status of snapshot immediately after start
+# - may hit race of checking already in-progress merge
+#lvs -a -o+lv_merging,lv_merge_failed $vg
+check lv_field $vg/$lv1 lv_merging "merging"
+
+lvm lvpoll -i 1 --polloperation merge $vg/$lv1
+
+# Here should be everything already merged
+#lvs -a -o+lv_merging,lv_merge_failed $vg
+# check we see thin filled 100% (1MiB written to 1MiB LV)
+check lv_field $vg/$lv1 data_percent "100.00"
+
+# -real must not exist for $vg/$lv1
+not dmsetup info ${vg}-${lv1}-real 2>&1 | tee out
+grep "not exist" out
+
+not dmsetup info ${vg}-${lv2}-cow 2>&1 | tee out
+grep "not exist" out
+
+check lv_not_exists $vg $lv2
+
+vgremove -f $vg
diff --git a/test/shell/snapshot-merge.sh b/test/shell/snapshot-merge.sh
index a42b6f8..ff9de96 100644
--- a/test/shell/snapshot-merge.sh
+++ b/test/shell/snapshot-merge.sh
@@ -1,5 +1,6 @@
-#!/bin/sh
-# Copyright (C) 2010-2012 Red Hat, Inc. All rights reserved.
+#!/usr/bin/env bash
+
+# Copyright (C) 2010-2017 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
@@ -7,9 +8,14 @@
#
# 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
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+
-. lib/test
+. lib/inittest
+
+# test if snapshot-merge target is available
+aux target_at_least dm-snapshot-merge 1 0 0 || skip
which mkfs.ext3 || skip
@@ -18,22 +24,24 @@ lvdev_() {
}
snap_lv_name_() {
- echo ${1}_snap
+ 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)
+ local BASE_SNAP_LV_NAME
+
+ BASE_SNAP_LV_NAME=$(snap_lv_name_ $LV_NAME)
- lvcreate -n $LV_NAME -l 50%FREE $VG_NAME
+ lvcreate -aey -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}
+ for i in $(seq 1 $NUM_EXTRA_SNAPS); do
+ lvcreate -s -n ${BASE_SNAP_LV_NAME}_${i} -l 20%ORIGIN ${VG_NAME}/${LV_NAME}
done
fi
}
@@ -43,26 +51,37 @@ 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)
+not lvconvert --merge
+
+# check read-only origin is protected from being merge
+lvchange -pr $vg/$lv1
+not lvconvert --merge "$vg/$(snap_lv_name_ "$lv1")" |& tee out
+grep "read-only origin" out
+lvchange -prw $vg/$lv1
+
+# check exclusive lock is preserved after merge
+check lv_field "$vg/$lv1" lv_active_exclusively "active exclusively"
+lvconvert --merge "$vg/$(snap_lv_name_ "$lv1")"
+check lv_field "$vg/$lv1" lv_active_exclusively "active exclusively"
lvremove -f $vg/$lv1
+setup_merge_ $vg $lv1
+lvconvert --mergesnapshot "$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)
+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)
+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
@@ -78,13 +97,12 @@ dm_table $vg-$lv1 | grep " snapshot-merge " || dm_table $vg-$lv1 | grep " linear
# 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)
+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
@@ -95,19 +113,27 @@ 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)
+lvconvert --merge "$vg/$(snap_lv_name_ "$lv1")"
lvremove -f $vg/$lv1
+# test merging cannot start on already merging origin
+setup_merge_ $vg $lv1 3
+lvchange -an $vg
+lvs -a $vg
+lvconvert --merge "$vg/$(snap_lv_name_ "$lv1")"
+not lvconvert --merge "$vg/$(snap_lv_name_ "$lv1")_1" 2>&1 | tee err
+grep "Cannot merge snapshot" err
+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)
+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
+lvs $vg | tee 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?
diff --git a/test/shell/snapshot-raid.sh b/test/shell/snapshot-raid.sh
new file mode 100644
index 0000000..3dfe624
--- /dev/null
+++ b/test/shell/snapshot-raid.sh
@@ -0,0 +1,423 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2018 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+# Test snapshots of raid
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+aux have_raid 1 3 0 || skip
+which mkfs.ext4 || skip
+
+mount_dir="mnt"
+mkdir -p "$mount_dir"
+
+snap_dir="mnt_snap"
+mkdir -p "$snap_dir"
+
+# add and remove a snapshot
+
+test_add_del_snap() {
+ mkfs.ext4 "$DM_DEV_DIR/$vg/$lv1"
+
+ mount "$DM_DEV_DIR/$vg/$lv1" "$mount_dir"
+ touch "$mount_dir/A"
+
+ lvcreate -s -n snap -L12M $vg/$lv1 "$dev3"
+ mount "$DM_DEV_DIR/$vg/snap" "$snap_dir"
+
+ touch "$mount_dir/B"
+ not ls "$snap_dir/B"
+ touch "$snap_dir/C"
+ not ls "$mount_dir/C"
+ ls "$mount_dir/A"
+ ls "$snap_dir/A"
+
+ umount "$snap_dir"
+ lvremove -y $vg/snap
+ umount "$mount_dir"
+}
+
+# add and remove snapshot while origin has a missing raid image
+
+test_snap_with_missing_image() {
+ mkfs.ext4 "$DM_DEV_DIR/$vg/$lv1"
+
+ mount "$DM_DEV_DIR/$vg/$lv1" "$mount_dir"
+ touch "$mount_dir/A"
+
+ aux disable_dev "$dev1"
+ lvs -a -o+devices $vg
+
+ not lvcreate -s -n snap -L12M $vg/$lv1 "$dev3"
+
+ aux enable_dev "$dev1"
+ aux wait_for_sync $vg $lv1
+
+ lvcreate -s -n snap -L12M $vg/$lv1 "$dev3"
+
+ aux disable_dev "$dev1"
+ lvs -a -o+devices $vg
+
+ lvremove -y $vg/snap
+
+ aux enable_dev "$dev1"
+ vgextend --restoremissing $vg "$dev1"
+ lvs -a -o+devices $vg
+ aux wait_for_sync $vg $lv1
+
+ umount "$mount_dir"
+}
+
+# raid image is lost and restored while a snapshot exists
+
+test_missing_image_with_snap() {
+ mkfs.ext4 "$DM_DEV_DIR/$vg/$lv1"
+
+ mount "$DM_DEV_DIR/$vg/$lv1" "$mount_dir"
+ touch "$mount_dir/A"
+
+ lvcreate -s -n snap -L12M $vg/$lv1 "$dev3"
+ mount "$DM_DEV_DIR/$vg/snap" "$snap_dir"
+
+ aux disable_dev "$dev1"
+ lvs -a -o+devices $vg
+
+ touch "$mount_dir/B"
+ not ls "$snap_dir/B"
+ touch "$snap_dir/C"
+ not ls "$mount_dir/C"
+ ls "$mount_dir/A"
+ ls "$snap_dir/A"
+
+ aux enable_dev "$dev1"
+ aux wait_for_sync $vg $lv1
+
+ ls "$mount_dir/B"
+ ls "$snap_dir/C"
+
+ umount "$snap_dir"
+ lvremove -y $vg/snap
+ umount "$mount_dir"
+}
+
+# add and remove raid image while snapshot exists
+
+test_add_del_image_with_snap() {
+ mkfs.ext4 "$DM_DEV_DIR/$vg/$lv1"
+
+ mount "$DM_DEV_DIR/$vg/$lv1" "$mount_dir"
+ touch "$mount_dir/A"
+
+ lvcreate -s -n snap -L12M $vg/$lv1 "$dev3"
+ mount "$DM_DEV_DIR/$vg/snap" "$snap_dir"
+
+ touch "$mount_dir/B"
+ touch "$snap_dir/C"
+
+ lvconvert -y -m+1 $vg/$lv1 "$dev4"
+ aux wait_for_sync $vg $lv1
+
+ ls "$mount_dir/B"
+ ls "$snap_dir/C"
+ ls "$mount_dir/A"
+ ls "$snap_dir/A"
+
+ touch "$mount_dir/B2"
+ touch "$snap_dir/C2"
+
+ lvconvert -y -m-1 $vg/$lv1 "$dev4"
+
+ ls "$mount_dir/B"
+ ls "$snap_dir/C"
+ ls "$mount_dir/A"
+ ls "$snap_dir/A"
+ ls "$mount_dir/B2"
+ ls "$snap_dir/C2"
+ umount "$snap_dir"
+ lvremove -y $vg/snap
+
+ umount "$mount_dir"
+}
+
+test_replace_image_with_snap() {
+ # add an image to replace
+ lvconvert -y -m+1 $vg/$lv1 "$dev4"
+ aux wait_for_sync $vg $lv1
+
+ mkfs.ext4 "$DM_DEV_DIR/$vg/$lv1"
+
+ mount "$DM_DEV_DIR/$vg/$lv1" "$mount_dir"
+ touch "$mount_dir/A"
+
+ lvcreate -s -n snap -L12M $vg/$lv1 "$dev3"
+ mount "$DM_DEV_DIR/$vg/snap" "$snap_dir"
+
+ touch "$mount_dir/B"
+ touch "$snap_dir/C"
+
+ lvconvert -y --replace "$dev4" $vg/$lv1 "$dev5"
+ aux wait_for_sync $vg $lv1
+
+ ls "$mount_dir/B"
+ ls "$snap_dir/C"
+ ls "$mount_dir/A"
+ ls "$snap_dir/A"
+
+ touch "$mount_dir/B2"
+ touch "$snap_dir/C2"
+
+ umount "$snap_dir"
+ lvremove -y $vg/snap
+
+ # put lv1 back to original state with images on dev1 and dev2
+ lvconvert -y -m-1 $vg/$lv1 "$dev5"
+
+ umount "$mount_dir"
+}
+
+test_repair_image_with_snap() {
+ # add an image to repair
+ lvconvert -y -m+1 $vg/$lv1 "$dev4"
+ aux wait_for_sync $vg $lv1
+
+ mkfs.ext4 "$DM_DEV_DIR/$vg/$lv1"
+
+ mount "$DM_DEV_DIR/$vg/$lv1" "$mount_dir"
+ touch "$mount_dir/A"
+
+ lvcreate -s -n snap -L12M $vg/$lv1 "$dev3"
+ mount "$DM_DEV_DIR/$vg/snap" "$snap_dir"
+
+ touch "$mount_dir/B"
+ touch "$snap_dir/C"
+
+ aux disable_dev "$dev4"
+ lvs -a -o+devices $vg
+
+ lvconvert -y --repair $vg/$lv1 "$dev5"
+ aux wait_for_sync $vg $lv1
+
+ ls "$mount_dir/B"
+ ls "$snap_dir/C"
+ ls "$mount_dir/A"
+ ls "$snap_dir/A"
+
+ touch "$mount_dir/B2"
+ touch "$snap_dir/C2"
+
+ umount "$snap_dir"
+ lvremove -y $vg/snap
+
+ aux enable_dev "$dev4"
+ lvs -a -o+devices $vg
+ vgck --updatemetadata $vg
+
+ # put lv1 back to original state with images on dev1 and dev2
+ lvconvert -y -m-1 $vg/$lv1 "$dev5"
+
+ umount "$mount_dir"
+}
+
+test_merge_snap()
+{
+ mkfs.ext4 "$DM_DEV_DIR/$vg/$lv1"
+
+ mount "$DM_DEV_DIR/$vg/$lv1" "$mount_dir"
+ touch "$mount_dir/A"
+
+ lvcreate -s -n snap -L12M $vg/$lv1 "$dev3"
+ mount "$DM_DEV_DIR/$vg/snap" "$snap_dir"
+
+ touch "$mount_dir/B"
+ touch "$snap_dir/C"
+
+ umount "$snap_dir"
+
+ lvconvert --merge $vg/snap
+
+ # the merge will begin once the origin is not in use
+ umount "$mount_dir"
+
+ lvs -a $vg
+ lvchange -an $vg/$lv1
+ lvchange -ay $vg/$lv1
+ lvs -a $vg
+
+ mount "$DM_DEV_DIR/$vg/$lv1" "$mount_dir"
+ ls "$mount_dir/A"
+ ls "$mount_dir/C"
+ not ls "$mount_dir/B"
+
+ umount "$mount_dir"
+}
+
+test_extend_snap()
+{
+ mkfs.ext4 "$DM_DEV_DIR/$vg/$lv1"
+
+ mount "$DM_DEV_DIR/$vg/$lv1" "$mount_dir"
+ touch "$mount_dir/A"
+
+ lvcreate -s -n snap -L8M $vg/$lv1 "$dev3"
+ mount "$DM_DEV_DIR/$vg/snap" "$snap_dir"
+
+ touch "$mount_dir/B"
+ touch "$snap_dir/C"
+
+ lvextend -L+8M $vg/snap
+
+ umount "$mount_dir"
+ umount "$snap_dir"
+ lvremove -y $vg/snap
+}
+
+test_fill_snap()
+{
+ mkfs.ext4 "$DM_DEV_DIR/$vg/$lv1"
+
+ mount "$DM_DEV_DIR/$vg/$lv1" "$mount_dir"
+ touch "$mount_dir/A"
+
+ lvcreate -s -n snap -L4M $vg/$lv1 "$dev3"
+
+ lvs -a $vg
+ get lv_field $vg/snap lv_attr | grep "swi-a-s---"
+
+ dd if=/dev/zero of="$mount_dir/1" bs=1M count=1 oflag=direct
+ dd if=/dev/zero of="$mount_dir/2" bs=1M count=1 oflag=direct
+ dd if=/dev/zero of="$mount_dir/3" bs=1M count=1 oflag=direct
+ dd if=/dev/zero of="$mount_dir/4" bs=1M count=1 oflag=direct
+ dd if=/dev/zero of="$mount_dir/5" bs=1M count=1 oflag=direct
+
+ lvs -a $vg
+ get lv_field $vg/snap lv_attr | grep "swi-I-s---"
+ check lv_field $vg/snap data_percent "100.00"
+
+ umount "$mount_dir"
+ lvremove -y $vg/snap
+}
+
+aux prepare_devs 5 200
+
+vgcreate $SHARED $vg "$dev1" "$dev2" "$dev3" "$dev4" "$dev5"
+
+lvcreate --type raid1 -m1 -n $lv1 -L32M $vg "$dev1" "$dev2"
+dmsetup table
+aux wait_for_sync $vg $lv1
+test_add_del_snap
+test_snap_with_missing_image
+test_missing_image_with_snap
+test_add_del_image_with_snap
+test_replace_image_with_snap
+test_repair_image_with_snap
+test_merge_snap
+test_extend_snap
+test_fill_snap
+lvremove -y $vg/$lv1
+
+# INTEGRITY TESTS FOLLOWING:
+if aux have_integrity 1 5 0; then
+
+lvcreate --type raid1 -m1 --raidintegrity y -n $lv1 -L32M $vg "$dev1" "$dev2"
+aux wait_recalc $vg ${lv1}_rimage_0
+aux wait_recalc $vg ${lv1}_rimage_1
+aux wait_for_sync $vg $lv1
+test_add_del_snap
+test_snap_with_missing_image
+test_missing_image_with_snap
+test_add_del_image_with_snap
+test_replace_image_with_snap
+test_repair_image_with_snap
+test_merge_snap
+test_extend_snap
+test_fill_snap
+lvremove -y $vg/$lv1
+
+# Repeat above with cache|writecache on the raid image?
+
+#
+# Add/remove integrity while a snapshot exists
+#
+
+lvcreate --type raid1 -m1 -n $lv1 -L32M $vg "$dev1" "$dev2"
+aux wait_for_sync $vg $lv1
+mkfs.ext4 "$DM_DEV_DIR/$vg/$lv1"
+
+mount "$DM_DEV_DIR/$vg/$lv1" "$mount_dir"
+touch "$mount_dir/A"
+
+lvcreate -s -n snap -L12M $vg/$lv1 "$dev3"
+mount "$DM_DEV_DIR/$vg/snap" "$snap_dir"
+
+touch "$mount_dir/B"
+touch "$snap_dir/C"
+
+lvconvert --raidintegrity y $vg/$lv1
+aux wait_recalc $vg ${lv1}_rimage_0
+aux wait_recalc $vg ${lv1}_rimage_1
+
+ls "$mount_dir/B"
+ls "$snap_dir/C"
+ls "$mount_dir/A"
+ls "$snap_dir/A"
+
+touch "$mount_dir/B2"
+touch "$snap_dir/C2"
+
+lvconvert --raidintegrity n $vg/$lv1
+
+ls "$mount_dir/B"
+ls "$snap_dir/C"
+ls "$mount_dir/A"
+ls "$snap_dir/A"
+ls "$mount_dir/B2"
+ls "$snap_dir/C2"
+umount "$snap_dir"
+umount "$mount_dir"
+lvremove -y $vg/snap
+lvremove -y $vg/$lv1
+
+#
+# Add integrity not allowed with missing image and snapshot exists
+#
+
+lvcreate --type raid1 -m1 -n $lv1 -L32M $vg "$dev1" "$dev2"
+aux wait_for_sync $vg $lv1
+mkfs.ext4 "$DM_DEV_DIR/$vg/$lv1"
+
+mount "$DM_DEV_DIR/$vg/$lv1" "$mount_dir"
+touch "$mount_dir/A"
+
+lvcreate -s -n snap -L12M $vg/$lv1 "$dev3"
+mount "$DM_DEV_DIR/$vg/snap" "$snap_dir"
+
+touch "$mount_dir/B"
+touch "$snap_dir/C"
+
+aux disable_dev "$dev1"
+lvs -a $vg
+
+not lvconvert --raidintegrity y $vg/$lv1
+
+aux enable_dev "$dev1"
+lvs -a $vg
+
+umount "$snap_dir"
+umount "$mount_dir"
+lvremove -y $vg/snap
+lvremove -y $vg/$lv1
+
+fi # INTEGRITY TESTS SKIPPED
+
+vgremove -ff $vg
diff --git a/test/shell/snapshot-reactivate.sh b/test/shell/snapshot-reactivate.sh
new file mode 100644
index 0000000..4138e6e
--- /dev/null
+++ b/test/shell/snapshot-reactivate.sh
@@ -0,0 +1,60 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2014 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+#
+# Checking consistency of old-snapshot metadata after de/activation
+# Validates recent snapshot target kernel updates and error
+# is triggered by kernel 3.14-rc[1..5]
+# http://www.redhat.com/archives/dm-devel/2014-March/msg00005.html
+#
+
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+# Snapshot should remain unmodified
+check_s_() {
+ check dev_md5sum $vg s
+ #diff data "$DM_DEV_DIR/$vg/s"
+}
+
+which md5sum || skip
+
+aux prepare_vg
+
+# 8M file with some random data
+dd if=/dev/urandom of=data bs=1M count=1 conv=fdatasync
+dd if=data of=data bs=1M count=7 seek=1 conv=fdatasync
+echo "$(md5sum data | cut -d' ' -f1) $DM_DEV_DIR/$vg/s" >md5.${vg}-s
+
+lvcreate -aey -L 8M -n o $vg
+dd if=data of="$DM_DEV_DIR/$vg/o" bs=1M conv=fdatasync
+
+lvcreate -L 8M -s -n s $vg/o
+check_s_
+
+dd if=data of="$DM_DEV_DIR/$vg/o" bs=1234567 count=1 skip=1 conv=fdatasync
+check_s_
+lvchange -an $vg
+
+lvchange -ay $vg
+check_s_
+
+dd if=data of="$DM_DEV_DIR/$vg/o" bs=1234567 count=2 skip=1 conv=fdatasync
+check_s_
+
+lvchange -an $vg
+lvchange -ay $vg
+check_s_
+
+vgremove -f $vg
diff --git a/test/shell/snapshot-remove-dmsetup.sh b/test/shell/snapshot-remove-dmsetup.sh
new file mode 100644
index 0000000..ab5e2e9
--- /dev/null
+++ b/test/shell/snapshot-remove-dmsetup.sh
@@ -0,0 +1,93 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2015 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+# check if 'dmsetup --noflush' will work properly for mounted snapshot
+
+SKIP_WITH_LVMLOCKD=1
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+which mkfs.ext2 || skip
+
+aux prepare_vg 5
+
+# Create stacked device
+lvcreate --type snapshot -s -L10 -n $lv1 $vg --virtualsize 100M
+aux lvmconf "devices/scan_lvs = 1"
+aux extend_filter_LVMTEST
+aux extend_devices "$DM_DEV_DIR"/$vg/$lv1
+vgcreate $vg1 "$DM_DEV_DIR"/$vg/$lv1
+
+lvcreate -L20 -n $lv1 $vg1
+lvcreate -L10 -n snap -s $vg1/$lv1
+
+mkfs.ext2 "$DM_DEV_DIR/$vg1/snap"
+mkdir mnt
+mount -o errors=remount-ro "$DM_DEV_DIR/$vg1/snap" mnt
+
+sync
+
+# intentionally suspend layer below
+dmsetup suspend $vg-$lv1
+
+# now this should pass without blocking
+dmsetup suspend --noflush --nolockfs $vg1-snap &
+DMPID=$!
+#dmsetup suspend $vg1-snap &
+
+sleep .5
+
+dmsetup info --noheadings -c -o suspended $vg1-snap | tee out
+should grep -i suspend out
+
+# unlock device below
+dmsetup resume $vg-$lv1
+# so this will pass without blocking on udev
+# otherwise --noudevsync would be needed
+dmsetup resume $vg1-snap
+
+# Expecting success from 'dmsetup'
+wait $DMPID
+
+
+# Try how force removal works (and wait till there is no user)
+sync
+sleep .5
+dmsetup suspend $vg-$lv1
+# needs to fail as device is still open
+not dmsetup remove --force $vg1-snap &
+DMPID=$!
+
+# on older snapshot target 'remove' will wait till $lv1 is resumed
+if aux target_at_least dm-snapshot 1 6 0 ; then
+sleep .5
+
+dmsetup table $vg1-snap | tee out
+should grep -i error out
+fi
+
+dmsetup resume $vg-$lv1
+
+# Expecting success from 'not dmsetup'
+wait $DMPID
+
+# check it really is now 'error' target
+dmsetup table $vg1-snap | tee out
+grep error out
+
+umount mnt || true
+
+lvremove -f $vg1
+
+vgremove -ff $vg1
+vgremove -ff $vg
diff --git a/test/shell/snapshot-rename.sh b/test/shell/snapshot-rename.sh
new file mode 100644
index 0000000..e8d77a3
--- /dev/null
+++ b/test/shell/snapshot-rename.sh
@@ -0,0 +1,28 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2014 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+# Testing renaming snapshots (had problem in cluster)
+# https://bugzilla.redhat.com/show_bug.cgi?id=1136925
+
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+aux prepare_vg 1
+
+lvcreate -aey -L1 -n $lv1 $vg
+lvcreate -s -L1 -n $lv2 $vg/$lv1
+lvrename $vg/$lv2 $vg/$lv3
+lvremove -f $vg/$lv1
+
+vgremove -f $vg
diff --git a/test/shell/snapshot-usage-exa.sh b/test/shell/snapshot-usage-exa.sh
new file mode 100644
index 0000000..475960d
--- /dev/null
+++ b/test/shell/snapshot-usage-exa.sh
@@ -0,0 +1,47 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2015 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+# Check very large device size (upto 15Exa bytes)
+# this needs 64bit arch
+
+SKIP_WITH_LVMLOCKD=1
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+aux can_use_16T || skip
+
+aux prepare_pvs 1
+get_devs
+
+# Prepare large enough backend device
+vgcreate -s 4M "$vg" "${DEVICES[@]}"
+lvcreate --type snapshot -s -l 100%FREE -n $lv $vg --virtualsize 15P
+
+aux lvmconf "devices/scan_lvs = 1"
+aux extend_filter_LVMTEST
+aux extend_devices "$DM_DEV_DIR/$vg/$lv"
+
+# Check usability with largest extent size
+pvcreate "$DM_DEV_DIR/$vg/$lv"
+vgcreate -s 4G $vg1 "$DM_DEV_DIR/$vg/$lv"
+
+lvcreate -an -Zn -l50%FREE -n $lv1 $vg1
+lvcreate -s -l100%FREE -n $lv2 $vg1/$lv1
+check lv_field $vg1/$lv2 size "7.50p"
+lvremove -ff $vg1
+
+lvcreate --type snapshot -V15E -l1 -n $lv1 -s $vg1
+check lv_field $vg1/$lv1 origin_size "15.00e"
+
+vgremove -ff $vg1
+vgremove -ff $vg
diff --git a/test/shell/snapshot-usage.sh b/test/shell/snapshot-usage.sh
new file mode 100644
index 0000000..0f14dd6
--- /dev/null
+++ b/test/shell/snapshot-usage.sh
@@ -0,0 +1,205 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2013 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+# no automatic extensions please
+
+SKIP_WITH_LVMLOCKD=1
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+MKFS=mkfs.ext2
+which $MKFS || skip
+
+fill() {
+ dd if=/dev/zero of="$DM_DEV_DIR/${2:-$vg1/lvol0}" bs=$1 count=1 oflag=direct || \
+ die "Snapshot does not fit $1"
+}
+
+cleanup_tail()
+{
+ test -z "${SLEEP_PID-}" || kill $SLEEP_PID || true
+ wait
+ vgremove -ff $vg1 || true
+ vgremove -ff $vg
+ aux teardown
+}
+
+TSIZE=15P
+aux can_use_16T || TSIZE=15T
+
+# With different snapshot target driver we may obtain different results.
+# Older targets have metadata leak bug which needs extra compenstion.
+# Ancient targets do not even provide separate info for metadata.
+EXPECT1="16.00k"
+EXPECT2="512.00k"
+EXPECT3="32.00k"
+EXPECT4="66.67"
+if aux target_at_least dm-snapshot 1 10 0 ; then
+ # Extra metadata size
+ EXPECT4="0.00"
+
+ if aux target_at_least dm-snapshot 1 12 0 ; then
+ # When fixed leak, expect smaller sizes
+ EXPECT1="12.00k"
+ EXPECT2="384.00k"
+ EXPECT3="28.00k"
+ fi
+fi
+
+aux prepare_pvs 1
+get_devs
+
+vgcreate -s 4M "$vg" "${DEVICES[@]}"
+
+# Play with 1 extent
+lvcreate -aey -l1 -n $lv $vg
+# 100%LV is not supported for snapshot
+fail lvcreate -s -l 100%LV -n snap $vg/$lv 2>&1 | tee out
+grep 'Please express size as %FREE, %ORIGIN, %PVS or %VG' out
+# 100%ORIGIN needs to have enough space for all data and needs to round-up
+lvcreate -s -l 100%ORIGIN -n $lv1 $vg/$lv
+# everything needs to fit
+fill 4M $vg/$lv1
+lvremove -f $vg
+
+
+# Automatically activates exclusively in cluster
+lvcreate --type snapshot -s -l 100%FREE -n $lv $vg --virtualsize $TSIZE
+
+aux extend_filter_LVMTEST
+aux extend_devices "$DM_DEV_DIR/$vg/$lv"
+aux lvmconf "devices/scan_lvs = 1"
+aux lvmconf "activation/snapshot_autoextend_percent = 20" \
+ "activation/snapshot_autoextend_threshold = 50"
+
+# Check usability with smallest (1k) extent size ($lv has 15P)
+pvcreate --yes --setphysicalvolumesize 4T "$DM_DEV_DIR/$vg/$lv"
+trap 'cleanup_tail' EXIT
+vgcreate -s 4K $vg1 "$DM_DEV_DIR/$vg/$lv"
+
+# Play with small 1k 128 extents
+lvcreate -aey -L128K -n $lv $vg1
+# 100%ORIGIN needs to have enough space for all data
+lvcreate -s -l 100%ORIGIN -n snap100 $vg1/$lv
+# everything needs to fit
+fill 128k $vg1/snap100
+
+# 50%ORIGIN needs to have enough space for 50% of data
+lvcreate -s -l 50%ORIGIN -n snap50 $vg1/$lv
+fill 64k $vg1/snap50
+
+lvcreate -s -l 25%ORIGIN -n snap25 $vg1/$lv
+fill 32k $vg1/snap25
+
+# Check we do not provide too much extra space
+not fill 33k $vg1/snap25
+
+lvs -a $vg1
+lvremove -f $vg1
+
+# Test virtual snapshot over /dev/zero
+lvcreate --type snapshot -V50 -L10 -n $lv1 -s $vg1
+CHECK_ACTIVE="active"
+test ! -e LOCAL_CLVMD || CHECK_ACTIVE="local exclusive"
+check lv_field $vg1/$lv1 lv_active "$CHECK_ACTIVE"
+lvchange -an $vg1
+
+# On cluster snapshot gets exclusive activation
+lvchange -ay $vg1
+check lv_field $vg1/$lv1 lv_active "$CHECK_ACTIVE"
+
+# Test removal of opened (but unmounted) snapshot (device busy) for a while
+SLEEP_PID=$(aux hold_device_open $vg1 $lv1 60)
+
+# Opened virtual snapshot device is not removable
+# it should retry device removal for a few seconds
+not lvremove -f $vg1/$lv1
+
+kill $SLEEP_PID
+SLEEP_PID=
+# Wait for killed task, so there is no device holder
+wait
+
+lvremove -f $vg1/$lv1
+check lv_not_exists $vg1 $lv1
+
+# Check border size
+lvcreate -aey -L4095G $vg1
+lvcreate -s -L100K $vg1/lvol0
+fill 4K
+check lv_field $vg1/lvol1 data_percent "12.00"
+
+lvremove -ff $vg1
+
+# Create 4KB snapshot, does not need to be active here
+lvcreate -an -Zn -l1 -n $lv1 $vg1
+not lvcreate -s -l1 $vg1/$lv1
+# snapshot cannot be smaller then 3 chunks (12K)
+not lvcreate -s -l2 $vg1/$lv1
+lvcreate -s -l30 -n $lv2 $vg1/$lv1
+check lv_field $vg1/$lv2 size "$EXPECT1"
+
+not lvcreate -s -c512 -l128 $vg1/$lv1
+lvcreate -s -c128 -l1700 -n $lv3 $vg1/$lv1
+# 3 * 128
+check lv_field $vg1/$lv3 size "$EXPECT2"
+lvremove -ff $vg1
+
+lvcreate -aey -l5 $vg1
+lvcreate -s -l3 $vg1/lvol0
+
+# Fill 4KB -> 100% snapshot (1x 4KB chunk)
+fill 4K
+check lv_field $vg1/lvol1 data_percent "100.00"
+
+# Check it resizes 100% full valid snapshot to fit threshold
+lvextend --use-policies $vg1/lvol1
+check lv_field $vg1/lvol1 data_percent "50.00"
+
+fill 4K
+lvextend --use-policies $vg1/lvol1
+check lv_field $vg1/lvol1 size "24.00k"
+
+lvextend -l+8 $vg1/lvol1
+check lv_field $vg1/lvol1 size "$EXPECT3"
+
+fill 20K
+
+lvremove -f $vg1
+
+# Check snapshot really deletes COW header for read-only snapshot
+# Test needs special relation between chunk size and extent size
+# This test expects extent size 1K
+aux lvmconf "allocation/wipe_signatures_when_zeroing_new_lvs = 1"
+lvcreate -aey -L4 -n $lv $vg1
+lvcreate -c 8 -s -L1 -n snap $vg1/$lv
+# Populate snapshot
+#dd if=/dev/urandom of="$DM_DEV_DIR/$vg1/$lv" bs=4096 count=10
+$MKFS "$DM_DEV_DIR/$vg1/$lv"
+lvremove -f $vg1/snap
+
+# Undeleted header would trigger attempt to access
+# beyond end of COW device
+# Fails to create when chunk size is different
+lvcreate -s -pr -l3 -n snap $vg1/$lv
+
+# When header is undelete, fails to read snapshot without read errors
+#dd if="$DM_DEV_DIR/$vg1/snap" of=/dev/null bs=1M count=2
+fsck -n "$DM_DEV_DIR/$vg1/snap"
+
+# This test would trigger read of weird percentage for undeleted header
+# And since older snapshot target counts with metadata sectors
+# we have 2 valid results (unsure about correct version number)
+check lv_field $vg1/snap data_percent "$EXPECT4"
+
+vgremove -ff $vg1
diff --git a/test/shell/snapshots-of-mirrors.sh b/test/shell/snapshots-of-mirrors.sh
index 183d3ac..f2f2943 100644
--- a/test/shell/snapshots-of-mirrors.sh
+++ b/test/shell/snapshots-of-mirrors.sh
@@ -1,5 +1,6 @@
-#!/bin/sh
-# Copyright (C) 2010 Red Hat, Inc. All rights reserved.
+#!/usr/bin/env bash
+
+# Copyright (C) 2010,2018 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
@@ -7,25 +8,29 @@
#
# 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
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+
+
+. lib/inittest
-. lib/test
+aux lvmconf "global/support_mirrored_mirror_log=1"
aux prepare_vg 4
-# Attempt to create snapshot of a mirror origin - should fail
-lvcreate -m 1 -L 10M -n lv $vg
+lvcreate -aey --type mirror -m 1 -L 10M --nosync -n lv $vg
+# Create snapshot of a mirror origin
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
+lvconvert --type mirror -m2 $vg/lv
# Down-convert (mirror -> mirror)
-lvconvert -m1 $vg/lv
+lvconvert -m 1 $vg/lv
# Up-convert (mirror -> mirror) -- Not supported!
not lvconvert -m2 $vg/lv
@@ -34,7 +39,10 @@ not lvconvert -m2 $vg/lv
lvconvert --mirrorlog core $vg/lv
# Log conversion (core -> mirrored)
-lvconvert --mirrorlog mirrored $vg/lv
+# FIXME on cluster
+SHOULD=""
+test -e LOCAL_CLVMD && SHOULD=should
+$SHOULD lvconvert --mirrorlog mirrored $vg/lv
# Log conversion (mirrored -> core)
lvconvert --mirrorlog core $vg/lv
diff --git a/test/shell/stray-device-node.sh b/test/shell/stray-device-node.sh
new file mode 100644
index 0000000..003afb7
--- /dev/null
+++ b/test/shell/stray-device-node.sh
@@ -0,0 +1,36 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2014 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+aux prepare_devs 3
+get_devs
+
+# Avoid manipulation with real /dev dir
+test "$DM_DEV_DIR" = "/dev" && skip "Skipping stray test on real /dev dir"
+
+cp -r "$dev1" "$DM_DEV_DIR/stray"
+
+vgcreate $SHARED "$vg" "${DEVICES[@]}"
+lvcreate -an -Zn --type mirror -m 1 -l 1 -n mirror $vg
+aux disable_dev "$dev1"
+# FIXME:
+# for the .cache use case we need to run pvscan
+# to keep clvmd in sync.
+pvscan
+vgreduce --removemissing --force $vg
+aux enable_dev "$dev1"
+
+rm -f "$DM_DEV_DIR/stray"
diff --git a/test/shell/stress_multi_threads_1.sh b/test/shell/stress_multi_threads_1.sh
new file mode 100644
index 0000000..c5695eb
--- /dev/null
+++ b/test/shell/stress_multi_threads_1.sh
@@ -0,0 +1,113 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2021 Seagate, 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 v2.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+[ -z "$LVM_TEST_LOCK_TYPE_IDM" ] && skip;
+
+aux prepare_devs 6
+get_devs
+
+pvcreate -M2 "${DEVICES[@]}"
+
+vgcreate $SHARED -M2 "$vg1" "$dev1" "$dev2" "$dev3"
+vgcreate $SHARED -M2 "$vg2" "$dev4" "$dev5" "$dev6"
+
+test_vg_thread1()
+{
+ for i in {1..1000}
+ do
+ # Create new logic volume and deactivate it
+ lvcreate -a n --zero n -l 1 -n foo $vg1
+
+ # Set minor number
+ lvchange $vg1/foo -My --major=255 --minor=123
+
+ # Activate logic volume
+ lvchange $vg1/foo -a y
+
+ # Extend logic volume with 10%
+ lvextend -l+10 $vg1/foo
+
+ # Deactivate logic volume
+ lvchange $vg1/foo -a n
+
+ # Deactivate volume group
+ vgchange $vg1 -a n
+
+ # Activate volume group with shareable mode
+ vgchange $vg1 -a sy
+
+ # lvextend fails due to mismatched lock mode
+ not lvextend -l+10 $vg1/foo
+
+ # Promote volume group to exclusive mode
+ vgchange $vg1 -a ey
+
+ lvreduce -f -l-4 $vg1/foo
+
+ lvchange -an $vg1/foo
+ lvremove $vg1/foo
+ done
+}
+
+test_vg_thread2()
+{
+ for i in {1..1000}
+ do
+ # Create new logic volume and deactivate it
+ lvcreate -a n --zero n -l 1 -n foo $vg2
+
+ # Set minor number
+ lvchange $vg2/foo -My --major=255 --minor=124
+
+ # Activate logic volume
+ lvchange $vg2/foo -a y
+
+ # Extend logic volume with 10%
+ lvextend -l+10 $vg2/foo
+
+ # Deactivate logic volume
+ lvchange $vg2/foo -a n
+
+ # Deactivate volume group
+ vgchange $vg2 -a n
+
+ # Activate volume group with shareable mode
+ vgchange $vg2 -a sy
+
+ # lvextend fails due to mismatched lock mode
+ not lvextend -l+10 $vg2/foo
+
+ # Promote volume group to exclusive mode
+ vgchange $vg2 -a ey
+
+ lvreduce -f -l-4 $vg2/foo
+
+ lvchange -an $vg2/foo
+ lvremove $vg2/foo
+ done
+}
+
+test_vg_thread1 &
+WAITPID=$!
+
+test_vg_thread2 &
+WAITPID="$WAITPID "$!
+
+wait $WAITPID
+
+vgremove -ff $vg1
+vgremove -ff $vg2
diff --git a/test/shell/stress_multi_threads_2.sh b/test/shell/stress_multi_threads_2.sh
new file mode 100644
index 0000000..9b586a2
--- /dev/null
+++ b/test/shell/stress_multi_threads_2.sh
@@ -0,0 +1,95 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2021 Seagate, 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 v2.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+[ -z "$LVM_TEST_LOCK_TYPE_IDM" ] && skip;
+
+aux prepare_devs 8
+get_devs
+
+pvcreate -M2 "$dev1" "$dev2" "$dev3" "$dev4" "$dev5" "$dev6"
+
+test_vg_thread1()
+{
+ for i in {1..1000}
+ do
+ vgcreate $SHARED -M2 "$vg1" "$dev1" "$dev2" "$dev3"
+ vgremove -ff $vg1
+ done
+}
+
+test_vg_thread2()
+{
+ vgcreate $SHARED -M2 "$vg2" "$dev4" "$dev5" "$dev6"
+
+ for i in {1..1000}
+ do
+ # Create new logic volume and deactivate it
+ lvcreate -a n --zero n -l 1 -n foo $vg2
+
+ # Set minor number
+ lvchange $vg2/foo -My --major=255 --minor=124
+
+ # Activate logic volume
+ lvchange $vg2/foo -a y
+
+ # Extend logic volume with 10%
+ lvextend -l+10 $vg2/foo
+
+ # Deactivate logic volume
+ lvchange $vg2/foo -a n
+
+ # Deactivate volume group
+ vgchange $vg2 -a n
+
+ # Activate volume group with shareable mode
+ vgchange $vg2 -a sy
+
+ # lvextend fails due to mismatched lock mode
+ not lvextend -l+10 $vg2/foo
+
+ # Promote volume group to exclusive mode
+ vgchange $vg2 -a ey
+
+ lvreduce -f -l-4 $vg2/foo
+
+ lvchange -an $vg2/foo
+ lvremove $vg2/foo
+ done
+
+ vgremove -ff $vg2
+}
+
+test_vg_thread3()
+{
+ for i in {1..1000}
+ do
+ pvcreate -M2 "$dev7" "$dev8"
+ pvremove "$dev7"
+ pvremove "$dev8"
+ done
+}
+
+test_vg_thread1 &
+WAITPID=$!
+
+test_vg_thread2 &
+WAITPID="$WAITPID "$!
+
+test_vg_thread3 &
+WAITPID="$WAITPID "$!
+
+wait $WAITPID
diff --git a/test/shell/stress_single_thread.sh b/test/shell/stress_single_thread.sh
new file mode 100644
index 0000000..7982e9d
--- /dev/null
+++ b/test/shell/stress_single_thread.sh
@@ -0,0 +1,61 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2021 Seagate, 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 v2.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+[ -z "$LVM_TEST_LOCK_TYPE_IDM" ] && skip;
+
+aux prepare_vg 3
+
+for i in {1..1000}
+do
+ # Create new logic volume and deactivate it
+ lvcreate -a n --zero n -l 1 -n foo $vg
+
+ # Set minor number
+ lvchange $vg/foo -My --major=255 --minor=123
+
+ # Activate logic volume
+ lvchange $vg/foo -a y
+
+ # Check device mapper
+ dmsetup info $vg-foo | tee info
+ grep -E "^Major, minor: *[0-9]+, 123" info
+
+ # Extend logic volume with 10%
+ lvextend -l+10 $vg/foo
+
+ # Deactivate logic volume
+ lvchange $vg/foo -a n
+
+ # Deactivate volume group
+ vgchange $vg -a n
+
+ # Activate volume group with shareable mode
+ vgchange $vg -a sy
+
+ # lvextend fails due to mismatched lock mode
+ not lvextend -l+10 $vg/foo
+
+ # Promote volume group to exclusive mode
+ vgchange $vg -a ey
+
+ lvreduce -f -l-4 $vg/foo
+
+ lvchange -an $vg/foo
+ lvremove $vg/foo
+done
+
+vgremove -ff $vg
diff --git a/test/shell/system_id.sh b/test/shell/system_id.sh
new file mode 100644
index 0000000..486fba1
--- /dev/null
+++ b/test/shell/system_id.sh
@@ -0,0 +1,709 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2015 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+test_description='Test system_id'
+
+# test does not apply to lvmlockd
+SKIP_WITH_LVMLOCKD=1
+SKIP_WITH_LVMPOLLD=1
+
+print_lvmlocal() {
+ { echo "local {"; printf "%s\n" "$@"; echo "}"; } >"$LVMLOCAL"
+}
+
+. lib/inittest
+
+aux prepare_devs 5
+
+# get lvm.conf location in a form of: etc=path
+eval "$(lvmconfig global/etc)"
+
+SIDFILE="$etc/lvm_test.conf"
+LVMLOCAL="$etc/lvmlocal.conf"
+
+DFDIR="$etc/devices"
+DF="$DFDIR/system.devices"
+
+# Avoid system id validation in the devices file
+# which gets in the way of the test switching the
+# local system id.
+clear_df_systemid() {
+ if [[ -f $DF ]]; then
+ sed -e "s|SYSTEMID=.||" "$DF" > tmpdf
+ cp tmpdf $DF
+ fi
+}
+
+# create vg with system_id using each source
+
+## none
+
+SID=""
+aux lvmconf "global/system_id_source = none"
+vgcreate $vg1 "$dev1"
+check vg_field $vg1 systemid "$SID"
+vgremove $vg1
+
+## machineid
+if [ -e "$etc/machine-id" ]; then
+SID=$(cat "$etc/machine-id")
+aux lvmconf "global/system_id_source = machineid"
+vgcreate $vg1 "$dev1"
+vgs -o+systemid $vg1
+check vg_field $vg1 systemid "$SID"
+vgremove $vg1
+fi
+
+## appmachineid
+lvm version > lvmver
+if grep app-machineid lvmver; then
+aux lvmconf "global/system_id_source = appmachineid"
+lvm systemid | awk '{ print $3 }' > sid_lvm
+vgcreate $vg1 "$dev1"
+vgs -o systemid --noheadings $vg1 | awk '{print $1}' > sid_vg
+diff sid_lvm sid_vg
+vgremove $vg1
+fi
+
+## uname
+
+SID1=$(uname -n)
+if [ -n "$SID1" ]; then
+aux lvmconf "global/system_id_source = uname"
+SID2=$(lvm systemid | awk '{ print $3 }')
+vgcreate $vg1 "$dev1"
+vgs -o+systemid $vg1
+check vg_field $vg1 systemid "$SID2"
+vgremove $vg1
+fi
+
+## lvmlocal
+
+SID=sidfoolocal
+print_lvmlocal " system_id = $SID"
+aux lvmconf "global/system_id_source = lvmlocal"
+vgcreate $vg1 "$dev1"
+vgs -o+systemid $vg1
+check vg_field $vg1 systemid "$SID"
+vgremove $vg1
+rm -f "$LVMLOCAL"
+
+## file
+
+SID=sidfoofile
+echo "$SID" > "$SIDFILE"
+clear_df_systemid
+aux lvmconf "global/system_id_source = file" \
+ "global/system_id_file = \"$SIDFILE\""
+vgcreate $vg1 "$dev1"
+vgs -o+systemid $vg1
+check vg_field $vg1 systemid "$SID"
+vgremove $vg1
+
+# override system_id to create a foreign vg, then fail to use the vg
+
+SID1=sidfoofile1
+SID2=sidfoofile2
+echo "$SID1" > "$SIDFILE"
+clear_df_systemid
+aux lvmconf "global/system_id_source = file" \
+ "global/system_id_file = \"$SIDFILE\""
+# create a vg, overriding the local system_id so the vg looks foreign
+vgcreate --systemid "$SID2" "$vg1" "$dev1"
+# normal vgs is not an error and does not see the vg
+vgs >err
+not grep $vg1 err
+# vgs on the foreign vg is an error and not displayed
+not vgs $vg1 >err
+not grep $vg1 err
+# fail to remove foreign vg
+not vgremove $vg1
+# using --foreign we can see foreign vg
+vgs --foreign >err
+grep $vg1 err
+vgs --foreign $vg1 >err
+grep $vg1 err
+# change the local system_id to the second value, making the vg not foreign
+echo "$SID2" > "$SIDFILE"
+clear_df_systemid
+# we can now see and remove the vg
+vgs $vg1 >err
+grep $vg1 err
+vgremove $vg1
+
+# create a vg, then change the local system_id, making the vg foreign
+
+SID1=sidfoofile1
+SID2=sidfoofile2
+echo "$SID1" > "$SIDFILE"
+clear_df_systemid
+aux lvmconf "global/system_id_source = file" \
+ "global/system_id_file = \"$SIDFILE\""
+# create a vg
+vgcreate $vg1 "$dev1"
+# normal vgs sees the vg
+vgs >err
+grep $vg1 err
+# change the local system_id, making the vg foreign
+echo "$SID2" > "$SIDFILE"
+clear_df_systemid
+# normal vgs doesn't see the vg
+vgs >err
+not grep $vg1 err
+# using --foreign we can see the vg
+vgs --foreign >err
+grep $vg1 err
+# change the local system_id back to the first value, making the vg not foreign
+echo "$SID1" > "$SIDFILE"
+clear_df_systemid
+vgs >err
+grep $vg1 err
+vgremove $vg1
+
+# create a vg, then change the vg's system_id, making it foreign
+
+SID1=sidfoofile1
+SID2=sidfoofile2
+echo "$SID1" > "$SIDFILE"
+clear_df_systemid
+aux lvmconf "global/system_id_source = file" \
+ "global/system_id_file = \"$SIDFILE\""
+# create a vg
+vgcreate $vg1 "$dev1"
+# normal vgs sees the vg
+vgs >err
+grep $vg1 err
+# change the vg's system_id, making the vg foreign
+vgchange --yes --systemid "$SID2" $vg1
+# normal vgs doesn't see the vg
+vgs >err
+not grep $vg1 err
+# using --foreign we can see the vg
+vgs --foreign >err
+grep $vg1 err
+# change the local system_id to the second system_id so we can remove the vg
+echo "$SID2" > "$SIDFILE"
+clear_df_systemid
+vgs >err
+grep $vg1 err
+vgremove $vg1
+
+# create a vg, create active lvs in it, change our system_id, making
+# the VG foreign, verify that we can still see the foreign VG,
+# and can deactivate the LVs
+
+SID1=sidfoofile1
+SID2=sidfoofile2
+echo "$SID1" > "$SIDFILE"
+clear_df_systemid
+aux lvmconf "global/system_id_source = file" \
+ "global/system_id_file = \"$SIDFILE\""
+# create a vg
+vgcreate $vg1 "$dev1"
+lvcreate -n $lv1 -l 2 $vg1
+# normal vgs sees the vg and lv
+vgs >err
+grep $vg1 err
+check lv_exists $vg1 $lv1
+# change our system_id, making the vg foreign, but accessible
+echo "$SID2" > "$SIDFILE"
+clear_df_systemid
+vgs >err
+grep $vg1 err
+check lv_exists $vg1 $lv1
+# can deactivate the lv
+lvchange -an $vg1/$lv1
+# now that the foreign vg has no active lvs, we can't access it
+not lvremove $vg1/$lv1
+not vgremove $vg1
+# change our system_id back to match the vg so it's not foreign
+echo "$SID1" > "$SIDFILE"
+clear_df_systemid
+vgs >err
+grep $vg1 err
+lvremove $vg1/$lv1
+vgremove $vg1
+
+# local system has no system_id, so it can't access a vg with a system_id
+
+SID1=sidfoofile1
+echo "$SID1" > "$SIDFILE"
+clear_df_systemid
+aux lvmconf "global/system_id_source = file" \
+ "global/system_id_file = \"$SIDFILE\""
+# create a vg
+vgcreate $vg1 "$dev1"
+aux lvmconf "global/system_id_source = none"
+vgs >err
+not grep $vg1 err
+not vgs $vg1 >err
+not grep $vg1 err
+aux lvmconf "global/system_id_source = file"
+vgs >err
+grep $vg1 err
+vgremove $vg1
+
+# local system has a system_id, and can use a vg without a system_id
+
+SID1=sidfoofile1
+rm -f "$SIDFILE"
+clear_df_systemid
+# create a vg with no system_id
+aux lvmconf "global/system_id_source = none"
+vgcreate $vg1 "$dev1"
+check vg_field $vg1 systemid ""
+# set a local system_id
+echo "$SID1" > "$SIDFILE"
+clear_df_systemid
+aux lvmconf "global/system_id_source = file" \
+ "global/system_id_file = \"$SIDFILE\""
+# check we can see and use the vg with no system_id
+vgs >err
+grep $vg1 err
+vgs $vg1 >err
+grep $vg1 err
+vgremove $vg1
+
+# vgexport clears system_id, vgimport sets system_id
+
+SID1=sidfoofile1
+echo "$SID1" > "$SIDFILE"
+clear_df_systemid
+aux lvmconf "global/system_id_source = file" \
+ "global/system_id_file = \"$SIDFILE\""
+# create a vg
+vgcreate $vg1 "$dev1"
+# normal vgs sees the vg
+vgs -o+systemid >err
+grep $vg1 err
+grep "$SID1" err
+# after vgexport there is no systemid
+vgexport $vg1
+vgs -o+systemid >err
+grep $vg1 err
+not grep "$SID1" err
+# after vgimport there is a systemid
+vgimport $vg1
+vgs -o+systemid >err
+grep $vg1 err
+grep "$SID1" err
+vgremove $vg1
+
+# Test max system_id length (128) and invalid system_id characters.
+# The 128 length limit is imposed before invalid characters are omitted.
+
+# 120 numbers followed by 8 letters (max len)
+SID1=012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789abcdefgh
+# 120 numbers followed by 9 letters (too long by 1 character, the last is omitted)
+SID2=012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789abcdefghi
+
+# max len system_id should appear normally
+echo "$SID1" > "$SIDFILE"
+clear_df_systemid
+aux lvmconf "global/system_id_source = file" \
+ "global/system_id_file = \"$SIDFILE\""
+# create a vg
+vgcreate $vg1 "$dev1"
+# normal vgs sees the vg
+vgs -o+systemid $vg1 >err
+grep $vg1 err
+grep "$SID1" err
+vgremove $vg1
+
+# max+1 len system_id should be missing the last character
+echo "$SID2" > "$SIDFILE"
+clear_df_systemid
+aux lvmconf "global/system_id_source = file" \
+ "global/system_id_file = \"$SIDFILE\""
+# create a vg
+vgcreate $vg1 "$dev1"
+# normal vgs sees the vg
+vgs -o+systemid $vg1 >err
+grep $vg1 err
+grep "$SID1" err
+not grep "$SID2" err
+vgremove $vg1
+
+# max len system_id containing an invalid character should appear without
+# the invalid character
+# 120 numbers followed by invalid '%' character followed by 8 letters (too long by 1 character)
+SID1=012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789%abcdefgh
+# After the invalid character is omitted from SID1
+# The string is truncated to max length (128) before the invalid character is omitted
+SID2=012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789abcdefg
+echo "$SID1" > "$SIDFILE"
+clear_df_systemid
+aux lvmconf "global/system_id_source = file" \
+ "global/system_id_file = \"$SIDFILE\""
+# create a vg
+vgcreate $vg1 "$dev1"
+# normal vgs sees the vg
+vgs -o+systemid $vg1 >err
+grep $vg1 err
+not grep $SID1 err
+grep $SID2 err
+vgremove $vg1
+
+# contains a bunch of invalid characters
+SID1="?%$&A.@1]"
+# SID1 without the invalid characters
+SID2=A.1
+echo "$SID1" > "$SIDFILE"
+clear_df_systemid
+aux lvmconf "global/system_id_source = file" \
+ "global/system_id_file = \"$SIDFILE\""
+# create a vg
+vgcreate $vg1 "$dev1"
+# normal vgs sees the vg
+vgs -o+systemid $vg1 >err
+grep $vg1 err
+not grep "$SID1" err
+grep "$SID2" err
+vgremove $vg1
+
+
+# pvs: pv in a foreign vg not reported
+# pvs --foreign: pv in a foreign vg is reported
+
+SID1=sidfoofile1
+SID2=sidfoofile2
+echo "$SID1" > "$SIDFILE"
+clear_df_systemid
+aux lvmconf "global/system_id_source = file" \
+ "global/system_id_file = \"$SIDFILE\""
+# create a vg
+vgcreate $vg1 "$dev1"
+# normal pvs sees the vg and pv
+pvs >err
+grep $vg1 err
+grep "$dev1" err
+# change the local system_id, making the vg foreign
+echo "$SID2" > "$SIDFILE"
+clear_df_systemid
+# normal pvs does not see the vg or pv
+pvs >err
+not grep $vg1 err
+not grep "$dev1" err
+# pvs --foreign does see the vg and pv
+pvs --foreign >err
+grep $vg1 err
+grep "$dev1" err
+# change the local system_id back so the vg can be removed
+echo "$SID1" > "$SIDFILE"
+clear_df_systemid
+vgremove $vg1
+rm -f "$SIDFILE"
+
+# lvs: lvs in a foreign vg not reported
+# lvs --foreign: lvs in a foreign vg are reported
+
+SID1=sidfoofile1
+SID2=sidfoofile2
+echo "$SID1" > "$SIDFILE"
+clear_df_systemid
+aux lvmconf "global/system_id_source = file" \
+ "global/system_id_file = \"$SIDFILE\""
+# create a vg
+vgcreate $vg1 "$dev1"
+lvcreate -n $lv1 -l 2 $vg1
+lvchange -an $vg1/$lv1
+# normal lvs sees the vg and lv
+lvs >err
+grep $vg1 err
+grep $lv1 err
+# change the local system_id, making the vg foreign
+echo "$SID2" > "$SIDFILE"
+clear_df_systemid
+# normal lvs does not see the vg or lv
+lvs >err
+not grep $vg1 err
+not grep $lv1 err
+# lvs --foreign does see the vg and lv
+lvs --foreign >err
+grep $vg1 err
+grep $lv1 err
+# change the local system_id back so the vg can be removed
+echo "$SID1" > "$SIDFILE"
+clear_df_systemid
+lvremove $vg1/$lv1
+vgremove $vg1
+rm -f "$SIDFILE"
+
+# use extra_system_ids to read a foreign VG
+
+SID1=sidfoofile1
+SID2=sidfoofile2
+rm -f "$LVMLOCAL"
+echo "$SID1" > "$SIDFILE"
+clear_df_systemid
+aux lvmconf "global/system_id_source = file" \
+ "global/system_id_file = \"$SIDFILE\""
+# create a vg
+vgcreate $vg1 "$dev1"
+# normal vgs sees the vg
+vgs >err
+grep $vg1 err
+# change the local system_id, making the vg foreign
+echo "$SID2" > "$SIDFILE"
+clear_df_systemid
+# normal vgs doesn't see the vg
+vgs >err
+not grep $vg1 err
+# using --foreign we can see the vg
+vgs --foreign >err
+grep $vg1 err
+# add the first system_id to extra_system_ids so we can see the vg
+print_lvmlocal " extra_system_ids = [ $SID1 ] "
+vgs >err
+grep $vg1 err
+vgremove $vg1
+rm -f "$LVMLOCAL"
+
+# vgcreate --systemid "" creates a vg without a system_id even if source is set
+SID1=sidfoofile1
+echo "$SID1" > "$SIDFILE"
+clear_df_systemid
+aux lvmconf "global/system_id_source = file" \
+ "global/system_id_file = \"$SIDFILE\""
+# create a vg
+vgcreate --systemid "" $vg1 "$dev1"
+# normal vgs sees the vg
+vgs >err
+grep $vg1 err
+# our system_id is not displayed for the vg
+vgs -o+systemid >err
+not grep "$SID1" err
+vgremove $vg1
+rm -f "$SIDFILE"
+
+# vgchange --systemid "" clears the system_id on owned vg
+SID1=sidfoofile1
+echo "$SID1" > "$SIDFILE"
+clear_df_systemid
+aux lvmconf "global/system_id_source = file" \
+ "global/system_id_file = \"$SIDFILE\""
+# create a vg
+vgcreate $vg1 "$dev1"
+# normal vgs sees the vg
+vgs >err
+grep $vg1 err
+# the vg has our system_id
+vgs -o+systemid >err
+grep $SID1 err
+# clear the system_id
+vgchange --yes --systemid "" $vg1
+# normal vgs sees the vg
+vgs >err
+grep $vg1 err
+# the vg does not have our system_id
+vgs -o+systemid >err
+not grep "$SID1" err
+vgremove $vg1
+
+# vgchange --systemid does not set the system_id on foreign vg
+SID1=sidfoofile1
+SID2=sidfoofile2
+rm -f "$LVMLOCAL"
+echo "$SID1" > "$SIDFILE"
+clear_df_systemid
+aux lvmconf "global/system_id_source = file" \
+ "global/system_id_file = \"$SIDFILE\""
+# create a vg
+vgcreate $vg1 "$dev1"
+# normal vgs sees the vg
+vgs >err
+grep $vg1 err
+# change the local system_id, making the vg foreign
+echo "$SID2" > "$SIDFILE"
+clear_df_systemid
+# normal vgs doesn't see the vg
+vgs >err
+not grep $vg1 err
+# using --foreign we can see the vg
+vgs --foreign >err
+grep $vg1 err
+# cannot clear the system_id of the foreign vg
+not vgchange --yes --systemid "" $vg1
+# cannot set the system_id of the foreign vg
+not vgchange --yes --systemid foo $vg1
+# change our system_id back so we can remove the vg
+echo "$SID1" > "$SIDFILE"
+clear_df_systemid
+vgremove $vg1
+
+# vgchange --systemid --majoritypvs
+SID1=sidfoofile1
+SID2=sidfoofile2
+rm -f "$LVMLOCAL"
+echo "$SID1" > "$SIDFILE"
+clear_df_systemid
+aux lvmconf "global/system_id_source = file" \
+ "global/system_id_file = \"$SIDFILE\""
+# create a vg
+vgcreate $vg1 "$dev1" "$dev2" "$dev3"
+vgcreate $vg2 "$dev4" "$dev5"
+# normal vgs sees the vg
+# change the local system_id, making the vg foreign
+echo "$SID2" > "$SIDFILE"
+clear_df_systemid
+# normal vgs doesn't see the vg
+vgs >err
+not grep $vg1 err
+not grep $vg2 err
+# using --foreign we can see the vg
+vgs --foreign >err
+grep $vg1 err
+grep $vg2 err
+# cannot clear the system_id of the foreign vg
+not vgchange --yes --systemid "" $vg1
+not vgchange --yes --systemid "" $vg2
+# cannot set the system_id of the foreign vg
+not vgchange --yes --systemid foo $vg1
+not vgchange --yes --systemid foo $vg2
+# we are local node SID2, foreign node is SID1
+# use extra_system_ids to take over the foreign vg, making it local
+vgchange --config "local/extra_system_ids=[\"${SID1}\"]" --systemid $SID2 $vg1
+vgs $vg1
+# make it foreign again
+vgchange --yes --systemid sidfoofile1 $vg1
+not vgs $vg1
+# both vgs are foreign, drop dev1/dev4 so both vgs are missing a device
+aux hide_dev "$dev1"
+aux hide_dev "$dev4"
+not pvs "$dev1"
+not pvs "$dev4"
+# neither VG can be changed because both are missing a dev
+not vgchange --config "local/extra_system_ids=[\"${SID1}\"]" --systemid $SID2 $vg1
+not vgchange --config "local/extra_system_ids=[\"${SID1}\"]" --systemid $SID2 $vg2
+# using majoritypvs, vg1 can be changed because 2 of 3 PVs exist
+vgchange --majoritypvs --config "local/extra_system_ids=[\"${SID1}\"]" --systemid $SID2 $vg1
+vgs $vg1
+# using majoritypvs, vg2 cannot be changed because 1 of 2 PVs exist
+not vgchange --majoritypvs --config "local/extra_system_ids=[\"${SID1}\"]" --systemid $SID2 $vg2
+not vgs $vg2
+vgs --foreign $vg2
+# dev1/dev4 return so we can take over vg2 now
+# vg1 will complain about stale metadata on dev1
+aux unhide_dev "$dev1"
+aux unhide_dev "$dev4"
+vgs
+pvs
+vgchange --majoritypvs --config "local/extra_system_ids=[\"${SID1}\"]" --systemid $SID2 $vg2
+vgs $vg2
+# update metadata on dev1
+vgck --updatemetadata $vg1
+vgs $vg1
+clear_df_systemid
+vgremove $vg1
+vgremove $vg2
+
+
+# vgcfgbackup backs up foreign vg with --foreign
+SID1=sidfoofile1
+SID2=sidfoofile2
+rm -f "$LVMLOCAL"
+echo "$SID1" > "$SIDFILE"
+clear_df_systemid
+aux lvmconf "global/system_id_source = file" \
+ "global/system_id_file = \"$SIDFILE\""
+# create a vg
+vgcreate $vg1 "$dev1"
+# normal vgs sees the vg
+vgs >err
+grep $vg1 err
+# change the local system_id, making the vg foreign
+echo "$SID2" > "$SIDFILE"
+clear_df_systemid
+# normal vgs doesn't see the vg
+vgs >err
+not grep $vg1 err
+# using --foreign we can back up the vg
+not vgcfgbackup $vg1
+vgcfgbackup --foreign $vg1
+# change our system_id back so we can remove the vg
+echo "$SID1" > "$SIDFILE"
+clear_df_systemid
+vgremove $vg1
+rm -f "$SIDFILE"
+
+
+# Test handling of bad system_id source configurations
+# The commands should proceed without a system_id.
+# Look at the warning/error messages.
+
+# vgcreate with source machineid, where no $etc/machine-id file exists
+if [ ! -e "$etc/machine-id" ]; then
+SID=""
+aux lvmconf "global/system_id_source = machineid"
+vgcreate $vg1 "$dev1" 2>&1 | tee err
+vgs -o+systemid $vg1
+check vg_field $vg1 systemid $SID
+grep "No system ID found from system_id_source" err
+vgremove $vg1
+fi
+
+# vgcreate with source uname, but uname is localhost
+# TODO: don't want to change the hostname on the test machine...
+
+# vgcreate with source lvmlocal, but no lvmlocal.conf file
+SID=""
+rm -f $LVMLOCAL
+aux lvmconf "global/system_id_source = lvmlocal"
+vgcreate $vg1 "$dev1" 2>&1 | tee err
+vgs -o+systemid $vg1
+check vg_field $vg1 systemid $SID
+grep "No system ID found from system_id_source" err
+vgremove $vg1
+
+# vgcreate with source lvmlocal, but no system_id = "x" entry
+SID=""
+print_lvmlocal # " system_id = $SID"
+aux lvmconf "global/system_id_source = lvmlocal"
+vgcreate $vg1 "$dev1" 2>&1 | tee err
+vgs -o+systemid $vg1
+check vg_field $vg1 systemid $SID
+grep "No system ID found from system_id_source" err
+vgremove $vg1
+
+# vgcreate with source lvmlocal, and empty string system_id = ""
+SID=""
+print_lvmlocal " system_id = \"\""
+aux lvmconf "global/system_id_source = lvmlocal"
+vgcreate $vg1 "$dev1" 2>&1 | tee err
+vgs -o+systemid $vg1
+check vg_field $vg1 systemid "$SID"
+grep "No system ID found from system_id_source" err
+vgremove $vg1
+rm -f $LVMLOCAL
+
+# vgcreate with source file, but no system_id_file config
+SID=""
+rm -f "$SIDFILE"
+clear_df_systemid
+aux lvmconf "global/system_id_source = file"
+vgcreate $vg1 "$dev1" 2>&1 | tee err
+vgs -o+systemid $vg1
+check vg_field $vg1 systemid "$SID"
+grep "No system ID found from system_id_source" err
+vgremove $vg1
+
+# vgcreate with source file, but system_id_file does not exist
+SID=""
+rm -f "$SIDFILE"
+clear_df_systemid
+aux lvmconf "global/system_id_source = file" \
+ "global/system_id_file = \"$SIDFILE\""
+vgcreate $vg1 "$dev1" 2>&1 | tee err
+vgs -o+systemid $vg1
+check vg_field $vg1 systemid "$SID"
+grep "No system ID found from system_id_source" err
+vgremove $vg1
diff --git a/test/shell/tags.sh b/test/shell/tags.sh
index 6c35fc3..5b636a8 100644
--- a/test/shell/tags.sh
+++ b/test/shell/tags.sh
@@ -1,4 +1,5 @@
-#!/bin/sh
+#!/usr/bin/env bash
+
# Copyright (C) 2008-2012 Red Hat, Inc. All rights reserved.
#
# This copyrighted material is made available to anyone wishing to use,
@@ -7,22 +8,25 @@
#
# 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
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+
+SKIP_WITH_LVMPOLLD=1
-. lib/test
+. lib/inittest
aux prepare_pvs 4
-# vgcreate with --addtag
-vgcreate -c n --addtag firstvg $vg1 "$dev1" "$dev2"
-vgcreate -c n --addtag secondvg $vg2 "$dev3" "$dev4"
+# vgcreate $SHARED with --addtag
+vgcreate $SHARED --addtag firstvg $vg1 "$dev1" "$dev2"
+vgcreate $SHARED --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"
+vgcreate $SHARED $vg1 "$dev1" "$dev2"
+vgcreate $SHARED $vg2 "$dev3" "$dev4"
vgchange --addtag firstvgtag1 $vg1
# adding a tag multiple times is not an error
vgchange --addtag firstvgtag2 $vg1
@@ -41,17 +45,22 @@ vgchange --deltag firstvgtag1 $vg2
vgremove -f $vg1 $vg2
# lvcreate with --addtag
-vgcreate -c n $vg1 "$dev1" "$dev2"
+vgcreate $SHARED $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"
+
+# LV is not zeroed when tag matches read only volume list
+lvcreate -l1 $vg1 --addtag "RO" --config "activation/read_only_volume_list = [ \"@RO\" ]" 2>&1 | tee out
+grep "not zeroed" out
+
vgremove -f $vg1
# lvchange with --addtag and --deltag
-vgcreate -c n $vg1 "$dev1" "$dev2"
+vgcreate $SHARED $vg1 "$dev1" "$dev2"
lvcreate -l 4 -n $lv1 $vg1
lvcreate -l 4 -n $lv2 $vg1
lvchange --addtag firstlvtag1 $vg1/$lv1
@@ -71,3 +80,5 @@ 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"
+
+vgremove -ff $vg1
diff --git a/test/shell/test-partition.sh b/test/shell/test-partition.sh
index f7e91b8..0e92f00 100644
--- a/test/shell/test-partition.sh
+++ b/test/shell/test-partition.sh
@@ -1,4 +1,5 @@
-#!/bin/sh
+#!/usr/bin/env bash
+
# Copyright (C) 2010 Red Hat, Inc. All rights reserved.
#
# This copyrighted material is made available to anyone wishing to use,
@@ -7,7 +8,7 @@
#
# 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
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
#
# Testcase for bugzilla #621173
@@ -15,9 +16,12 @@
#
+
+SKIP_WITH_LVMPOLLD=1
+
LVM_TEST_CONFIG_DEVICES="types = [\"device-mapper\", 142]"
-. lib/test
+. lib/inittest
which sfdisk || skip
@@ -26,6 +30,6 @@ aux prepare_pvs 1 30
pvs "$dev1"
# create small partition table
-echo "1 2" | sfdisk "$dev1"
+echo "1 2" | sfdisk --force "$dev1"
-pvs "$dev1"
+not pvs "$dev1"
diff --git a/test/shell/thin-16g.sh b/test/shell/thin-16g.sh
new file mode 100644
index 0000000..ee7e22e
--- /dev/null
+++ b/test/shell/thin-16g.sh
@@ -0,0 +1,88 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2021 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+# Test usability of 16g thin pool metadata LV
+
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+aux have_thin 1 0 0 || skip
+
+aux prepare_vg 1 50000
+
+lvcreate -T -L10 --poolmetadatasize 16g $vg/pool
+check lv_field $vg/pool_tmeta size "<15.88g"
+lvremove -f $vg
+
+# Cropped way
+lvcreate -T -L10 --poolmetadatasize 16g --config 'allocation/thin_pool_crop_metadata=1' $vg/pool
+check lv_field $vg/pool_tmeta size "15.81g"
+lvremove -f $vg
+
+lvcreate -L16G -n meta $vg
+lvcreate -L10 -n pool $vg
+lvconvert --yes --thinpool $vg/pool --poolmetadata meta
+# Uncropped size 33554432 sectors - 16GiB
+dmsetup table ${vg}-pool_tmeta | grep 33554432
+lvremove -f $vg
+
+# Uses 20G metadata volume, but crops the size in DM table
+lvcreate -L20G -n meta $vg
+lvcreate -L10 -n pool $vg
+lvconvert --yes --thinpool $vg/pool --poolmetadata meta --config 'allocation/thin_pool_crop_metadata=1'
+check lv_field $vg/lvol0_pmspare size "16.00g"
+# Size should be cropped to 33161216 sectors ~15.81GiB
+dmsetup table ${vg}-pool_tmeta | grep 33161216
+
+# Also size remains unchanged with activation has no cropping,
+# but metadata have no CROP_METADATA flag set
+lvchange -an $vg
+lvchange -ay $vg
+# Size still stays cropped to 33161216 sectors ~15.81GiB
+dmsetup table ${vg}-pool_tmeta | grep 33161216
+lvremove -f $vg
+
+# Minimal size is 2M
+lvcreate -L1M -n meta $vg
+lvcreate -L10 -n pool $vg
+not lvconvert --yes --thinpool $vg/pool --poolmetadata meta
+lvremove -f $vg
+
+# Uses 20G metadata volume, but crops the size in DM table
+lvcreate -L1 --poolmetadatasize 10G -T $vg/pool
+lvresize -L+10G $vg/pool_tmeta --config 'allocation/thin_pool_crop_metadata=1'
+check lv_field $vg/lvol0_pmspare size "15.81g"
+# Size should be cropped to 33161216 sectors ~15.81GiB
+dmsetup table ${vg}-pool_tmeta | grep 33161216
+
+# Without cropping we can grop to ~15.88GiB
+lvresize -L+10G $vg/pool_tmeta
+check lv_field $vg/lvol0_pmspare size "<15.88g"
+lvremove -f $vg
+
+# User has already 'bigger' metadata and wants them uncropped
+lvcreate -L16G -n meta $vg
+lvcreate -L10 -n pool $vg
+lvconvert --yes --thinpool $vg/pool --poolmetadata meta --config 'allocation/thin_pool_crop_metadata=1'
+
+# No change with cropping
+lvresize -l+1 $vg/pool_tmeta --config 'allocation/thin_pool_crop_metadata=1'
+dmsetup table ${vg}-pool_tmeta | grep 33161216
+
+# Resizes to 'uncropped' size 16GiB with ANY size
+lvresize -l+1 $vg/pool_tmeta
+dmsetup table ${vg}-pool_tmeta | grep 33554432
+check lv_field $vg/pool_tmeta size "16.00g"
+
+vgremove -ff $vg
diff --git a/test/shell/thin-autoumount-dmeventd.sh b/test/shell/thin-autoumount-dmeventd.sh
index bbffe8a..7244333 100644
--- a/test/shell/thin-autoumount-dmeventd.sh
+++ b/test/shell/thin-autoumount-dmeventd.sh
@@ -1,5 +1,6 @@
-#!/bin/bash
-# Copyright (C) 2012 Red Hat, Inc. All rights reserved.
+#!/usr/bin/env bash
+
+# Copyright (C) 2012-2016 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
@@ -7,64 +8,121 @@
#
# 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
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
# no automatic extensions, just umount
-is_dir_mounted_()
+
+SKIP_WITH_LVMPOLLD=1
+
+export LVM_TEST_THIN_REPAIR_CMD=${LVM_TEST_THIN_REPAIR_CMD-/bin/false}
+
+. lib/inittest
+
+mntdir="${PREFIX}mnt with space"
+mntusedir="${PREFIX}mntuse"
+
+cleanup_mounted_and_teardown()
{
- cat /proc/mounts | sed 's:\\040: :g' | grep "$1"
+ umount "$mntdir" 2>/dev/null || true
+ umount "$mntusedir" 2>/dev/null || true
+ vgremove -ff $vg
+ aux teardown
}
-. lib/test
+is_lv_opened_()
+{
+ test "$(get lv_field "$1" lv_device_open --binary)" = 1
+}
#
# Main
#
-which mkfs.ext2 || skip
+which mkfs.ext4 || skip
+export MKE2FS_CONFIG="$TESTDIR/lib/mke2fs.conf"
aux have_thin 1 0 0 || skip
-aux prepare_dmeventd
+# Simple implementation of umount when lvextend fails
+cat <<- EOF >testcmd.sh
+#!/bin/sh
+
+echo "Data: \$DMEVENTD_THIN_POOL_DATA"
+echo "Metadata: \$DMEVENTD_THIN_POOL_METADATA"
+
+"$TESTDIR/lib/lvextend" --use-policies \$1 || {
+ umount "$mntdir" || true
+ umount "$mntusedir" || true
+ return 0
+}
+test "\$($TESTDIR/lib/lvs -o selected -S "data_percent>95||metadata_percent>95" --noheadings \$1)" -eq 0 || {
+ umount "$mntdir" || true
+ umount "$mntusedir" || true
+ return 0
+}
+EOF
+chmod +x testcmd.sh
+# Show prepared script
+cat testcmd.sh
+# Use autoextend percent 0 - so extension fails and triggers umount...
aux lvmconf "activation/thin_pool_autoextend_percent = 0" \
- "activation/thin_pool_autoextend_threshold = 70"
+ "activation/thin_pool_autoextend_threshold = 70" \
+ "dmeventd/thin_command = \"/$PWD/testcmd.sh\""
-aux prepare_vg 2
+aux prepare_dmeventd
-mntdir="${PREFIX}mnt with space"
-mntusedir="${PREFIX}mntuse"
+aux prepare_vg 2
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"
+mkfs.ext4 "$DM_DEV_DIR/$vg/$lv1"
+mkfs.ext4 "$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"
+trap 'cleanup_mounted_and_teardown' EXIT
+mount "$DM_DEV_DIR/$vg/$lv1" "$mntdir"
+mount "$DM_DEV_DIR/$vg/$lv2" "$mntusedir"
-is_dir_mounted_ "$mntdir"
+# Check both LVs are opened (~mounted)
+is_lv_opened_ "$vg/$lv1"
+is_lv_opened_ "$vg/$lv2"
-# fill above 70%
-dd if=/dev/zero of="$mntdir/file$$" bs=1M count=6
touch "$mntusedir/file$$"
-tail -f "$mntusedir/file$$" &
-PID_TAIL=$!
sync
+
+# Running 'keeper' process sleep holds the block device still in use
+sleep 60 < "$mntusedir/file$$" >/dev/null 2>&1 &
+PID_SLEEP=$!
+
lvs -a $vg
-sleep 12 # dmeventd only checks every 10 seconds :(
+# Fill pool above 95% (to cause 'forced lazy umount)
+dd if=/dev/zero of="$mntdir/file$$" bs=256K count=20 conv=fdatasync
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
+# Could loop here for a few secs so dmeventd can do some work
+# In the worst case check only happens every 10 seconds :(
+# With low water mark it quickly discovers overflow and umounts $vg/$lv1
+for i in $(seq 1 12) ; do
+ is_lv_opened_ "$vg/$lv1" || break
+ test $i -lt 12 || die "$mntdir should have been unmounted by dmeventd!"
+ sleep 1
+done
+
lvs -a $vg
-vgremove -f $vg
+is_lv_opened_ "$vg/$lv2" || \
+ die "$mntusedir is not mounted here (sleep already expired??)"
+
+# Kill device holding process
+kill $PID_SLEEP
+wait
+
+not is_lv_opened_ "$vg/$lv2" || {
+ mount
+ die "$mntusedir should have been unmounted by dmeventd!"
+}
diff --git a/test/shell/thin-defaults.sh b/test/shell/thin-defaults.sh
new file mode 100644
index 0000000..3f2db20
--- /dev/null
+++ b/test/shell/thin-defaults.sh
@@ -0,0 +1,41 @@
+#!/usr/bin/env 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+# test defaults entered through lvm.conf
+
+
+SKIP_WITH_LVMPOLLD=1
+
+export LVM_TEST_THIN_REPAIR_CMD=${LVM_TEST_THIN_REPAIR_CMD-/bin/false}
+
+. lib/inittest
+
+#
+# Main
+#
+aux have_thin 1 0 0 || skip
+
+aux prepare_vg 2
+
+lvcreate -T -L8M $vg/pool0
+
+aux lvmconf "allocation/thin_pool_chunk_size = 128" \
+ "allocation/thin_pool_discards = \"ignore\"" \
+ "allocation/thin_pool_zero = 0"
+
+lvcreate -T -L8M $vg/pool1
+
+check lv_field $vg/pool1 chunksize "128.00k"
+check lv_field $vg/pool1 discards "ignore"
+check lv_field $vg/pool1 zero ""
+
+vgremove -f $vg
diff --git a/test/shell/thin-dmeventd-warns.sh b/test/shell/thin-dmeventd-warns.sh
new file mode 100644
index 0000000..2eb8e41
--- /dev/null
+++ b/test/shell/thin-dmeventd-warns.sh
@@ -0,0 +1,83 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2017 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+# test if dmeventd produces multiple warnings when pools runs above 80%
+
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+which blkdiscard || skip
+
+percent_() {
+ get lv_field $vg/pool data_percent | cut -d. -f1
+}
+
+wait_warn_() {
+
+ for i in $(seq 1 7)
+ do
+ test "$(grep -E -c "WARNING: Thin pool.*is now" debug.log_DMEVENTD_out)" -eq "$1" && return 0
+ sleep 2
+ done
+
+ die "Waiting too log for dmeventd log warning"
+}
+#
+# Main
+#
+aux have_thin 1 0 0 || skip
+
+aux prepare_dmeventd
+aux prepare_vg
+
+lvcreate -L8 -V8 -T $vg/pool -n $lv1
+
+
+dd if=/dev/zero of="$DM_DEV_DIR/$vg/$lv1" bs=256K count=26 oflag=direct
+test "$(percent_)" -gt 80
+
+# Give it some time to dmeventd to log WARNING
+wait_warn_ 1
+
+dd if=/dev/zero of="$DM_DEV_DIR/$vg/$lv1" bs=256K count=30 oflag=direct
+test "$(percent_)" -gt 90
+
+# Give it some time to dmeventd to log WARNING
+wait_warn_ 2
+
+dd if=/dev/zero of="$DM_DEV_DIR/$vg/$lv1" bs=1M count=8 oflag=direct
+test "$(percent_)" -eq 100
+
+wait_warn_ 3
+
+blkdiscard "$DM_DEV_DIR/$vg/$lv1"
+
+# FIXME: Enforce thin-pool metadata commit with flushing status
+dmsetup status ${vg}-pool-tpool
+# Wait for thin-pool monitoring to notice lower values
+sleep 11
+# ATM dmeventd is not logging event for thin-pool getting
+# below 'WARNED' threshold.
+
+
+dd if=/dev/zero of="$DM_DEV_DIR/$vg/$lv1" bs=256K count=30 oflag=direct
+test "$(percent_)" -gt 90
+
+lvs -a $vg
+dmsetup status ${vg}-pool-tpool
+
+# Check pool again Warns
+wait_warn_ 4
+
+vgremove -f $vg
diff --git a/test/shell/thin-errors.sh b/test/shell/thin-errors.sh
new file mode 100644
index 0000000..7bdf268
--- /dev/null
+++ b/test/shell/thin-errors.sh
@@ -0,0 +1,79 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2020 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+# Test various error conditions user may hit with thin volumes
+
+SKIP_WITH_LVMLOCKD=1
+SKIP_WITH_LVMPOLLD=1
+
+export LVM_TEST_THIN_REPAIR_CMD=${LVM_TEST_THIN_REPAIR_CMD-/bin/false}
+
+. lib/inittest
+
+#
+# Main
+#
+aux have_thin 1 3 0 || skip
+aux thin_pool_error_works_32 || skip
+
+aux prepare_vg 2
+
+###############################################
+# Testing failing thin-pool metadata device #
+###############################################
+
+lvcreate -T -L1M --errorwhenfull y $vg/pool
+lvcreate -V2 -n $lv1 $vg/pool
+lvcreate -s -n $lv2 $vg/$lv1
+
+# Prepare old metadata with transaction_id 2
+vgcfgbackup -f mda_tid_2 $vg
+
+lvcreate -s -n $lv3 $vg/$lv1
+lvcreate -s -n $lv4 $vg/$lv1
+lvcreate -s -n $lv5 $vg/$lv1
+
+vgcfgbackup -f mda_tid_5 $vg
+
+# Restore mismatching old metadata with different transaction_id
+vgcfgrestore -f mda_tid_2 --force --yes $vg
+
+
+not lvcreate -s -n $lv5 $vg/$lv1
+
+sed -e 's/transaction_id = 2/transaction_id = 5/g' mda_tid_2 > mda_tid_2_5
+
+# Restore metadata with matching transaction_id,
+# but already existing device in kernel, unknown to lvm2
+vgcfgrestore -f mda_tid_2_5 --force --yes $vg
+
+not lvcreate -s -n $lv5 $vg/$lv1
+# can be tried repeatedly
+not lvcreate -s -n $lv5 $vg/$lv1
+
+
+# Restore matching metadata and check all works
+# and no kernel thin device was lost
+vgcfgrestore -f mda_tid_5 --force --yes $vg
+
+lvcreate -s -n $lv6 $vg/$lv1
+
+lvchange -ay -K $vg
+
+check active $vg $lv1
+check active $vg $lv2
+check active $vg $lv3
+check active $vg $lv4
+check active $vg $lv5
+check active $vg $lv6
+
+vgremove -ff $vg
diff --git a/test/shell/thin-flags.sh b/test/shell/thin-flags.sh
new file mode 100644
index 0000000..a3adee4
--- /dev/null
+++ b/test/shell/thin-flags.sh
@@ -0,0 +1,140 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2016 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+# test presence of various thin-pool/thin flags
+
+SKIP_WITH_LVMLOCKD=1
+SKIP_WITH_LVMPOLLD=1
+
+export LVM_TEST_THIN_REPAIR_CMD=${LVM_TEST_THIN_REPAIR_CMD-/bin/false}
+
+. lib/inittest
+
+#
+# Main
+#
+aux have_thin 1 3 0 || skip
+aux thin_pool_error_works_32 || skip
+
+aux prepare_vg 2 256
+
+###############################################
+# Testing failing thin-pool metadata device #
+###############################################
+
+lvcreate -T -L1M --errorwhenfull y $vg/pool
+lvcreate -V2 -n $lv2 $vg/pool
+
+aux error_dev "$dev2" 2054:2
+# Check our 'lvs' is not flushing pool - should be still OK
+check lv_attr_bit health $vg/pool "-"
+# Enforce flush on thin pool device to notice error device.
+dmsetup status $vg-pool-tpool
+check lv_attr_bit health $vg/pool "F"
+check lv_attr_bit health $vg/$lv2 "F"
+aux enable_dev "$dev2"
+
+lvchange -an $vg
+
+# Overfill data area
+lvchange -ay $vg
+dd if=/dev/zero of="$DM_DEV_DIR/mapper/$vg-$lv2" bs=1M count=2 oflag=direct || true
+check lv_attr_bit health $vg/pool "D"
+# TODO use spaces ??
+check lv_field $vg/pool lv_health_status "out_of_data"
+
+lvremove -ff $vg
+
+
+#######################################################
+# Testing what happens on system without thin-check #
+#######################################################
+
+lvcreate -L200M --errorwhenfull y -T $vg/pool
+lvcreate -V2 -n $lv2 $vg/pool
+lvchange -an $vg
+
+# Drop usage of thin_check
+aux lvmconf 'global/thin_check_executable = ""'
+
+# Prepare some fake metadata prefilled to ~100%
+lvcreate -L2 -n $lv1 $vg "$dev2" # tmp for metadata
+
+VOLS=490
+aux thin_restore_needs_more_volumes || VOLS=445
+aux prepare_thin_metadata $VOLS 1 | tee data
+
+# Note: we like want to test BOTH sizes (445 & 490) as ATM it gives
+# different errors (5.9-rc5 kernel does not handle it as expected by this test)
+
+"$LVM_TEST_THIN_RESTORE_CMD" -i data -o "$DM_DEV_DIR/mapper/$vg-$lv1"
+
+# Swap volume with restored fake metadata
+lvconvert -y --thinpool $vg/pool --poolmetadata $vg/$lv1
+
+lvchange -ay $vg
+
+lvchange -ay $vg/$lv2
+# Provisiong and last free bits in metadata
+dd if=/dev/zero of="$DM_DEV_DIR/mapper/$vg-$lv2" bs=1M count=1 oflag=direct || true
+
+check lv_attr_bit health $vg/pool "M" || {
+ echo "TEST ""WARNING: Missing metadata corruption for this version of thin-pool."
+ exit 0
+}
+
+# TODO - use spaces ??
+check lv_field $vg/pool lv_health_status "metadata_read_only"
+check lv_attr_bit health $vg/$lv2 "-"
+
+not lvcreate -s $vg/$lv2
+not lvcreate -V10 -n $lv3 $vg/pool
+
+lvs -ao+seg_pe_ranges $vg
+
+# needs_check needs newer version
+THINMINVER="1 20 0"
+aux kernel_at_least 4 18 && THINMINVER="1 19 0" # kernel >=4.18 already had changes from 1.20
+
+if aux have_thin $THINMINVER ; then
+ check lv_attr_bit state $vg/pool "a"
+
+ dmsetup suspend $vg-pool-tpool
+
+ check lv_attr_bit state $vg/pool "s"
+
+ dmsetup resume $vg-pool-tpool
+
+ lvresize -L+2M $vg/pool_tmeta
+
+ # Newer version recovers when metadata grow up
+ check lv_attr_bit state $vg/pool "a"
+ check lv_field $vg/pool lv_health_status ""
+
+elif aux have_thin 1 16 0 ; then
+ check lv_attr_bit state $vg/pool "c"
+ check lv_field $vg/pool lv_check_needed "check needed"
+
+ dmsetup suspend $vg-pool-tpool
+
+ # suspended thin-pool with Capital 'c'
+ check lv_attr_bit state $vg/pool "C"
+
+ dmsetup resume $vg-pool-tpool
+
+ lvresize -L+2M $vg/pool_tmeta
+
+ # still require thin_check
+ check lv_attr_bit state $vg/pool "c"
+fi
+
+vgremove -ff $vg
diff --git a/test/shell/thin-foreign-dmeventd.sh b/test/shell/thin-foreign-dmeventd.sh
new file mode 100644
index 0000000..76995a3
--- /dev/null
+++ b/test/shell/thin-foreign-dmeventd.sh
@@ -0,0 +1,108 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2016 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+# test foreing user of thin-pool
+
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+MOUNT_DIR=mnt
+
+cleanup_mounted_and_teardown()
+{
+ umount "$MOUNT_DIR" || true
+ dmsetup remove $THIN
+ vgremove -ff $vg
+ aux teardown
+}
+
+percent_() {
+ get lv_field $vg/pool data_percent | cut -d. -f1
+}
+
+#
+# Main
+#
+aux have_thin 1 0 0 || skip
+which mkfs.ext4 || skip
+
+# Use our mkfs config file to get approximately same results
+# TODO: maybe use it for all test via some 'prepare' function
+export MKE2FS_CONFIG="$TESTOLDPWD/lib/mke2fs.conf"
+
+aux prepare_dmeventd
+aux prepare_vg 2 64
+
+# Create named pool only
+lvcreate --errorwhenfull y -L2 -T $vg/pool
+
+POOL="$vg-pool"
+THIN="${PREFIX}_thin"
+
+# Foreing user is using own ioctl command to create thin devices
+dmsetup message $POOL 0 "create_thin 0"
+dmsetup message $POOL 0 "set_transaction_id 0 1"
+
+dmsetup status
+# Once the transaction id has changed, lvm2 shall not be able to create thinLV
+fail lvcreate -V10 $vg/pool
+
+trap 'cleanup_mounted_and_teardown' EXIT
+
+# 20M thin device
+dmsetup create $THIN --table "0 40960 thin $DM_DEV_DIR/mapper/$POOL 0"
+
+dmsetup table
+dmsetup info -c
+
+mkdir "$MOUNT_DIR"
+# This mkfs should fill 2MB pool over 95%
+# no autoresize is configured
+mkfs.ext4 "$DM_DEV_DIR/mapper/$THIN"
+# ensure all data from mkfs are written to disk
+sync
+test "$(percent_)" -gt 95
+mount "$DM_DEV_DIR/mapper/$THIN" "$MOUNT_DIR"
+
+pvchange -x n "$dev1" "$dev2"
+
+test "$(percent_)" -gt 95
+# Configure autoresize
+aux lvmconf 'activation/thin_pool_autoextend_percent = 10' \
+ 'activation/thin_pool_autoextend_threshold = 75'
+
+# Give it some time to left dmeventd do some (failing to resize) work
+sleep 20
+
+# And check foreign thin device is still mounted
+mount | grep "$MOUNT_DIR" | grep "$THIN"
+test "$(percent_)" -gt 95
+
+pvchange -x y "$dev1" "$dev2"
+
+# FIXME: ATM tell dmeventd explicitely we've changed metadata
+# however dmeventd shall be aware of any metadata change
+# and automagically retry resize operation after that.
+lvchange --refresh $vg/pool
+
+# Give it some time and let dmeventd do some work
+for i in $(seq 1 15) ; do
+ test "$(percent_)" -ge 75 || break
+ sleep 1
+done
+
+test "$(percent_)" -lt 75
+
+# And check foreign thin device is still mounted
+mount | grep "$MOUNT_DIR" | grep "$THIN"
diff --git a/test/shell/thin-foreign-repair.sh b/test/shell/thin-foreign-repair.sh
new file mode 100644
index 0000000..55e9f62
--- /dev/null
+++ b/test/shell/thin-foreign-repair.sh
@@ -0,0 +1,80 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2020 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+# test foreing user of thin-pool
+
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+clean_thin_()
+{
+ aux udev_wait
+ dmsetup remove "$THIN" || { sleep .5 ; dmsetup remove "$THIN" ; }
+}
+
+cleanup_mounted_and_teardown()
+{
+ clean_thin_ || true
+ vgremove -ff $vg
+ aux teardown
+}
+
+#
+# Main
+#
+aux have_thin 1 0 0 || skip
+which mkfs.ext4 || skip
+
+# Use our mkfs config file to get approximately same results
+# TODO: maybe use it for all test via some 'prepare' function
+export MKE2FS_CONFIG="$TESTOLDPWD/lib/mke2fs.conf"
+
+aux prepare_vg 2 64
+
+# Create named pool only
+lvcreate -L2 -T $vg/pool
+
+POOL="$vg-pool"
+THIN="${PREFIX}_thin"
+
+# Foreing user is using own ioctl command to create thin devices
+dmsetup message $POOL 0 "create_thin 0"
+dmsetup message $POOL 0 "set_transaction_id 0 2"
+
+# Once the transaction id has changed, lvm2 shall not be able to create thinLV
+fail lvcreate -V10 $vg/pool
+
+trap 'cleanup_mounted_and_teardown' EXIT
+
+# 20M thin device
+dmsetup create "$THIN" --table "0 40960 thin $DM_DEV_DIR/mapper/$POOL 0"
+
+mkfs.ext4 "$DM_DEV_DIR/mapper/$THIN"
+
+clean_thin_
+
+lvchange -an $vg/pool
+
+# Repair thin-pool used by 'foreing' apps (setting their own tid)
+lvconvert --repair $vg/pool 2>&1 | tee out
+
+not grep "Transaction id" out
+
+lvchange -ay $vg/pool
+
+dmsetup create "$THIN" --table "0 40960 thin $DM_DEV_DIR/mapper/$POOL 0"
+
+fsck -n "$DM_DEV_DIR/mapper/$THIN"
+
+# exit calls cleanup_mounted_and_teardown
diff --git a/test/shell/thin-large.sh b/test/shell/thin-large.sh
new file mode 100644
index 0000000..714f91e
--- /dev/null
+++ b/test/shell/thin-large.sh
@@ -0,0 +1,55 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2017 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+# 'Exercise logic around boundary sizes of thin-pool data and chunksize
+
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+# FIXME update test to make something useful on <16T
+aux can_use_16T || skip
+
+aux have_thin 1 0 0 || skip
+
+# Prepare ~1P sized devices
+aux prepare_vg 1 1000000000
+
+lvcreate -an -T -L250T $vg/pool250
+
+lvcreate -an -T -L250T --poolmetadatasize 16G $vg/pool16
+
+fail lvcreate -an -T -L250T --chunksize 64K --poolmetadatasize 16G $vg/pool64
+
+# Creation of thin-pool with proper chunk-size but not enough metadata size
+# which can grow later needs to pass
+lvcreate -an -T -L250T --chunksize 1M --poolmetadatasize 4G $vg/pool1024
+
+# Creation of chunk should fit
+lvcreate -an -T -L12T --chunksize 64K --poolmetadatasize 16G $vg/pool64
+
+check lv_field $vg/pool64 chunksize "64.00k"
+
+lvremove -ff $vg
+
+
+### Check also lvconvert ###
+
+lvcreate -an -L250T -n pool $vg
+
+fail lvconvert -y --chunksize 64 --thinpool $vg/pool
+lvconvert -y --chunksize 1M --thinpool $vg/pool
+
+check lv_field $vg/pool chunksize "1.00m"
+
+vgremove -ff $vg
diff --git a/test/shell/thin-many-dmeventd.sh b/test/shell/thin-many-dmeventd.sh
new file mode 100644
index 0000000..b93b0c6
--- /dev/null
+++ b/test/shell/thin-many-dmeventd.sh
@@ -0,0 +1,69 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2018 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+# test activation of monitoring with more thin-pool
+
+SKIP_WITH_LVMLOCKD=1
+SKIP_WITH_LVMPOLLD=1
+
+export LVM_TEST_THIN_REPAIR_CMD=${LVM_TEST_THIN_REPAIR_CMD-/bin/false}
+
+. lib/inittest
+
+#
+# Main
+#
+aux have_thin 1 0 0 || skip
+
+aux prepare_dmeventd
+aux prepare_vg 2 64
+
+# Create couple pools to later cause race in dmeventd during activation.
+# each pool may add 1sec. extra delay
+
+for i in $(seq 1 5)
+do
+ lvcreate --errorwhenfull y -Zn -T -L4M -V4M $vg/pool_${i} -n $lv${i}
+ # Fill thin-pool to some capacity >50%
+ dd if=/dev/zero of="$DM_DEV_DIR/$vg/$lv${i}" bs=256K count=9 oflag=direct
+done
+
+lvs -a $vg
+vgchange -an $vg
+
+
+# Try to now activate all existing pool - this will generate in about 10sec later
+# storm of intial call of 'lvextend --use-policies'
+vgchange -ay $vg
+
+# Every 10sec. ATM there is DM status monitoring made by dmeventd
+sleep 9
+
+# Here try to hit the race by creating several new thin-pools in sequence.
+# Creation meets with dmeventd running 'lvextend' command and taking
+# it's internal lvm2 library lock - this used to make impossible to proceed with
+# new thin-pool registration.
+for i in $(seq 11 15)
+do
+ #/usr/bin/time -o TM -f %e lvcreate --errorwhenfull y -Zn -T -L4M -V4M $vg/pool_${i} -n $lv${i}
+ #read -r t < TM
+ #test ${t%%.*} -lt 8 || die "Creation of thin pool took more then 8 second! ($t seconds)"
+ START=$(date +%s)
+ lvcreate --errorwhenfull y -Zn -T -L4M -V4M $vg/pool_${i} -n $lv${i}
+ END=$(date +%s)
+ DIFF=$(( END - START ))
+ test "$DIFF" -lt 8 || die "Creation of thin pool took more then 8 second! ($DIFF seconds)"
+ # Fill thin-pool to some capacity >50%
+ dd if=/dev/zero of="$DM_DEV_DIR/$vg/$lv${i}" bs=256K count=9 oflag=direct
+done
+
+vgremove -f $vg
diff --git a/test/shell/thin-merge.sh b/test/shell/thin-merge.sh
new file mode 100644
index 0000000..34f5c74
--- /dev/null
+++ b/test/shell/thin-merge.sh
@@ -0,0 +1,142 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2013 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+# test merge of thin snapshot
+
+
+
+export LVM_TEST_THIN_REPAIR_CMD=${LVM_TEST_THIN_REPAIR_CMD-/bin/false}
+
+. lib/inittest
+
+MKFS=mkfs.ext2
+which $MKFS || skip
+which fsck || skip
+
+MKFS="$MKFS -b4096"
+#
+# Main
+#
+aux have_thin 1 0 0 || skip
+
+aux prepare_vg 2
+
+lvcreate -T -L8M $vg/pool -V10M -n $lv1
+lvcreate -s -K -n snap $vg/$lv1
+# check exclusive lock is preserved after merge
+check lv_field "$vg/$lv1" lv_active_exclusively "active exclusively"
+lvconvert --merge $vg/snap
+check lv_field "$vg/$lv1" lv_active_exclusively "active exclusively"
+lvremove -ff $vg
+
+
+lvcreate -T -L8M $vg/pool -V10M -n $lv1
+lvchange --addtag tagL $vg/$lv1
+
+mkdir mnt
+$MKFS "$DM_DEV_DIR/$vg/$lv1"
+mount "$DM_DEV_DIR/$vg/$lv1" mnt
+touch mnt/test
+
+lvcreate -K -s -n snap --addtag tagS $vg/$lv1
+mkdir mntsnap
+$MKFS "$DM_DEV_DIR/$vg/snap"
+mount "$DM_DEV_DIR/$vg/snap" mntsnap
+touch mntsnap/test_snap
+
+lvs -o+tags,thin_id $vg
+
+lvcreate -s -n snap1 $vg/$lv1
+
+lvconvert --merge $vg/snap &>out
+grep "Merging of thin snapshot $vg/snap will occur on next activation of $vg/${lv1}." out
+
+# Can't merge another snapshot while "snap" is still being 'merged'.
+not lvconvert --merge $vg/snap1 &>out
+grep "Cannot merge snapshot" out
+
+# Check lvdisplay is not crashing while merge needs to wait
+lvdisplay -a $vg
+
+umount mnt
+
+# Merge cannot happen
+lvchange --refresh $vg/$lv1
+check lv_field $vg/$lv1 thin_id "1"
+
+# Fails since it cannot deactivate both
+not lvchange -an $vg/$lv1
+
+# But test $lv1 is not active
+check inactive $vg $lv1
+
+# Also still cannot reactivate $lv1
+not lvchange -ay $vg/$lv1
+
+umount mntsnap
+
+lvdisplay -a $vg | tee out
+grep "merged with" out
+grep "merging to" out
+
+# Check there is no support for manipulation with hidden 'snap'
+not lvchange --refresh $vg/snap
+not lvchange -an $vg/snap
+not lvremove $vg/snap
+
+
+# Finally deactivate 'snap' again via $lv1
+lvchange -an $vg/$lv1
+
+# Still must not be activable
+not lvchange -K -ay $vg/snap
+
+lvs -a -o +tags,thin_id $vg
+
+# Test if merge happens
+lvchange -ay $vg/$lv1
+check lv_exists $vg $lv1
+check lv_field $vg/$lv1 thin_id "2"
+check lv_field $vg/$lv1 tags "tagL"
+check lv_not_exists $vg snap
+
+fsck -n "$DM_DEV_DIR/$vg/$lv1"
+mount "$DM_DEV_DIR/$vg/$lv1" mnt
+test -e mnt/test_snap
+umount mnt
+
+
+# test if thin snapshot has also 'old-snapshot'
+
+lvcreate -s -n snap $vg/$lv1
+
+# Also add old snapshot to thin origin
+lvcreate -s -L10 -n oldsnapof_${lv1} $vg/$lv1
+not lvconvert --merge $vg/snap
+$MKFS "$DM_DEV_DIR/$vg/oldsnapof_${lv1}"
+lvconvert --merge $vg/oldsnapof_${lv1}
+fsck -n "$DM_DEV_DIR/$vg/$lv1"
+check lv_not_exists $vg oldsnapof_${lv1}
+# Add old snapshot to thin snapshot
+lvcreate -s -L10 -n oldsnapof_snap $vg/snap
+lvconvert --merge $vg/snap
+lvremove -f $vg/oldsnapof_snap
+check lv_field $vg/$lv1 thin_id "4"
+
+# Check --mergethin
+lvcreate -s -n snap $vg/$lv1
+check lv_field $vg/snap thin_id "5"
+lvconvert --mergethin $vg/snap &>out
+grep "Volume $vg/snap replaced origin $vg/${lv1}." out
+check lv_field $vg/$lv1 thin_id "5"
+
+vgremove -ff $vg
diff --git a/test/shell/thin-overprovisioning.sh b/test/shell/thin-overprovisioning.sh
new file mode 100644
index 0000000..d4ab63d
--- /dev/null
+++ b/test/shell/thin-overprovisioning.sh
@@ -0,0 +1,79 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2015 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+# Test warns when thin pool is overprovisiong
+
+
+SKIP_WITH_LVMPOLLD=1
+
+export LVM_TEST_THIN_REPAIR_CMD=${LVM_TEST_THIN_REPAIR_CMD-/bin/false}
+
+. lib/inittest
+
+aux have_thin 1 3 0 || skip
+
+# 2PVs by 32M
+aux prepare_vg 2 33
+
+lvcreate -L32 -T $vg/pool
+# check there is link node for UNUSED thin-pool
+test -e "$DM_DEV_DIR/$vg/pool"
+
+# leave 12M free space
+lvcreate -an -n $lv1 -L16 $vg 2>&1 | tee out
+vgs $vg
+
+lvcreate -n thin1 -V30 $vg/pool 2>&1 | tee out
+not grep "WARNING: Sum" out
+# check again link node is now gone for a USED thin-pool
+test ! -e "$DM_DEV_DIR/$vg/pool"
+
+# Pool gets overprovisioned
+lvcreate -an -n thin2 -V4 $vg/pool 2>&1 | tee out
+grep "WARNING: Sum" out
+grep "amount of free space in volume group (12.00 MiB)" out
+
+# Eat all space in VG
+lvcreate -an -n $lv2 -L12 $vg 2>&1 | tee out
+grep "WARNING: Sum" out
+grep "no free space in volume group" out
+
+lvcreate -an -n thin3 -V1G $vg/pool 2>&1 | tee out
+grep "WARNING: Sum" out
+grep "the size of whole volume group" out
+
+lvremove -ff $vg/thin2 $vg/thin3 $vg/$lv2
+
+# Create 2nd thin pool in a VG
+
+lvcreate -L4 -T $vg/pool2
+lvcreate -V4 -n thin2 $vg/pool2 2>&1 | tee out
+not grep "WARNING: Sum" out
+
+lvcreate -an -V4 -n thin3 $vg/pool2 2>&1 | tee out
+grep "WARNING: Sum of all thin volume sizes (38.00 MiB)" out
+grep "free space in volume group (6.00 MiB)" out
+
+lvcreate -an -L6 -n $lv3 $vg 2>&1 | tee out
+grep "no free space in volume group" out
+
+lvremove -ff $vg/thin2 $vg/thin3
+
+lvcreate -an -V4 -n thin2 $vg/pool2 2>&1 | tee out
+not grep "WARNING: Sum" out
+
+# Check if resize notices problem
+lvextend -L+8 $vg/thin2
+
+vgs $vg
+
+vgremove -ff $vg
diff --git a/test/shell/thin-resize-match.sh b/test/shell/thin-resize-match.sh
new file mode 100644
index 0000000..dda5573
--- /dev/null
+++ b/test/shell/thin-resize-match.sh
@@ -0,0 +1,84 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2015 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+# ensure there is no data loss during thin-pool resize
+
+
+SKIP_WITH_LVMPOLLD=1
+
+export LVM_TEST_THIN_REPAIR_CMD=${LVM_TEST_THIN_REPAIR_CMD-/bin/false}
+
+. lib/inittest
+
+which md5sum || skip
+
+aux have_thin 1 0 0 || skip
+
+aux prepare_vg 2 20
+
+lvcreate -L1M -V2M -n $lv1 -T $vg/pool
+
+# just ensure we check what we need to check
+check lv_field $vg/pool size "1.00m"
+check lv_field $vg/$lv1 size "2.00m"
+
+# prepare 2097152 file content
+seq 0 315465 > 2M
+md5sum 2M | cut -f 1 -d ' ' | tee MD5
+dd if=2M of="$DM_DEV_DIR/mapper/$vg-$lv1" bs=512K conv=fdatasync >log 2>&1 &
+#dd if=2M of="$DM_DEV_DIR/mapper/$vg-$lv1" bs=2M oflag=direct &
+
+# give it some time to fill thin-volume
+# eventually loop to wait for 100% full pool...
+sleep .1
+lvs -a $vg
+
+# this must not 'block & wait' on suspending flush
+# if it waits on thin-pool's target timeout
+# it will harm queued data
+lvextend -L+512k $vg/pool
+lvextend -L+512k $vg/pool
+
+# collect 'dd' result
+wait
+cat log
+
+lvs -a $vg
+
+dd if="$DM_DEV_DIR/mapper/$vg-$lv1" of=2M-2 iflag=direct
+md5sum 2M-2 | cut -f 1 -d ' ' | tee MD5-2
+
+# these 2 are supposed to match
+diff MD5 MD5-2
+
+
+# Do not want to see Live & Inactive table entry
+( dm_info attr,name | not grep "LI-.*${PREFIX}" ) || {
+ dmsetup table --inactive | grep ${PREFIX}
+ die "Found device with Inactive table"
+}
+
+# Check wrapping active thin-pool linear mapping has matching size
+POOLSZ=$(dmsetup table ${vg}-pool-tpool | cut -d ' ' -f 2)
+WRAPSZ=$(dmsetup table ${vg}-pool | cut -d ' ' -f 2)
+
+#
+# FIXME: currently requires to update 2 dependent targets in one 'preload'
+# lvm2 cannot handle this and would need one extra --refresh pass.
+# Once resolved - enabled this test.
+# Maybe other solution without fake linear mapping could be found.
+# Eventually strictly map just single sector as it has no real use?
+#
+#should test "${POOLSZ}" = "${WRAPSZ}" || \
+# die "Wrapping pool device size does not match real pool size"
+
+vgremove -f $vg
diff --git a/test/shell/thin-restore.sh b/test/shell/thin-restore.sh
new file mode 100644
index 0000000..d8bae3c
--- /dev/null
+++ b/test/shell/thin-restore.sh
@@ -0,0 +1,40 @@
+#!/usr/bin/env 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+# test restore operation of thin pool metadata
+
+
+SKIP_WITH_LVMPOLLD=1
+
+export LVM_TEST_THIN_REPAIR_CMD=${LVM_TEST_THIN_REPAIR_CMD-/bin/false}
+
+. lib/inittest
+
+#
+# Main
+#
+aux have_thin 1 0 0 || skip
+
+aux prepare_vg 2
+
+lvcreate -T -L8M $vg/pool -V10M -n $lv1
+
+vgcfgbackup -f backup $vg
+
+# use of --force is mandatory
+not vgcfgrestore -f backup $vg
+
+vgcfgrestore -y -f backup --force $vg
+
+check lv_field $vg/pool transaction_id 1
+
+vgremove -f $vg
diff --git a/test/shell/thin-vglock.sh b/test/shell/thin-vglock.sh
new file mode 100644
index 0000000..b48ef25
--- /dev/null
+++ b/test/shell/thin-vglock.sh
@@ -0,0 +1,65 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2014-2016 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+# Test locking works and doesn't update metadata
+# RHBZ: https://bugzilla.redhat.com/show_bug.cgi?id=1063542
+
+
+
+export LVM_TEST_THIN_REPAIR_CMD=${LVM_TEST_THIN_REPAIR_CMD-/bin/false}
+
+. lib/inittest
+
+MKFS=mkfs.ext2
+which $MKFS || skip
+
+aux have_thin 1 0 0 || skip
+aux prepare_vg
+
+lvcreate -L10 -T -V5 -n $lv1 $vg/pool
+lvcreate -an -V10 -T $vg/pool
+
+$MKFS "$DM_DEV_DIR/$vg/$lv1"
+mkdir mnt
+mount "$DM_DEV_DIR/$vg/$lv1" mnt
+
+lvcreate -s -n snap $vg/$lv1
+check lv_field $vg/snap thin_id "3"
+
+lvconvert --merge $vg/snap
+
+umount mnt
+
+check lv_field $vg/$lv1 thin_id "1"
+check lv_field $vg/pool transaction_id "3"
+
+vgchange -an $vg
+
+# Check reboot case
+vgchange -ay --sysinit $vg
+
+# Check correct thin_id is shown after activation
+# even when metadata were not yet physically modified.
+# Merge take its place during activation,
+# but pool transaction_id still needs metadata update.
+check lv_field $vg/$lv1 thin_id "3"
+check lv_field $vg/pool transaction_id "3"
+
+# Check the metadata are updated after refresh
+#
+vgchange --refresh $vg
+check lv_field $vg/$lv1 thin_id "3"
+check lv_field $vg/pool transaction_id "4"
+
+#lvs -a -o+transaction_id,thin_id $vg
+
+vgremove -f $vg
diff --git a/test/shell/thin-volume-list.sh b/test/shell/thin-volume-list.sh
new file mode 100644
index 0000000..6caa720
--- /dev/null
+++ b/test/shell/thin-volume-list.sh
@@ -0,0 +1,60 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2014 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+# test pool behaviour when volume_list masks activation
+
+
+SKIP_WITH_LVMPOLLD=1
+
+export LVM_TEST_THIN_REPAIR_CMD=${LVM_TEST_THIN_REPAIR_CMD-/bin/false}
+
+. lib/inittest
+
+#
+# Main
+#
+aux have_thin 1 0 0 || skip
+
+aux prepare_vg 2
+
+lvcreate -T -L8M $vg/pool -V10M -n $lv1
+
+# skip $vg from activation
+aux lvmconf "activation/volume_list = [ \"$vg1\" ]"
+
+# We still could pass - since pool is still active
+lvcreate -V10 -n $lv2 -T $vg/pool
+
+# but $lv2 is not active
+check inactive $vg $lv2
+
+vgchange -an $vg
+
+# Pool is not active - so it cannot create thin volume
+not lvcreate -V10 -T $vg/pool
+
+# Cannot create even new pool
+# check there are not left devices (RHBZ #1140128)
+not lvcreate -L10 -T $vg/new_pool
+check lv_not_exists $vg/new_pool
+
+aux lvmconf "activation/volume_list = [ \"$vg\" ]"
+
+lvcreate -V10 -T $vg/pool
+
+lvs -o +transaction_id,thin_id $vg
+
+lvremove -ff $vg
+
+check vg_field $vg lv_count "0"
+
+vgremove -ff $vg
diff --git a/test/shell/thin-zero-meta.sh b/test/shell/thin-zero-meta.sh
new file mode 100644
index 0000000..a466729
--- /dev/null
+++ b/test/shell/thin-zero-meta.sh
@@ -0,0 +1,68 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2021 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+# Test how zeroing of thin-pool metadata works
+
+SKIP_WITH_LVMLOCKD=1
+SKIP_WITH_LVMPOLLD=1
+
+export LVM_TEST_THIN_REPAIR_CMD=${LVM_TEST_THIN_REPAIR_CMD-/bin/false}
+
+. lib/inittest
+
+#
+# Main
+#
+aux have_thin 1 3 0 || skip
+aux have_cache 1 3 0 || skip
+
+aux prepare_vg 3 40000
+
+# Create mostly-zero devs only front of it has some 'real' back-end
+aux zero_dev "$dev1" "$(( $(get first_extent_sector "$dev1") + 8192 )):"
+aux zero_dev "$dev2" "$(( $(get first_extent_sector "$dev2") + 8192 )):"
+aux zero_dev "$dev3" "$(( $(get first_extent_sector "$dev3") + 8192 )):"
+
+# Prepare randomly filled 4M LV on dev2
+lvcreate -L16G -n $lv1 $vg "$dev2"
+dd if=/dev/urandom of="$DM_DEV_DIR/$vg/$lv1" bs=1M count=4 oflag=direct || true
+lvremove -f $vg
+
+for i in 0 1
+do
+ aux lvmconf "allocation/zero_metadata = $i"
+
+ # Lvm2 should allocate metadata on dev2
+ lvcreate -T -L10G --poolmetadatasize 16G $vg/pool "$dev1" "$dev2"
+ lvchange -an $vg
+
+ lvs -ao+seg_pe_ranges $vg
+ lvchange -ay $vg/pool_tmeta --yes
+
+ # Skip past 1.2M which is 'created' by thin-pool initialization
+ hexdump -C -n 200 -s 2000000 "$DM_DEV_DIR/$vg/pool_tmeta" | tee out
+
+ # When fully zeroed, it should be zero - so almost no output from hexdump
+ case "$i" in
+ 0) test "$(wc -l < out)" -ge 10 ;; # should not be zeroed
+ 1) test "$(wc -l < out)" -le 10 ;; # should be zeroed
+ esac
+
+ lvremove -f $vg/pool
+done
+
+# Check lvm2 spots error during full zeroing of metadata device
+aux error_dev "$dev2" "$(( $(get first_extent_sector "$dev2") + 32 )):"
+not lvcreate -T -L10G --poolmetadatasize 16G $vg/pool "$dev1" "$dev2" |& tee err
+grep "Failed to initialize logical volume" err
+
+vgremove -ff $vg
diff --git a/test/shell/topology-support.sh b/test/shell/topology-support.sh
index e952dc0..ffd637f 100644
--- a/test/shell/topology-support.sh
+++ b/test/shell/topology-support.sh
@@ -1,5 +1,6 @@
-#!/bin/sh
-# Copyright (C) 2010 Red Hat, Inc. All rights reserved.
+#!/usr/bin/env bash
+
+# Copyright (C) 2010-2015 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
@@ -7,42 +8,36 @@
#
# 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
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
-. lib/test
-which mkfs.ext3 || skip
+SKIP_WITH_LVMPOLLD=1
-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
-}
+. lib/inittest
+
+which mkfs.ext3 || skip
lvdev_() {
echo "$DM_DEV_DIR/$1/$2"
}
test_snapshot_mount() {
- lvcreate -L 16M -n $lv1 $vg "$dev1"
- mkfs.ext3 $(lvdev_ $vg $lv1)
+ lvcreate -aey -L4M -n $lv1 $vg "$dev1"
+ mkfs.ext3 -b4096 "$(lvdev_ $vg $lv1)"
mkdir test_mnt
mount "$(lvdev_ $vg $lv1)" test_mnt
- lvcreate -L 16M -n $lv2 -s $vg/$lv1
+ lvcreate -L4M -n $lv2 -s $vg/$lv1
umount test_mnt
+ aux udev_wait
# mount the origin
mount "$(lvdev_ $vg $lv1)" test_mnt
umount test_mnt
+ aux udev_wait
# 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
}
@@ -50,16 +45,7 @@ test_snapshot_mount() {
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
+DEV_SIZE=$(( NUM_DEVS * PER_DEV_SIZE ))
# ---------------------------------------------
# Create "desktop-class" 4K drive
@@ -67,10 +53,16 @@ aux cleanup_scsi_debug_dev
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
-
+# Test that kernel supports topology
+if [ ! -e "/sys/block/$(basename "$(< SCSI_DEBUG_DEV)")/alignment_offset" ] ; then
+ aux cleanup_scsi_debug_dev
+ skip
+fi
+check sysfs "$(< SCSI_DEBUG_DEV)" queue/logical_block_size "$LOGICAL_BLOCK_SIZE"
aux prepare_pvs $NUM_DEVS $PER_DEV_SIZE
-vgcreate -c n $vg $(cat DEVICES)
+get_devs
+
+vgcreate $SHARED $vg "${DEVICES[@]}"
test_snapshot_mount
vgremove $vg
@@ -82,10 +74,10 @@ aux cleanup_scsi_debug_dev
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
+check sysfs "$(< SCSI_DEBUG_DEV)" queue/logical_block_size $LOGICAL_BLOCK_SIZE
aux prepare_pvs $NUM_DEVS $PER_DEV_SIZE
-vgcreate -c n $vg $(cat DEVICES)
+vgcreate $SHARED $vg "${DEVICES[@]}"
test_snapshot_mount
vgremove $vg
@@ -97,9 +89,36 @@ aux cleanup_scsi_debug_dev
LOGICAL_BLOCK_SIZE=4096
aux prepare_scsi_debug_dev $DEV_SIZE \
sector_size=$LOGICAL_BLOCK_SIZE
-check_logical_block_size $LOGICAL_BLOCK_SIZE
+check sysfs "$(< SCSI_DEBUG_DEV)" queue/logical_block_size $LOGICAL_BLOCK_SIZE
aux prepare_pvs $NUM_DEVS $PER_DEV_SIZE
-vgcreate -c n $vg $(cat DEVICES)
+vgcreate $SHARED $vg "${DEVICES[@]}"
test_snapshot_mount
vgremove $vg
+
+aux cleanup_scsi_debug_dev
+
+# scsi_debug option opt_blks appeared in Oct 2010
+aux kernel_at_least 2 6 37 || exit 0
+
+# ---------------------------------------------
+# Create "enterprise-class" 512 drive w/ HW raid stripe_size = 768K
+# (logical_block_size=512, physical_block_size=512, alignment_offset=0):
+# - tests case where optimal_io_size=768k < default PE alignment=1MB
+LOGICAL_BLOCK_SIZE=512
+aux prepare_scsi_debug_dev $DEV_SIZE \
+ sector_size=$LOGICAL_BLOCK_SIZE opt_blks=1536
+
+check sysfs "$(< SCSI_DEBUG_DEV)" queue/logical_block_size $LOGICAL_BLOCK_SIZE
+check sysfs "$(< SCSI_DEBUG_DEV)" queue/optimal_io_size 786432
+
+aux prepare_devs 1 $PER_DEV_SIZE
+pvcreate --metadatasize 255s "${DEVICES[@]}"
+
+# Kernel (3.19) could provide wrong results - in this case skip
+# test with incorrect result - lvm2 can't figure out good values.
+SHOULD=""
+check sysfs "$dev1" queue/optimal_io_size 786432 || SHOULD=should
+$SHOULD check pv_field "${DEVICES[@]}" pe_start 768.00k
+
+aux cleanup_scsi_debug_dev
diff --git a/test/shell/udev-pvscan-vgchange.sh b/test/shell/udev-pvscan-vgchange.sh
new file mode 100644
index 0000000..14dbe82
--- /dev/null
+++ b/test/shell/udev-pvscan-vgchange.sh
@@ -0,0 +1,457 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2021 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+test_description='udev rule and systemd unit run vgchange'
+
+SKIP_WITH_LVMPOLLD=1
+SKIP_WITH_LVMLOCKD=1
+
+. lib/inittest
+
+# FIXME: currently test relies on several system properties to be
+# explcitely configure and directly modifies their state
+
+#
+# $ cat /tmp/devs
+# /dev/sdb
+# /dev/sdc
+# /dev/sdd
+#
+# Specify this file as LVM_TEST_DEVICE_LIST=/tmp/devs
+# when running the test.
+#
+# This test will wipe these devices.
+#
+
+if [ -z ${LVM_TEST_DEVICE_LIST+x} ]; then
+ skip "LVM_TEST_DEVICE_LIST is unset"
+else
+ echo "LVM_TEST_DEVICE_LIST is set to '$LVM_TEST_DEVICE_LIST'"
+fi
+
+test -e "$LVM_TEST_DEVICE_LIST" || skip
+
+num_devs=$(cat "$LVM_TEST_DEVICE_LIST" | wc -l)
+
+RUNDIR="/run"
+test -d "$RUNDIR" || RUNDIR="/var/run"
+PVS_ONLINE_DIR="$RUNDIR/lvm/pvs_online"
+VGS_ONLINE_DIR="$RUNDIR/lvm/vgs_online"
+PVS_LOOKUP_DIR="$RUNDIR/lvm/pvs_lookup"
+
+_clear_online_files() {
+ # wait till udev is finished
+ aux udev_wait
+ rm -f "$PVS_ONLINE_DIR"/*
+ rm -f "$VGS_ONLINE_DIR"/*
+ rm -f "$PVS_LOOKUP_DIR"/*
+}
+
+test -d "$PVS_ONLINE_DIR" || mkdir -p "$PVS_ONLINE_DIR"
+test -d "$VGS_ONLINE_DIR" || mkdir -p "$VGS_ONLINE_DIR"
+test -d "$PVS_LOOKUP_DIR" || mkdir -p "$PVS_LOOKUP_DIR"
+_clear_online_files
+
+aux prepare_real_devs
+
+aux lvmconf 'devices/dir = "/dev"'
+aux lvmconf 'devices/use_devicesfile = 1'
+DFDIR="$LVM_SYSTEM_DIR/devices"
+DF="$DFDIR/system.devices"
+mkdir "$DFDIR" || true
+not ls "$DF"
+
+get_real_devs
+
+wipe_all() {
+ for dev in "${REAL_DEVICES[@]}"; do
+ wipefs -a "$dev"
+ done
+}
+
+wait_lvm_activate() {
+ local vgw=$1
+ local wait=0
+
+ while systemctl status lvm-activate-$vgw > /dev/null && test "$wait" -le 30; do
+ sleep .2
+ wait=$(( wait + 1 ))
+ done
+}
+
+# Test requires 3 devs
+test "$num_devs" -gt 2 || skip
+BDEV1=$(basename "$dev1")
+BDEV2=$(basename "$dev2")
+BDEV3=$(basename "$dev3")
+
+wipe_all
+touch "$DF"
+for dev in "${REAL_DEVICES[@]}"; do
+ pvcreate $dev
+done
+
+# 1 dev, 1 vg, 1 lv
+
+vgcreate $vg1 "$dev1"
+lvcreate -l1 -an -n $lv1 $vg1 "$dev1"
+
+PVID1=$(pvs "$dev1" --noheading -o uuid | tr -d - | awk '{print $1}')
+
+_clear_online_files
+udevadm trigger --settle -c add "/sys/block/$BDEV1"
+
+wait_lvm_activate $vg1
+
+ls "$RUNDIR/lvm/pvs_online/$PVID1" || true
+ls "$RUNDIR/lvm/vgs_online/$vg1" || true
+journalctl -u lvm-activate-$vg1 | tee out || true
+grep "now active" out
+check lv_field $vg1/$lv1 lv_active "active"
+
+vgchange -an $vg1
+vgremove -y $vg1
+
+
+# 2 devs, 1 vg, 2 lvs
+
+vgcreate $vg2 "$dev1" "$dev2"
+lvcreate -l1 -an -n $lv1 $vg2 "$dev1"
+lvcreate -l1 -an -n $lv2 $vg2 "$dev2"
+
+PVID1=$(pvs "$dev1" --noheading -o uuid | tr -d - | awk '{print $1}')
+PVID2=$(pvs "$dev2" --noheading -o uuid | tr -d - | awk '{print $1}')
+
+_clear_online_files
+
+udevadm trigger --settle -c add "/sys/block/$BDEV1"
+ls "$RUNDIR/lvm/pvs_online/$PVID1"
+not ls "$RUNDIR/lvm/vgs_online/$vg2"
+journalctl -u lvm-activate-$vg2 | tee out || true
+not grep "now active" out
+check lv_field $vg2/$lv1 lv_active ""
+check lv_field $vg2/$lv2 lv_active ""
+
+udevadm trigger --settle -c add "/sys/block/$BDEV2"
+ls "$RUNDIR/lvm/pvs_online/$PVID2"
+ls "$RUNDIR/lvm/vgs_online/$vg2"
+
+wait_lvm_activate $vg2
+
+journalctl -u lvm-activate-$vg2 | tee out || true
+grep "now active" out
+check lv_field $vg2/$lv1 lv_active "active"
+check lv_field $vg2/$lv2 lv_active "active"
+
+vgchange -an $vg2
+vgremove -y $vg2
+
+
+# 3 devs, 1 vg, 4 lvs, concurrent pvscans
+# (attempting to have the pvscans run concurrently and race
+# to activate the VG)
+
+vgcreate $vg3 "$dev1" "$dev2" "$dev3"
+lvcreate -l1 -an -n $lv1 $vg3 "$dev1"
+lvcreate -l1 -an -n $lv2 $vg3 "$dev2"
+lvcreate -l1 -an -n $lv3 $vg3 "$dev3"
+lvcreate -l8 -an -n $lv4 -i 2 $vg3 "$dev1" "$dev2"
+
+PVID1=$(pvs "$dev1" --noheading -o uuid | tr -d - | awk '{print $1}')
+PVID2=$(pvs "$dev2" --noheading -o uuid | tr -d - | awk '{print $1}')
+PVID3=$(pvs "$dev3" --noheading -o uuid | tr -d - | awk '{print $1}')
+
+_clear_online_files
+
+udevadm trigger -c add "/sys/block/$BDEV1" &
+udevadm trigger -c add "/sys/block/$BDEV2" &
+udevadm trigger -c add "/sys/block/$BDEV3"
+
+aux udev_wait
+wait_lvm_activate $vg3
+
+ls "$RUNDIR/lvm/pvs_online/$PVID1"
+ls "$RUNDIR/lvm/pvs_online/$PVID2"
+ls "$RUNDIR/lvm/pvs_online/$PVID3"
+ls "$RUNDIR/lvm/vgs_online/$vg3"
+journalctl -u lvm-activate-$vg3 | tee out || true
+grep "now active" out
+check lv_field $vg3/$lv1 lv_active "active"
+check lv_field $vg3/$lv2 lv_active "active"
+check lv_field $vg3/$lv3 lv_active "active"
+check lv_field $vg3/$lv4 lv_active "active"
+
+vgchange -an $vg3
+vgremove -y $vg3
+
+
+# 3 devs, 1 vg, 4 lvs, concurrent pvscans, metadata on only 1 PV
+
+wipe_all
+rm $DF
+touch $DF
+pvcreate --metadatacopies 0 "$dev1"
+pvcreate --metadatacopies 0 "$dev2"
+pvcreate "$dev3"
+
+vgcreate $vg4 "$dev1" "$dev2" "$dev3"
+lvcreate -l1 -an -n $lv1 $vg4 "$dev1"
+lvcreate -l1 -an -n $lv2 $vg4 "$dev2"
+lvcreate -l1 -an -n $lv3 $vg4 "$dev3"
+lvcreate -l8 -an -n $lv4 -i 2 $vg4 "$dev1" "$dev2"
+
+PVID1=$(pvs "$dev1" --noheading -o uuid | tr -d - | awk '{print $1}')
+PVID2=$(pvs "$dev2" --noheading -o uuid | tr -d - | awk '{print $1}')
+PVID3=$(pvs "$dev3" --noheading -o uuid | tr -d - | awk '{print $1}')
+
+_clear_online_files
+
+udevadm trigger -c add "/sys/block/$BDEV1" &
+udevadm trigger -c add "/sys/block/$BDEV2" &
+udevadm trigger -c add "/sys/block/$BDEV3"
+
+aux udev_wait
+wait_lvm_activate $vg4
+
+ls "$RUNDIR/lvm/pvs_lookup/"
+cat "$RUNDIR/lvm/pvs_lookup/$vg4" || true
+ls "$RUNDIR/lvm/pvs_online/$PVID1"
+ls "$RUNDIR/lvm/pvs_online/$PVID2"
+ls "$RUNDIR/lvm/pvs_online/$PVID3"
+ls "$RUNDIR/lvm/vgs_online/$vg4"
+journalctl -u lvm-activate-$vg4 | tee out || true
+grep "now active" out
+check lv_field $vg4/$lv1 lv_active "active"
+check lv_field $vg4/$lv2 lv_active "active"
+check lv_field $vg4/$lv3 lv_active "active"
+check lv_field $vg4/$lv4 lv_active "active"
+
+vgchange -an $vg4
+vgremove -y $vg4
+
+
+# 3 devs, 3 vgs, 2 lvs in each vg, concurrent pvscans
+
+wipe_all
+rm "$DF"
+touch "$DF"
+
+vgcreate $vg5 "$dev1"
+vgcreate $vg6 "$dev2"
+vgcreate $vg7 "$dev3"
+lvcreate -l1 -an -n $lv1 $vg5
+lvcreate -l1 -an -n $lv2 $vg5
+lvcreate -l1 -an -n $lv1 $vg6
+lvcreate -l1 -an -n $lv2 $vg6
+lvcreate -l1 -an -n $lv1 $vg7
+lvcreate -l1 -an -n $lv2 $vg7
+
+_clear_online_files
+
+udevadm trigger -c add "/sys/block/$BDEV1" &
+udevadm trigger -c add "/sys/block/$BDEV2" &
+udevadm trigger -c add "/sys/block/$BDEV3"
+
+aux udev_wait
+wait_lvm_activate $vg5
+wait_lvm_activate $vg6
+wait_lvm_activate $vg7
+
+ls "$RUNDIR/lvm/vgs_online/$vg5"
+ls "$RUNDIR/lvm/vgs_online/$vg6"
+ls "$RUNDIR/lvm/vgs_online/$vg7"
+journalctl -u lvm-activate-$vg5 | tee out || true
+grep "now active" out
+journalctl -u lvm-activate-$vg6 | tee out || true
+grep "now active" out
+journalctl -u lvm-activate-$vg7 | tee out || true
+grep "now active" out
+check lv_field $vg5/$lv1 lv_active "active"
+check lv_field $vg5/$lv2 lv_active "active"
+check lv_field $vg6/$lv1 lv_active "active"
+check lv_field $vg6/$lv2 lv_active "active"
+check lv_field $vg7/$lv1 lv_active "active"
+check lv_field $vg7/$lv2 lv_active "active"
+
+vgchange -an $vg5
+vgremove -y $vg5
+vgchange -an $vg6
+vgremove -y $vg6
+vgchange -an $vg7
+vgremove -y $vg7
+
+# 3 devs, 1 vg, 1000 LVs
+
+wipe_all
+rm "$DF"
+touch "$DF"
+pvcreate --metadatacopies 0 "$dev1"
+pvcreate "$dev2"
+pvcreate "$dev3"
+vgcreate -s 128K $vg8 "$dev1" "$dev2" "$dev3"
+
+# Number of LVs to create
+TEST_DEVS=1000
+# On low-memory boxes let's not stress too much
+test "$(aux total_mem)" -gt 524288 || TEST_DEVS=256
+
+vgcfgbackup -f data $vg8
+
+# Generate a lot of devices (size of 1 extent)
+awk -v TEST_DEVS=$TEST_DEVS '/^\t\}/ {
+ printf("\t}\n\tlogical_volumes {\n");
+ cnt=0;
+ for (i = 0; i < TEST_DEVS; i++) {
+ printf("\t\tlvol%06d {\n", i);
+ printf("\t\t\tid = \"%06d-1111-2222-3333-2222-1111-%06d\"\n", i, i);
+ print "\t\t\tstatus = [\"READ\", \"WRITE\", \"VISIBLE\"]";
+ print "\t\t\tsegment_count = 1";
+ print "\t\t\tsegment1 {";
+ print "\t\t\t\tstart_extent = 0";
+ print "\t\t\t\textent_count = 1";
+ print "\t\t\t\ttype = \"striped\"";
+ print "\t\t\t\tstripe_count = 1";
+ print "\t\t\t\tstripes = [";
+ print "\t\t\t\t\t\"pv0\", " cnt++;
+ printf("\t\t\t\t]\n\t\t\t}\n\t\t}\n");
+ }
+ }
+ {print}
+' data >data_new
+
+vgcfgrestore -f data_new $vg8
+
+_clear_online_files
+
+udevadm trigger -c add "/sys/block/$BDEV1" &
+udevadm trigger -c add "/sys/block/$BDEV2" &
+udevadm trigger -c add "/sys/block/$BDEV3"
+
+aux udev_wait
+wait_lvm_activate $vg8
+
+ls "$RUNDIR/lvm/vgs_online/$vg8"
+journalctl -u lvm-activate-$vg8 | tee out || true
+grep "now active" out
+
+num_active=$(lvs $vg8 --noheading -o active | grep -c active)
+
+test "$num_active" -eq "$TEST_DEVS"
+
+vgchange -an $vg8
+vgremove -y $vg8
+
+# 1 pv on an md dev, 1 vg
+
+wait_md_create() {
+ local md=$1
+
+ while :; do
+ if ! grep "$(basename $md)" /proc/mdstat; then
+ echo "$md not ready"
+ cat /proc/mdstat
+ sleep 2
+ else
+ break
+ fi
+ done
+ echo "$md" > WAIT_MD_DEV
+}
+
+test -f /proc/mdstat && grep -q raid1 /proc/mdstat || \
+ modprobe raid1 || skip
+
+wipe_all
+rm "$DF"
+touch "$DF"
+
+aux mdadm_create --metadata=1.0 --level 1 --chunk=64 --raid-devices=2 "$dev1" "$dev2"
+mddev=$(< MD_DEV)
+
+wait_md_create "$mddev"
+vgcreate $vg9 "$mddev"
+lvmdevices --adddev "$mddev" || true
+
+PVIDMD=$(pvs "$mddev" --noheading -o uuid | tr -d - | awk '{print $1}')
+BDEVMD=$(basename "$mddev")
+
+lvcreate -l1 -an -n $lv1 $vg9
+lvcreate -l1 -an -n $lv2 $vg9
+
+mdadm --stop "$mddev"
+_clear_online_files
+aux mdadm_assemble "$mddev" "$dev1" "$dev2"
+
+# this trigger might be redundant because the mdadm --assemble
+# probably triggers an add uevent
+udevadm trigger --settle -c add /sys/block/$BDEVMD
+
+wait_lvm_activate $vg9
+
+ls "$RUNDIR/lvm/vgs_online/$vg9"
+journalctl -u lvm-activate-$vg9 | tee out || true
+grep "now active" out
+check lv_field $vg9/$lv1 lv_active "active"
+check lv_field $vg9/$lv2 lv_active "active"
+
+vgchange -an $vg9
+vgremove -y $vg9
+
+mdadm --stop "$mddev"
+aux udev_wait
+wipe_all
+
+# no devices file, filter with symlink of PV
+# the pvscan needs to look at all dev names to
+# match the symlink in the filter with the
+# dev name (or major minor) passed to pvscan.
+# This test doesn't really belong in this file
+# because it's not testing lvm-activate.
+
+aux lvmconf 'devices/use_devicesfile = 0'
+_clear_online_files
+rm "$DF"
+vgcreate $vg10 "$dev1"
+lvcreate -l1 -an -n $lv1 $vg10 "$dev1"
+
+PVID1=$(pvs "$dev1" --noheading -o uuid | tr -d - | awk '{print $1}')
+# PVID with dashes
+OPVID1=$(pvs "$dev1" --noheading -o uuid | awk '{print $1}')
+
+udevadm trigger --settle -c add "/sys/block/$BDEV1"
+
+# uevent from the trigger should create this symlink
+ls "/dev/disk/by-id/lvm-pv-uuid-$OPVID1"
+
+vgchange -an $vg10
+_clear_online_files
+
+aux lvmconf "devices/filter = [ \"a|/dev/disk/by-id/lvm-pv-uuid-$OPVID1|\", \"r|.*|\" ]"
+aux lvmconf 'devices/global_filter = [ "a|.*|" ]'
+
+pvscan --cache -aay "$dev1"
+
+check lv_field $vg10/$lv1 lv_active "active"
+
+vgchange -an $vg10
+_clear_online_files
+
+aux lvmconf 'devices/filter = [ "a|lvm-pv-uuid|", "r|.*|" ]'
+aux lvmconf 'devices/global_filter = [ "a|.*|" ]'
+
+pvscan --cache -aay "$dev1"
+
+check lv_field $vg10/$lv1 lv_active "active"
+
+vgchange -an $vg10
+vgremove -y $vg10
+wipe_all
diff --git a/test/shell/unknown-segment.sh b/test/shell/unknown-segment.sh
index d6071a1..ef66447 100644
--- a/test/shell/unknown-segment.sh
+++ b/test/shell/unknown-segment.sh
@@ -1,4 +1,5 @@
-#!/bin/sh
+#!/usr/bin/env bash
+
# Copyright (C) 2009 Red Hat, Inc. All rights reserved.
#
# This copyrighted material is made available to anyone wishing to use,
@@ -7,28 +8,40 @@
#
# 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
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+
+SKIP_WITH_LVMPOLLD=1
-. lib/test
+. lib/inittest
aux prepare_vg 4
-lvcreate -l 1 -n $lv1 $vg
-lvcreate -l 2 -m 1 -n $lv2 $vg
+lvcreate -an -Zn -l 1 -n $lv1 $vg
+lvcreate -an -Zn -l 2 --type mirror -m 1 -n $lv2 $vg
+lvcreate -an -Zn --type zero -l 1 -n $lv3 $vg
vgcfgbackup -f bak0 $vg
-sed -e 's,striped,unstriped,;s,mirror,unmirror,' -i.orig bak0
+sed -e 's,striped,unstriped,;s,mirror,unmirror,;s,zero,zero+NEWFLAG,' -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
+not lvchange -aey $vg/$lv1 # check that activation is refused
+
+# try once more to catch invalid memory access with valgrind
+# when clvmd flushes cmd mem pool
+not lvchange -aey $vg/$lv2 # check that activation is refused
+
+not lvchange -aey $vg/$lv3 # check that activation is refused
vgcfgbackup -f bak1 $vg
cat bak1
-sed -e 's,unstriped,striped,;s,unmirror,mirror,' -i.orig bak1
+sed -e 's,unstriped,striped,;s,unmirror,mirror,;s,zero+NEWFLAG,zero,' -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
+grep -v -E 'description|seqno|creation_time|Generated' < bak0.orig > a
+grep -v -E 'description|seqno|creation_time|Generated' < bak2 > b
diff -u a b
+
+vgremove -ff $vg
diff --git a/test/shell/unlost-pv.sh b/test/shell/unlost-pv.sh
index 962fe22..50f8928 100644
--- a/test/shell/unlost-pv.sh
+++ b/test/shell/unlost-pv.sh
@@ -1,4 +1,5 @@
-#!/bin/sh
+#!/usr/bin/env bash
+
# Copyright (C) 2008 Red Hat, Inc. All rights reserved.
#
# This copyrighted material is made available to anyone wishing to use,
@@ -7,38 +8,66 @@
#
# 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
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
-. lib/test
+SKIP_WITH_LVMPOLLD=1
-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
-}
+. lib/inittest
aux prepare_vg 3
-lvcreate -m 1 -l 1 -n mirror $vg
-lvchange -a n $vg
+lvcreate -an -Zn --type mirror -m 1 -l 1 -n mirror $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
+vgscan 2>&1 | tee vgscan.out
+grep "Inconsistent metadata found for VG $vg" vgscan.out
+
+# erase outdated dev1
+vgck --updatemetadata $vg
+
+vgscan 2>&1 | tee vgscan.out
+not grep "Inconsistent metadata found for VG $vg" vgscan.out
+
-# 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
+
+vgscan 2>&1 | tee vgscan.out
+grep "Inconsistent metadata found for VG $vg" vgscan.out
+
+# write the vg to update the metadata on dev1
+vgck --updatemetadata $vg
+
+vgscan 2>&1 | tee vgscan.out
+not grep "Inconsistent metadata found for VG $vg" vgscan.out
+
+aux disable_dev "$dev1"
+
+vgreduce --removemissing --force $vg
+
+aux enable_dev "$dev1"
+
+vgscan 2>&1 | tee out
+
+vgscan 2>&1 | tee vgscan.out
+grep "Inconsistent metadata found for VG $vg" vgscan.out
+
+# erase outdated dev1
+vgck --updatemetadata $vg
+
+vgscan 2>&1 | tee vgscan.out
+not grep "Inconsistent metadata found for VG $vg" vgscan.out
+
+vgremove -ff $vg
diff --git a/test/shell/vdo-autoumount-dmeventd.sh b/test/shell/vdo-autoumount-dmeventd.sh
new file mode 100644
index 0000000..e0449ff
--- /dev/null
+++ b/test/shell/vdo-autoumount-dmeventd.sh
@@ -0,0 +1,127 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2019 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+# no automatic extensions, just umount
+
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+mntdir="${PREFIX}mnt with space"
+PERCENT=70
+
+cleanup_mounted_and_teardown()
+{
+ test -z "$PID_SLEEP" || { kill "$PID_SLEEP" || true ; }
+ umount "$mntdir" 2>/dev/null || true
+ vgremove -ff $vg
+ aux teardown
+}
+
+is_lv_opened_()
+{
+ test "$(get lv_field "$1" lv_device_open --binary)" = 1
+}
+
+#
+# Main
+#
+which mkfs.ext4 || skip
+export MKE2FS_CONFIG="$TESTDIR/lib/mke2fs.conf"
+
+aux have_vdo 6 2 0 || skip
+
+# Simple implementation of umount when lvextend fails
+# Script enforces failin exit, so dmeventd tries several times
+# repeatedly to invoke this for given percentage
+cat <<- EOF >testcmd.sh
+#!/bin/sh
+
+echo "VDO Pool: \$DMEVENTD_VDO_POOL"
+
+"$TESTDIR/lib/lvextend" --use-policies \$1 || {
+ umount "$mntdir" && exit 0
+ touch $PWD/TRIED_UMOUNT
+}
+test "\$($TESTDIR/lib/lvs -o selected -S "data_percent>=$PERCENT" --noheadings \$1)" -eq 0 || {
+ echo "Percentage still above $PERCENT"
+}
+exit 1
+EOF
+chmod +x testcmd.sh
+# Show prepared script
+cat testcmd.sh
+
+# Use autoextend percent 0 - so extension fails and triggers umount...
+aux lvmconf "activation/vdo_pool_autoextend_percent = 0" \
+ "activation/vdo_pool_autoextend_threshold = $PERCENT" \
+ "dmeventd/vdo_command = \"$PWD/testcmd.sh\"" \
+ "allocation/vdo_slab_size_mb = 128"
+
+aux prepare_dmeventd
+
+aux prepare_vg 1 9000
+
+lvcreate --vdo -L4G -V2G -n $lv1 $vg/vpool
+
+mkfs.ext4 -E nodiscard "$DM_DEV_DIR/$vg/$lv1"
+
+lvchange --monitor y $vg/vpool
+
+mkdir "$mntdir"
+trap 'cleanup_mounted_and_teardown' EXIT
+mount "$DM_DEV_DIR/$vg/$lv1" "$mntdir"
+
+# Check both LV is opened (~mounted)
+is_lv_opened_ "$vg/$lv1"
+
+touch "$mntdir/file$$"
+sync
+
+# Running 'keeper' process sleep holds the block device still in use
+sleep 60 < "$mntdir/file$$" >/dev/null 2>&1 &
+PID_SLEEP=$!
+
+lvs -a $vg
+# Fill pool above 95% (to cause 'forced lazy umount)
+dd if=/dev/urandom of="$mntdir/file$$" bs=256K count=200 oflag=direct
+
+lvs -a $vg
+
+# Could loop here for a few secs so dmeventd can do some work
+# In the worst case check only happens every 10 seconds :(
+for i in $(seq 1 12) ; do
+ is_lv_opened_ "$vg/$lv1" || break
+ test ! -f "TRIED_UMOUNT" || continue # finish loop quickly
+ sleep 1
+done
+
+rm -f "TRIED_UMOUNT"
+test "$i" -eq 12 || die "$mntdir should NOT have been unmounted by dmeventd!"
+
+lvs -a $vg
+
+# Kill device holding process - umount should work now
+kill "$PID_SLEEP"
+PID_SLEEP=
+wait
+
+# Could loop here for a few secs so dmeventd can do some work
+# In the worst case check only happens every 10 seconds :(
+for i in $(seq 1 12) ; do
+ is_lv_opened_ "$vg/$lv1" || break
+ test "$i" -lt 12 || die "$mntdir should have been unmounted by dmeventd!"
+ sleep 1
+done
+
+# vgremove is managed through cleanup_mounted_and_teardown()
diff --git a/test/shell/vdo-convert.sh b/test/shell/vdo-convert.sh
new file mode 100644
index 0000000..231939c
--- /dev/null
+++ b/test/shell/vdo-convert.sh
@@ -0,0 +1,230 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2021 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+# Test conversion of VDO volumes made by vdo manager into VDO LV.
+
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+# Use local for this test vdo configuratoin
+VDO_CONFIG="vdotestconf.yml"
+VDOCONF="-f $VDO_CONFIG"
+#VDOCONF=""
+export VDOCONF VDO_CONFIG
+VDONAME="${PREFIX}-TESTVDO"
+export DM_UUID_PREFIX=$PREFIX
+
+# VDO automatically starts dmeventd
+aux prepare_dmeventd
+
+#
+# Main
+#
+if not which vdo ; then
+ which lvm_vdo_wrapper || skip "Missing 'lvm_vdo_wrapper'."
+ which oldvdoformat || skip "Emulation of vdo manager 'oldvdoformat' missing."
+ which oldvdoprepareforlvm || skip "Emulation of vdo manager 'oldvdoprepareforlvm' missing."
+ # enable expansion of aliasis within script itself
+ shopt -s expand_aliases
+ alias vdo='lvm_vdo_wrapper'
+ export VDO_BINARY=lvm_vdo_wrapper
+ echo "Using 'lvm_vdo_wrapper' emulation of 'vdo' manager."
+fi
+which mkfs.ext4 || skip
+export MKE2FS_CONFIG="$TESTDIR/lib/mke2fs.conf"
+
+aux have_vdo 6 2 0 || skip
+
+aux prepare_devs 2 20000
+
+aux extend_filter_LVMTEST
+
+export TMPDIR=$PWD
+
+
+# Conversion can be made with this version of vdo driver
+aux have_vdo 6 2 5 || skip
+
+#
+# Check conversion of VDO volume made on some LV
+#
+# In this case we do not need to move any VDO headers.
+#
+vgcreate $vg "$dev1"
+
+lvcreate -L5G -n $lv1 $vg
+
+# use some not so 'well' aligned virtual|logical size
+vdo create $VDOCONF --name "$VDONAME" --device "$DM_DEV_DIR/$vg/$lv1" --vdoSlabSize 128M --vdoLogicalSize 10G
+
+mkfs -E nodiscard "$DM_DEV_DIR/mapper/$VDONAME"
+##XXXXX
+# Different VG name fails
+not lvm_import_vdo -y -v --name $vg1/$lv1 "$DM_DEV_DIR/$vg/$lv1"
+
+# Try just dry run and observe logging
+lvm_import_vdo --dry-run -y -v --name $lv1 "$DM_DEV_DIR/$vg/$lv1"
+
+lvm_import_vdo -y --name $lv1 "$DM_DEV_DIR/$vg/$lv1"
+
+# ensure VDO device is not left in config file
+vdo remove $VDOCONF --force --name "$VDONAME" 2>/dev/null || true
+
+lvremove -f $vg
+
+
+# Test user can specify different VDO LV name (so the original LV is renamed)
+lvcreate -y -L5G -n $lv1 $vg
+
+vdo create $VDOCONF --name "$VDONAME" --device "$DM_DEV_DIR/$vg/$lv1" --vdoSlabSize 128M --vdoLogicalSize 10G
+
+lvm_import_vdo -y --name $vg/$lv2 "$DM_DEV_DIR/$vg/$lv1"
+
+check lv_exists $vg $lv2
+check lv_not_exists $vg $lv1
+
+vgremove -f $vg
+
+# ensure VDO device is not left in config file
+vdo remove $VDOCONF --force --name "$VDONAME" 2>/dev/null || true
+
+aux wipefs_a "$dev1"
+
+# prepare 'unused' $vg2
+vgcreate $vg2 "$dev2"
+
+#
+# Check conversion of VDO volume on non-LV device and with >2T size
+#
+vdo create $VDOCONF --name "$VDONAME" --device "$dev1" --vdoSlabSize 128M --vdoLogicalSize 3T
+
+# Fail with an already existing volume group $vg2
+not lvm_import_vdo --dry-run -y -v --name $vg2/$lv1 "$dev1" |& tee err
+grep "already existing volume group" err
+
+# User can also convert already stopped VDO volume
+vdo stop $VDOCONF --name "$VDONAME"
+
+lvm_import_vdo -y -v --name $vg/$lv1 "$dev1"
+
+check lv_field $vg/$lv1 size "3.00t"
+
+vgremove -f $vg
+
+
+#
+# Try once again with different vgname/lvname and sizes
+#
+aux teardown_devs
+aux prepare_devs 1 23456
+
+vdo create $VDOCONF --name "$VDONAME" --device "$dev1" --vdoSlabSize 128M --vdoLogicalSize 23G
+
+mkfs -E nodiscard "$DM_DEV_DIR/mapper/$VDONAME"
+
+lvm_import_vdo --vdo-config "$VDO_CONFIG" -y -v --name $vg1/$lv2 "$dev1"
+
+fsck -n "$DM_DEV_DIR/$vg1/$lv2"
+
+vgremove -f $vg1
+
+aux wipefs_a "$dev1"
+
+# let's assume users with VDO target have 'new' enough version of stat too
+# otherwise use more universal code from lvm_vdo_import
+read major minor < <(stat -c '%Hr %Lr' $(readlink -e "$dev1"))
+dmsetup create "$PREFIX-vdotest" --table "0 30280004 linear $major:$minor 32"
+
+TEST="$DM_DEV_DIR/mapper/$PREFIX-vdotest"
+
+aux wipefs_a "$TEST"
+aux extend_filter "a|$TEST|"
+aux extend_devices "$TEST"
+
+#
+# Unfortunatelly generates this in syslog:
+#
+# vdo-start-by-dev@loop0.service: Main process exited, code=exited, status=1/FAILURE
+# vdo-start-by-dev@loop0.service: Failed with result 'exit-code'.
+# Failed to start Start VDO volume backed by loop0.
+#
+# TODO: Could be handled by:
+#
+# systemctl mask vdo-start-by-dev@
+# systemctl unmask vdo-start-by-dev@
+#
+# automate...
+#
+
+# use slightly smaller size then 'rounded' 23G - to enforce vdo_logicalSize rounding
+vdo create $VDOCONF --name "$VDONAME" --device "$TEST" --vdoSlabSize 128M --vdoLogicalSize 24117240K\
+ --blockMapCacheSize 192 \
+ --blockMapPeriod 2048 \
+ --emulate512 disabled \
+ --indexMem 0.5 \
+ --maxDiscardSize 10 \
+ --sparseIndex disabled \
+ --vdoAckThreads 2 \
+ --vdoBioRotationInterval 8 \
+ --vdoBioThreads 2 \
+ --vdoCpuThreads 5 \
+ --vdoHashZoneThreads 3 \
+ --vdoLogicalThreads 3 \
+ --writePolicy async-unsafe
+dmsetup table
+
+# Get VDO table line
+dmsetup table "$VDONAME" | tr " " "\n" | sed -e '5,6d' -e '12d' | tee vdo-orig
+
+mkfs.ext4 -E nodiscard "$DM_DEV_DIR/mapper/$VDONAME"
+
+# For conversion we
+aux lvmconf 'global/vdo_disabled_features = [ "version4" ]'
+
+#
+# Try to prepare 'broken' case where header was moved by older tool to 2M position
+#
+export LVM_VDO_PREPARE=oldvdoprepareforlvm2M
+if which "$LVM_VDO_PREPARE" ; then
+# Use old vdoprepareforlvm tool, that always moves header to 2M offset
+cp "$VDO_CONFIG" "$VDO_CONFIG.backup"
+lvm_import_vdo --abort-after-vdo-convert --vdo-config "$VDO_CONFIG" -v -y --name $vg/$lv "$TEST"
+# Restore VDO configuration (as it's been removed with succeful vdo conversion
+cp "$VDO_CONFIG.backup" "$VDO_CONFIG"
+# Check VDO header is seen at 2M offset
+blkid -c /dev/null --probe --offset 2M "$TEST"
+fi
+unset LVM_VDO_PREPARE
+
+#lvm_import_vdo --no-snapshot --vdo-config "$VDO_CONFIG" -v -y --name $vg/$lv "$TEST"
+lvm_import_vdo --vdo-config "$VDO_CONFIG" --uuid-prefix "$PREFIX" -v -y --name $vg/$lv "$TEST"
+dmsetup table
+
+# check our filesystem is OK
+fsck -n "$DM_DEV_DIR/$vg/$lv"
+
+# Compare converted LV uses same VDO table line
+dmsetup table "$vg-${lv}_vpool-vpool" | tr " " "\n" | sed -e '5,6d' -e '12d' | tee new-vdo-lv
+
+tail -n+3 vdo-orig >vdo-orig-3
+tail -n+3 new-vdo-lv >new-vdo-lv-3
+
+# Check there is a match between VDO and LV managed volume
+# (when differentiating parameters are deleted first)
+# we need to skip first 2 lines as the device size gets rounded to match VG extent size
+diff -u vdo-orig-3 new-vdo-lv-3 || die "Found mismatching VDO table lines!"
+
+check lv_field $vg/$lv size "23.00g"
+unset LVM_VDO_PREPARE
+
diff --git a/test/shell/vg-check-devs-used.sh b/test/shell/vg-check-devs-used.sh
new file mode 100644
index 0000000..15cdff6
--- /dev/null
+++ b/test/shell/vg-check-devs-used.sh
@@ -0,0 +1,39 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2016 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+SKIP_WITH_LVMPOLLD=1
+
+
+. lib/inittest
+
+# We need "dm" directory for dm devices in sysfs.
+aux driver_at_least 4 15 || skip
+
+aux prepare_devs 3 8
+
+vgcreate $SHARED "$vg" "$dev1" "$dev2"
+lvcreate -l100%FREE -n $lv $vg
+dd if="$dev1" of="$dev3" bs=1M oflag=direct
+pvs --devices $dev2,$dev3 2>err
+grep "WARNING: Device mismatch detected for $vg/$lv which is accessing $dev1 instead of $dev3" err
+
+dd if=/dev/zero of="$dev3" bs=1M count=8 oflag=direct
+lvremove -ff $vg
+
+# Also test if sub LVs with suffixes are correctly processed.
+# Check with thick snapshot which has sub LVs with -real and -cow suffix in UUID.
+lvcreate -l1 -aey -n $lv $vg
+lvcreate -l1 -aey -s $vg/$lv
+pvs 2>err
+not grep "WARNING: Device mismatch detected for $vg/$lv" err
+
+vgremove -ff $vg
diff --git a/test/shell/vg-name-from-env.sh b/test/shell/vg-name-from-env.sh
new file mode 100644
index 0000000..48e471c
--- /dev/null
+++ b/test/shell/vg-name-from-env.sh
@@ -0,0 +1,108 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2008-2013 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.
+
+test_description='Test the vg name for an lv from env var'
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+aux prepare_devs 2
+
+pvcreate "$dev1"
+pvcreate "$dev2"
+
+vgcreate $SHARED $vg1 "$dev1"
+vgcreate $SHARED $vg2 "$dev2"
+
+export LVM_VG_NAME=$vg1
+
+# should use env
+lvcreate -n $lv1 -l 2
+lvcreate -n $lv3 -l 2
+
+lvcreate -n $lv2 -l 2 $vg2
+lvcreate -n $lv4 -l 2 $vg2
+
+lvs >err
+grep $lv1 err
+grep $lv3 err
+grep $lv2 err
+grep $lv4 err
+
+not lvs $vg1 >err
+not grep $lv1 err
+not grep $lv3 err
+not grep $lv2 err
+not grep $lv4 err
+
+not lvs $vg2 >err
+not grep $lv1 err
+not grep $lv3 err
+not grep $lv2 err
+not grep $lv4 err
+
+lvs $lv1 >err
+grep $lv1 err
+not grep $lv3 err
+not grep $lv2 err
+not grep $lv4 err
+
+lvs $lv1 $lv3 >err
+grep $lv1 err
+grep $lv3 err
+not grep $lv2 err
+not grep $lv4 err
+
+# should use env and fail to fine lv4 in vg1
+not lvs $lv4 >err
+not grep $lv1 err
+not grep $lv3 err
+not grep $lv2 err
+not grep $lv4 err
+
+lvs $vg2/$lv4 >err
+not grep $lv1 err
+not grep $lv3 err
+not grep $lv2 err
+grep $lv4 err
+
+lvs $vg2/$lv2 $vg2/$lv4 >err
+not grep $lv1 err
+not grep $lv3 err
+grep $lv2 err
+grep $lv4 err
+
+# should use env
+lvchange -an $lv3
+lvremove $lv3
+not lvremove $lv4
+
+lvs >err
+grep $lv1 err
+not grep $lv3 err
+grep $lv2 err
+grep $lv4 err
+
+# should use env
+lvcreate -n $lv3 -l 2
+lvchange --addtag foo $lv3
+lvchange -an $lv3
+
+# lvremove by tag should apply to all vgs, not env vg
+lvchange --addtag foo $vg2/$lv4
+lvchange -an $vg2/$lv4
+lvremove @foo
+
+lvs >err
+grep $lv1 err
+not grep $lv3 err
+grep $lv2 err
+not grep $lv4 err
+
+vgremove -ff $vg1 $vg2
diff --git a/test/shell/vg-raid-takeover-1.sh b/test/shell/vg-raid-takeover-1.sh
new file mode 100644
index 0000000..98e043a
--- /dev/null
+++ b/test/shell/vg-raid-takeover-1.sh
@@ -0,0 +1,202 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2023 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+test_description='Test VG takeover with raid LVs'
+
+# test does not apply to lvmlockd
+SKIP_WITH_LVMLOCKD=1
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+aux have_raid 1 9 0 || skip
+aux prepare_devs ${PREPARE_DEVS-3}
+
+SIDFILE="etc/lvm_test.conf"
+LVMLOCAL="etc/lvmlocal.conf"
+
+DFDIR="$LVM_SYSTEM_DIR/devices"
+DF="$DFDIR/system.devices"
+
+print_lvmlocal() {
+ { echo "local {"; printf "%s\n" "$@"; echo "}"; } >"$LVMLOCAL"
+}
+
+# Avoid system id validation in the devices file
+# which gets in the way of the test switching the
+# local system id.
+clear_df_systemid() {
+ if [[ -f $DF ]]; then
+ sed -e "s|SYSTEMID=.||" "$DF" > tmpdf
+ cp tmpdf $DF
+ fi
+}
+
+test_check_mount() {
+ pvs -o+missing
+ vgs -o+systemid,partial $vg
+ lvs -a -o+devices $vg
+
+ mount "$DM_DEV_DIR/$vg/$lv1" "$mount_dir"
+ diff pattern1 "$mount_dir/pattern1a"
+ diff pattern1 "$mount_dir/pattern1c"
+ umount "$mount_dir"
+ fsck -n "$DM_DEV_DIR/$vg/$lv1"
+
+ mount "$DM_DEV_DIR/$vg/$lv2" "$mount_dir"
+ diff pattern1 "$mount_dir/pattern1a"
+ diff pattern1 "$mount_dir/pattern1c"
+ umount "$mount_dir"
+ fsck -n "$DM_DEV_DIR/$vg/$lv2"
+}
+
+
+SID1=sidfoofile1
+SID2=sidfoofile2
+echo "$SID1" > "$SIDFILE"
+clear_df_systemid
+aux lvmconf "global/system_id_source = file" \
+ "global/system_id_file = \"$SIDFILE\""
+vgcreate $vg "$dev1" "$dev2" "$dev3"
+vgs -o+systemid,partial $vg
+check vg_field $vg systemid "$SID1"
+
+lvcreate --type raid1 -L 8 -m1 -n $lv1 $vg "$dev1" "$dev2"
+lvcreate --type raid1 -L 8 -m2 -n $lv2 $vg "$dev1" "$dev2" "$dev3"
+
+# give some time for raid init
+aux wait_for_sync $vg $lv1
+aux wait_for_sync $vg $lv2
+lvs -a -o+devices $vg
+
+mkfs.ext4 "$DM_DEV_DIR/$vg/$lv1"
+mkfs.ext4 "$DM_DEV_DIR/$vg/$lv2"
+
+dd if=/dev/urandom of=pattern1 bs=512K count=1
+
+mount_dir="mnt_takeover"
+mkdir -p "$mount_dir"
+
+mount "$DM_DEV_DIR/$vg/$lv1" "$mount_dir"
+dd if=/dev/zero of="$mount_dir/file1" bs=1M count=4 oflag=direct
+cp pattern1 "$mount_dir/pattern1a"
+cp pattern1 "$mount_dir/pattern1b"
+umount "$mount_dir"
+
+mount "$DM_DEV_DIR/$vg/$lv2" "$mount_dir"
+dd if=/dev/zero of="$mount_dir/file1" bs=1M count=4 oflag=direct
+cp pattern1 "$mount_dir/pattern1a"
+cp pattern1 "$mount_dir/pattern1b"
+umount "$mount_dir"
+
+vgchange -an $vg
+
+# make the vg foreign
+vgchange --yes --systemid "$SID2" $vg
+not vgs $vg
+
+# make one dev missing
+aux hide_dev "$dev1"
+
+# take over the vg, like cluster failover would do
+vgchange --majoritypvs --config "local/extra_system_ids=[\"${SID2}\"]" --systemid "$SID1" $vg
+pvs -o+missing
+vgs -o+systemid,partial $vg
+lvs -a -o+devices $vg
+
+lvchange -ay --activationmode degraded $vg/$lv1
+lvchange -ay --activationmode degraded $vg/$lv2
+
+mount "$DM_DEV_DIR/$vg/$lv1" "$mount_dir"
+dd of=/dev/null if="$mount_dir/file1" bs=1M count=4
+diff pattern1 "$mount_dir/pattern1a"
+diff pattern1 "$mount_dir/pattern1b"
+rm "$mount_dir/pattern1b"
+rm "$mount_dir/file1"
+cp pattern1 "$mount_dir/pattern1c"
+umount "$mount_dir"
+
+mount "$DM_DEV_DIR/$vg/$lv2" "$mount_dir"
+dd of=/dev/null if="$mount_dir/file1" bs=1M count=4
+diff pattern1 "$mount_dir/pattern1a"
+diff pattern1 "$mount_dir/pattern1b"
+rm "$mount_dir/pattern1b"
+rm "$mount_dir/file1"
+cp pattern1 "$mount_dir/pattern1c"
+umount "$mount_dir"
+
+pvs -o+missing
+vgs -o+systemid,partial $vg
+lvs -a -o+devices $vg
+
+
+
+#----------------------------------------------------------
+# test will continue differently when var OTHER_TEST is set
+#----------------------------------------------------------
+test -n "${CONTINUE_ELSEWHERE-}" && return 0
+
+
+
+# fails because the missing dev is used by lvs
+not vgreduce --removemissing $vg
+# works because lvs can be used with missing leg
+vgreduce --removemissing --mirrorsonly --force $vg
+
+pvs -o+missing
+vgs -o+systemid,partial $vg
+lvs -a -o+devices $vg
+
+# decline to repair (answer no)
+lvconvert --repair $vg/$lv1
+# fails to find another disk to use to repair
+not lvconvert -y --repair $vg/$lv2
+
+
+test_check_mount
+
+
+aux unhide_dev "$dev1"
+
+pvs -o+missing
+vgs -o+systemid,partial $vg
+lvs -a -o+devices $vg
+
+vgck --updatemetadata $vg
+
+pvs -o+missing
+vgs -o+systemid,partial $vg
+lvs -a -o+devices $vg
+
+# remove the failed unused leg, leaving 2 legs
+lvconvert -y -m-1 $vg/$lv2
+# remove the failed unused leg, leaving 1 leg
+lvconvert -y -m-1 $vg/$lv1
+
+
+test_check_mount
+
+
+vgextend $vg "$dev1"
+lvconvert -y -m+1 $vg/$lv1 "$dev1"
+lvconvert -y -m+1 $vg/$lv2 "$dev1"
+
+# let raid sync new leg
+aux wait_for_sync $vg $lv1
+aux wait_for_sync $vg $lv2
+
+
+test_check_mount
+
+
+vgchange -an $vg
+vgremove -f $vg
diff --git a/test/shell/vg-raid-takeover-2.sh b/test/shell/vg-raid-takeover-2.sh
new file mode 100644
index 0000000..afc8db4
--- /dev/null
+++ b/test/shell/vg-raid-takeover-2.sh
@@ -0,0 +1,65 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2023 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+test_description='Test VG takeover with raid LVs'
+
+CONTINUE_ELSEWHERE=y
+PREPARE_DEVS=4
+
+. ./shell/vg-raid-takeover-1.sh
+
+# fails because the missing dev is used by lvs
+not vgreduce --removemissing $vg
+# works because lvs can be used with missing leg
+vgreduce --removemissing --mirrorsonly --force $vg
+
+pvs -o+missing
+vgs -o+systemid,partial $vg
+lvs -a -o+devices $vg
+
+# unhide_dev before lvconvert --repair
+# i.e. the device reappears before the LVs are repaired
+
+aux unhide_dev "$dev1"
+
+pvs -o+missing
+vgs -o+systemid,partial $vg
+lvs -a -o+devices $vg
+
+# this repairs lv1 by using dev3 in place of dev1
+lvconvert -y --repair $vg/$lv1
+
+pvs -o+missing
+vgs -o+systemid,partial $vg
+lvs -a -o+devices $vg
+
+# add a new disk to use for replacing dev1 in lv2
+vgextend $vg "$dev4"
+
+lvconvert -y --repair $vg/$lv2
+
+
+test_check_mount
+
+
+# let the new legs sync
+aux wait_for_sync $vg $lv1
+aux wait_for_sync $vg $lv2
+
+vgck --updatemetadata $vg
+
+
+test_check_mount
+
+
+vgchange -an $vg
+vgremove -f $vg
diff --git a/test/shell/vg-raid-takeover-3.sh b/test/shell/vg-raid-takeover-3.sh
new file mode 100644
index 0000000..0050c19
--- /dev/null
+++ b/test/shell/vg-raid-takeover-3.sh
@@ -0,0 +1,52 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2023 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+test_description='Test VG takeover with raid LVs'
+
+CONTINUE_ELSEWHERE=y
+
+. ./shell/vg-raid-takeover-1.sh
+
+#-----------------------
+# replaces dev1 with dev3
+lvconvert -y --repair $vg/$lv1
+
+# no other disk to replace dev1 so remove the leg,
+# but that's not allowed until the missing disk is removed from the vg
+not lvconvert -y -m-1 $vg/$lv2
+vgreduce --removemissing --mirrorsonly --force $vg
+
+pvs -o+missing
+vgs -o+systemid,partial $vg
+lvs -a -o+devices $vg
+lvconvert -y -m-1 $vg/$lv2
+
+
+test_check_mount
+
+
+aux unhide_dev "$dev1"
+
+# put dev1 back into lv2,
+# requires clearing outdated metadata and putting dev1 back in vg
+vgck --updatemetadata $vg
+pvs -o+missing
+vgextend $vg "$dev1"
+pvs -o+missing
+lvconvert -y -m+1 $vg/$lv2 "$dev1"
+
+
+test_check_mount
+
+
+vgchange -an $vg
+vgremove -f $vg
diff --git a/test/shell/vg-raid-takeover-4.sh b/test/shell/vg-raid-takeover-4.sh
new file mode 100644
index 0000000..8e29f2d
--- /dev/null
+++ b/test/shell/vg-raid-takeover-4.sh
@@ -0,0 +1,37 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2023 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+test_description='Test VG takeover with raid LVs'
+
+CONTINUE_ELSEWHERE=y
+PREPARE_DEVS=4
+
+. ./shell/vg-raid-takeover-1.sh
+
+# unhide_dev
+# the device reappears before the LVs are repaired
+# and before the missing dev is removed from the vg
+
+aux unhide_dev "$dev1"
+
+pvs -o+missing
+vgs -o+systemid,partial $vg
+lvs -a -o+devices $vg
+
+vgextend --restoremissing $vg "$dev1"
+
+
+test_check_mount
+
+
+vgchange -an $vg
+vgremove -f $vg
diff --git a/test/shell/vgcfgbackup-lvm1.sh b/test/shell/vgcfgbackup-lvm1.sh
new file mode 100644
index 0000000..9b81e28
--- /dev/null
+++ b/test/shell/vgcfgbackup-lvm1.sh
@@ -0,0 +1,38 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2008-2013 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+aux prepare_pvs 4
+get_devs
+
+if test -n "$LVM_TEST_LVM1" ; then
+
+pvcreate --metadatacopies 0 "$dev4"
+
+# No automatic backup
+aux lvmconf "backup/backup = 0"
+
+# vgcfgbackup correctly stores metadata LVM1 with missing PVs
+
+pvcreate -M1 "${DEVICES[@]}"
+vgcreate $SHARED -M1 "$vg" "${DEVICES[@]}"
+lvcreate -l1 -n $lv1 $vg "$dev1"
+pvremove -ff -y "$dev2"
+not lvcreate -l1 -n $lv1 $vg "$dev3"
+lvchange -an $vg
+vgcfgbackup -f "backup.$$" $vg
+
+fi
diff --git a/test/shell/vgcfgbackup-usage.sh b/test/shell/vgcfgbackup-usage.sh
index c8245b0..801f9ce 100644
--- a/test/shell/vgcfgbackup-usage.sh
+++ b/test/shell/vgcfgbackup-usage.sh
@@ -1,5 +1,6 @@
-#!/bin/sh
-# Copyright (C) 2008 Red Hat, Inc. All rights reserved.
+#!/usr/bin/env bash
+
+# Copyright (C) 2008-2013 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
@@ -7,47 +8,71 @@
#
# 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
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
-. lib/test
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
aux prepare_pvs 4
+get_devs
+
+pvcreate --metadatacopies 0 "$dev4"
+
+# No automatic backup
+aux lvmconf "backup/backup = 0"
# vgcfgbackup handles similar VG names (bz458941)
vg1=${PREFIX}vg00
vg2=${PREFIX}vg01
-vgcreate $vg1 "$dev1"
-vgcreate $vg2 "$dev2"
-vgcfgbackup -f $TESTDIR/bak-%s >out
+vgcreate $SHARED $vg1 "$dev1"
+vgcreate $SHARED $vg2 "$dev2"
+
+# Enforces system backup
+test ! -e etc/backup/$vg1
+test ! -e etc/backup/$vg2
+vgcfgbackup
+test -e etc/backup/$vg1
+test -e etc/backup/$vg2
+
+aux lvmconf "backup/archive = 1"
+
+vgcfgbackup -f "bak-%s" >out
grep "Volume group \"$vg1\" successfully backed up." out
grep "Volume group \"$vg2\" successfully backed up." out
+# increase seqno
+lvcreate -an -Zn -l1 $vg1
+
+invalid vgcfgrestore -f "bak-$vg1" $vg1-inv@lid
+invalid vgcfgrestore -f "bak-$vg1" $vg1 $vg2
+
+vgcfgrestore -l $vg1 | tee out
+test "$(grep -c Description out)" -eq 2
+
+vgcfgrestore -l -f "bak-$vg1" $vg1
+
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)
+vgcreate $SHARED "$vg" "${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"
+vgcfgbackup -f "backup.$$" $vg
+sed 's/flags = \[\"MISSING\"\]/flags = \[\]/' "backup.$$" > "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
+
+# Try to recover nonexisting vgname
+not vgcfgrestore -f "backup.$$1" ${vg}_nonexistent
+vgcfgrestore -f "backup.$$1" $vg
+vgchange -an $vg
+vgremove -f $vg
+
diff --git a/test/shell/vgchange-many.sh b/test/shell/vgchange-many.sh
new file mode 100644
index 0000000..389877a
--- /dev/null
+++ b/test/shell/vgchange-many.sh
@@ -0,0 +1,57 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2013 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+# Check perfomance of activation and deactivation
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+# Number of LVs to create
+TEST_DEVS=1000
+# On low-memory boxes let's not stress too much
+test "$(aux total_mem)" -gt 524288 || TEST_DEVS=256
+
+aux prepare_pvs 1 400
+get_devs
+
+vgcreate $SHARED -s 128K "$vg" "${DEVICES[@]}"
+
+vgcfgbackup -f data $vg
+
+# Generate a lot of devices (size of 1 extent)
+awk -v TEST_DEVS=$TEST_DEVS '/^\t\}/ {
+ printf("\t}\n\tlogical_volumes {\n");
+ cnt=0;
+ for (i = 0; i < TEST_DEVS; i++) {
+ printf("\t\tlvol%06d {\n", i);
+ printf("\t\t\tid = \"%06d-1111-2222-3333-2222-1111-%06d\"\n", i, i);
+ print "\t\t\tstatus = [\"READ\", \"WRITE\", \"VISIBLE\"]";
+ print "\t\t\tsegment_count = 1";
+ print "\t\t\tsegment1 {";
+ print "\t\t\t\tstart_extent = 0";
+ print "\t\t\t\textent_count = 1";
+ print "\t\t\t\ttype = \"striped\"";
+ print "\t\t\t\tstripe_count = 1";
+ print "\t\t\t\tstripes = [";
+ print "\t\t\t\t\t\"pv0\", " cnt++;
+ printf("\t\t\t\t]\n\t\t\t}\n\t\t}\n");
+ }
+ }
+ {print}
+' data >data_new
+
+vgcfgrestore -f data_new $vg
+
+# Activate and deactivate all of them
+vgchange -ay $vg
+vgchange -an $vg
diff --git a/test/shell/vgchange-maxlv.sh b/test/shell/vgchange-maxlv.sh
index 413fef9..626128e 100644
--- a/test/shell/vgchange-maxlv.sh
+++ b/test/shell/vgchange-maxlv.sh
@@ -1,4 +1,5 @@
-#!/bin/sh
+#!/usr/bin/env bash
+
# Copyright (C) 2010 Red Hat, Inc. All rights reserved.
#
# This copyrighted material is made available to anyone wishing to use,
@@ -7,24 +8,30 @@
#
# 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
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+
+SKIP_WITH_LVMPOLLD=1
-. lib/test
+. lib/inittest
aux prepare_dmeventd
aux prepare_pvs 3
+get_devs
-vgcreate -c n -l 2 $vg $(cat DEVICES)
-lvcreate -n one -l 1 $vg
+vgcreate $SHARED -l 2 "$vg" "${DEVICES[@]}"
+lvcreate -aey -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
+vgcreate $SHARED -l 3 "$vg" "${DEVICES[@]}"
+lvcreate -aey -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
+
+vgremove -ff $vg
diff --git a/test/shell/vgchange-partial.sh b/test/shell/vgchange-partial.sh
index 5b21a40..854b8aa 100644
--- a/test/shell/vgchange-partial.sh
+++ b/test/shell/vgchange-partial.sh
@@ -1,4 +1,5 @@
-#!/bin/bash
+#!/usr/bin/env bash
+
# Copyright (C) 2012 Red Hat, Inc. All rights reserved.
#
# This copyrighted material is made available to anyone wishing to use,
@@ -7,9 +8,12 @@
#
# 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
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+
+SKIP_WITH_LVMPOLLD=1
-. lib/test
+. lib/inittest
aux prepare_vg 2
@@ -37,9 +41,6 @@ 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
@@ -50,3 +51,5 @@ not vgchange --vgmetadatacopies 2 $vg
# Ensure that allowed args don't cause disallowed args to get through
#
not vgchange -p 10 --addtag foo $vg
+
+vgremove -ff $vg
diff --git a/test/shell/vgchange-pvs-online.sh b/test/shell/vgchange-pvs-online.sh
new file mode 100644
index 0000000..165e96d
--- /dev/null
+++ b/test/shell/vgchange-pvs-online.sh
@@ -0,0 +1,232 @@
+SKIP_WITH_LVMPOLLD=1
+SKIP_WITH_LVMLOCKD=1
+
+RUNDIR="/run"
+test -d "$RUNDIR" || RUNDIR="/var/run"
+PVS_ONLINE_DIR="$RUNDIR/lvm/pvs_online"
+VGS_ONLINE_DIR="$RUNDIR/lvm/vgs_online"
+PVS_LOOKUP_DIR="$RUNDIR/lvm/pvs_lookup"
+
+_clear_online_files() {
+ # wait till udev is finished
+ aux udev_wait
+ rm -f "$PVS_ONLINE_DIR"/*
+ rm -f "$VGS_ONLINE_DIR"/*
+ rm -f "$PVS_LOOKUP_DIR"/*
+}
+
+. lib/inittest
+
+aux prepare_devs 4
+
+# skip rhel5 which doesn't seem to have /dev/mapper/LVMTESTpv1
+aux driver_at_least 4 15 || skip
+
+test "$DM_DEV_DIR" = "/dev" || skip "Only works with /dev access -> make check LVM_TEST_DEVDIR=/dev"
+
+DFDIR="$LVM_SYSTEM_DIR/devices"
+mkdir -p "$DFDIR" || true
+DF="$DFDIR/system.devices"
+
+# Because mapping devno to devname gets dm name from sysfs
+aux lvmconf 'devices/scan = "/dev"'
+bd1="$DM_DEV_DIR/mapper/$(basename $dev1)"
+bd2="$DM_DEV_DIR/mapper/$(basename $dev2)"
+bd3="$DM_DEV_DIR/mapper/$(basename $dev3)"
+bd4="$DM_DEV_DIR/mapper/$(basename $dev4)"
+aux extend_filter "a|$bd1|" "a|$bd2|" "a|$bd3|" "a|$bd4|"
+
+# Changing names will confuse df based on devname
+if lvmdevices; then
+rm -f "$DF"
+touch "$DF"
+lvmdevices --adddev "$bd1"
+lvmdevices --adddev "$bd2"
+lvmdevices --adddev "$bd3"
+lvmdevices --adddev "$bd4"
+cat "$DF"
+fi
+
+# Using $bd instead of $dev because validation of pvid file content
+# checks that the devname begins with /dev.
+
+# FIXME: test vgchange aay with pvs_online that includes devname in pvid file
+# and the devices file entry uses devname with a stale name.
+
+vgcreate $vg1 "$bd1" "$bd2"
+vgcreate $vg2 "$bd3"
+pvcreate "$bd4"
+
+lvcreate -l1 -n $lv1 -an $vg1
+lvcreate -l1 -n $lv2 -an $vg1
+lvcreate -l1 -n $lv1 -an $vg2
+
+# Expected use, with vg name and all online files exist for vgchange.
+
+_clear_online_files
+
+pvscan --cache "$bd1"
+pvscan --cache "$bd2"
+vgchange -aay --autoactivation event $vg1
+check lv_field $vg1/$lv1 lv_active "active"
+check lv_field $vg1/$lv2 lv_active "active"
+check lv_field $vg2/$lv1 lv_active ""
+
+pvscan --cache "$bd3"
+vgchange -aay --autoactivation event $vg2
+check lv_field $vg2/$lv1 lv_active "active"
+
+# Count io to check the pvs_online optimization
+# is working to limit scanning.
+
+if which strace; then
+vgchange -an
+_clear_online_files
+
+pvscan --cache "$bd1"
+pvscan --cache "$bd2"
+strace -e io_submit vgchange -aay --autoactivation event $vg1 2>&1|tee trace.out
+test "$(grep -c io_submit trace.out)" -eq 3
+rm trace.out
+
+strace -e io_submit pvscan --cache "$bd3" 2>&1|tee trace.out
+test "$(grep -c io_submit trace.out)" -eq 1
+rm trace.out
+
+strace -e io_submit vgchange -aay --autoactivation event $vg2 2>&1|tee trace.out
+test "$(grep -c io_submit trace.out)" -eq 2
+rm trace.out
+fi
+
+# non-standard usage: no VG name arg, vgchange will only used pvs_online files
+
+vgchange -an
+_clear_online_files
+
+vgchange -aay --autoactivation event
+check lv_field $vg1/$lv1 lv_active ""
+check lv_field $vg1/$lv2 lv_active ""
+check lv_field $vg2/$lv1 lv_active ""
+
+pvscan --cache "$bd1"
+vgchange -aay --autoactivation event
+check lv_field $vg1/$lv1 lv_active ""
+check lv_field $vg1/$lv2 lv_active ""
+check lv_field $vg2/$lv1 lv_active ""
+
+pvscan --cache "$bd2"
+vgchange -aay --autoactivation event
+check lv_field $vg1/$lv1 lv_active "active"
+check lv_field $vg1/$lv2 lv_active "active"
+check lv_field $vg2/$lv1 lv_active ""
+
+pvscan --cache "$bd3"
+vgchange -aay --autoactivation event
+check lv_field $vg2/$lv1 lv_active "active"
+
+# non-standard usage: include VG name arg, but missing or incomplete pvs_online files
+
+vgchange -an
+_clear_online_files
+
+# all missing pvs_online, vgchange falls back to full label scan
+vgchange -aay --autoactivation event $vg1
+check lv_field $vg1/$lv1 lv_active "active"
+check lv_field $vg1/$lv2 lv_active "active"
+
+vgchange -an
+_clear_online_files
+
+# incomplete pvs_online, vgchange falls back to full label scan
+pvscan --cache "$bd1"
+vgchange -aay --autoactivation event $vg1
+check lv_field $vg1/$lv1 lv_active "active"
+check lv_field $vg1/$lv2 lv_active "active"
+
+vgchange -an
+_clear_online_files
+
+# incomplete pvs_online, pvs_online from different vg,
+# no pvs_online found for vg arg so vgchange falls back to full label scan
+
+pvscan --cache "$bd3"
+vgchange -aay --autoactivation event $vg1
+check lv_field $vg1/$lv1 lv_active "active"
+check lv_field $vg1/$lv2 lv_active "active"
+check lv_field $vg2/$lv1 lv_active ""
+
+vgchange -aay --autoactivation event $vg2
+check lv_field $vg2/$lv1 lv_active "active"
+
+vgchange -an
+_clear_online_files
+
+# same tests but using command options matching udev rule
+
+pvscan --cache --listvg --checkcomplete --vgonline --autoactivation event --udevoutput --journal=output "$bd1"
+pvscan --cache --listvg --checkcomplete --vgonline --autoactivation event --udevoutput --journal=output "$bd2"
+vgchange -aay --autoactivation event $vg1
+check lv_field $vg1/$lv1 lv_active "active"
+check lv_field $vg1/$lv2 lv_active "active"
+check lv_field $vg2/$lv1 lv_active ""
+
+pvscan --cache --listvg --checkcomplete --vgonline --autoactivation event --udevoutput --journal=output "$bd3"
+vgchange -aay --autoactivation event $vg2
+check lv_field $vg2/$lv1 lv_active "active"
+
+vgchange -an $vg1
+vgchange -an $vg2
+
+# with a full pvscan --cache
+
+_clear_online_files
+
+pvscan --cache
+check lv_field $vg1/$lv1 lv_active ""
+check lv_field $vg2/$lv1 lv_active ""
+vgchange -aay --autoactivation event $vg1
+vgchange -aay --autoactivation event $vg2
+check lv_field $vg1/$lv1 lv_active "active"
+check lv_field $vg2/$lv1 lv_active "active"
+
+vgchange -an $vg1
+vgchange -an $vg2
+
+# vgremove clears online files
+
+PVID1=$(pvs "$bd1" --noheading -o uuid | tr -d - | awk '{print $1}')
+PVID2=$(pvs "$bd2" --noheading -o uuid | tr -d - | awk '{print $1}')
+PVID3=$(pvs "$bd3" --noheading -o uuid | tr -d - | awk '{print $1}')
+
+_clear_online_files
+
+pvscan --cache --listvg --checkcomplete --vgonline --autoactivation event --udevoutput --journal=output "$bd1"
+pvscan --cache --listvg --checkcomplete --vgonline --autoactivation event --udevoutput --journal=output "$bd2"
+vgchange -aay --autoactivation event $vg1
+check lv_field $vg1/$lv1 lv_active "active"
+check lv_field $vg1/$lv2 lv_active "active"
+check lv_field $vg2/$lv1 lv_active ""
+
+pvscan --cache --listvg --checkcomplete --vgonline --autoactivation event --udevoutput --journal=output "$bd3"
+vgchange -aay --autoactivation event $vg2
+check lv_field $vg2/$lv1 lv_active "active"
+
+ls "$RUNDIR/lvm/pvs_online/$PVID1"
+ls "$RUNDIR/lvm/pvs_online/$PVID2"
+ls "$RUNDIR/lvm/pvs_online/$PVID3"
+ls "$RUNDIR/lvm/pvs_lookup/$vg1"
+ls "$RUNDIR/lvm/vgs_online/$vg1"
+ls "$RUNDIR/lvm/vgs_online/$vg2"
+
+vgremove -y $vg1
+
+not ls "$RUNDIR/lvm/pvs_online/$PVID1"
+not ls "$RUNDIR/lvm/pvs_online/$PVID2"
+not ls "$RUNDIR/lvm/pvs_lookup/$vg1"
+not ls "$RUNDIR/lvm/vgs_online/$vg1"
+
+vgremove -y $vg2
+
+not ls "$RUNDIR/lvm/pvs_online/$PVID3"
+not ls "$RUNDIR/lvm/vgs_online/$vg2"
+
diff --git a/test/shell/vgchange-sysinit.sh b/test/shell/vgchange-sysinit.sh
index d7a166c..5740add 100644
--- a/test/shell/vgchange-sysinit.sh
+++ b/test/shell/vgchange-sysinit.sh
@@ -1,4 +1,5 @@
-#!/bin/sh
+#!/usr/bin/env bash
+
# Copyright (C) 2011 Red Hat, Inc. All rights reserved.
#
# This copyrighted material is made available to anyone wishing to use,
@@ -7,18 +8,22 @@
#
# 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
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+SKIP_WITH_CLVMD=1
+SKIP_WITH_LVMPOLLD=1
-. lib/test
+. lib/inittest
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"
+mkdir -p $mount_dir
+aux lvmconf "global/locking_dir = \"$TESTDIR/$mount_dir\""
cleanup_mounted_and_teardown()
{
@@ -26,8 +31,8 @@ cleanup_mounted_and_teardown()
aux teardown
}
-vgcreate -c n $vg1 "$dev1"
-vgcreate -c n $vg2 "$dev2"
+vgcreate $SHARED $vg1 "$dev1"
+vgcreate $SHARED $vg2 "$dev2"
lvcreate -l 1 -n $lv2 $vg2
vgchange -an $vg2
@@ -49,3 +54,13 @@ vgchange --sysinit -an $vg2
test ! -b "$DM_DEV_DIR/$vg2/$lv2"
vgchange --ignorelockingfailure -ay $vg2
+
+if test -n "$LVM_TEST_LVMLOCKD"; then
+vgremove --config 'global{locking_type=0}' -ff $vg2
+else
+# TODO maybe also support --ignorelockingfailure ??
+vgremove --config 'global{locking_type=0}' -ff $vg2
+fi
+
+umount "$mount_dir" || true
+vgremove -ff $vg1
diff --git a/test/shell/vgchange-usage.sh b/test/shell/vgchange-usage.sh
index a7bd488..f6fc842 100644
--- a/test/shell/vgchange-usage.sh
+++ b/test/shell/vgchange-usage.sh
@@ -1,4 +1,5 @@
-#!/bin/sh
+#!/usr/bin/env bash
+
# Copyright (C) 2008 Red Hat, Inc. All rights reserved.
#
# This copyrighted material is made available to anyone wishing to use,
@@ -7,38 +8,90 @@
#
# 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
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
test_description='Exercise some vgchange diagnostics'
-. lib/test
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+aux prepare_pvs 4
-aux prepare_pvs 3
pvcreate --metadatacopies 0 "$dev1"
-vgcreate $vg $(cat DEVICES)
+vgcreate $SHARED -s 4M $vg "$dev1" "$dev2" "$dev3"
+
+# cannot change anything in exported vg
+vgexport $vg
+fail vgchange -ay $vg
+fail vgchange -p 8 $vg
+fail vgchange -x n $vg
+fail vgchange --addtag tag $vg
+fail vgchange --deltag tag $vg
+fail vgchange -s 4k $vg
+fail vgchange --uuid $vg
+fail vgchange --alloc anywhere $vg
+vgimport $vg
+
+# unsupported combinations of options...
+invalid vgchange --ignorelockingfailure --uuid $vg
+invalid vgchange --sysinit --alloc normal $vg
+invalid vgchange --sysinit --poll y $vg
+invalid vgchange -an --poll y $vg
+invalid vgchange -an --monitor y $vg
+invalid vgchange -ay --refresh $vg
vgdisplay $vg
# vgchange -p MaxPhysicalVolumes (bz202232)
-aux check vg_field $vg max_pv 0
+check vg_field $vg max_pv 0
vgchange -p 128 $vg
-aux check vg_field $vg max_pv 128
+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
+check vg_field $vg max_pv 128
+
+# try some numbers around MAX limit (uint32)
+vgchange -p 4294967295 $vg
+invalid vgchange -p 4294967296 $vg
+invalid vgchange -p 18446744073709551615 $vg
+invalid vgchange -p 18446744073709551616 $vg
+check vg_field $vg max_pv 4294967295
# vgchange -l MaxLogicalVolumes
-aux check vg_field $vg max_lv 0
+check vg_field $vg max_lv 0
+invalid vgchange -l -128 $vg
+vgchange -l 4294967295 $vg
+invalid vgchange -l 4294967296 $vg
+invalid vgchange -l 18446744073709551615 $vg
+invalid vgchange -l 18446744073709551616 $vg
+check vg_field $vg max_lv 4294967295
vgchange -l 128 $vg
-aux check vg_field $vg max_lv 128
+check vg_field $vg max_lv 128
+# vgchange -s
lvcreate -l4 -n $lv1 $vg
lvcreate -l4 -n $lv2 $vg
+SIZELV2=$(get lv_field $vg/$lv2 size)
+check lv_field $vg/$lv2 seg_size_pe "4"
+vgchange -s 4K $vg
+check vg_field $vg vg_extent_size "4.00k"
+check lv_field $vg/$lv2 size "$SIZELV2"
+check lv_field $vg/$lv2 seg_size_pe "4096"
+
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
+check vg_field $vg max_lv 128
+# check non-resizebility
+fail vgchange -x y $vg
+check vg_attr_bit resizeable $vg "z"
+vgchange -x n $vg
+check vg_attr_bit resizeable $vg "-"
+fail vgchange -x n $vg
+fail vgextend $vg "$dev4"
+vgremove -ff $vg
diff --git a/test/shell/vgck.sh b/test/shell/vgck.sh
new file mode 100644
index 0000000..b6c2cba
--- /dev/null
+++ b/test/shell/vgck.sh
@@ -0,0 +1,34 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2013 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+aux prepare_vg 3
+lvcreate -n blabla -L 1 $vg
+
+dd if=/dev/urandom bs=512 seek=2 count=32 of="$dev2"
+
+# TODO: aux lvmconf "global/locking_type = 4"
+
+vgscan 2>&1 | tee vgscan.out || true
+
+grep "checksum" vgscan.out
+
+dd if=/dev/urandom bs=512 seek=2 count=32 of="$dev2"
+
+vgck $vg 2>&1 | tee vgck.out || true
+grep "checksum" vgck.out
+
+vgremove -ff $vg
diff --git a/test/shell/vgcreate-many-pvs.sh b/test/shell/vgcreate-many-pvs.sh
new file mode 100644
index 0000000..c68afeb
--- /dev/null
+++ b/test/shell/vgcreate-many-pvs.sh
@@ -0,0 +1,64 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2015 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+#
+# Test to exercise larger number of PVs in a VG
+# Related to https://bugzilla.redhat.com/show_bug.cgi?id=736027
+#
+# Original measured times of the whole test case before
+# and with the acceleration patch from my bare metal hw
+# (Lenovo T61, 2.2GHz, 4G RAM, rawhide 2015-03-06 with ndebug kernel):
+#
+# export LVM_TEST_PVS=300
+#
+# make check_local ~52sec (U:29s, S:13s)
+#
+# With patch from 2015-03-06:
+#
+# make check_local ~30sec (U:10s, S:12s)
+#
+
+# TODO: extend test suite to monitor performance and report regressions...
+
+# Use just 100 to get 'decent' speed on slow boxes
+LVM_TEST_PVS=${LVM_TEST_PVS:-100}
+
+#aux prepare_devs $LVM_TEST_PVS 8
+#vgcreate $SHARED $vg $(< DEVICES)
+
+# prepare_vg is now directly using steps above
+aux prepare_vg $LVM_TEST_PVS
+
+# Check we have decent speed with typical commands
+vgs
+
+lvs
+
+pvs
+
+lvcreate -l1 -n $lv1 $vg
+
+lvremove -f $vg/$lv1
+
+vgremove -ff $vg
+
+#
+# TODO Turn this into another test case:
+#
+#for i in $(seq 1 $LVM_TEST_PVS); do
+# vgcreate $SHARED ${vg}$i "$DM_DEV_DIR/mapper/${PREFIX}pv$i"
+#done
diff --git a/test/shell/vgcreate-usage.sh b/test/shell/vgcreate-usage.sh
index db80f0f..1959313 100644
--- a/test/shell/vgcreate-usage.sh
+++ b/test/shell/vgcreate-usage.sh
@@ -1,4 +1,5 @@
-#!/bin/sh
+#!/usr/bin/env bash
+
# Copyright (C) 2008-2012 Red Hat, Inc. All rights reserved.
#
# This copyrighted material is made available to anyone wishing to use,
@@ -7,11 +8,13 @@
#
# 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
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
test_description='Exercise some vgcreate diagnostics'
-. lib/test
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
aux prepare_devs 3
pvcreate "$dev1" "$dev2"
@@ -19,89 +22,90 @@ pvcreate --metadatacopies 0 "$dev3"
vg=${PREFIX}vg
-#COMM 'vgcreate accepts 8.00m physicalextentsize for VG'
-vgcreate -c n $vg --physicalextentsize 8.00m "$dev1" "$dev2"
+#COMM 'vgcreate $SHARED accepts 8.00m physicalextentsize for VG'
+vgcreate $SHARED $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"
+#COMM 'vgcreate $SHARED accepts smaller (128) maxlogicalvolumes for VG'
+vgcreate $SHARED $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"
+#COMM 'vgcreate $SHARED accepts smaller (128) maxphysicalvolumes for VG'
+vgcreate $SHARED $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
+#COMM 'vgcreate $SHARED rejects a zero physical extent size'
+not vgcreate $SHARED --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
+#COMM 'vgcreate $SHARED rejects "inherit" allocation policy'
+not vgcreate $SHARED --alloc inherit $vg "$dev1" "$dev2" 2>err
grep "Volume Group allocation policy cannot inherit from anything" err
-#COMM 'vgcreate rejects vgname "."'
+#COMM 'vgcreate $SHARED rejects vgname "."'
vginvalid=.;
-not vgcreate -c n $vginvalid "$dev1" "$dev2" 2>err
+not vgcreate $SHARED $vginvalid "$dev1" "$dev2" 2>err
grep "New volume group name \"$vginvalid\" is invalid" err
-#COMM 'vgcreate rejects vgname greater than 128 characters'
+#COMM 'vgcreate $SHARED rejects vgname greater than 128 characters'
vginvalid=thisnameisridiculouslylongtotestvalidationcodecheckingmaximumsizethisiswhathappenswhenprogrammersgetboredandorarenotcreativedonttrythisathome
-not vgcreate -c n $vginvalid "$dev1" "$dev2" 2>err
+not vgcreate $SHARED $vginvalid "$dev1" "$dev2" 2>err
grep "New volume group name \"$vginvalid\" is invalid" err
-#COMM 'vgcreate rejects already existing vgname "/tmp/$vg"'
+#COMM 'vgcreate $SHARED rejects already existing vgname "/tmp/$vg"'
#touch /tmp/$vg
-#not vgcreate $vg "$dev1" "$dev2" 2>err
+#not vgcreate $SHARED $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"
+#COMM "vgcreate $SHARED rejects repeated invocation (run 2 times) (bz178216)"
+vgcreate $SHARED $vg "$dev1" "$dev2"
+not vgcreate $SHARED $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"
+#COMM "vgcreate $SHARED fails when the only pv has --metadatacopies 0"
+not vgcreate $SHARED $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
+not vgcreate $SHARED --physicalextentsize 0k $vg "$dev1" "$dev2"
+vgcreate $SHARED --physicalextentsize 4k $vg "$dev1" "$dev2"
+check vg_field $vg vg_extent_size 4.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!
+not vgcreate $SHARED --physicalextentsize 7K $vg "$dev1" "$dev2"
+not vgcreate $SHARED --physicalextentsize 1024t $vg "$dev1" "$dev2"
+#not vgcreate $SHARED --physicalextentsize 1T $vg "$dev1" "$dev2"
+# FIXME: vgcreate $SHARED allows physicalextentsize larger than pv size!
# Test default max_lv, max_pv, extent_size, alloc_policy, clustered
-vgcreate -c n $vg "$dev1" "$dev2"
+vgcreate $SHARED $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-"
+ATTRS="wz--n-"
+test -e LOCAL_CLVMD && ATTRS="wz--nc"
+if test -n "$LVM_TEST_LVMLOCKD"; then
+ATTRS="wz--ns"
+fi
+check vg_field $vg vg_attr $ATTRS
vgremove -ff $vg
-# Implicit pvcreate tests, test pvcreate options on vgcreate
+# Implicit pvcreate tests, test pvcreate options on vgcreate $SHARED
# --force, --yes, --metadata{size|copies|type}, --zero
# --dataalignment[offset]
pvremove "$dev1" "$dev2"
-vgcreate -c n --force --yes --zero y $vg "$dev1" "$dev2"
+vgcreate $SHARED --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"
+# vgcreate $SHARED (lvm2) succeeds writing LVM label at sector $i
+ vgcreate $SHARED --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"
@@ -110,14 +114,14 @@ done
# pvmetadatacopies
for i in 1 2
do
- vgcreate -c n --pvmetadatacopies $i $vg "$dev1"
+ vgcreate $SHARED --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"
+not vgcreate $SHARED --pvmetadatacopies 0 $vg "$dev1"
pvcreate --metadatacopies 1 "$dev2"
-vgcreate -c n --pvmetadatacopies 0 $vg "$dev1" "$dev2"
+vgcreate $SHARED --pvmetadatacopies 0 $vg "$dev1" "$dev2"
check pv_field "$dev1" pv_mda_count 0
check pv_field "$dev2" pv_mda_count 1
vgremove -f $vg
@@ -125,7 +129,7 @@ pvremove -f "$dev1"
# metadatasize, dataalignment, dataalignmentoffset
#COMM 'pvcreate sets data offset next to mda area'
-vgcreate -c n --metadatasize 100k --dataalignment 100k $vg "$dev1"
+vgcreate $SHARED --metadatasize 100k --dataalignment 100k $vg "$dev1"
check pv_field "$dev1" pe_start 200.00k
vgremove -f $vg
pvremove -f "$dev1"
@@ -133,31 +137,36 @@ 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"
+vgcreate $SHARED --metadatasize 128k --dataalignmentoffset 7s $vg "$dev1"
check pv_field "$dev1" pe_start ${pv_align}B --units b
vgremove -f $vg
pvremove -f "$dev1"
+if test -n "$LVM_TEST_LVM1" ; then
+mdatypes='1 2'
+else
+mdatypes='2'
+fi
+
# metadatatype
-for i in 1 2
+for i in $mdatypes
do
- vgcreate -c n -M $i $vg "$dev1"
+ vgcreate $SHARED -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"
+# vgcreate $SHARED fails if pv belongs to existing vg
+vgcreate $SHARED $vg1 "$dev1" "$dev2"
+not vgcreate $SHARED $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"
+vgcreate $SHARED $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
index fae68e4..afbe5ba 100644
--- a/test/shell/vgextend-restoremissing.sh
+++ b/test/shell/vgextend-restoremissing.sh
@@ -1,4 +1,5 @@
-#!/bin/sh
+#!/usr/bin/env bash
+
# Copyright (C) 2010 Red Hat, Inc. All rights reserved.
#
# This copyrighted material is made available to anyone wishing to use,
@@ -7,24 +8,51 @@
#
# 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
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
-. lib/test
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
aux prepare_vg 3
-lvcreate -m 1 -l 1 -n mirror $vg
-lvchange -a n $vg/mirror
+lvcreate -an -Zn --type mirror -m 1 -l 1 -n mirror $vg
lvcreate -l 1 -n lv1 $vg "$dev1"
+# vgextend require vgname
+invalid vgextend
+# --metadatacopies => use --pvmetadatacopies
+invalid vgextend --metadatacopies 3 $vg "$dev1" 2>&1 | tee out
+#grep -- "use --pvmetadatacopies" out
+grep -E -- "unrecognized option.*--metadatacopies" out
+
+# VG name should exist
+fail vgextend --restoremissing $vg-invalid "$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
+# try restore the still existing device
+fail vgextend --restore $vg "$dev1"
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
+not lvcreate -aey --type mirror -m 1 -l 1 -n mirror $vg # write operations fail
+# try restore the non-missing device
+fail vgextend --restore $vg "$dev2"
+# try restore the non-existing device
+fail vgextend --restore $vg "$dev2-invalid"
+# restore the missing device
+vgextend --restore $vg "$dev1"
+
+vgreduce $vg "$dev3"
+vgchange --metadatacopies 1 $vg
+# 'n' failing to change volume group
+fail vgextend --metadataignore y --pvmetadatacopies 2 $vg "$dev3"
+vgextend --yes --metadataignore y --pvmetadatacopies 2 $vg "$dev3"
vgck $vg
-lvcreate -m 1 -l 1 -n mirror $vg
+lvcreate -an -Zn --type mirror -m 1 -l 1 -n mirror $vg
+
+vgremove -ff $vg
diff --git a/test/shell/vgextend-usage.sh b/test/shell/vgextend-usage.sh
index 0e347c3..3d5adfd 100644
--- a/test/shell/vgextend-usage.sh
+++ b/test/shell/vgextend-usage.sh
@@ -1,4 +1,5 @@
-#!/bin/sh
+#!/usr/bin/env bash
+
# Copyright (C) 2008 Red Hat, Inc. All rights reserved.
#
# This copyrighted material is made available to anyone wishing to use,
@@ -7,45 +8,54 @@
#
# 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
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
#
# Exercise various vgextend commands
#
-. lib/test
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
aux prepare_devs 5
-for mdatype in 1 2
+if test -n "$LVM_TEST_LVM1" ; then
+mdatypes='1 2'
+else
+mdatypes='2'
+fi
+
+for mdatype in $mdatypes
do
# Explicit pvcreate
pvcreate -M$mdatype "$dev1" "$dev2" "$dev3" "$dev4" "$dev5"
-vgcreate -M$mdatype $vg1 "$dev1" "$dev2"
+vgcreate $SHARED -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"
+vgcreate $SHARED -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
+# Implicit pvcreate tests, test pvcreate options on vgcreate $SHARED
# --force, --yes, --metadata{size|copies|type}, --zero
# --dataalignment[offset]
-vgcreate $vg "$dev2"
+vgcreate $SHARED $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
+# vgcreate $SHARED (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"
@@ -77,15 +87,15 @@ vgremove -f $vg
pvremove -f "$dev1"
# vgextend fails if pv belongs to existing vg
-vgcreate $vg1 "$dev1" "$dev3"
-vgcreate $vg2 "$dev2"
+vgcreate $SHARED $vg1 "$dev1" "$dev3"
+vgcreate $SHARED $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"
+vgcreate $SHARED $vg1 "$dev1" "$dev2"
vgchange --resizeable n $vg1
not vgextend $vg1 "$dev3"
vgremove -f $vg1
@@ -93,7 +103,7 @@ pvremove -f "$dev1" "$dev2"
# all PVs exist in the VG after extended
pvcreate "$dev1"
-vgcreate $vg1 "$dev2"
+vgcreate $SHARED $vg1 "$dev2"
vgextend $vg1 "$dev1" "$dev3"
check pv_field "$dev1" vg_name $vg1
check pv_field "$dev2" vg_name $vg1
@@ -105,7 +115,7 @@ 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"
+ vgcreate $SHARED $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
@@ -117,11 +127,11 @@ for ignore in y n; do
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))
+ 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))
+ check vg_field $vg vg_mda_used_count $(( mdacp * 2 + 1 ))
fi
check vg_field $vg vg_mda_copies unmanaged
vgremove $vg
diff --git a/test/shell/vgimportclone.sh b/test/shell/vgimportclone.sh
index 9b1c121..13924c3 100644
--- a/test/shell/vgimportclone.sh
+++ b/test/shell/vgimportclone.sh
@@ -1,5 +1,6 @@
-#!/bin/sh
-# Copyright (C) 2010-2011 Red Hat, Inc. All rights reserved.
+#!/usr/bin/env bash
+
+# Copyright (C) 2010-2014 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
@@ -7,33 +8,140 @@
#
# 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
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+SKIP_WITH_LVMPOLLD=1
-. lib/test
+. lib/inittest
-aux prepare_devs 2
+aux prepare_devs 3
-vgcreate -c n --metadatasize 128k $vg1 "$dev1"
+vgcreate $SHARED --metadatasize 128k $vg1 "$dev1"
lvcreate -l100%FREE -n $lv1 $vg1
+# Test plain vgexport vgimport tools
+
+# Argument is needed
+invalid vgexport
+invalid vgimport
+# Cannot combine -a and VG name
+invalid vgexport -a $vg
+invalid vgimport -a $vg1
+# Cannot export unknonw VG
+fail vgexport ${vg1}-non
+fail vgimport ${vg1}-non
+# Cannot export VG with active volumes
+fail vgexport $vg1
+
+vgchange -an $vg1
+vgexport $vg1
+# Already exported
+fail vgexport $vg1
+
+vgimport $vg1
+# Already imported
+fail vgimport $vg1
+vgchange -ay $vg1
+
+# Since the devices file is using devnames as ids,
+# it will not automatically know that dev2 is a
+# duplicate after the dd, so we need to remove dev2
+# from df, then add it again after the dd.
+if lvmdevices; then
+ lvmdevices --deldev "$dev2"
+fi
+
# Clone the LUN
dd if="$dev1" of="$dev2" bs=256K count=1
-aux notify_lvmetad "$dev2"
+
+# Requires -y to confirm prompt about adding
+# a duplicate pvid.
+if lvmdevices; then
+ lvmdevices -y --adddev "$dev2"
+fi
# Verify pvs works on each device to give us vgname
+aux hide_dev "$dev2"
check pv_field "$dev1" vg_name $vg1
+aux unhide_dev "$dev2"
+
+aux hide_dev "$dev1"
check pv_field "$dev2" vg_name $vg1
+aux unhide_dev "$dev1"
+
+lvmdevices || true
+pvs -a -o+uuid
# 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"
+lvmdevices || true
+pvs -a -o+uuid
+vgs
# Verify we can activate / deactivate the LV from both VGs
lvchange -ay $vg1/$lv1 $vg2/$lv1
vgchange -an $vg1 $vg2
+
+vgremove -ff $vg1 $vg2
+
+pvremove "$dev1"
+pvremove "$dev2"
+
+# Test vgimportclone with incomplete list of devs, and with nomda PV.
+vgcreate $SHARED --vgmetadatacopies 2 $vg1 "$dev1" "$dev2" "$dev3"
+lvcreate -l1 -an $vg1
+not vgimportclone -n newvgname "$dev1"
+not vgimportclone -n newvgname "$dev2"
+not vgimportclone -n newvgname "$dev3"
+not vgimportclone -n newvgname "$dev1" "$dev2"
+not vgimportclone -n newvgname "$dev1" "$dev3"
+not vgimportclone -n newvgname "$dev2" "$dev3"
+vgimportclone -n ${vg1}new "$dev1" "$dev2" "$dev3"
+lvs ${vg1}new
+vgremove -y ${vg1}new
+pvremove "$dev1"
+pvremove "$dev2"
+pvremove "$dev3"
+
+# Test importing a non-duplicate pv using the existing vg name
+vgcreate $vg1 "$dev1"
+vgimportclone -n $vg1 "$dev1"
+vgs ${vg1}1
+not vgs $vg1
+vgremove ${vg1}1
+
+# Test importing a non-duplicate pv using the existing vg name
+# Another existing VG is using the initial generated vgname with
+# the "1" suffix, so "2" is used.
+vgcreate $vg1 "$dev1"
+vgcreate ${vg1}1 "$dev2"
+vgimportclone -n $vg1 "$dev1"
+vgs ${vg1}1
+vgs ${vg1}2
+vgremove ${vg1}1
+vgremove ${vg1}2
+pvremove "$dev1"
+pvremove "$dev2"
+
+# Verify that if we provide the -n|--basevgname,
+# the number suffix is not added unnecessarily.
+vgcreate $SHARED --metadatasize 128k A${vg1}B "$dev1"
+
+# vg1B is not the same as Avg1B - we don't need number suffix
+dd if="$dev1" of="$dev2" bs=256K count=1
+vgimportclone -n ${vg1}B "$dev2"
+check pv_field "$dev2" vg_name ${vg1}B
+
+# Avg1 is not the same as Avg1B - we don't need number suffix
+dd if="$dev1" of="$dev2" bs=256K count=1
+vgimportclone -n A${vg1} "$dev2"
+check pv_field "$dev2" vg_name A${vg1}
+
+# Avg1B is the same as Avg1B - we need to add the number suffix
+dd if="$dev1" of="$dev2" bs=256K count=1
+vgimportclone -n A${vg1}B "$dev2"
+aux vgs
+check pv_field "$dev2" vg_name A${vg1}B1
+
+vgremove -ff A${vg1}B A${vg1}B1
diff --git a/test/shell/vgimportdevices.sh b/test/shell/vgimportdevices.sh
new file mode 100644
index 0000000..384ea44
--- /dev/null
+++ b/test/shell/vgimportdevices.sh
@@ -0,0 +1,309 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2020 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+test_description='vgimportdevices'
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+aux prepare_devs 5
+
+DFDIR="$LVM_SYSTEM_DIR/devices"
+mkdir "$DFDIR" || true
+DF="$DFDIR/system.devices"
+
+aux lvmconf 'devices/use_devicesfile = 1'
+
+not ls "$DF"
+pvcreate "$dev1"
+ls "$DF"
+grep "$dev1" "$DF"
+rm -f "$DF"
+dd if=/dev/zero of="$dev1" bs=1M count=1
+
+#
+# vgimportdevices -a with no prev df
+#
+
+# no devs found
+not vgimportdevices -a
+not ls "$DF"
+
+# one orphan pv, no vgs
+pvcreate "$dev1"
+rm -f "$DF"
+not vgimportdevices -a
+not ls "$DF"
+
+# one complete vg
+vgcreate $vg1 "$dev1"
+rm -f "$DF"
+vgimportdevices -a
+ls "$DF"
+grep "$dev1" "$DF"
+
+# reset
+dd if=/dev/zero of="$dev1" bs=1M count=1
+rm -f "$DF"
+
+# two complete vgs
+vgcreate $vg1 "$dev1"
+vgcreate $vg2 "$dev2"
+rm -f "$DF"
+vgimportdevices -a
+ls "$DF"
+grep "$dev1" "$DF"
+grep "$dev2" "$DF"
+
+# reset
+dd if=/dev/zero of="$dev1" bs=1M count=1
+dd if=/dev/zero of="$dev2" bs=1M count=1
+rm -f "$DF"
+
+# one incomplete vg
+vgcreate $vg1 "$dev1" "$dev2"
+lvcreate -l1 -an $vg1
+rm -f "$DF"
+dd if=/dev/zero of="$dev1" bs=1M count=1
+not vgimportdevices -a
+not ls "$DF"
+vgs $vg1
+pvs "$dev2"
+
+# reset
+dd if=/dev/zero of="$dev1" bs=1M count=1
+dd if=/dev/zero of="$dev2" bs=1M count=1
+rm -f "$DF"
+
+# three complete, one incomplete vg
+vgcreate $vg1 "$dev1"
+vgcreate $vg2 "$dev2"
+vgcreate $vg3 "$dev3"
+vgcreate $vg4 "$dev4" "$dev5"
+rm -f "$DF"
+dd if=/dev/zero of="$dev5" bs=1M count=1
+vgimportdevices -a
+ls "$DF"
+grep "$dev1" "$DF"
+grep "$dev2" "$DF"
+grep "$dev3" "$DF"
+not grep "$dev4" "$DF"
+not grep "$dev5" "$DF"
+
+# reset
+dd if=/dev/zero of="$dev1" bs=1M count=1
+dd if=/dev/zero of="$dev2" bs=1M count=1
+dd if=/dev/zero of="$dev3" bs=1M count=1
+dd if=/dev/zero of="$dev4" bs=1M count=1
+rm -f "$DF"
+
+
+#
+# vgimportdevices -a with existing df
+#
+
+# no devs found
+vgcreate $vg1 "$dev1"
+grep "$dev1" "$DF"
+dd if=/dev/zero of="$dev1" bs=1M count=1
+not vgimportdevices -a
+ls "$DF"
+
+# one complete vg
+vgcreate $vg1 "$dev1"
+vgimportdevices -a
+grep "$dev1" "$DF"
+vgcreate --devicesfile "" $vg2 "$dev2"
+not grep "$dev2" "$DF"
+vgimportdevices -a
+grep "$dev1" "$DF"
+grep "$dev2" "$DF"
+
+# reset
+dd if=/dev/zero of="$dev1" bs=1M count=1
+dd if=/dev/zero of="$dev2" bs=1M count=1
+rm -f "$DF"
+
+# two complete vgs
+vgcreate --devicesfile "" $vg1 "$dev1"
+vgcreate --devicesfile "" $vg2 "$dev2"
+rm -f "$DF"
+vgimportdevices -a
+ls "$DF"
+grep "$dev1" "$DF"
+grep "$dev2" "$DF"
+
+# reset
+dd if=/dev/zero of="$dev1" bs=1M count=1
+dd if=/dev/zero of="$dev2" bs=1M count=1
+rm -f "$DF"
+
+# one incomplete vg
+vgcreate $vg1 "$dev1"
+vgimportdevices -a
+grep "$dev1" "$DF"
+dd if=/dev/zero of="$dev1" bs=1M count=1
+vgcreate --devicesfile "" $vg2 "$dev2" "$dev3"
+not grep "$dev2" "$DF"
+not grep "$dev3" "$DF"
+dd if=/dev/zero of="$dev2" bs=1M count=1
+not vgimportdevices -a
+ls "$DF"
+
+# reset
+dd if=/dev/zero of="$dev1" bs=1M count=1
+dd if=/dev/zero of="$dev2" bs=1M count=1
+dd if=/dev/zero of="$dev3" bs=1M count=1
+rm -f "$DF"
+
+# import the same vg again
+vgcreate --devicesfile "" $vg1 "$dev1"
+not ls "$DF"
+vgimportdevices -a
+ls "$DF"
+grep "$dev1" "$DF"
+vgimportdevices -a
+ls "$DF"
+grep "$dev1" "$DF"
+
+# reset
+dd if=/dev/zero of="$dev1" bs=1M count=1
+rm -f "$DF"
+
+# import a series of vgs
+vgcreate --devicesfile "" $vg1 "$dev1"
+vgimportdevices -a
+grep "$dev1" "$DF"
+vgcreate --devicesfile "" $vg2 "$dev2"
+vgimportdevices -a
+grep "$dev1" "$DF"
+grep "$dev2" "$DF"
+vgcreate --devicesfile "" $vg3 "$dev3"
+vgimportdevices -a
+grep "$dev1" "$DF"
+grep "$dev2" "$DF"
+grep "$dev3" "$DF"
+
+# reset
+dd if=/dev/zero of="$dev1" bs=1M count=1
+dd if=/dev/zero of="$dev2" bs=1M count=1
+dd if=/dev/zero of="$dev3" bs=1M count=1
+rm -f "$DF"
+
+#
+# vgimportdevices vg with no prev df
+#
+
+# no devs found
+not vgimportdevices $vg1
+not ls "$DF"
+
+# one complete vg
+vgcreate $vg1 "$dev1"
+rm -f "$DF"
+vgimportdevices $vg1
+ls "$DF"
+grep "$dev1" "$DF"
+
+# reset
+dd if=/dev/zero of="$dev1" bs=1M count=1
+rm -f "$DF"
+
+# two complete vgs
+vgcreate $vg1 "$dev1"
+vgcreate $vg2 "$dev2"
+rm -f "$DF"
+vgimportdevices $vg1
+ls "$DF"
+grep "$dev1" "$DF"
+vgimportdevices $vg2
+ls "$DF"
+grep "$dev2" "$DF"
+
+# reset
+dd if=/dev/zero of="$dev1" bs=1M count=1
+dd if=/dev/zero of="$dev2" bs=1M count=1
+rm -f "$DF"
+
+# one incomplete vg
+vgcreate $vg1 "$dev1" "$dev2"
+lvcreate -l1 -an $vg1
+rm -f "$DF"
+dd if=/dev/zero of="$dev1" bs=1M count=1
+not vgimportdevices $vg1
+not ls "$DF"
+vgs $vg1
+pvs "$dev2"
+
+# reset
+dd if=/dev/zero of="$dev1" bs=1M count=1
+dd if=/dev/zero of="$dev2" bs=1M count=1
+rm -f "$DF"
+
+# three complete, one incomplete vg
+vgcreate $vg1 "$dev1"
+vgcreate $vg2 "$dev2"
+vgcreate $vg3 "$dev3"
+vgcreate $vg4 "$dev4" "$dev5"
+rm -f "$DF"
+dd if=/dev/zero of="$dev5" bs=1M count=1
+not vgimportdevices $vg4
+not ls "$DF"
+vgimportdevices $vg3
+ls "$DF"
+grep "$dev3" "$DF"
+not grep "$dev1" "$DF"
+not grep "$dev2" "$DF"
+not grep "$dev4" "$DF"
+not grep "$dev5" "$DF"
+
+# reset
+dd if=/dev/zero of="$dev1" bs=1M count=1
+dd if=/dev/zero of="$dev2" bs=1M count=1
+dd if=/dev/zero of="$dev3" bs=1M count=1
+dd if=/dev/zero of="$dev4" bs=1M count=1
+rm -f "$DF"
+
+#
+# vgimportdevices vg with existing df
+#
+
+# vg not found
+vgcreate $vg1 "$dev1"
+vgimportdevices -a
+grep "$dev1" "$DF"
+not vgimportdevices $vg2
+grep "$dev1" "$DF"
+
+# reset
+dd if=/dev/zero of="$dev1" bs=1M count=1
+rm -f "$DF"
+
+# vg incomplete
+vgcreate $vg1 "$dev1"
+vgimportdevices -a
+grep "$dev1" "$DF"
+vgcreate --devicesfile "" $vg2 "$dev2" "$dev3"
+dd if=/dev/zero of="$dev2" bs=1M count=1
+not vgimportdevices $vg2
+grep "$dev1" "$DF"
+not grep "$dev2" "$DF"
+not grep "$dev3" "$DF"
+
+# reset
+dd if=/dev/zero of="$dev1" bs=1M count=1
+dd if=/dev/zero of="$dev2" bs=1M count=1
+dd if=/dev/zero of="$dev3" bs=1M count=1
+dd if=/dev/zero of="$dev4" bs=1M count=1
+rm -f "$DF"
+
diff --git a/test/shell/vgmerge-operation.sh b/test/shell/vgmerge-operation.sh
index bdd5000..0bf517d 100644
--- a/test/shell/vgmerge-operation.sh
+++ b/test/shell/vgmerge-operation.sh
@@ -1,4 +1,5 @@
-#!/bin/sh
+#!/usr/bin/env bash
+
# Copyright (C) 2007-2012 Red Hat, Inc. All rights reserved.
#
# This copyrighted material is made available to anyone wishing to use,
@@ -7,17 +8,19 @@
#
# 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
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
test_description='Test vgmerge operation'
+SKIP_WITH_LVMLOCKD=1
+SKIP_WITH_LVMPOLLD=1
-. lib/test
+. lib/inittest
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"
+vgcreate $vg1 "$dev1" "$dev2"
+vgcreate $vg2 "$dev3" "$dev4"
lvcreate -l 4 -n $lv1 $vg1 "$dev1"
vgchange -an $vg1
check pvlv_counts $vg1 2 1 0
@@ -27,8 +30,8 @@ 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"
+vgcreate $vg1 "$dev1" "$dev2"
+vgcreate $vg2 "$dev3" "$dev4"
lvcreate -l 4 -n $lv1 $vg1
lvcreate -l 4 -n $lv2 $vg2
vgchange -an $vg1
@@ -40,9 +43,9 @@ 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
+vgcreate $vg1 "$dev1" "$dev2"
+vgcreate $vg2 "$dev3" "$dev4"
+lvcreate -aey -l 16 -n $lv1 $vg1
lvcreate -l 4 -s -n $lv2 $vg1/$lv1
vgchange -an $vg1
check pvlv_counts $vg1 2 2 1
@@ -53,9 +56,9 @@ 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
+vgcreate $vg1 "$dev1" "$dev2" "$dev3"
+vgcreate $vg2 "$dev4"
+lvcreate -aey -l 4 -n $lv1 --type mirror -m1 $vg1
vgchange -an $vg1
check pvlv_counts $vg1 3 1 0
check pvlv_counts $vg2 1 0 0
@@ -65,8 +68,8 @@ lvremove -f $vg2/$lv1
vgremove -f $vg2
# 'vgmerge rejects LV name collision'
-vgcreate -c n $vg1 "$dev1" "$dev2"
-vgcreate -c n $vg2 "$dev3" "$dev4"
+vgcreate $vg1 "$dev1" "$dev2"
+vgcreate $vg2 "$dev3" "$dev4"
lvcreate -l 4 -n $lv1 $vg1
lvcreate -l 4 -n $lv1 $vg2
vgchange -an $vg1
@@ -77,3 +80,45 @@ 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
+
+
+# 'vgmerge' handle pmspare for merged VG
+if aux have_thin 1 5 0; then
+
+# With disabled pmspare nothing is created
+vgcreate $vg1 "$dev1" "$dev2"
+vgcreate $vg2 "$dev3" "$dev4"
+lvcreate -T -L8M $vg1/pool1 --poolmetadatasize 8M --poolmetadataspare n
+lvcreate -T -L8M $vg2/pool2 --poolmetadatasize 4M --poolmetadataspare n
+vgchange -an $vg1 $vg2
+
+vgmerge --poolmetadataspare n $vg1 $vg2
+check lv_not_exists $vg/lvol0_pmspare
+vgremove -ff $vg1
+
+
+# With pmspare handling there are one created
+vgcreate $vg1 "$dev1" "$dev2"
+vgcreate $vg2 "$dev3" "$dev4"
+lvcreate -T -L8M $vg1/pool1 --poolmetadatasize 8M --poolmetadataspare n
+lvcreate -T -L8M $vg2/pool2 --poolmetadatasize 4M --poolmetadataspare n
+vgchange -an $vg1 $vg2
+
+vgmerge $vg1 $vg2
+check lv_field $vg1/lvol0_pmspare size "8.00m"
+vgremove -ff $vg1
+
+
+# When merged, bigger pmspare is preserved
+vgcreate $vg1 "$dev1" "$dev2"
+vgcreate $vg2 "$dev3" "$dev4"
+lvcreate -T -L8M $vg1/pool1 --poolmetadatasize 8M
+lvcreate -T -L8M $vg2/pool2 --poolmetadatasize 4M
+vgchange -an $vg1 $vg2
+
+vgmerge $vg1 $vg2
+
+check lv_field $vg1/lvol0_pmspare size "8.00m"
+vgremove -ff $vg1
+
+fi
diff --git a/test/shell/vgmerge-usage.sh b/test/shell/vgmerge-usage.sh
index 17779b5..fa9bb19 100644
--- a/test/shell/vgmerge-usage.sh
+++ b/test/shell/vgmerge-usage.sh
@@ -1,4 +1,5 @@
-#!/bin/sh
+#!/usr/bin/env bash
+
# Copyright (C) 2008-2011 Red Hat, Inc. All rights reserved.
#
# This copyrighted material is made available to anyone wishing to use,
@@ -7,11 +8,13 @@
#
# 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
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
# 'Test vgmerge command options for validity'
+SKIP_WITH_LVMLOCKD=1
+SKIP_WITH_LVMPOLLD=1
-. lib/test
+. lib/inittest
aux prepare_pvs 4
@@ -21,8 +24,8 @@ 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"
+vgcreate $vg2 "$dev1" "$dev2"
+vgcreate $vg1 "$dev3" "$dev4"
vgmerge $vg2 $vg1
vgremove $vg2
diff --git a/test/shell/vgreduce-removemissing-snapshot.sh b/test/shell/vgreduce-removemissing-snapshot.sh
index 488d8fe..a74ff34 100644
--- a/test/shell/vgreduce-removemissing-snapshot.sh
+++ b/test/shell/vgreduce-removemissing-snapshot.sh
@@ -1,4 +1,5 @@
-#!/bin/sh
+#!/usr/bin/env bash
+
# Copyright (C) 2011 Red Hat, Inc. All rights reserved.
#
# This copyrighted material is made available to anyone wishing to use,
@@ -7,11 +8,13 @@
#
# 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
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
-. lib/test
+SKIP_WITH_CLVMD=1
+SKIP_WITH_LVMPOLLD=1
-exit 0
+. lib/inittest
#
# Snapshots of 'mirrors' are not supported. They can no longer be created.
@@ -21,7 +24,7 @@ exit 0
aux prepare_vg 5
-lvcreate -m 3 --ig -L 2M -n 4way $vg "$dev1" "$dev2" "$dev3" "$dev4" "$dev5":0
+lvcreate --type mirror -m 3 -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
@@ -33,3 +36,5 @@ 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"
+
+vgremove -ff $vg
diff --git a/test/shell/vgreduce-usage.sh b/test/shell/vgreduce-usage.sh
index 9a55d3c..e6f10f0 100644
--- a/test/shell/vgreduce-usage.sh
+++ b/test/shell/vgreduce-usage.sh
@@ -1,4 +1,5 @@
-#!/bin/sh
+#!/usr/bin/env bash
+
# Copyright (C) 2008 Red Hat, Inc. All rights reserved.
#
# This copyrighted material is made available to anyone wishing to use,
@@ -7,30 +8,40 @@
#
# 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
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+
+SKIP_WITH_LVMPOLLD=1
-. lib/test
+. lib/inittest
aux prepare_devs 4
+get_devs
-for mdatype in 1 2
+if test -n "$LVM_TEST_LVM1" ; then
+mdatypes='1 2'
+else
+mdatypes='2'
+fi
+
+for mdatype in $mdatypes
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"
+ vgcreate $SHARED -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"
+ vgcreate $SHARED -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"
+ vgcreate $SHARED -M$mdatype $vg1 "$dev1" "$dev2"
not vgreduce $vg1 "$dev1" "$dev2"
vgremove -f $vg1
@@ -44,14 +55,14 @@ 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"
+vgcreate $SHARED -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
+vgcreate $SHARED -M$mdatype $vg1 "$dev1" "$dev2" "$dev3"
+lvcreate -aey -n $lv1 --type mirror -m1 -l 4 $vg1
lvcreate -n $lv2 -l 4 $vg1 "$dev2"
lvcreate -n $lv3 -l 4 $vg1 "$dev3"
vgchange -an $vg1
@@ -68,11 +79,11 @@ 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)
+vgcreate $SHARED -M$mdatype "$vg1" "${DEVICES[@]}"
lvcreate -n $lv2 -l 4 $vg1
-lvcreate -m1 -n $lv1 -l 4 $vg1 "$dev1" "$dev2" "$dev3"
+lvcreate -aey --type mirror -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
+pvs --segments -o +lv_name "${DEVICES[@]}" # for record only
# (lvm$mdatype) setup: damage one pv
vgchange -an $vg1
aux disable_dev "$dev1"
@@ -84,6 +95,8 @@ vgreduce --removemissing --mirrorsonly --force $vg1
aux enable_dev "$dev1"
-pvs -P $(cat DEVICES) # for record
+pvs -P "${DEVICES[@]}" # for record
lvs -P $vg1 # for record
vgs -P $vg1 # for record
+
+vgremove -ff $vg1
diff --git a/test/api/lvtest.sh b/test/shell/vgremove-corrupt-vg.sh
index 0b7684a..3b17746 100644
--- a/test/api/lvtest.sh
+++ b/test/shell/vgremove-corrupt-vg.sh
@@ -1,7 +1,6 @@
-#!/bin/sh
-# Copyright (C) 2011 Red Hat, Inc. All rights reserved.
-#
-# This file is part of LVM2.
+#!/usr/bin/env bash
+
+# Copyright (C) 2013 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
@@ -9,13 +8,16 @@
#
# 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
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+
+SKIP_WITH_LVMPOLLD=1
-. lib/test
+. lib/inittest
-aux prepare_vg 1
+aux prepare_vg 3
+lvcreate -n blabla -L 1 $vg -an --zero n
-lvcreate -n test -l 5 $vg
-aux apitest lvtest $vg
+dd if=/dev/urandom bs=512 seek=2 count=32 of="$dev2"
-check lv_field $vg/test lv_name test
+vgremove -f $vg
diff --git a/test/shell/vgrename-usage.sh b/test/shell/vgrename-usage.sh
index 2b8ac5a..3b69453 100644
--- a/test/shell/vgrename-usage.sh
+++ b/test/shell/vgrename-usage.sh
@@ -1,4 +1,5 @@
-#!/bin/sh
+#!/usr/bin/env bash
+
# Copyright (C) 2008 Red Hat, Inc. All rights reserved.
#
# This copyrighted material is made available to anyone wishing to use,
@@ -7,9 +8,12 @@
#
# 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
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+SKIP_WITH_LVMLOCKD=1
+SKIP_WITH_LVMPOLLD=1
-. lib/test
+. lib/inittest
aux prepare_devs 4
pvcreate "$dev1" "$dev2"
@@ -38,3 +42,18 @@ vgcreate $vg1 "$dev1"
vgcreate $vg2 "$dev2"
not vgrename $vg1 $vg2
vgremove $vg1 $vg2
+
+# vgrename duplicate name
+vgcreate $vg1 "$dev1"
+aux disable_dev "$dev1"
+vgcreate $vg1 "$dev2"
+UUID=$(vgs --noheading -o vg_uuid $vg1)
+aux enable_dev "$dev1"
+
+not vgrename $vg1 $vg2
+vgrename $UUID $vg2
+not vgrename $UUID $vg1
+
+vgs
+
+vgremove $vg1 $vg2
diff --git a/test/shell/vgsplit-cache.sh b/test/shell/vgsplit-cache.sh
new file mode 100644
index 0000000..65a711f
--- /dev/null
+++ b/test/shell/vgsplit-cache.sh
@@ -0,0 +1,135 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2019 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+# Test vgsplit command options with cached volumes
+
+SKIP_WITH_LVMLOCKD=1
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+aux have_cache 1 3 0 || skip
+
+aux prepare_vg 7
+vgcfgbackup -f vgb $vg
+
+lvcreate -L5 -n $lv2 $vg "$dev2"
+lvcreate -L5 -n $lv3 $vg "$dev3"
+lvconvert -y --type cache-pool --poolmetadata $vg/$lv2 $vg/$lv3
+
+# Cannot split data and metadata from cache-pool
+fail vgsplit $vg $vg1 "$dev2" 2>&1 | tee err
+grep "Cannot split cache pool data" err
+
+fail vgsplit $vg $vg1 "$dev3" 2>&1 | tee err
+grep "Cannot split cache pool data" err
+
+# Cache $lv1
+lvcreate -L1 -n $lv1 $vg "$dev1"
+lvconvert -y --cache --cachepool $vg/$lv3 $vg/$lv1
+
+
+
+# Cannot move active cache
+fail vgsplit $vg $vg1 "$dev1" "$dev2" "$dev3" 2>&1 | tee err
+grep "must be inactive" err
+
+vgchange -an $vg
+
+
+# Try spliting component into separe VG
+fail vgsplit $vg $vg1 "$dev1" 2>&1 | tee err
+grep "Cannot split cache origin" err
+
+fail vgsplit $vg $vg1 "$dev2" 2>&1 | tee err
+grep "Cannot split cache origin" err
+
+fail vgsplit $vg $vg1 "$dev3" 2>&1 | tee err
+grep "Cannot split cache origin" err
+
+fail vgsplit $vg $vg1 "$dev1" "$dev2" 2>&1 | tee err
+grep "Cannot split cache origin" err
+
+fail vgsplit $vg $vg1 "$dev2" "$dev3" 2>&1 | tee err
+
+# Finaly something that should pass
+vgsplit $vg $vg1 "$dev1" "$dev2" "$dev3"
+
+vgs $vg $vg1
+
+test 4 -eq "$(get vg_field $vg pv_count)"
+test 3 -eq "$(get vg_field $vg1 pv_count)"
+
+lvremove -y $vg
+
+# dm-cache with cachevol must not separated main LV and cachevol
+
+vgremove -ff $vg
+vgremove -ff $vg1
+
+#
+# Check we handle pmspare for splitted VGs
+#
+vgcfgrestore -f vgb $vg
+
+# Create cache-pool and pmspare on single PV1
+lvcreate -L10 --type cache-pool $vg/cpool "$dev1"
+# Move spare to separate PV3
+pvmove -n $vg/lvol0_pmspare "$dev1" "$dev3"
+# Create origin on PV2
+lvcreate -L10 -n orig $vg "$dev2"
+lvconvert -H -y --cachepool $vg/cpool $vg/orig
+
+vgchange -an $vg
+
+# Check we do not create new _pmspare
+vgsplit --poolmetadataspare n $vg $vg1 "$dev2" "$dev1"
+
+check lv_exists $vg/lvol0_pmspare
+check lv_not_exists $vg1/lvol0_pmspare
+
+vgremove $vg
+vgremove -f $vg1
+
+
+vgcfgrestore -f vgb $vg
+
+# Again - now with handling _pmspare by vgsplit
+lvcreate -L10 --type cache-pool $vg/cpool "$dev1"
+# Move spare to separate PV3
+pvmove -n $vg/lvol0_pmspare "$dev1" "$dev3"
+# Create origin on PV2
+lvcreate -L10 -n orig $vg "$dev2"
+lvconvert -H -y --cachepool $vg/cpool $vg/orig
+
+vgchange -an $vg
+
+# Handle _pmspare (default)
+vgsplit --poolmetadataspare y $vg $vg1 "$dev2" "$dev1"
+
+check lv_not_exists $vg/lvol0_pmspare
+check lv_exists $vg1/lvol0_pmspare
+
+vgremove $vg
+vgremove -f $vg1
+
+
+vgcreate $vg "$dev1" "$dev2" "$dev3" "$dev4"
+
+lvcreate -L6 -n $lv1 -an $vg "$dev2"
+lvcreate -L6 -n $lv2 -an $vg "$dev3"
+lvconvert -y --type cache --cachevol $lv2 $vg/$lv1
+fail vgsplit $vg $vg1 "$dev2"
+fail vgsplit $vg $vg1 "$dev3"
+lvremove $vg/$lv1
+
+vgremove -ff $vg
diff --git a/test/shell/vgsplit-operation.sh b/test/shell/vgsplit-operation.sh
index c9cc04a..eb24a58 100644
--- a/test/shell/vgsplit-operation.sh
+++ b/test/shell/vgsplit-operation.sh
@@ -1,5 +1,6 @@
-#!/bin/sh
-# Copyright (C) 2007 Red Hat, Inc. All rights reserved.
+#!/usr/bin/env bash
+
+# Copyright (C) 2007,2018 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
@@ -7,18 +8,23 @@
#
# 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
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
# Test vgsplit operation, including different LV types
-. lib/test
+SKIP_WITH_LVMLOCKD=1
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+aux lvmconf "global/support_mirrored_mirror_log=1"
COMM() {
- LAST_TEST="$@"
+ LAST_TEST="$*"
}
create_vg_() {
- vgcreate -c n -s 64k "$@"
+ vgcreate -s 64k "$@"
}
aux prepare_pvs 5 10
@@ -40,8 +46,7 @@ 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
+ lvcreate -an -Zn -l 4 -n $lv1 $vg1 "$dev1"
if [ $j = PV ]; then
vgsplit $vg1 $vg2 "$dev1"
else
@@ -60,8 +65,7 @@ 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
+ lvcreate -an -Zn -l 4 -i 2 -n $lv1 $vg1 "$dev1" "$dev2"
if [ $j = PV ]; then
vgsplit $vg1 $vg2 "$dev1" "$dev2"
else
@@ -79,9 +83,12 @@ 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
+ lvcreate -an -Zn -l 64 --type mirror -m1 -n $lv1 $vg1 "$dev1" "$dev2" "$dev3"
if [ $j = PV ]; then
+ # FIXME: Not an exhaustive check of possible bad combinations
+ not vgsplit $vg1 $vg2 "$dev1" "$dev2"
+ not vgsplit $vg1 $vg2 "$dev1" "$dev3"
+ not vgsplit $vg1 $vg2 "$dev2" "$dev3"
vgsplit $vg1 $vg2 "$dev1" "$dev2" "$dev3"
else
vgsplit -n $lv1 $vg1 $vg2
@@ -93,17 +100,44 @@ COMM "vgsplit correctly splits mirror LV into $i VG ($j args)"
fi
lvremove -f $vg2/$lv1
vgremove -f $vg2
-# FIXME: ensure split /doesn't/ work when not all devs of mirror specified
+# RHBZ 875903
+COMM "vgsplit correctly splits mirror (log+leg on same dev) into $i VG ($j args)"
+ create_vg_ $vg1 "$dev1" "$dev2" "$dev3"
+ test $i = existing && create_vg_ $vg2 "$dev4"
+
+ lvcreate -an -Zn -l 64 --type mirror -m1 -n $lv1 $vg1 "$dev1" "$dev2"
+ if [ $j = PV ]; then
+ not vgsplit $vg1 $vg2 "$dev1"
+ not vgsplit $vg1 $vg2 "$dev2"
+ vgsplit $vg1 $vg2 "$dev1" "$dev2"
+ else
+ vgsplit -n $lv1 $vg1 $vg2
+ fi
+ if [ $i = existing ]; then
+ check pvlv_counts $vg2 3 1 0
+ else
+ check pvlv_counts $vg2 2 1 0
+ fi
+ lvremove -f $vg2/$lv1
+ vgremove -f $vg1 $vg2
+
+# Can't use mirrored log without cmirrord
+# TODO: Should work for inactive device, needs some fixes....
+if test ! -e LOCAL_CLVMD ; then
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 \
+ lvcreate -an -Zn -l 64 --mirrorlog mirrored --type mirror -m1 -n $lv1 $vg1 \
"$dev1" "$dev2" "$dev3" "$dev4"
- vgchange -an $vg1
if [ $j = PV ]; then
+ # FIXME: Not an exhaustive check of possible bad combinations
+ not vgsplit $vg1 $vg2 "$dev1" "$dev2"
+ not vgsplit $vg1 $vg2 "$dev3" "$dev4"
+ not vgsplit $vg1 $vg2 "$dev1" "$dev3"
+ not vgsplit $vg1 $vg2 "$dev2" "$dev4"
vgsplit $vg1 $vg2 "$dev1" "$dev2" "$dev3" "$dev4"
else
vgsplit -n $lv1 $vg1 $vg2
@@ -115,13 +149,36 @@ COMM "vgsplit correctly splits mirror LV with mirrored log into $i VG ($j args)"
fi
lvremove -f $vg2/$lv1
vgremove -f $vg2
-# FIXME: ensure split /doesn't/ work when not all devs of mirror specified
+
+# RHBZ 875903
+COMM "vgsplit correctly splits mirror LV with mirrored log on same devs into $i VG ($j args)"
+ create_vg_ $vg1 "$dev1" "$dev2" "$dev3" "$dev4"
+ test $i = existing && create_vg_ $vg2 "$dev5"
+
+ lvcreate -an -Zn -l 64 --mirrorlog mirrored --type mirror -m1 -n $lv1 $vg1 \
+ "$dev1" "$dev2"
+
+ if [ $j = PV ]; then
+ not vgsplit $vg1 $vg2 "$dev1"
+ not vgsplit $vg1 $vg2 "$dev2"
+ vgsplit $vg1 $vg2 "$dev1" "$dev2"
+ else
+ vgsplit -n $lv1 $vg1 $vg2
+ fi
+ if [ $i = existing ]; then
+ check pvlv_counts $vg2 3 1 0
+ else
+ check pvlv_counts $vg2 2 1 0
+ fi
+ lvremove -f $vg2/$lv1
+ vgremove -f $vg1 $vg2
+fi
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 -aey -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
@@ -142,7 +199,7 @@ COMM "vgsplit correctly splits linear LV but not snap+origin LV into $i VG ($j a
create_vg_ $vg1 "$dev1" "$dev2"
test $i = existing && create_vg_ $vg2 "$dev3"
- lvcreate -l 64 -i 2 -n $lv1 $vg1
+ lvcreate -aey -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"
@@ -167,10 +224,9 @@ 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"
+ lvcreate -an -Zn -l 64 --type mirror -m1 -n $lv1 $vg1 "$dev1" "$dev2" "$dev3"
vgextend $vg1 "$dev4"
- lvcreate -l 64 -n $lv2 $vg1 "$dev4"
- vgchange -an $vg1
+ lvcreate -an -Zn -l 64 -n $lv2 $vg1 "$dev4"
if [ $j = PV ]; then
vgsplit $vg1 $vg2 "$dev4"
else
@@ -184,7 +240,6 @@ COMM "vgsplit correctly splits linear LV but not mirror LV into $i VG ($j args)"
check pvlv_counts $vg2 1 1 0
fi
vgremove -f $vg1 $vg2
-
done
done
@@ -194,16 +249,15 @@ done
#
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
+lvcreate -an -Zn -l 4 -n $lv1 -i 2 $vg1 "$dev1" "$dev2"
+lvcreate -an -Zn -l 4 -n $lv2 -i 2 $vg1 "$dev2" "$dev3"
+lvcreate -an -Zn -l 4 -n $lv3 -i 2 $vg1 "$dev3" "$dev4"
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 -aey -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
@@ -215,7 +269,7 @@ 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 -aey -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
@@ -227,18 +281,16 @@ 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"
+lvcreate -an -Zn -l 16 -n $lv1 --type mirror -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"
+lvcreate -an -Zn -l 16 -n $lv1 --type mirror --nosync -m1 $vg1 "$dev1" "$dev2" "$dev3"
+lvcreate -an -Zn -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
@@ -247,7 +299,7 @@ vgremove -f $vg1
#
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 -aey -l 16 -n $lv1 --type mirror --nosync -m1 $vg1 "$dev1" "$dev2" "$dev3"
lvcreate -l 16 -n $lv2 $vg1 "$dev4"
lvchange -an $vg1/$lv2
check pvlv_counts $vg1 4 2 0
@@ -257,7 +309,7 @@ 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 -aey -l 16 -n $lv1 --type mirror --nosync -m1 $vg1 "$dev1" "$dev2" "$dev3"
lvcreate -l 16 -n $lv2 $vg1 "$dev4"
lvchange -an $vg1/$lv2
check pvlv_counts $vg1 4 2 0
@@ -268,10 +320,9 @@ 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 -aey -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
+lvcreate -an -Zn -l 64 -i 2 -n $lv3 $vg1 "$dev3" "$dev4"
check pvlv_counts $vg1 4 3 1
not vgsplit -n $lv2 $vg1 $vg2;
check pvlv_counts $vg1 4 3 1
@@ -280,11 +331,10 @@ 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 -aey -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
+lvcreate -an -Zn -l 64 -n $lv3 $vg1 "$dev4"
check pvlv_counts $vg1 4 3 1
vgsplit -n $lv3 $vg1 $vg2
check pvlv_counts $vg1 3 2 1
diff --git a/test/shell/vgsplit-raid.sh b/test/shell/vgsplit-raid.sh
new file mode 100644
index 0000000..08e2a8e
--- /dev/null
+++ b/test/shell/vgsplit-raid.sh
@@ -0,0 +1,61 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2014 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+# Test vgsplit operation, including different LV types
+SKIP_WITH_LVMLOCKD=1
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+COMM() {
+ LAST_TEST="$*"
+}
+
+create_vg_() {
+ vgcreate -s 64k "$@"
+}
+
+aux have_raid 1 3 0 || skip
+
+aux prepare_pvs 5 10
+
+#
+# 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 RAID LV into $i VG ($j args)"
+ create_vg_ $vg1 "$dev1" "$dev2" "$dev3"
+ test $i = existing && create_vg_ $vg2 "$dev5"
+
+ lvcreate -an -Zn -l 64 --type raid5 -i 2 -n $lv1 $vg1
+ if [ $j = PV ]; then
+ not vgsplit $vg1 $vg2 "$dev1"
+ not vgsplit $vg1 $vg2 "$dev2"
+ not vgsplit $vg1 $vg2 "$dev1" "$dev2"
+ 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
+ vgremove -f $vg2
+ done
+done
diff --git a/test/shell/vgsplit-stacked.sh b/test/shell/vgsplit-stacked.sh
index 62a5304..2f99a2e 100644
--- a/test/shell/vgsplit-stacked.sh
+++ b/test/shell/vgsplit-stacked.sh
@@ -1,4 +1,5 @@
-#!/bin/sh
+#!/usr/bin/env bash
+
# Copyright (C) 2010 Red Hat, Inc. All rights reserved.
#
# This copyrighted material is made available to anyone wishing to use,
@@ -7,21 +8,30 @@
#
# 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
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+
+SKIP_WITH_LVMPOLLD=1
-. lib/test
+. lib/inittest
+
+aux extend_filter_LVMTEST
+aux lvmconf "devices/scan_lvs = 1"
-aux lvmconf 'devices/filter = [ "a/dev\/mirror/", "a/dev\/mapper\/.*$/", "a/dev\/LVMTEST/", "r/.*/" ]'
aux prepare_pvs 3
-vgcreate $vg1 "$dev1" "$dev2"
+vgcreate $SHARED $vg1 "$dev1" "$dev2"
lvcreate -n $lv1 -l 100%FREE $vg1
+aux extend_devices "$DM_DEV_DIR/$vg1/$lv1"
+
#top VG
-pvcreate $DM_DEV_DIR/$vg1/$lv1
-vgcreate $vg $DM_DEV_DIR/$vg1/$lv1 "$dev3"
+pvcreate "$DM_DEV_DIR/$vg1/$lv1"
+vgcreate $SHARED $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"
+
+vgremove -ff $vg $vg1
diff --git a/test/shell/vgsplit-thin.sh b/test/shell/vgsplit-thin.sh
new file mode 100644
index 0000000..abe9f55
--- /dev/null
+++ b/test/shell/vgsplit-thin.sh
@@ -0,0 +1,67 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2013 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+# Test vgsplit command options for validity
+
+SKIP_WITH_LVMLOCKD=1
+SKIP_WITH_LVMPOLLD=1
+
+export LVM_TEST_THIN_REPAIR_CMD=${LVM_TEST_THIN_REPAIR_CMD-/bin/false}
+
+. lib/inittest
+
+aux have_thin 1 0 0 || skip
+
+aux prepare_devs 5
+get_devs
+
+vgcreate "$vg1" "${DEVICES[@]}"
+lvcreate -T -L8M $vg1/pool1 -V10M -n $lv1 "$dev1" "$dev2"
+lvcreate -T -L8M $vg1/pool2 -V10M -n $lv2 "$dev3" "$dev4"
+lvcreate -s -L2M -n snap $vg1/$lv1 "$dev2"
+
+# Test with external origin if available
+lvcreate -l1 -an -pr --zero n -n eorigin $vg1 "$dev5"
+aux have_thin 1 5 0 && lvcreate -an -s $vg1/eorigin -n $lv3 --thinpool $vg1/pool1
+
+# Cannot move active thin
+not vgsplit $vg1 $vg2 "$dev1" "$dev2" "$dev5"
+
+vgchange -an $vg1
+not vgsplit $vg1 $vg2 "$dev1"
+not vgsplit $vg1 $vg2 "$dev2" "$dev3"
+vgsplit $vg1 $vg2 "$dev1" "$dev2" "$dev5"
+lvs -a -o+devices $vg1 $vg2
+
+vgmerge $vg1 $vg2
+
+vgremove -ff $vg1
+
+# Test vgsplit with ext.origin:
+if aux have_thin 1 5 0; then
+vgcreate "$vg1" "${DEVICES[@]}"
+lvcreate -T -L8M $vg1/pool1 -V10M -n $lv1 "$dev1" "$dev2"
+lvcreate -l1 -an -pr -n $lv2 $vg1 "$dev3"
+lvcreate -s $vg1/$lv2 -n $lv3 --thinpool $vg1/pool1
+lvcreate -l1 -n $lv4 $vg1 "$dev4"
+vgchange -an $vg1
+
+# Can not split ext.origin from thin-data:
+not vgsplit $vg1 $vg2 "$dev1" "$dev2"
+not vgsplit $vg1 $vg2 "$dev3"
+
+vgsplit $vg1 $vg2 "$dev1" "$dev2" "$dev3"
+
+vgmerge $vg1 $vg2
+
+vgremove -ff $vg1
+fi
diff --git a/test/shell/vgsplit-usage.sh b/test/shell/vgsplit-usage.sh
index 10167d7..33a606e 100644
--- a/test/shell/vgsplit-usage.sh
+++ b/test/shell/vgsplit-usage.sh
@@ -1,4 +1,5 @@
-#!/bin/sh
+#!/usr/bin/env bash
+
# Copyright (C) 2007-2011 Red Hat, Inc. All rights reserved.
#
# This copyrighted material is made available to anyone wishing to use,
@@ -7,32 +8,42 @@
#
# 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
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
# Test vgsplit command options for validity
-. lib/test
+SKIP_WITH_LVMLOCKD=1
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
aux prepare_devs 5
+get_devs
-for mdatype in 1 2
+if test -n "$LVM_TEST_LVM1" ; then
+mdatypes='1 2'
+else
+mdatypes='2'
+fi
+
+for mdatype in $mdatypes
do
-pvcreate -M$mdatype $(cat DEVICES)
+pvcreate -M$mdatype "${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)
+vgcreate -M$mdatype "$vg1" "${DEVICES[@]}"
vgsplit -M$mdatype $vg1 $vg2 "$dev1"
vgremove $vg1 $vg2
-vgcreate -M$mdatype $vg2 $(cat DEVICES)
+vgcreate -M$mdatype "$vg2" "${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)
+vgcreate -M$mdatype "$vg1" "${DEVICES[@]}"
vgsplit $vg1 $vg2 "$dev1" 1>err
grep "New volume group \"$vg2\" successfully split from \"$vg1\"" err
vgremove $vg1 $vg2
@@ -84,13 +95,6 @@ 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"
@@ -143,8 +147,22 @@ lvcreate -l 4 -n $lv2 $vg1
vgchange -an $vg1
not vgsplit $vg1 $vg2 "$dev3" 2>err;
vgremove -f $vg2 $vg1
+
+# Restart clvm because using the same
+# devs as lvm1 and then lvm2 causes problems.
+if test -e LOCAL_CLVMD ; then
+ kill "$(< LOCAL_CLVMD)"
+ for i in $(seq 1 100) ; do
+ test $i -eq 100 && die "Shutdown of clvmd is too slow."
+ pgrep clvmd || break
+ sleep .1
+ done # wait for the pid removal
+ aux prepare_clvmd
+fi
+
done
+if test -z "$LVM_TEST_LVM1" ; then
# ONLY LVM2 metadata
# setup PVs" '
pvcreate --metadatacopies 0 "$dev5"
@@ -159,6 +177,7 @@ check pvlv_counts $vg1 2 1 0
vgremove -f $vg1
# vgsplit rejects split because metadata types differ
+if test -n "$LVM_TEST_LVM1" ; then
pvcreate -ff -M1 "$dev3" "$dev4"
pvcreate -ff "$dev1" "$dev2"
vgcreate -M1 $vg1 "$dev3" "$dev4"
@@ -166,3 +185,5 @@ vgcreate $vg2 "$dev1" "$dev2"
not vgsplit $vg1 $vg2 "$dev3" 2>err;
grep "Metadata types differ" err
vgremove -f $vg1 $vg2
+fi
+fi
diff --git a/test/shell/vgsplit-vdo.sh b/test/shell/vgsplit-vdo.sh
new file mode 100644
index 0000000..1d5ddf8
--- /dev/null
+++ b/test/shell/vgsplit-vdo.sh
@@ -0,0 +1,56 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2020 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+# Test vgsplit command options with vdo volumes
+
+SKIP_WITH_LVMLOCKD=1
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+aux have_vdo 6 2 0 || skip
+
+aux lvmconf "allocation/vdo_slab_size_mb = 128"
+
+aux prepare_vg 4 2200
+
+lvcreate --vdo -L4G -n $lv1 $vg "$dev1" "$dev2"
+lvcreate --vdo -L4G -n $lv2 $vg "$dev3" "$dev4"
+
+# Cannot move only part of VDO _vdata
+not vgsplit $vg $vg2 "$dev3" |& tee out
+grep "split" out
+
+# Cannot move active VDO
+not vgsplit $vg $vg2 "$dev3" "$dev4" |& tee out
+grep "inactive" out
+
+lvchange -an $vg/$lv2
+
+vgsplit $vg $vg2 "$dev3" "$dev4"
+
+lvchange -ay $vg2/$lv2
+lvs -ao+devices $vg $vg2
+
+# Cannot merge active VDO
+not vgmerge $vg $vg2 |& tee out
+grep "inactive" out
+
+lvchange -an $vg2/$lv2
+
+vgmerge $vg $vg2
+
+lvs -ao+devices $vg
+
+lvchange -ay $vg/$lv2
+
+vgremove -ff $vg
diff --git a/test/shell/writecache-cache-blocksize-2.sh b/test/shell/writecache-cache-blocksize-2.sh
new file mode 100644
index 0000000..d50b369
--- /dev/null
+++ b/test/shell/writecache-cache-blocksize-2.sh
@@ -0,0 +1,242 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2018 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+# Test dm-writecache and dm-cache with different block size combinations
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+aux have_writecache 1 0 0 || skip
+which mkfs.xfs || skip
+
+mnt="mnt"
+mkdir -p $mnt
+
+awk 'BEGIN { while (z++ < 16384) printf "A" }' > fileA
+awk 'BEGIN { while (z++ < 16384) printf "B" }' > fileB
+awk 'BEGIN { while (z++ < 16384) printf "C" }' > fileC
+
+# generate random data
+dd if=/dev/urandom of=randA bs=512K count=2
+dd if=/dev/urandom of=randB bs=512K count=3
+dd if=/dev/urandom of=randC bs=512K count=4
+
+_add_new_data_to_mnt() {
+ mount "$DM_DEV_DIR/$vg/$lv1" $mnt
+
+ # add original data
+ cp randA $mnt
+ cp randB $mnt
+ cp randC $mnt
+ mkdir $mnt/1
+ cp fileA $mnt/1
+ cp fileB $mnt/1
+ cp fileC $mnt/1
+ mkdir $mnt/2
+ cp fileA $mnt/2
+ cp fileB $mnt/2
+ cp fileC $mnt/2
+ sync
+}
+
+_add_more_data_to_mnt() {
+ mkdir $mnt/more
+ cp fileA $mnt/more
+ cp fileB $mnt/more
+ cp fileC $mnt/more
+ cp randA $mnt/more
+ cp randB $mnt/more
+ cp randC $mnt/more
+ sync
+}
+
+_verify_data_on_mnt() {
+ diff randA $mnt/randA
+ diff randB $mnt/randB
+ diff randC $mnt/randC
+ diff fileA $mnt/1/fileA
+ diff fileB $mnt/1/fileB
+ diff fileC $mnt/1/fileC
+ diff fileA $mnt/2/fileA
+ diff fileB $mnt/2/fileB
+ diff fileC $mnt/2/fileC
+}
+
+_verify_more_data_on_mnt() {
+ diff randA $mnt/more/randA
+ diff randB $mnt/more/randB
+ diff randC $mnt/more/randC
+ diff fileA $mnt/more/fileA
+ diff fileB $mnt/more/fileB
+ diff fileC $mnt/more/fileC
+}
+
+_verify_data_on_lv() {
+ lvchange -ay $vg/$lv1
+ mount "$DM_DEV_DIR/$vg/$lv1" $mnt
+ _verify_data_on_mnt
+ rm $mnt/randA
+ rm $mnt/randB
+ rm $mnt/randC
+ rm -rf $mnt/1
+ rm -rf $mnt/2
+ umount $mnt
+ lvchange -an $vg/$lv1
+}
+
+# Check that the LBS ($1) and PBS ($2) are accurately reported.
+_check_env() {
+
+ check sysfs "$(< SCSI_DEBUG_DEV)" queue/logical_block_size "$1"
+ check sysfs "$(< SCSI_DEBUG_DEV)" queue/physical_block_size "$2"
+
+ blockdev --getss "$dev1"
+ blockdev --getpbsz "$dev1"
+ blockdev --getss "$dev2"
+ blockdev --getpbsz "$dev2"
+}
+
+#
+# _run_test $BD1 $BD2 $type $optname "..."
+#
+# $BD1: device to place the main LV on
+# $BD2: device to place the cache on
+# $type is cache or writecache to use in lvconvert --type $type
+# $optname is either --cachevol or --cachepool to use in lvconvert
+# "..." a sector size option to use in mkfs.xfs
+#
+
+_run_test() {
+ vgcreate $SHARED $vg "$1"
+ vgextend $vg "$2"
+ lvcreate -n $lv1 -L 300 -an $vg "$1"
+ lvcreate -n $lv2 -l 4 -an $vg "$2"
+ lvchange -ay $vg/$lv1
+ mkfs.xfs -f $5 "$DM_DEV_DIR/$vg/$lv1" |tee out
+ _add_new_data_to_mnt
+ lvconvert --yes --type $3 $4 $lv2 $vg/$lv1
+
+ # TODO: check expected LBS of LV1
+ # blockdev --getss "$DM_DEV_DIR/$vg/$lv1" |tee out
+ # grep "$N" out
+ # TODO: check expected PBS of LV1
+ # blockdev --getpbsz "$DM_DEV_DIR/$vg/$lv1" |tee out
+ # grep "$N" out
+
+ _add_more_data_to_mnt
+ _verify_data_on_mnt
+ lvconvert --splitcache $vg/$lv1
+ check lv_field $vg/$lv1 segtype linear
+ blockdev --getss "$DM_DEV_DIR/$vg/$lv1"
+ blockdev --getpbsz "$DM_DEV_DIR/$vg/$lv1"
+ _verify_data_on_mnt
+ _verify_more_data_on_mnt
+ umount $mnt
+ lvchange -an $vg/$lv1
+ lvchange -an $vg/$lv2
+ _verify_data_on_lv
+ lvremove $vg/$lv1
+ lvremove $vg/$lv2
+ vgremove $vg
+}
+
+# Setup: dev1 LBS 512, PBS 4096 (using scsi-debug)
+# dev2 LBS 512, PBS 4096 (using scsi-debug)
+# dev3 LBS 512, PBS 512 (using loop)
+# dev4 LBS 512, PBS 512 (using loop)
+#
+
+# On scsi debug 2 PVs has to fit!
+aux prepare_scsi_debug_dev 602 sector_size=512 physblk_exp=3 || skip
+aux prepare_devs 2 301
+
+# Tests with fs block sizes require a libblkid version that shows BLOCK_SIZE
+vgcreate $vg "$dev1"
+lvcreate -n $lv1 -L300 $vg
+mkfs.xfs -f "$DM_DEV_DIR/$vg/$lv1"
+blkid -p "$DM_DEV_DIR/$vg/$lv1" | grep BLOCK_SIZE || skip
+lvchange -an $vg
+vgremove -ff $vg
+
+# loopa/loopb have LBS 512 PBS 512
+which fallocate || skip
+fallocate -l 301M loopa
+fallocate -l 301M loopb
+
+for i in {1..5}; do
+ LOOP1=$(losetup -f loopa --show || true)
+ test -n "$LOOP1" && break
+done
+for i in {1..5} ; do
+ LOOP2=$(losetup -f loopb --show || true)
+ test -n "$LOOP2" && break
+done
+
+# prepare devX mapping so it works for real & fake dev dir
+d=3
+for i in "$LOOP1" "$LOOP2"; do
+ echo "$i"
+ m=${i##*loop}
+ test -e "$DM_DEV_DIR/loop$m" || mknod "$DM_DEV_DIR/loop$m" b 7 "$m"
+ eval "dev$d=\"$DM_DEV_DIR/loop$m\""
+ d=$(( d + 1 ))
+done
+
+# verify dev1/dev2 have LBS 512 PBS 4096
+_check_env "512" "4096"
+
+# verify dev3/dev4 have LBS 512 PBS 512
+blockdev --getss "$LOOP1" | grep 512
+blockdev --getss "$LOOP2" | grep 512
+blockdev --getpbsz "$LOOP1" | grep 512
+blockdev --getpbsz "$LOOP2" | grep 512
+
+aux extend_filter "a|$dev3|" "a|$dev4|"
+aux extend_devices "$dev3" "$dev4"
+
+# place main LV on dev1 with LBS 512, PBS 4096
+# and the cache on dev3 with LBS 512, PBS 512
+
+_run_test "$dev1" "$dev3" "writecache" "--cachevol" ""
+_run_test "$dev1" "$dev3" "cache" "--cachevol" ""
+_run_test "$dev1" "$dev3" "cache" "--cachepool" ""
+
+# place main LV on dev3 with LBS 512, PBS 512
+# and the cache on dev1 with LBS 512, PBS 4096
+
+_run_test "$dev3" "$dev1" "writecache" "--cachevol" ""
+_run_test "$dev3" "$dev1" "cache" "--cachevol" ""
+_run_test "$dev3" "$dev1" "cache" "--cachepool" ""
+
+# place main LV on dev1 with LBS 512, PBS 4096
+# and the cache on dev3 with LBS 512, PBS 512
+# and force xfs sectsz 512
+
+_run_test "$dev1" "$dev3" "writecache" "--cachevol" "-s size=512"
+_run_test "$dev1" "$dev3" "cache" "--cachevol" "-s size=512"
+_run_test "$dev1" "$dev3" "cache" "--cachepool" "-s size=512"
+
+# place main LV on dev3 with LBS 512, PBS 512
+# and the cache on dev1 with LBS 512, PBS 4096
+# and force xfs sectsz 4096
+
+_run_test "$dev3" "$dev1" "writecache" "--cachevol" "-s size=4096"
+_run_test "$dev3" "$dev1" "cache" "--cachevol" "-s size=4096"
+_run_test "$dev3" "$dev1" "cache" "--cachepool" "-s size=4096"
+
+
+losetup -d "$LOOP1" || true
+losetup -d "$LOOP2" || true
+rm loopa loopb
+
+aux cleanup_scsi_debug_dev
diff --git a/test/shell/writecache-cache-blocksize.sh b/test/shell/writecache-cache-blocksize.sh
new file mode 100644
index 0000000..18be6ed
--- /dev/null
+++ b/test/shell/writecache-cache-blocksize.sh
@@ -0,0 +1,251 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2018 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+# Test dm-writecache and dm-cache with different block size combinations
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+aux have_writecache 1 0 0 || skip
+which mkfs.xfs || skip
+
+mnt="mnt"
+mkdir -p $mnt
+
+awk 'BEGIN { while (z++ < 16384) printf "A" }' > fileA
+awk 'BEGIN { while (z++ < 16384) printf "B" }' > fileB
+awk 'BEGIN { while (z++ < 16384) printf "C" }' > fileC
+
+# generate random data
+dd if=/dev/urandom of=randA bs=512K count=2
+dd if=/dev/urandom of=randB bs=512K count=3
+dd if=/dev/urandom of=randC bs=512K count=4
+
+_add_new_data_to_mnt() {
+ mount "$DM_DEV_DIR/$vg/$lv1" $mnt
+
+ # add original data
+ cp randA $mnt
+ cp randB $mnt
+ cp randC $mnt
+ mkdir $mnt/1
+ cp fileA $mnt/1
+ cp fileB $mnt/1
+ cp fileC $mnt/1
+ mkdir $mnt/2
+ cp fileA $mnt/2
+ cp fileB $mnt/2
+ cp fileC $mnt/2
+ sync
+}
+
+_add_more_data_to_mnt() {
+ mkdir $mnt/more
+ cp fileA $mnt/more
+ cp fileB $mnt/more
+ cp fileC $mnt/more
+ cp randA $mnt/more
+ cp randB $mnt/more
+ cp randC $mnt/more
+ sync
+}
+
+_verify_data_on_mnt() {
+ diff randA $mnt/randA
+ diff randB $mnt/randB
+ diff randC $mnt/randC
+ diff fileA $mnt/1/fileA
+ diff fileB $mnt/1/fileB
+ diff fileC $mnt/1/fileC
+ diff fileA $mnt/2/fileA
+ diff fileB $mnt/2/fileB
+ diff fileC $mnt/2/fileC
+}
+
+_verify_more_data_on_mnt() {
+ diff randA $mnt/more/randA
+ diff randB $mnt/more/randB
+ diff randC $mnt/more/randC
+ diff fileA $mnt/more/fileA
+ diff fileB $mnt/more/fileB
+ diff fileC $mnt/more/fileC
+}
+
+_verify_data_on_lv() {
+ lvchange -ay $vg/$lv1
+ mount "$DM_DEV_DIR/$vg/$lv1" $mnt
+ _verify_data_on_mnt
+ rm $mnt/randA
+ rm $mnt/randB
+ rm $mnt/randC
+ rm -rf $mnt/1
+ rm -rf $mnt/2
+ umount $mnt
+ lvchange -an $vg/$lv1
+}
+
+# Check that the LBS/PBS that were set up is accurately reported for the devs.
+_check_env() {
+
+ check sysfs "$(< SCSI_DEBUG_DEV)" queue/logical_block_size "$1"
+ check sysfs "$(< SCSI_DEBUG_DEV)" queue/physical_block_size "$2"
+
+ blockdev --getss "$dev1"
+ blockdev --getpbsz "$dev1"
+ blockdev --getss "$dev2"
+ blockdev --getpbsz "$dev2"
+}
+
+#
+# _run_test $BS1 $BS2 $type $optname "..."
+#
+# $BS1: the xfs sectsz is verified to match $BS1, after mkfs
+# $BS2: the lv1 LBS is verified to match $BS2, after cache is added to lv1
+# $type is cache or writecache to use in lvconvert --type $type
+# $optname is either --cachevol or --cachepool to use in lvconvert
+# "..." a sector size option to use in mkfs.xfs
+#
+
+_run_test() {
+ vgcreate $SHARED $vg "$dev1"
+ vgextend $vg "$dev2"
+ lvcreate -n $lv1 -L 300 -an $vg "$dev1"
+ lvcreate -n $lv2 -l 4 -an $vg "$dev2"
+ lvchange -ay $vg/$lv1
+ mkfs.xfs -f $5 "$DM_DEV_DIR/$vg/$lv1" |tee out
+ grep "sectsz=$1" out
+ _add_new_data_to_mnt
+ lvconvert --yes --type $3 $4 $lv2 $vg/$lv1
+ blockdev --getss "$DM_DEV_DIR/$vg/$lv1" |tee out
+ grep "$2" out
+ blockdev --getpbsz "$DM_DEV_DIR/$vg/$lv1"
+ _add_more_data_to_mnt
+ _verify_data_on_mnt
+ lvconvert --splitcache $vg/$lv1
+ check lv_field $vg/$lv1 segtype linear
+ blockdev --getss "$DM_DEV_DIR/$vg/$lv1"
+ blockdev --getpbsz "$DM_DEV_DIR/$vg/$lv1"
+ _verify_data_on_mnt
+ _verify_more_data_on_mnt
+ umount $mnt
+ lvchange -an $vg/$lv1
+ lvchange -an $vg/$lv2
+ _verify_data_on_lv
+ lvremove $vg/$lv1
+ lvremove $vg/$lv2
+ vgremove $vg
+}
+
+# Setup: LBS 512, PBS 512
+aux prepare_scsi_debug_dev 602 || skip
+aux prepare_devs 2 301
+
+# Tests with fs block sizes require a libblkid version that shows BLOCK_SIZE
+vgcreate $vg "$dev1"
+lvcreate -n $lv1 -L300 $vg
+mkfs.xfs -f "$DM_DEV_DIR/$vg/$lv1"
+blkid -p "$DM_DEV_DIR/$vg/$lv1" | grep BLOCK_SIZE || skip
+lvchange -an $vg
+vgremove -ff $vg
+
+_check_env "512" "512"
+
+# lbs 512, pbs 512, xfs 512, wc bs 512
+_run_test 512 512 "writecache" "--cachevol" ""
+# lbs 512, pbs 512, xfs 512, cache bs 512
+_run_test 512 512 "cache" "--cachevol" ""
+_run_test 512 512 "cache" "--cachepool" ""
+
+# lbs 512, pbs 512, xfs -s 4096, wc bs 4096
+_run_test 4096 4096 "writecache" "--cachevol" "-s size=4096"
+# lbs 512, pbs 512, xfs -s 4096, cache bs 512
+_run_test 4096 512 "cache" "--cachevol" "-s size=4096"
+_run_test 4096 512 "cache" "--cachepool" "-s size=4096"
+
+aux cleanup_scsi_debug_dev
+
+
+# Setup: LBS 512, PBS 4096
+aux prepare_scsi_debug_dev 602 sector_size=512 physblk_exp=3
+aux prepare_devs 2 301
+
+_check_env "512" "4096"
+
+# lbs 512, pbs 4k, xfs 4k, wc bs 4k
+_run_test 4096 4096 "writecache" "--cachevol" ""
+# lbs 512, pbs 4k, xfs 4k, cache bs 512
+_run_test 4096 512 "cache" "--cachevol" ""
+_run_test 4096 512 "cache" "--cachepool" ""
+
+# lbs 512, pbs 4k, xfs -s 512, wc bs 512
+_run_test 512 512 "writecache" "--cachevol" "-s size=512"
+# lbs 512, pbs 4k, xfs -s 512, cache bs 512
+_run_test 512 512 "cache" "--cachevol" "-s size=512"
+_run_test 512 512 "cache" "--cachepool" "-s size=512"
+
+aux cleanup_scsi_debug_dev
+
+# Setup: LBS 4096, PBS 4096
+# NOTE: Here we actually need PV of size 304M to get 300M ??
+aux prepare_scsi_debug_dev 608 sector_size=4096 || skip
+aux prepare_devs 2 304
+
+_check_env "4096" "4096"
+
+# lbs 4k, pbs 4k, xfs 4k, wc bs 4k
+_run_test 4096 4096 "writecache" "--cachevol" ""
+# lbs 4k, pbs 4k, xfs 4k, cache bs 4k
+_run_test 4096 4096 "cache" "--cachevol" ""
+_run_test 4096 4096 "cache" "--cachepool" ""
+
+aux cleanup_scsi_debug_dev
+
+
+# Setup: LBS 512, PBS 512
+aux prepare_scsi_debug_dev 602 || skip
+aux prepare_devs 2 301
+
+_check_env "512" "512"
+
+vgcreate $SHARED $vg "$dev1"
+vgextend $vg "$dev2"
+lvcreate -n $lv1 -L 300 -an $vg "$dev1"
+lvcreate -n $lv2 -l 4 -an $vg "$dev2"
+lvconvert --yes --type writecache --cachevol $lv2 --cachesettings "block_size=4096" $vg/$lv1
+lvs -o writecacheblocksize $vg/$lv1 |tee out
+grep 4096 out
+lvchange -ay $vg/$lv1
+mkfs.xfs -f "$DM_DEV_DIR/$vg/$lv1" |tee out
+grep "sectsz=4096" out
+_add_new_data_to_mnt
+blockdev --getss "$DM_DEV_DIR/$vg/$lv1" |tee out
+grep 4096 out
+blockdev --getpbsz "$DM_DEV_DIR/$vg/$lv1"
+_add_more_data_to_mnt
+_verify_data_on_mnt
+lvconvert --splitcache $vg/$lv1
+check lv_field $vg/$lv1 segtype linear
+check lv_field $vg/$lv2 segtype linear
+blockdev --getss "$DM_DEV_DIR/$vg/$lv1"
+blockdev --getpbsz "$DM_DEV_DIR/$vg/$lv1"
+_verify_data_on_mnt
+_verify_more_data_on_mnt
+umount $mnt
+lvchange -an $vg/$lv1
+lvchange -an $vg/$lv2
+_verify_data_on_lv
+lvremove $vg/$lv1
+lvremove $vg/$lv2
+vgremove $vg
+
+aux cleanup_scsi_debug_dev
diff --git a/test/shell/writecache-large.sh b/test/shell/writecache-large.sh
new file mode 100644
index 0000000..000a2cc
--- /dev/null
+++ b/test/shell/writecache-large.sh
@@ -0,0 +1,181 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2018 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+# Test writecache usage
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+aux have_writecache 1 0 0 || skip
+which mkfs.xfs || skip
+
+# scsi_debug devices with 512 LBS 512 PBS
+aux prepare_scsi_debug_dev 1200
+check sysfs "$(< SCSI_DEBUG_DEV)" queue/logical_block_size "512"
+check sysfs "$(< SCSI_DEBUG_DEV)" queue/physical_block_size "512"
+
+aux prepare_devs 2 600
+blockdev --getss "$dev1"
+blockdev --getpbsz "$dev1"
+blockdev --getss "$dev2"
+blockdev --getpbsz "$dev2"
+
+mnt="mnt"
+mkdir -p $mnt
+
+awk 'BEGIN { while (z++ < 16384) printf "A" }' > fileA
+awk 'BEGIN { while (z++ < 16384) printf "B" }' > fileB
+awk 'BEGIN { while (z++ < 16384) printf "C" }' > fileC
+
+# generate random data
+dd if=/dev/urandom of=randA bs=512K count=2
+dd if=/dev/urandom of=randB bs=512K count=3
+dd if=/dev/urandom of=randC bs=512K count=4
+
+_add_new_data_to_mnt() {
+ mkfs.xfs -f "$DM_DEV_DIR/$vg/$lv1"
+
+ mount "$DM_DEV_DIR/$vg/$lv1" $mnt
+
+ # add original data
+ cp randA $mnt
+ cp randB $mnt
+ cp randC $mnt
+ mkdir $mnt/1
+ cp fileA $mnt/1
+ cp fileB $mnt/1
+ cp fileC $mnt/1
+ mkdir $mnt/2
+ cp fileA $mnt/2
+ cp fileB $mnt/2
+ cp fileC $mnt/2
+ sync
+}
+
+_add_more_data_to_mnt() {
+ mkdir $mnt/more
+ cp fileA $mnt/more
+ cp fileB $mnt/more
+ cp fileC $mnt/more
+ cp randA $mnt/more
+ cp randB $mnt/more
+ cp randC $mnt/more
+ sync
+}
+
+_verify_data_on_mnt() {
+ diff randA $mnt/randA
+ diff randB $mnt/randB
+ diff randC $mnt/randC
+ diff fileA $mnt/1/fileA
+ diff fileB $mnt/1/fileB
+ diff fileC $mnt/1/fileC
+ diff fileA $mnt/2/fileA
+ diff fileB $mnt/2/fileB
+ diff fileC $mnt/2/fileC
+}
+
+_verify_more_data_on_mnt() {
+ diff randA $mnt/more/randA
+ diff randB $mnt/more/randB
+ diff randC $mnt/more/randC
+ diff fileA $mnt/more/fileA
+ diff fileB $mnt/more/fileB
+ diff fileC $mnt/more/fileC
+}
+
+_verify_data_on_lv() {
+ lvchange -ay $vg/$lv1
+ mount "$DM_DEV_DIR/$vg/$lv1" $mnt
+ _verify_data_on_mnt
+ rm $mnt/randA
+ rm $mnt/randB
+ rm $mnt/randC
+ rm -rf $mnt/1
+ rm -rf $mnt/2
+ umount $mnt
+ lvchange -an $vg/$lv1
+}
+
+vgcreate $SHARED $vg "$dev1"
+vgextend $vg "$dev2"
+
+# Use a large enough size so that the cleaner will not
+# finish immediately when detaching, and will require
+# a secondary check from command top level.
+
+lvcreate -n $lv1 -L 560M -an $vg "$dev1"
+lvcreate -n $lv2 -L 500M -an $vg "$dev2"
+
+lvchange -ay $vg/$lv1
+blockdev --getss "$DM_DEV_DIR/$vg/$lv1"
+blockdev --getpbsz "$DM_DEV_DIR/$vg/$lv1"
+
+lvconvert --yes --type writecache --cachevol $lv2 $vg/$lv1
+dmsetup table $vg-$lv1
+blockdev --getss "$DM_DEV_DIR/$vg/$lv1"
+blockdev --getpbsz "$DM_DEV_DIR/$vg/$lv1"
+
+_add_new_data_to_mnt
+_add_more_data_to_mnt
+_verify_data_on_mnt
+
+dd if=/dev/zero of=$mnt/big1 bs=1M count=100 conv=fdatasync
+dd if=/dev/zero of=$mnt/big2 bs=1M count=100 conv=fdatasync
+dd if=/dev/zero of=$mnt/big3 bs=1M count=100 conv=fdatasync
+dd if=/dev/zero of=$mnt/big4 bs=1M count=100 conv=fdatasync
+
+lvconvert --splitcache $vg/$lv1
+check lv_field $vg/$lv1 segtype linear
+check lv_field $vg/$lv2 segtype linear
+dmsetup table $vg-$lv1
+_verify_data_on_mnt
+_verify_more_data_on_mnt
+dd if=$mnt/big4 of=/dev/null bs=1M count=100
+umount $mnt
+lvchange -an $vg/$lv1
+_verify_data_on_lv
+lvchange -an $vg/$lv2
+lvremove $vg/$lv1
+lvremove $vg/$lv2
+
+# Repeat similar using uncache
+
+lvcreate -n $lv1 -L 560M -an $vg "$dev1"
+lvcreate -n $lv2 -L 500M -an $vg "$dev2"
+
+lvchange -ay $vg/$lv1
+lvconvert --yes --type writecache --cachevol $lv2 $vg/$lv1
+
+_add_new_data_to_mnt
+_add_more_data_to_mnt
+dd if=/dev/zero of=$mnt/big1 bs=1M count=100 conv=fdatasync
+
+umount $mnt
+lvchange -an $vg/$lv1
+
+lvconvert --uncache $vg/$lv1
+
+check lv_field $vg/$lv1 segtype linear
+not lvs $vg/$lv2
+
+lvchange -ay $vg/$lv1
+mount "$DM_DEV_DIR/$vg/$lv1" $mnt
+
+_verify_data_on_mnt
+_verify_more_data_on_mnt
+
+umount $mnt
+lvchange -an $vg/$lv1
+
+vgremove -ff $vg
diff --git a/test/shell/writecache-misc.sh b/test/shell/writecache-misc.sh
new file mode 100644
index 0000000..ba8196c
--- /dev/null
+++ b/test/shell/writecache-misc.sh
@@ -0,0 +1,116 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2018 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+# Test single lv cache options
+
+SKIP_WITH_LVMPOLLD=1
+SKIP_WITH_LVMLOCKD=1
+
+. lib/inittest
+
+mkfs_mount_umount()
+{
+ lvt=$1
+
+ mkfs.xfs -f -s size=4096 "$DM_DEV_DIR/$vg/$lvt"
+ mount "$DM_DEV_DIR/$vg/$lvt" "$mount_dir"
+ cp pattern1 "$mount_dir/pattern1"
+ dd if=/dev/zero of="$mount_dir/zeros2M" bs=1M count=32 conv=fdatasync
+ umount "$mount_dir"
+}
+
+mount_umount()
+{
+ lvt=$1
+
+ mount "$DM_DEV_DIR/$vg/$lvt" "$mount_dir"
+ diff pattern1 "$mount_dir/pattern1"
+ dd if="$mount_dir/zeros2M" of=/dev/null bs=1M count=32
+ umount "$mount_dir"
+}
+
+aux have_writecache 1 0 0 || skip
+which mkfs.xfs || skip
+
+mount_dir="mnt"
+mkdir -p "$mount_dir"
+
+# generate random data
+dd if=/dev/urandom of=pattern1 bs=512K count=1
+
+aux prepare_devs 4 301
+
+vgcreate $vg "$dev1" "$dev2" "$dev3" "$dev4"
+
+
+# Create writecache without a specified name so it gets automatic name
+lvcreate -n $lv1 -L 300 -an $vg "$dev1"
+lvcreate -y --type writecache -l 4 --cachevol $lv1 $vg "$dev2"
+check lv_exists $vg lvol0
+lvremove -y $vg
+
+#
+# Test pvmove with writecache
+#
+
+lvcreate -n $lv1 -L 300 -an $vg "$dev1" "$dev4"
+lvcreate -n $lv2 -l 4 -an $vg "$dev2"
+
+lvconvert -y --type writecache --cachevol $lv2 $vg/$lv1
+
+lvchange -ay $vg/$lv1
+mkfs_mount_umount $lv1
+
+# cannot pvmove the cachevol
+not pvmove "$dev2" "$dev3"
+
+# can pvmove the origin
+pvmove "$dev1" "$dev3"
+
+mount_umount $lv1
+
+# can pvmove the origin, naming the lv with the writecache
+pvmove -n $vg/$lv1 "$dev3" "$dev1"
+
+mount_umount $lv1
+lvchange -an $vg/$lv1
+lvremove -y $vg/$lv1
+
+
+#
+# Test partial and degraded activation
+#
+
+lvcreate -n $lv1 -l 16 -an $vg "$dev1" "$dev2"
+lvcreate -n $lv2 -l 16 -an $vg "$dev3" "$dev4"
+
+lvconvert -y --type writecache --cachevol $lv2 $vg/$lv1
+lvs -a -o+devices $vg
+lvchange -an $vg/$lv1
+
+aux hide_dev "$dev1"
+not lvchange -ay $vg/$lv1
+not lvchange -ay --partial $vg/$lv1
+not lvchange -ay --activationmode degraded $vg/$lv1
+aux unhide_dev "$dev1"
+lvchange -ay $vg/$lv1
+lvchange -an $vg/$lv1
+
+aux hide_dev "$dev3"
+not lvchange -ay $vg/$lv1
+not lvchange -ay --partial $vg/$lv1
+not lvchange -ay --activationmode degraded $vg/$lv1
+aux unhide_dev "$dev3"
+lvchange -ay $vg/$lv1
+lvchange -an $vg/$lv1
+
+vgremove -ff $vg
diff --git a/test/shell/writecache-split.sh b/test/shell/writecache-split.sh
new file mode 100644
index 0000000..c68f29b
--- /dev/null
+++ b/test/shell/writecache-split.sh
@@ -0,0 +1,265 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2018 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+# Test single lv cache options
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+mkfs_mount_umount()
+{
+ lvt=$1
+
+ mkfs.xfs -f -s size=4096 "$DM_DEV_DIR/$vg/$lvt"
+ mount "$DM_DEV_DIR/$vg/$lvt" "$mount_dir"
+ cp pattern1 "$mount_dir/pattern1"
+ dd if=/dev/zero of="$mount_dir/zeros2M" bs=1M count=32 conv=fdatasync
+ umount "$mount_dir"
+}
+
+mount_umount()
+{
+ lvt=$1
+
+ mount "$DM_DEV_DIR/$vg/$lvt" "$mount_dir"
+ diff pattern1 "$mount_dir/pattern1"
+ dd if="$mount_dir/zeros2M" of=/dev/null bs=1M count=32
+ umount "$mount_dir"
+}
+
+aux have_writecache 1 0 0 || skip
+which mkfs.xfs || skip
+
+mount_dir="mnt"
+mkdir -p "$mount_dir"
+
+# generate random data
+dd if=/dev/urandom of=pattern1 bs=512K count=1
+
+aux prepare_devs 4 301
+
+vgcreate $SHARED $vg "$dev1" "$dev2" "$dev3" "$dev4"
+
+lvcreate -n $lv1 -L 300 -an $vg "$dev1" "$dev4"
+lvcreate -n $lv2 -l 4 -an $vg "$dev2"
+
+#
+# split while inactive
+#
+
+lvconvert -y --type writecache --cachevol $lv2 $vg/$lv1
+
+lvchange -ay $vg/$lv1
+mkfs_mount_umount $lv1
+lvchange -an $vg/$lv1
+
+lvconvert --splitcache $vg/$lv1
+lvs -o segtype $vg/$lv1 | grep linear
+lvs -o segtype $vg/$lv2 | grep linear
+
+lvchange -ay $vg/$lv1
+mount_umount $lv1
+lvchange -an $vg/$lv1
+
+#
+# split while active
+#
+
+lvconvert -y --type writecache --cachevol $lv2 $vg/$lv1
+
+lvchange -ay $vg/$lv1
+mkfs_mount_umount $lv1
+
+lvconvert --splitcache $vg/$lv1
+lvs -o segtype $vg/$lv1 | grep linear
+lvs -o segtype $vg/$lv2 | grep linear
+
+mount_umount $lv1
+lvchange -an $vg/$lv1
+
+#
+# split while cachevol is missing
+#
+
+lvconvert -y --type writecache --cachevol $lv2 $vg/$lv1
+
+lvchange -ay $vg/$lv1
+mkfs_mount_umount $lv1
+lvchange -an $vg/$lv1
+
+aux disable_dev "$dev2"
+
+lvs -a -o+lv_health_status $vg |tee out
+grep $lv1 out | grep partial
+grep $lv2 out | grep partial
+check lv_attr_bit health $vg/$lv1 "p"
+
+not lvconvert --splitcache $vg/$lv1
+lvconvert --splitcache --force --yes $vg/$lv1
+
+lvs -o segtype $vg/$lv1 | grep linear
+
+aux enable_dev "$dev2"
+lvs -o segtype $vg/$lv2 | grep linear
+
+vgck --updatemetadata $vg
+lvs $vg
+vgchange -an $vg
+vgextend --restoremissing $vg "$dev2"
+
+
+#
+# split while cachevol has 1 of 2 PVs
+#
+
+lvremove $vg/$lv2
+lvcreate -n $lv2 -l 14 -an $vg "$dev2:0-10" "$dev3"
+
+lvconvert -y --type writecache --cachevol $lv2 $vg/$lv1
+
+lvchange -ay $vg/$lv1
+mkfs_mount_umount $lv1
+lvchange -an $vg/$lv1
+
+aux disable_dev "$dev3"
+
+lvs -a -o+lv_health_status $vg |tee out
+grep $lv1 out | grep partial
+grep $lv2 out | grep partial
+check lv_attr_bit health $vg/$lv1 "p"
+
+not lvconvert --splitcache $vg/$lv1
+lvconvert --splitcache --force --yes $vg/$lv1
+
+lvs -o segtype $vg/$lv1 | grep linear
+
+aux enable_dev "$dev3"
+lvs -o segtype $vg/$lv2 | grep linear
+
+vgck --updatemetadata $vg
+lvs $vg
+vgchange -an $vg
+vgextend --restoremissing $vg "$dev3"
+
+vgremove -ff $vg
+
+#
+# split while cachevol is damaged
+#
+
+vgcreate $SHARED $vg "$dev1" "$dev2" "$dev3" "$dev4"
+
+lvcreate -n $lv1 -L 300 -an $vg "$dev1" "$dev4"
+lvcreate -n $lv2 -l 4 -an $vg "$dev2"
+
+lvchange -ay $vg/$lv1
+
+mkfs_mount_umount $lv1
+
+lvconvert -y --type writecache --cachevol $lv2 $vg/$lv1
+
+mount "$DM_DEV_DIR/$vg/$lv1" "$mount_dir"
+diff pattern1 "$mount_dir/pattern1"
+cp pattern1 "$mount_dir/pattern2"
+umount "$mount_dir"
+lvchange -an $vg/$lv1
+
+dd if=/dev/zero of="$dev2" seek=1 bs=1M count=16
+
+lvconvert --splitcache --force --yes $vg/$lv1
+
+lvchange -ay $vg/$lv1
+
+mount "$DM_DEV_DIR/$vg/$lv1" "$mount_dir"
+diff pattern1 "$mount_dir/pattern1"
+umount "$mount_dir"
+lvchange -an $vg/$lv1
+
+vgremove -ff $vg
+
+#
+# splitcache when origin is raid
+#
+
+vgcreate $vg "$dev1" "$dev2" "$dev3" "$dev4"
+
+lvcreate --type raid1 -m1 -L6 -n $lv1 -an $vg "$dev1" "$dev2"
+lvcreate -L6 -n $lv2 -an $vg "$dev3"
+lvconvert -y --type writecache --cachevol $lv2 $vg/$lv1
+lvchange -ay $vg/$lv1
+lvchange -an $vg/$lv1
+lvconvert --splitcache $vg/$lv1
+lvs $vg/$lv1
+lvs $vg/$lv2
+
+vgremove -ff $vg
+
+#
+# vgsplit should not separate cachevol from main lv
+#
+
+vgcreate $vg "$dev1" "$dev2" "$dev3" "$dev4"
+lvcreate -L6 -n $lv1 -an $vg "$dev2"
+lvcreate -L6 -n $lv2 -an $vg "$dev3"
+lvconvert -y --type writecache --cachevol $lv2 $vg/$lv1
+fail vgsplit $vg $vg1 "$dev2"
+fail vgsplit $vg $vg1 "$dev3"
+lvremove $vg/$lv1
+vgremove $vg
+
+#
+# uncache
+#
+vgcreate $SHARED $vg "$dev1" "$dev2" "$dev3" "$dev4"
+
+# while inactive
+
+lvcreate -n $lv1 -L 300 -an $vg "$dev1" "$dev4"
+lvcreate -n $lv2 -l 4 -an $vg "$dev2"
+
+lvconvert -y --type writecache --cachevol $lv2 $vg/$lv1
+
+lvchange -ay $vg/$lv1
+mkfs_mount_umount $lv1
+lvchange -an $vg/$lv1
+
+lvconvert --uncache $vg/$lv1
+lvs -o segtype $vg/$lv1 | grep linear
+not lvs $vg/$lv2
+
+lvchange -ay $vg/$lv1
+mount_umount $lv1
+lvchange -an $vg/$lv1
+lvremove -y $vg/$lv1
+
+# while active
+
+lvcreate -n $lv1 -L 300 -an $vg "$dev1" "$dev4"
+lvcreate -n $lv2 -l 4 -an $vg "$dev2"
+
+lvconvert -y --type writecache --cachevol $lv2 $vg/$lv1
+
+lvchange -ay $vg/$lv1
+mkfs_mount_umount $lv1
+
+lvconvert --uncache $vg/$lv1
+lvs -o segtype $vg/$lv1 | grep linear
+not lvs $vg/$lv2
+
+lvchange -an $vg/$lv1
+lvchange -ay $vg/$lv1
+mount_umount $lv1
+lvchange -an $vg/$lv1
+lvremove -y $vg/$lv1
+
+vgremove -ff $vg
diff --git a/test/shell/writecache.sh b/test/shell/writecache.sh
new file mode 100644
index 0000000..9d1a5c0
--- /dev/null
+++ b/test/shell/writecache.sh
@@ -0,0 +1,272 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2018 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+# Test writecache usage
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+aux have_writecache 1 0 0 || skip
+which mkfs.xfs || skip
+
+# scsi_debug devices with 512 LBS 512 PBS
+aux prepare_scsi_debug_dev 602
+check sysfs "$(< SCSI_DEBUG_DEV)" queue/logical_block_size "512"
+check sysfs "$(< SCSI_DEBUG_DEV)" queue/physical_block_size "512"
+aux prepare_devs 2 301
+
+# Tests with fs block sizes require a libblkid version that shows BLOCK_SIZE
+vgcreate $vg "$dev1"
+lvcreate -n $lv1 -L 300 $vg
+mkfs.xfs -f "$DM_DEV_DIR/$vg/$lv1"
+blkid -p "$DM_DEV_DIR/$vg/$lv1" | grep BLOCK_SIZE || skip
+lvchange -an $vg
+vgremove -ff $vg
+
+# scsi_debug devices with 512 LBS and 4K PBS
+#aux prepare_scsi_debug_dev 256 sector_size=512 physblk_exp=3
+#check sysfs "$(< SCSI_DEBUG_DEV)" queue/logical_block_size "512"
+#check sysfs "$(< SCSI_DEBUG_DEV)" queue/physical_block_size "4096"
+#aux prepare_devs 2 64
+
+# loop devs with 512 LBS and 512 PBS
+#dd if=/dev/zero of=loopa bs=$((1024*1024)) count=64 2> /dev/null
+#dd if=/dev/zero of=loopb bs=$((1024*1024)) count=64 2> /dev/null
+#LOOP1=$(losetup -f loopa --show)
+#LOOP2=$(losetup -f loopb --show)
+#aux extend_filter "a|$LOOP1|"
+#aux extend_filter "a|$LOOP2|"
+#aux lvmconf 'devices/scan = "/dev"'
+#dev1=$LOOP1
+#dev2=$LOOP2
+
+# loop devs with 4096 LBS and 4096 PBS
+#dd if=/dev/zero of=loopa bs=$((1024*1024)) count=64 2> /dev/null
+#dd if=/dev/zero of=loopb bs=$((1024*1024)) count=64 2> /dev/null
+#LOOP1=$(losetup -f loopa --sector-size 4096 --show)
+#LOOP2=$(losetup -f loopb --sector-size 4096 --show)
+#aux extend_filter "a|$LOOP1|"
+#aux extend_filter "a|$LOOP2|"
+#aux lvmconf 'devices/scan = "/dev"'
+#dev1=$LOOP1
+#dev2=$LOOP2
+
+# the default is brd ram devs with 512 LBS 4K PBS
+# aux prepare_devs 2 64
+
+blockdev --getss "$dev1"
+blockdev --getpbsz "$dev1"
+blockdev --getss "$dev2"
+blockdev --getpbsz "$dev2"
+
+
+mnt="mnt"
+mkdir -p $mnt
+
+awk 'BEGIN { while (z++ < 16384) printf "A" }' > fileA
+awk 'BEGIN { while (z++ < 16384) printf "B" }' > fileB
+awk 'BEGIN { while (z++ < 16384) printf "C" }' > fileC
+
+# generate random data
+dd if=/dev/urandom of=randA bs=512K count=2
+dd if=/dev/urandom of=randB bs=512K count=3
+dd if=/dev/urandom of=randC bs=512K count=4
+
+_add_new_data_to_mnt() {
+ mkfs.xfs -f "$DM_DEV_DIR/$vg/$lv1"
+
+ mount "$DM_DEV_DIR/$vg/$lv1" $mnt
+
+ # add original data
+ cp randA $mnt
+ cp randB $mnt
+ cp randC $mnt
+ mkdir $mnt/1
+ cp fileA $mnt/1
+ cp fileB $mnt/1
+ cp fileC $mnt/1
+ mkdir $mnt/2
+ cp fileA $mnt/2
+ cp fileB $mnt/2
+ cp fileC $mnt/2
+ sync
+}
+
+_add_more_data_to_mnt() {
+ mkdir $mnt/more
+ cp fileA $mnt/more
+ cp fileB $mnt/more
+ cp fileC $mnt/more
+ cp randA $mnt/more
+ cp randB $mnt/more
+ cp randC $mnt/more
+ sync
+}
+
+_verify_data_on_mnt() {
+ diff randA $mnt/randA
+ diff randB $mnt/randB
+ diff randC $mnt/randC
+ diff fileA $mnt/1/fileA
+ diff fileB $mnt/1/fileB
+ diff fileC $mnt/1/fileC
+ diff fileA $mnt/2/fileA
+ diff fileB $mnt/2/fileB
+ diff fileC $mnt/2/fileC
+}
+
+_verify_more_data_on_mnt() {
+ diff randA $mnt/more/randA
+ diff randB $mnt/more/randB
+ diff randC $mnt/more/randC
+ diff fileA $mnt/more/fileA
+ diff fileB $mnt/more/fileB
+ diff fileC $mnt/more/fileC
+}
+
+_verify_data_on_lv() {
+ lvchange -ay $vg/$lv1
+ mount "$DM_DEV_DIR/$vg/$lv1" $mnt
+ _verify_data_on_mnt
+ rm $mnt/randA
+ rm $mnt/randB
+ rm $mnt/randC
+ rm -rf $mnt/1
+ rm -rf $mnt/2
+ umount $mnt
+ lvchange -an $vg/$lv1
+}
+
+
+vgcreate $SHARED $vg "$dev1"
+vgextend $vg "$dev2"
+
+blockdev --getss "$dev1"
+blockdev --getpbsz "$dev1"
+blockdev --getss "$dev2"
+blockdev --getpbsz "$dev2"
+
+# Test attach while inactive, detach while inactive
+# create fs on LV before writecache is attached
+
+lvcreate -n $lv1 -L 300 -an $vg "$dev1"
+lvcreate -n $lv2 -l 4 -an $vg "$dev2"
+lvchange -ay $vg/$lv1
+_add_new_data_to_mnt
+umount $mnt
+lvchange -an $vg/$lv1
+lvconvert --yes --type writecache --cachevol $lv2 $vg/$lv1
+check lv_field $vg/$lv1 segtype writecache
+lvs -a $vg/${lv2}_cvol --noheadings -o segtype >out
+grep linear out
+lvchange -ay $vg/$lv1
+blockdev --getss "$DM_DEV_DIR/$vg/$lv1"
+blockdev --getpbsz "$DM_DEV_DIR/$vg/$lv1"
+mount "$DM_DEV_DIR/$vg/$lv1" $mnt
+_add_more_data_to_mnt
+_verify_data_on_mnt
+_verify_more_data_on_mnt
+umount $mnt
+lvchange -an $vg/$lv1
+lvconvert --splitcache $vg/$lv1
+check lv_field $vg/$lv1 segtype linear
+check lv_field $vg/$lv2 segtype linear
+lvchange -ay $vg/$lv1
+blockdev --getss "$DM_DEV_DIR/$vg/$lv1"
+blockdev --getpbsz "$DM_DEV_DIR/$vg/$lv1"
+lvchange -an $vg/$lv1
+_verify_data_on_lv
+lvchange -an $vg/$lv2
+lvremove $vg/$lv1
+lvremove $vg/$lv2
+
+# Test attach while inactive, detach while inactive
+# create fs on LV after writecache is attached
+
+lvcreate -n $lv1 -L 300 -an $vg "$dev1"
+lvcreate -n $lv2 -l 4 -an $vg "$dev2"
+lvconvert --yes --type writecache --cachevol $lv2 $vg/$lv1
+check lv_field $vg/$lv1 segtype writecache
+lvs -a $vg/${lv2}_cvol --noheadings -o segtype >out
+grep linear out
+lvchange -ay $vg/$lv1
+blockdev --getss "$DM_DEV_DIR/$vg/$lv1"
+blockdev --getpbsz "$DM_DEV_DIR/$vg/$lv1"
+_add_new_data_to_mnt
+umount $mnt
+lvchange -an $vg/$lv1
+lvconvert --splitcache $vg/$lv1
+lvchange -ay $vg/$lv1
+blockdev --getss "$DM_DEV_DIR/$vg/$lv1"
+blockdev --getpbsz "$DM_DEV_DIR/$vg/$lv1"
+mount "$DM_DEV_DIR/$vg/$lv1" $mnt
+_add_more_data_to_mnt
+_verify_data_on_mnt
+_verify_more_data_on_mnt
+umount $mnt
+lvchange -an $vg/$lv1
+_verify_data_on_lv
+lvremove $vg/$lv1
+lvremove $vg/$lv2
+
+# Test attach while active, detach while active
+
+lvcreate -n $lv1 -L 300 -an $vg "$dev1"
+lvcreate -n $lv2 -l 4 -an $vg "$dev2"
+lvchange -ay $vg/$lv1
+_add_new_data_to_mnt
+lvconvert --yes --type writecache --cachevol $lv2 $vg/$lv1
+blockdev --getss "$DM_DEV_DIR/$vg/$lv1"
+blockdev --getpbsz "$DM_DEV_DIR/$vg/$lv1"
+_add_more_data_to_mnt
+_verify_data_on_mnt
+lvconvert --splitcache $vg/$lv1
+check lv_field $vg/$lv1 segtype linear
+check lv_field $vg/$lv2 segtype linear
+blockdev --getss "$DM_DEV_DIR/$vg/$lv1"
+blockdev --getpbsz "$DM_DEV_DIR/$vg/$lv1"
+_verify_data_on_mnt
+_verify_more_data_on_mnt
+umount $mnt
+lvchange -an $vg/$lv1
+lvchange -an $vg/$lv2
+_verify_data_on_lv
+lvremove $vg/$lv1
+lvremove $vg/$lv2
+
+# Test attach while active, detach while active,
+# skip cleaner so flush message is used instead
+lvcreate -n $lv1 -L 300 -an $vg "$dev1"
+lvcreate -n $lv2 -l 4 -an $vg "$dev2"
+lvchange -ay $vg/$lv1
+_add_new_data_to_mnt
+lvconvert --yes --type writecache --cachevol $lv2 $vg/$lv1
+blockdev --getss "$DM_DEV_DIR/$vg/$lv1"
+blockdev --getpbsz "$DM_DEV_DIR/$vg/$lv1"
+_add_more_data_to_mnt
+_verify_data_on_mnt
+lvconvert --splitcache --cachesettings cleaner=0 $vg/$lv1
+check lv_field $vg/$lv1 segtype linear
+check lv_field $vg/$lv2 segtype linear
+blockdev --getss "$DM_DEV_DIR/$vg/$lv1"
+blockdev --getpbsz "$DM_DEV_DIR/$vg/$lv1"
+_verify_data_on_mnt
+_verify_more_data_on_mnt
+umount $mnt
+lvchange -an $vg/$lv1
+lvchange -an $vg/$lv2
+_verify_data_on_lv
+lvremove $vg/$lv1
+lvremove $vg/$lv2
+
+vgremove -ff $vg
diff --git a/test/shell/zero-usage.sh b/test/shell/zero-usage.sh
new file mode 100644
index 0000000..063f018
--- /dev/null
+++ b/test/shell/zero-usage.sh
@@ -0,0 +1,46 @@
+#!/bin/bash
+# Copyright (C) 2014 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+# Basic usage of zero target
+
+
+SKIP_WITH_LVMPOLLD=1
+
+. lib/inittest
+
+which md5sum || skip
+
+aux prepare_vg 1
+
+lvcreate --type zero -L1 -n $lv1 $vg
+lvextend -L+1 $vg/$lv1
+
+sum1=$(dd if=/dev/zero bs=2M count=1 | md5sum | cut -f1 -d' ')
+sum2=$(dd if="$DM_DEV_DIR/$vg/$lv1" bs=2M count=1 | md5sum | cut -f1 -d' ')
+
+# has to match
+test "$sum1" = "$sum2"
+
+check lv_field $vg/$lv1 lv_modules "zero"
+check lv_field $vg/$lv1 segtype "zero"
+check lv_field $vg/$lv1 seg_count "1"
+check lv_field $vg/$lv1 seg_size_pe "4" # 4 * 512
+
+lvextend -L+1 --type error $vg/$lv1
+lvextend -L+1 --type linear $vg/$lv1
+lvextend -L+1 --type striped $vg/$lv1
+lvextend -L+1 --type zero $vg/$lv1
+
+lvs -o+segtype,seg_size $vg
+check lv_field $vg/$lv1 seg_count "4"
+check lv_field $vg/$lv1 size "6.00m"
+
+vgremove -ff $vg
diff --git a/test/shell/zz-lvmlockd-dlm-remove.sh b/test/shell/zz-lvmlockd-dlm-remove.sh
new file mode 100644
index 0000000..c7dfb1d
--- /dev/null
+++ b/test/shell/zz-lvmlockd-dlm-remove.sh
@@ -0,0 +1,30 @@
+#!/usr/bin/env bash
+
+# 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+test_description='Remove the dlm test setup'
+
+. lib/inittest
+
+[ -z "$LVM_TEST_LOCK_TYPE_DLM" ] && skip;
+
+# FIXME: collect debug logs (only if a test failed?)
+# lvmlockctl -d > lvmlockd-debug.txt
+# dlm_tool dump > dlm-debug.txt
+
+lvmlockctl --stop-lockspaces
+sleep 1
+killall lvmlockd
+sleep 1
+killall lvmlockd || true
+sleep 1
+systemctl stop dlm
+systemctl stop corosync
diff --git a/test/shell/zz-lvmlockd-idm-remove.sh b/test/shell/zz-lvmlockd-idm-remove.sh
new file mode 100644
index 0000000..25943a5
--- /dev/null
+++ b/test/shell/zz-lvmlockd-idm-remove.sh
@@ -0,0 +1,29 @@
+#!/usr/bin/env bash
+
+# Copyright (C) 2021 Seagate. 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 v2.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+test_description='Remove the idm test setup'
+
+. lib/inittest
+
+[ -z "$LVM_TEST_LOCK_TYPE_IDM" ] && skip;
+
+# FIXME: collect debug logs (only if a test failed?)
+# lvmlockctl -d > lvmlockd-debug.txt
+# dlm_tool dump > dlm-debug.txt
+
+lvmlockctl --stop-lockspaces
+sleep 1
+killall lvmlockd
+sleep 1
+killall lvmlockd || true
+sleep 1
+killall seagate_ilm
diff --git a/test/shell/zz-lvmlockd-sanlock-remove.sh b/test/shell/zz-lvmlockd-sanlock-remove.sh
new file mode 100644
index 0000000..081ee69
--- /dev/null
+++ b/test/shell/zz-lvmlockd-sanlock-remove.sh
@@ -0,0 +1,45 @@
+#!/usr/bin/env bash
+
+# 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+test_description='Remove the sanlock test setup'
+
+. lib/inittest
+
+[ -z "$LVM_TEST_LOCK_TYPE_SANLOCK" ] && skip;
+
+# FIMXME: get this to run after a test fails
+
+# Removes the VG with the global lock that was created by
+# the corresponding create script.
+
+vgremove --config 'devices { global_filter=["a|GL_DEV|", "r|.*|"] filter=["a|GL_DEV|", "r|.*|"]}' glvg
+
+# FIXME: collect debug logs (only if a test failed?)
+# lvmlockctl -d > lvmlockd-debug.txt
+# sanlock log_dump > sanlock-debug.txt
+
+lvmlockctl --stop-lockspaces
+sleep 1
+killall lvmlockd
+sleep 1
+killall lvmlockd || true
+sleep 1
+killall sanlock
+sleep 1
+killall -9 lvmlockd || true
+killall -9 sanlock || true
+
+# FIXME: dmsetup remove LVMTEST*-lvmlock
+
+dmsetup remove glvg-lvmlock || true
+dmsetup remove GL_DEV || true
+
diff --git a/test/unit/Makefile b/test/unit/Makefile
new file mode 100644
index 0000000..05e2501
--- /dev/null
+++ b/test/unit/Makefile
@@ -0,0 +1,65 @@
+# Copyright (C) 2011-2018 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+# NOTE: this Makefile only works as 'include' for toplevel Makefile
+# which defined all top_* variables
+
+UNIT_SOURCE=\
+ device_mapper/vdo/status.c \
+ \
+ test/unit/bcache_t.c \
+ test/unit/bcache_utils_t.c \
+ test/unit/bitset_t.c \
+ test/unit/config_t.c \
+ test/unit/dmlist_t.c \
+ test/unit/dmstatus_t.c \
+ test/unit/framework.c \
+ test/unit/io_engine_t.c \
+ test/unit/matcher_t.c \
+ test/unit/percent_t.c \
+ test/unit/radix_tree_t.c \
+ test/unit/run.c \
+ test/unit/string_t.c \
+ test/unit/vdo_t.c
+
+test/unit/radix_tree_t.o: test/unit/rt_case1.c
+
+UNIT_TARGET = test/unit/unit-test
+UNIT_DEPENDS = $(UNIT_SOURCE:%.c=%.d)
+UNIT_OBJECTS = $(UNIT_SOURCE:%.c=%.o)
+CLEAN_TARGETS += $(UNIT_DEPENDS) $(UNIT_OBJECTS) \
+ $(UNIT_SOURCE:%.c=%.gcda) \
+ $(UNIT_SOURCE:%.c=%.gcno) \
+ $(UNIT_TARGET)
+
+lib/liblvm-internal.a: lib
+libdaemon/client/libdaemonclient.a: libdaemon
+
+$(UNIT_TARGET): $(UNIT_OBJECTS) $(LVMINTERNAL_LIBS)
+ @echo " [LD] $@"
+ $(Q) $(CC) $(CFLAGS) $(LDFLAGS) $(EXTRA_EXEC_LDFLAGS) \
+ -o $@ $+ $(LVMLIBS)
+
+.PHONY: run-unit-test unit-test
+unit-test: $(UNIT_TARGET)
+run-unit-test: $(UNIT_TARGET)
+ @echo "Running unit tests"
+ test -n "$$LVM_TEST_DIR" || LVM_TEST_DIR=$${TMPDIR:-/tmp} ;\
+ TESTDIR=$$(mktemp -d -t -p "$$LVM_TEST_DIR" "LVMTEST.XXXXXXXXXX") ;\
+ cd "$$TESTDIR" ;\
+ LD_LIBRARY_PATH=$(abs_top_builddir)/libdm:$(abs_top_builddir)/daemons/dmeventd $(abs_top_builddir)/$(UNIT_TARGET) run ;\
+ cd $$OLDPWD ;\
+ $(RM) -r "$${TESTDIR:?}"
+
+ifeq ("$(DEPENDS)","yes")
+-include $(UNIT_SOURCE:%.c=%.d)
+endif
diff --git a/test/unit/Makefile.in b/test/unit/Makefile.in
deleted file mode 100644
index 740eb14..0000000
--- a/test/unit/Makefile.in
+++ /dev/null
@@ -1,33 +0,0 @@
-# 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/bcache_t.c b/test/unit/bcache_t.c
new file mode 100644
index 0000000..2668d3f
--- /dev/null
+++ b/test/unit/bcache_t.c
@@ -0,0 +1,1036 @@
+/*
+ * Copyright (C) 2018 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "units.h"
+#include "lib/device/bcache.h"
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#define SHOW_MOCK_CALLS 0
+
+/*----------------------------------------------------------------
+ * Mock engine
+ *--------------------------------------------------------------*/
+struct mock_engine {
+ struct io_engine e;
+ struct dm_list expected_calls;
+ struct dm_list issued_io;
+ unsigned max_io;
+ sector_t block_size;
+};
+
+enum method {
+ E_DESTROY,
+ E_ISSUE,
+ E_WAIT,
+ E_MAX_IO
+};
+
+struct mock_call {
+ struct dm_list list;
+ enum method m;
+
+ bool match_args;
+ enum dir d;
+ int di;
+ block_address b;
+ bool issue_r;
+ bool wait_r;
+};
+
+struct mock_io {
+ struct dm_list list;
+ int di;
+ sector_t sb;
+ sector_t se;
+ void *data;
+ void *context;
+ bool r;
+};
+
+static const char *_show_method(enum method m)
+{
+ switch (m) {
+ case E_DESTROY:
+ return "destroy()";
+ case E_ISSUE:
+ return "issue()";
+ case E_WAIT:
+ return "wait()";
+ case E_MAX_IO:
+ return "max_io()";
+ }
+
+ return "<unknown>";
+}
+
+static void _expect(struct mock_engine *e, enum method m)
+{
+ struct mock_call *mc = malloc(sizeof(*mc));
+
+ T_ASSERT(mc);
+ mc->m = m;
+ mc->match_args = false;
+ dm_list_add(&e->expected_calls, &mc->list);
+}
+
+static void _expect_read(struct mock_engine *e, int di, block_address b)
+{
+ struct mock_call *mc = malloc(sizeof(*mc));
+
+ T_ASSERT(mc);
+ mc->m = E_ISSUE;
+ mc->match_args = true;
+ mc->d = DIR_READ;
+ mc->di = di;
+ mc->b = b;
+ mc->issue_r = true;
+ mc->wait_r = true;
+ dm_list_add(&e->expected_calls, &mc->list);
+}
+
+static void _expect_read_any(struct mock_engine *e)
+{
+ struct mock_call *mc = malloc(sizeof(*mc));
+
+ T_ASSERT(mc);
+ mc->m = E_ISSUE;
+ mc->match_args = false;
+ mc->issue_r = true;
+ mc->wait_r = true;
+ dm_list_add(&e->expected_calls, &mc->list);
+}
+
+static void _expect_write(struct mock_engine *e, int di, block_address b)
+{
+ struct mock_call *mc = malloc(sizeof(*mc));
+
+ T_ASSERT(mc);
+ mc->m = E_ISSUE;
+ mc->match_args = true;
+ mc->d = DIR_WRITE;
+ mc->di = di;
+ mc->b = b;
+ mc->issue_r = true;
+ mc->wait_r = true;
+ dm_list_add(&e->expected_calls, &mc->list);
+}
+
+static void _expect_read_bad_issue(struct mock_engine *e, int di, block_address b)
+{
+ struct mock_call *mc = malloc(sizeof(*mc));
+
+ T_ASSERT(mc);
+ mc->m = E_ISSUE;
+ mc->match_args = true;
+ mc->d = DIR_READ;
+ mc->di = di;
+ mc->b = b;
+ mc->issue_r = false;
+ mc->wait_r = true;
+ dm_list_add(&e->expected_calls, &mc->list);
+}
+
+static void _expect_write_bad_issue(struct mock_engine *e, int di, block_address b)
+{
+ struct mock_call *mc = malloc(sizeof(*mc));
+
+ T_ASSERT(mc);
+ mc->m = E_ISSUE;
+ mc->match_args = true;
+ mc->d = DIR_WRITE;
+ mc->di = di;
+ mc->b = b;
+ mc->issue_r = false;
+ mc->wait_r = true;
+ dm_list_add(&e->expected_calls, &mc->list);
+}
+
+static void _expect_read_bad_wait(struct mock_engine *e, int di, block_address b)
+{
+ struct mock_call *mc = malloc(sizeof(*mc));
+
+ T_ASSERT(mc);
+ mc->m = E_ISSUE;
+ mc->match_args = true;
+ mc->d = DIR_READ;
+ mc->di = di;
+ mc->b = b;
+ mc->issue_r = true;
+ mc->wait_r = false;
+ dm_list_add(&e->expected_calls, &mc->list);
+}
+
+static void _expect_write_bad_wait(struct mock_engine *e, int di, block_address b)
+{
+ struct mock_call *mc = malloc(sizeof(*mc));
+
+ T_ASSERT(mc);
+ mc->m = E_ISSUE;
+ mc->match_args = true;
+ mc->d = DIR_WRITE;
+ mc->di = di;
+ mc->b = b;
+ mc->issue_r = true;
+ mc->wait_r = false;
+ dm_list_add(&e->expected_calls, &mc->list);
+}
+
+static struct mock_call *_match_pop(struct mock_engine *e, enum method m)
+{
+
+ struct mock_call *mc;
+
+ if (dm_list_empty(&e->expected_calls))
+ test_fail("unexpected call to method %s\n", _show_method(m));
+
+ mc = dm_list_item(e->expected_calls.n, struct mock_call);
+ dm_list_del(&mc->list);
+
+ if (mc->m != m)
+ test_fail("expected %s, but got %s\n", _show_method(mc->m), _show_method(m));
+#if SHOW_MOCK_CALLS
+ else
+ fprintf(stderr, "%s called (expected)\n", _show_method(m));
+#endif
+
+ return mc;
+}
+
+static void _match(struct mock_engine *e, enum method m)
+{
+ free(_match_pop(e, m));
+}
+
+static void _no_outstanding_expectations(struct mock_engine *e)
+{
+ struct mock_call *mc;
+
+ if (!dm_list_empty(&e->expected_calls)) {
+ fprintf(stderr, "unsatisfied expectations:\n");
+ dm_list_iterate_items (mc, &e->expected_calls)
+ fprintf(stderr, " %s\n", _show_method(mc->m));
+ }
+ T_ASSERT(dm_list_empty(&e->expected_calls));
+}
+
+static struct mock_engine *_to_mock(struct io_engine *e)
+{
+ return container_of(e, struct mock_engine, e);
+}
+
+static void _mock_destroy(struct io_engine *e)
+{
+ struct mock_engine *me = _to_mock(e);
+
+ _match(me, E_DESTROY);
+ T_ASSERT(dm_list_empty(&me->issued_io));
+ T_ASSERT(dm_list_empty(&me->expected_calls));
+ free(_to_mock(e));
+}
+
+static bool _mock_issue(struct io_engine *e, enum dir d, int di,
+ sector_t sb, sector_t se, void *data, void *context)
+{
+ bool r, wait_r;
+ struct mock_io *io;
+ struct mock_call *mc;
+ struct mock_engine *me = _to_mock(e);
+
+ mc = _match_pop(me, E_ISSUE);
+ if (mc->match_args) {
+ T_ASSERT(d == mc->d);
+ T_ASSERT(di == mc->di);
+ T_ASSERT(sb == mc->b * me->block_size);
+ T_ASSERT(se == (mc->b + 1) * me->block_size);
+ }
+ r = mc->issue_r;
+ wait_r = mc->wait_r;
+ free(mc);
+
+ if (r) {
+ io = malloc(sizeof(*io));
+ if (!io)
+ abort();
+
+ io->di = di;
+ io->sb = sb;
+ io->se = se;
+ io->data = data;
+ io->context = context;
+ io->r = wait_r;
+
+ dm_list_add(&me->issued_io, &io->list);
+ }
+
+ return r;
+}
+
+static bool _mock_wait(struct io_engine *e, io_complete_fn fn)
+{
+ struct mock_io *io;
+ struct mock_engine *me = _to_mock(e);
+ _match(me, E_WAIT);
+
+ // FIXME: provide a way to control how many are completed and whether
+ // they error.
+ T_ASSERT(!dm_list_empty(&me->issued_io));
+ io = dm_list_item(me->issued_io.n, struct mock_io);
+ dm_list_del(&io->list);
+ fn(io->context, io->r ? 0 : -EIO);
+ free(io);
+
+ return true;
+}
+
+static unsigned _mock_max_io(struct io_engine *e)
+{
+ struct mock_engine *me = _to_mock(e);
+ _match(me, E_MAX_IO);
+ return me->max_io;
+}
+
+static struct mock_engine *_mock_create(unsigned max_io, sector_t block_size)
+{
+ struct mock_engine *m = malloc(sizeof(*m));
+
+ T_ASSERT(m);
+
+ m->e.destroy = _mock_destroy;
+ m->e.issue = _mock_issue;
+ m->e.wait = _mock_wait;
+ m->e.max_io = _mock_max_io;
+
+ m->max_io = max_io;
+ m->block_size = block_size;
+ dm_list_init(&m->expected_calls);
+ dm_list_init(&m->issued_io);
+
+ return m;
+}
+
+/*----------------------------------------------------------------
+ * Fixtures
+ *--------------------------------------------------------------*/
+struct fixture {
+ struct mock_engine *me;
+ struct bcache *cache;
+};
+
+static struct fixture *_fixture_init(sector_t block_size, unsigned nr_cache_blocks)
+{
+ struct fixture *f = malloc(sizeof(*f));
+
+ T_ASSERT(f);
+
+ f->me = _mock_create(16, block_size);
+ T_ASSERT(f->me);
+
+ _expect(f->me, E_MAX_IO);
+ f->cache = bcache_create(block_size, nr_cache_blocks, &f->me->e);
+ T_ASSERT(f->cache);
+
+ return f;
+}
+
+static void _fixture_exit(struct fixture *f)
+{
+ if (f) {
+ _expect(f->me, E_DESTROY);
+ bcache_destroy(f->cache);
+
+ free(f);
+ }
+}
+
+static void *_small_fixture_init(void)
+{
+ return _fixture_init(128, 16);
+}
+
+static void _small_fixture_exit(void *context)
+{
+ _fixture_exit(context);
+}
+
+static void *_large_fixture_init(void)
+{
+ return _fixture_init(128, 1024);
+}
+
+static void _large_fixture_exit(void *context)
+{
+ _fixture_exit(context);
+}
+
+/*----------------------------------------------------------------
+ * Tests
+ *--------------------------------------------------------------*/
+#define MEG 2048
+#define SECTOR_SHIFT 9
+#define PAGE_SIZE_SECTORS ((PAGE_SIZE) >> SECTOR_SHIFT)
+
+static void good_create(sector_t block_size, unsigned nr_cache_blocks)
+{
+ struct bcache *cache;
+ struct mock_engine *me = _mock_create(16, 128);
+
+ _expect(me, E_MAX_IO);
+ cache = bcache_create(block_size, nr_cache_blocks, &me->e);
+ T_ASSERT(cache);
+
+ _expect(me, E_DESTROY);
+ bcache_destroy(cache);
+}
+
+static void bad_create(sector_t block_size, unsigned nr_cache_blocks)
+{
+ struct bcache *cache;
+ struct mock_engine *me = _mock_create(16, 128);
+
+ _expect(me, E_MAX_IO);
+ cache = bcache_create(block_size, nr_cache_blocks, &me->e);
+ T_ASSERT(!cache);
+
+ _expect(me, E_DESTROY);
+ me->e.destroy(&me->e);
+}
+
+static void test_create(void *fixture)
+{
+ good_create(PAGE_SIZE_SECTORS, 16);
+}
+
+static void test_nr_cache_blocks_must_be_positive(void *fixture)
+{
+ bad_create(PAGE_SIZE_SECTORS, 0);
+}
+
+static void test_block_size_must_be_positive(void *fixture)
+{
+ bad_create(0, 16);
+}
+
+static void test_block_size_must_be_multiple_of_page_size(void *fixture)
+{
+ static unsigned _bad_examples[] = {3, 9, 13, 1025};
+
+ unsigned i;
+
+ for (i = 0; i < DM_ARRAY_SIZE(_bad_examples); i++)
+ bad_create(_bad_examples[i], 16);
+
+ for (i = 1; i < 100; i++)
+ good_create(i * PAGE_SIZE_SECTORS, 16);
+}
+
+static void test_get_triggers_read(void *context)
+{
+ struct fixture *f = context;
+
+ int di = 17; // arbitrary key
+ struct block *b;
+
+ _expect_read(f->me, di, 0);
+ _expect(f->me, E_WAIT);
+ T_ASSERT(bcache_get(f->cache, di, 0, 0, &b));
+ bcache_put(b);
+
+ _expect_read(f->me, di, 1);
+ _expect(f->me, E_WAIT);
+ T_ASSERT(bcache_get(f->cache, di, 1, GF_DIRTY, &b));
+ _expect_write(f->me, di, 1);
+ _expect(f->me, E_WAIT);
+ bcache_put(b);
+}
+
+static void test_repeated_reads_are_cached(void *context)
+{
+ struct fixture *f = context;
+
+ int di = 17; // arbitrary key
+ unsigned i;
+ struct block *b;
+
+ _expect_read(f->me, di, 0);
+ _expect(f->me, E_WAIT);
+ for (i = 0; i < 100; i++) {
+ T_ASSERT(bcache_get(f->cache, di, 0, 0, &b));
+ bcache_put(b);
+ }
+}
+
+static void test_block_gets_evicted_with_many_reads(void *context)
+{
+ struct fixture *f = context;
+
+ struct mock_engine *me = f->me;
+ struct bcache *cache = f->cache;
+ const unsigned nr_cache_blocks = 16;
+
+ int di = 17; // arbitrary key
+ unsigned i;
+ struct block *b;
+
+ for (i = 0; i < nr_cache_blocks; i++) {
+ _expect_read(me, di, i);
+ _expect(me, E_WAIT);
+ T_ASSERT(bcache_get(cache, di, i, 0, &b));
+ bcache_put(b);
+ }
+
+ // Not enough cache blocks to hold this one
+ _expect_read(me, di, nr_cache_blocks);
+ _expect(me, E_WAIT);
+ T_ASSERT(bcache_get(cache, di, nr_cache_blocks, 0, &b));
+ bcache_put(b);
+
+ // Now if we run through we should find one block has been
+ // evicted. We go backwards because the oldest is normally
+ // evicted first.
+ _expect_read_any(me);
+ _expect(me, E_WAIT);
+ for (i = nr_cache_blocks; i; i--) {
+ T_ASSERT(bcache_get(cache, di, i - 1, 0, &b));
+ bcache_put(b);
+ }
+}
+
+static void test_prefetch_issues_a_read(void *context)
+{
+ struct fixture *f = context;
+ struct mock_engine *me = f->me;
+ struct bcache *cache = f->cache;
+ const unsigned nr_cache_blocks = 16;
+
+ int di = 17; // arbitrary key
+ unsigned i;
+ struct block *b;
+
+ for (i = 0; i < nr_cache_blocks; i++) {
+ // prefetch should not wait
+ _expect_read(me, di, i);
+ bcache_prefetch(cache, di, i);
+ }
+ _no_outstanding_expectations(me);
+
+ for (i = 0; i < nr_cache_blocks; i++) {
+ _expect(me, E_WAIT);
+ T_ASSERT(bcache_get(cache, di, i, 0, &b));
+ bcache_put(b);
+ }
+}
+
+static void test_too_many_prefetches_does_not_trigger_a_wait(void *context)
+{
+ struct fixture *f = context;
+ struct mock_engine *me = f->me;
+ struct bcache *cache = f->cache;
+
+ const unsigned nr_cache_blocks = 16;
+ int di = 17; // arbitrary key
+ unsigned i;
+
+ for (i = 0; i < 10 * nr_cache_blocks; i++) {
+ // prefetch should not wait
+ if (i < nr_cache_blocks)
+ _expect_read(me, di, i);
+ bcache_prefetch(cache, di, i);
+ }
+
+ // Destroy will wait for any in flight IO triggered by prefetches.
+ for (i = 0; i < nr_cache_blocks; i++)
+ _expect(me, E_WAIT);
+}
+
+static void test_dirty_data_gets_written_back(void *context)
+{
+ struct fixture *f = context;
+ struct mock_engine *me = f->me;
+ struct bcache *cache = f->cache;
+
+ int di = 17; // arbitrary key
+ struct block *b;
+
+ // Expect the read
+ _expect_read(me, di, 0);
+ _expect(me, E_WAIT);
+ T_ASSERT(bcache_get(cache, di, 0, GF_DIRTY, &b));
+ bcache_put(b);
+
+ // Expect the write
+ _expect_write(me, di, 0);
+ _expect(me, E_WAIT);
+}
+
+static void test_zeroed_data_counts_as_dirty(void *context)
+{
+ struct fixture *f = context;
+ struct mock_engine *me = f->me;
+ struct bcache *cache = f->cache;
+
+ int di = 17; // arbitrary key
+ struct block *b;
+
+ // No read
+ T_ASSERT(bcache_get(cache, di, 0, GF_ZERO, &b));
+ bcache_put(b);
+
+ // Expect the write
+ _expect_write(me, di, 0);
+ _expect(me, E_WAIT);
+}
+
+static void test_flush_waits_for_all_dirty(void *context)
+{
+ struct fixture *f = context;
+ struct mock_engine *me = f->me;
+ struct bcache *cache = f->cache;
+
+ const unsigned count = 16;
+ int di = 17; // arbitrary key
+ unsigned i;
+ struct block *b;
+
+ for (i = 0; i < count; i++) {
+ if (i % 2) {
+ T_ASSERT(bcache_get(cache, di, i, GF_ZERO, &b));
+ } else {
+ _expect_read(me, di, i);
+ _expect(me, E_WAIT);
+ T_ASSERT(bcache_get(cache, di, i, 0, &b));
+ }
+ bcache_put(b);
+ }
+
+ for (i = 0; i < count; i++) {
+ if (i % 2)
+ _expect_write(me, di, i);
+ }
+
+ for (i = 0; i < count; i++) {
+ if (i % 2)
+ _expect(me, E_WAIT);
+ }
+
+ T_ASSERT(bcache_flush(cache));
+ _no_outstanding_expectations(me);
+}
+
+static void test_multiple_files(void *context)
+{
+ static int _dis[] = {1, 128, 345, 678, 890};
+
+ struct fixture *f = context;
+ struct mock_engine *me = f->me;
+ struct bcache *cache = f->cache;
+ struct block *b;
+ unsigned i;
+
+ for (i = 0; i < DM_ARRAY_SIZE(_dis); i++) {
+ _expect_read(me, _dis[i], 0);
+ _expect(me, E_WAIT);
+
+ T_ASSERT(bcache_get(cache, _dis[i], 0, 0, &b));
+ bcache_put(b);
+ }
+}
+
+static void test_read_bad_issue(void *context)
+{
+ struct fixture *f = context;
+ struct mock_engine *me = f->me;
+ struct bcache *cache = f->cache;
+ struct block *b;
+
+ _expect_read_bad_issue(me, 17, 0);
+ T_ASSERT(!bcache_get(cache, 17, 0, 0, &b));
+}
+
+static void test_read_bad_issue_intermittent(void *context)
+{
+ struct fixture *f = context;
+ struct mock_engine *me = f->me;
+ struct bcache *cache = f->cache;
+ struct block *b;
+ int di = 17;
+
+ _expect_read_bad_issue(me, di, 0);
+ T_ASSERT(!bcache_get(cache, di, 0, 0, &b));
+
+ _expect_read(me, di, 0);
+ _expect(me, E_WAIT);
+ T_ASSERT(bcache_get(cache, di, 0, 0, &b));
+ bcache_put(b);
+}
+
+static void test_read_bad_wait(void *context)
+{
+ struct fixture *f = context;
+ struct mock_engine *me = f->me;
+ struct bcache *cache = f->cache;
+ struct block *b;
+ int di = 17;
+
+ _expect_read_bad_wait(me, di, 0);
+ _expect(me, E_WAIT);
+ T_ASSERT(!bcache_get(cache, di, 0, 0, &b));
+}
+
+static void test_read_bad_wait_intermittent(void *context)
+{
+ struct fixture *f = context;
+ struct mock_engine *me = f->me;
+ struct bcache *cache = f->cache;
+ struct block *b;
+ int di = 17;
+
+ _expect_read_bad_wait(me, di, 0);
+ _expect(me, E_WAIT);
+ T_ASSERT(!bcache_get(cache, di, 0, 0, &b));
+
+ _expect_read(me, di, 0);
+ _expect(me, E_WAIT);
+ T_ASSERT(bcache_get(cache, di, 0, 0, &b));
+ bcache_put(b);
+}
+
+static void test_write_bad_issue_stops_flush(void *context)
+{
+ struct fixture *f = context;
+ struct mock_engine *me = f->me;
+ struct bcache *cache = f->cache;
+ struct block *b;
+ int di = 17;
+
+ T_ASSERT(bcache_get(cache, di, 0, GF_ZERO, &b));
+ _expect_write_bad_issue(me, di, 0);
+ bcache_put(b);
+ T_ASSERT(!bcache_flush(cache));
+
+ // we'll let it succeed the second time
+ _expect_write(me, di, 0);
+ _expect(me, E_WAIT);
+ T_ASSERT(bcache_flush(cache));
+}
+
+static void test_write_bad_io_stops_flush(void *context)
+{
+ struct fixture *f = context;
+ struct mock_engine *me = f->me;
+ struct bcache *cache = f->cache;
+ struct block *b;
+ int di = 17;
+
+ T_ASSERT(bcache_get(cache, di, 0, GF_ZERO, &b));
+ _expect_write_bad_wait(me, di, 0);
+ _expect(me, E_WAIT);
+ bcache_put(b);
+ T_ASSERT(!bcache_flush(cache));
+
+ // we'll let it succeed the second time
+ _expect_write(me, di, 0);
+ _expect(me, E_WAIT);
+ T_ASSERT(bcache_flush(cache));
+}
+
+static void test_invalidate_not_present(void *context)
+{
+ struct fixture *f = context;
+ struct bcache *cache = f->cache;
+ int di = 17;
+
+ T_ASSERT(bcache_invalidate(cache, di, 0));
+}
+
+static void test_invalidate_present(void *context)
+{
+ struct fixture *f = context;
+ struct mock_engine *me = f->me;
+ struct bcache *cache = f->cache;
+ struct block *b;
+ int di = 17;
+
+ _expect_read(me, di, 0);
+ _expect(me, E_WAIT);
+ T_ASSERT(bcache_get(cache, di, 0, 0, &b));
+ bcache_put(b);
+
+ T_ASSERT(bcache_invalidate(cache, di, 0));
+}
+
+static void test_invalidate_after_read_error(void *context)
+{
+ struct fixture *f = context;
+ struct mock_engine *me = f->me;
+ struct bcache *cache = f->cache;
+ struct block *b;
+ int di = 17;
+
+ _expect_read_bad_issue(me, di, 0);
+ T_ASSERT(!bcache_get(cache, di, 0, 0, &b));
+ T_ASSERT(bcache_invalidate(cache, di, 0));
+}
+
+static void test_invalidate_after_write_error(void *context)
+{
+ struct fixture *f = context;
+ struct mock_engine *me = f->me;
+ struct bcache *cache = f->cache;
+ struct block *b;
+ int di = 17;
+
+ T_ASSERT(bcache_get(cache, di, 0, GF_ZERO, &b));
+ bcache_put(b);
+
+ // invalidate should fail if the write fails
+ _expect_write_bad_wait(me, di, 0);
+ _expect(me, E_WAIT);
+ T_ASSERT(!bcache_invalidate(cache, di, 0));
+
+ // and should succeed if the write does
+ _expect_write(me, di, 0);
+ _expect(me, E_WAIT);
+ T_ASSERT(bcache_invalidate(cache, di, 0));
+
+ // a read is not required to get the block
+ _expect_read(me, di, 0);
+ _expect(me, E_WAIT);
+ T_ASSERT(bcache_get(cache, di, 0, 0, &b));
+ bcache_put(b);
+}
+
+static void test_invalidate_held_block(void *context)
+{
+ struct fixture *f = context;
+ struct mock_engine *me = f->me;
+ struct bcache *cache = f->cache;
+ struct block *b;
+ int di = 17;
+
+ T_ASSERT(bcache_get(cache, di, 0, GF_ZERO, &b));
+
+ T_ASSERT(!bcache_invalidate(cache, di, 0));
+
+ _expect_write(me, di, 0);
+ _expect(me, E_WAIT);
+ bcache_put(b);
+}
+
+//----------------------------------------------------------------
+// abort tests
+
+static void test_abort_no_blocks(void *context)
+{
+ struct fixture *f = context;
+ struct bcache *cache = f->cache;
+ int di = 17;
+
+ // We have no expectations
+ bcache_abort_di(cache, di);
+}
+
+static void test_abort_single_block(void *context)
+{
+ struct fixture *f = context;
+ struct bcache *cache = f->cache;
+ struct block *b;
+ int di = 17;
+
+ T_ASSERT(bcache_get(cache, di, 0, GF_ZERO, &b));
+ bcache_put(b);
+
+ bcache_abort_di(cache, di);
+
+ // no write should be issued
+ T_ASSERT(bcache_flush(cache));
+}
+
+static void test_abort_forces_reread(void *context)
+{
+ struct fixture *f = context;
+ struct mock_engine *me = f->me;
+ struct bcache *cache = f->cache;
+ struct block *b;
+ int di = 17;
+
+ _expect_read(me, di, 0);
+ _expect(me, E_WAIT);
+ T_ASSERT(bcache_get(cache, di, 0, GF_DIRTY, &b));
+ bcache_put(b);
+
+ bcache_abort_di(cache, di);
+ T_ASSERT(bcache_flush(cache));
+
+ // Check the block is re-read
+ _expect_read(me, di, 0);
+ _expect(me, E_WAIT);
+ T_ASSERT(bcache_get(cache, di, 0, 0, &b));
+ bcache_put(b);
+}
+
+static void test_abort_only_specific_di(void *context)
+{
+ struct fixture *f = context;
+ struct mock_engine *me = f->me;
+ struct bcache *cache = f->cache;
+ struct block *b;
+ int di1 = 17, di2 = 18;
+
+ T_ASSERT(bcache_get(cache, di1, 0, GF_ZERO, &b));
+ bcache_put(b);
+
+ T_ASSERT(bcache_get(cache, di1, 1, GF_ZERO, &b));
+ bcache_put(b);
+
+ T_ASSERT(bcache_get(cache, di2, 0, GF_ZERO, &b));
+ bcache_put(b);
+
+ T_ASSERT(bcache_get(cache, di2, 1, GF_ZERO, &b));
+ bcache_put(b);
+
+ bcache_abort_di(cache, di2);
+
+ // writes for di1 should still be issued
+ _expect_write(me, di1, 0);
+ _expect_write(me, di1, 1);
+
+ _expect(me, E_WAIT);
+ _expect(me, E_WAIT);
+
+ T_ASSERT(bcache_flush(cache));
+}
+
+//----------------------------------------------------------------
+// Chasing a bug reported by dct
+
+static void _cycle(struct fixture *f, unsigned nr_cache_blocks)
+{
+ struct mock_engine *me = f->me;
+ struct bcache *cache = f->cache;
+
+ unsigned i;
+ struct block *b;
+
+ for (i = 0; i < nr_cache_blocks; i++) {
+ // prefetch should not wait
+ _expect_read(me, i, 0);
+ bcache_prefetch(cache, i, 0);
+ }
+
+ // This double checks the reads occur in response to the prefetch
+ _no_outstanding_expectations(me);
+
+ for (i = 0; i < nr_cache_blocks; i++) {
+ _expect(me, E_WAIT);
+ T_ASSERT(bcache_get(cache, i, 0, 0, &b));
+ bcache_put(b);
+ }
+
+ _no_outstanding_expectations(me);
+}
+
+static void test_concurrent_reads_after_invalidate(void *context)
+{
+ struct fixture *f = context;
+ unsigned i, nr_cache_blocks = 16;
+
+ _cycle(f, nr_cache_blocks);
+ for (i = 0; i < nr_cache_blocks; i++)
+ bcache_invalidate_di(f->cache, i);
+ _cycle(f, nr_cache_blocks);
+}
+
+/*----------------------------------------------------------------
+ * Top level
+ *--------------------------------------------------------------*/
+#define T(path, desc, fn) register_test(ts, "/base/device/bcache/" path, desc, fn)
+
+static struct test_suite *_tiny_tests(void)
+{
+ struct test_suite *ts = test_suite_create(NULL, NULL);
+ if (!ts) {
+ fprintf(stderr, "out of memory\n");
+ exit(1);
+ }
+
+ T("create-destroy", "simple create/destroy", test_create);
+ T("cache-blocks-positive", "nr cache blocks must be positive", test_nr_cache_blocks_must_be_positive);
+ T("block-size-positive", "block size must be positive", test_block_size_must_be_positive);
+ T("block-size-multiple-page", "block size must be a multiple of page size", test_block_size_must_be_multiple_of_page_size);
+
+ return ts;
+}
+
+static struct test_suite *_small_tests(void)
+{
+ struct test_suite *ts = test_suite_create(_small_fixture_init, _small_fixture_exit);
+ if (!ts) {
+ fprintf(stderr, "out of memory\n");
+ exit(1);
+ }
+
+ T("get-reads", "bcache_get() triggers read", test_get_triggers_read);
+ T("reads-cached", "repeated reads are cached", test_repeated_reads_are_cached);
+ T("blocks-get-evicted", "block get evicted with many reads", test_block_gets_evicted_with_many_reads);
+ T("prefetch-reads", "prefetch issues a read", test_prefetch_issues_a_read);
+ T("prefetch-never-waits", "too many prefetches does not trigger a wait", test_too_many_prefetches_does_not_trigger_a_wait);
+ T("writeback-occurs", "dirty data gets written back", test_dirty_data_gets_written_back);
+ T("zero-flag-dirties", "zeroed data counts as dirty", test_zeroed_data_counts_as_dirty);
+ T("read-multiple-files", "read from multiple files", test_multiple_files);
+ T("read-bad-issue", "read fails if io engine unable to issue", test_read_bad_issue);
+ T("read-bad-issue-intermittent", "failed issue, followed by succes", test_read_bad_issue_intermittent);
+ T("read-bad-io", "read issued ok, but io fails", test_read_bad_wait);
+ T("read-bad-io-intermittent", "failed io, followed by success", test_read_bad_wait_intermittent);
+ T("write-bad-issue-stops-flush", "flush fails temporarily if any block fails to write", test_write_bad_issue_stops_flush);
+ T("write-bad-io-stops-flush", "flush fails temporarily if any block fails to write", test_write_bad_io_stops_flush);
+ T("invalidate-not-present", "invalidate a block that isn't in the cache", test_invalidate_not_present);
+ T("invalidate-present", "invalidate a block that is in the cache", test_invalidate_present);
+ T("invalidate-read-error", "invalidate a block that errored", test_invalidate_after_read_error);
+ T("invalidate-write-error", "invalidate a block that errored", test_invalidate_after_write_error);
+ T("invalidate-fails-in-held", "invalidating a held block fails", test_invalidate_held_block);
+
+ T("abort-with-no-blocks", "you can call abort, even if there are no blocks in the cache", test_abort_no_blocks);
+ T("abort-single-block", "single block get silently discarded", test_abort_single_block);
+ T("abort-forces-read", "if a block has been discarded then another read is necc.", test_abort_forces_reread);
+ T("abort-specific-di", "abort doesn't effect other dis", test_abort_only_specific_di);
+
+ T("concurrent-reads-after-invalidate", "prefetch should still issue concurrent reads after invalidate",
+ test_concurrent_reads_after_invalidate);
+
+ return ts;
+}
+
+static struct test_suite *_large_tests(void)
+{
+ struct test_suite *ts = test_suite_create(_large_fixture_init, _large_fixture_exit);
+ if (!ts) {
+ fprintf(stderr, "out of memory\n");
+ exit(1);
+ }
+
+ T("flush-waits", "flush waits for all dirty", test_flush_waits_for_all_dirty);
+
+ return ts;
+}
+
+void bcache_tests(struct dm_list *all_tests)
+{
+ dm_list_add(all_tests, &_tiny_tests()->list);
+ dm_list_add(all_tests, &_small_tests()->list);
+ dm_list_add(all_tests, &_large_tests()->list);
+}
diff --git a/test/unit/bcache_utils_t.c b/test/unit/bcache_utils_t.c
new file mode 100644
index 0000000..f052924
--- /dev/null
+++ b/test/unit/bcache_utils_t.c
@@ -0,0 +1,474 @@
+/*
+ * Copyright (C) 2018 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "units.h"
+#include "lib/device/bcache.h"
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/statvfs.h>
+
+//----------------------------------------------------------------
+
+#define T_BLOCK_SIZE (PAGE_SIZE)
+#define NR_BLOCKS 64
+#define INIT_PATTERN 123
+
+struct fixture {
+ int fd;
+ int di;
+ char fname[32];
+ struct bcache *cache;
+};
+
+static inline uint8_t _pattern_at(uint8_t pat, uint8_t byte)
+{
+ return pat + byte;
+}
+
+static uint64_t byte(block_address b, uint64_t offset)
+{
+ return b * T_BLOCK_SIZE + offset;
+}
+
+static void *_fix_init(struct io_engine *engine)
+{
+ uint8_t buffer[T_BLOCK_SIZE];
+ struct fixture *f = malloc(sizeof(*f));
+ unsigned b, i;
+ static int _runs_is_tmpfs = -1;
+
+ memset(buffer, 0, sizeof(buffer));
+ T_ASSERT(f);
+
+ if (_runs_is_tmpfs == -1) {
+ snprintf(f->fname, sizeof(f->fname), "unit-test-XXXXXX");
+ /* coverity[secure_temp] don't care */
+ f->fd = mkstemp(f->fname);
+ T_ASSERT(f->fd >= 0);
+ (void) close(f->fd);
+ // test if we can reopen with O_DIRECT
+ if ((f->fd = open(f->fname, O_RDWR | O_DIRECT)) >= 0) {
+ _runs_is_tmpfs = 0;
+ (void) close(f->fd);
+ } else {
+ _runs_is_tmpfs = 1; // likely running on tmpfs
+ printf(" Running test in tmpfs, *NOT* using O_DIRECT\n");
+ }
+ (void) unlink(f->fname);
+ }
+
+ snprintf(f->fname, sizeof(f->fname), "unit-test-XXXXXX");
+ /* coverity[secure_temp] don't care */
+ f->fd = mkstemp(f->fname);
+ T_ASSERT(f->fd >= 0);
+
+ for (b = 0; b < NR_BLOCKS; b++) {
+ for (i = 0; i < sizeof(buffer); i++)
+ buffer[i] = _pattern_at(INIT_PATTERN, byte(b, i));
+ T_ASSERT(write(f->fd, buffer, T_BLOCK_SIZE) > 0);
+ }
+
+ if (!_runs_is_tmpfs) {
+ (void) close(f->fd);
+ // reopen with O_DIRECT
+ f->fd = open(f->fname, O_RDWR | O_DIRECT);
+ T_ASSERT(f->fd >= 0);
+ }
+
+ f->cache = bcache_create(T_BLOCK_SIZE / 512, NR_BLOCKS, engine);
+ T_ASSERT(f->cache);
+
+ f->di = bcache_set_fd(f->fd);
+
+ return f;
+}
+
+static void *_async_init(void)
+{
+ struct io_engine *e = create_async_io_engine();
+ T_ASSERT(e);
+ return _fix_init(e);
+}
+
+static void *_sync_init(void)
+{
+ struct io_engine *e = create_sync_io_engine();
+ T_ASSERT(e);
+ return _fix_init(e);
+}
+
+static void _fix_exit(void *fixture)
+{
+ struct fixture *f = fixture;
+
+ if (f) {
+ bcache_destroy(f->cache);
+ (void) close(f->fd);
+ bcache_clear_fd(f->di);
+ (void) unlink(f->fname);
+ free(f);
+ }
+}
+
+//----------------------------------------------------------------
+
+static void _verify_bytes(struct block *b, uint64_t base,
+ uint64_t offset, uint64_t len, uint8_t pat)
+{
+ unsigned i;
+
+ for (i = 0; i < len; i++)
+ T_ASSERT_EQUAL(((uint8_t *) b->data)[offset + i], _pattern_at(pat, base + offset + i));
+}
+
+static uint64_t _min(uint64_t lhs, uint64_t rhs)
+{
+ return rhs < lhs ? rhs : lhs;
+}
+
+static void _verify(struct fixture *f, uint64_t byte_b, uint64_t byte_e, uint8_t pat)
+{
+ struct block *b;
+ block_address bb = byte_b / T_BLOCK_SIZE;
+ block_address be = (byte_e + T_BLOCK_SIZE - 1) / T_BLOCK_SIZE;
+ uint64_t offset = byte_b % T_BLOCK_SIZE;
+ uint64_t blen, len = byte_e - byte_b;
+
+ // Verify via bcache_read_bytes
+ {
+ unsigned i;
+ size_t len2 = byte_e - byte_b;
+ uint8_t *buffer = malloc(len2);
+
+ T_ASSERT(buffer);
+ memset(buffer, 0, len2);
+
+ T_ASSERT(bcache_read_bytes(f->cache, f->di, byte_b, len2, buffer));
+ for (i = 0; i < len; i++)
+ T_ASSERT_EQUAL(buffer[i], _pattern_at(pat, byte_b + i));
+ free(buffer);
+ }
+
+ // Verify again, driving bcache directly
+ for (; bb != be; bb++) {
+ T_ASSERT(bcache_get(f->cache, f->di, bb, 0, &b));
+
+ blen = _min(T_BLOCK_SIZE - offset, len);
+ _verify_bytes(b, bb * T_BLOCK_SIZE, offset, blen, pat);
+
+ offset = 0;
+ len -= blen;
+
+ bcache_put(b);
+ }
+}
+
+static void _verify_set(struct fixture *f, uint64_t byte_b, uint64_t byte_e, uint8_t val)
+{
+ unsigned i;
+ struct block *b;
+ block_address bb = byte_b / T_BLOCK_SIZE;
+ block_address be = (byte_e + T_BLOCK_SIZE - 1) / T_BLOCK_SIZE;
+ uint64_t offset = byte_b % T_BLOCK_SIZE;
+ uint64_t blen, len = byte_e - byte_b;
+
+ for (; bb != be; bb++) {
+ T_ASSERT(bcache_get(f->cache, f->di, bb, 0, &b));
+
+ blen = _min(T_BLOCK_SIZE - offset, len);
+ for (i = 0; i < blen; i++)
+ T_ASSERT(((uint8_t *) b->data)[offset + i] == val);
+
+ offset = 0;
+ len -= blen;
+
+ bcache_put(b);
+ }
+}
+
+static void _verify_zeroes(struct fixture *f, uint64_t byte_b, uint64_t byte_e)
+{
+ _verify_set(f, byte_b, byte_e, 0);
+}
+
+static void _do_write(struct fixture *f, uint64_t byte_b, uint64_t byte_e, uint8_t pat)
+{
+ unsigned i;
+ size_t len = byte_e - byte_b;
+ uint8_t *buffer = malloc(len);
+
+ T_ASSERT(buffer);
+ memset(buffer, 0, len);
+
+ for (i = 0; i < len; i++)
+ buffer[i] = _pattern_at(pat, byte_b + i);
+
+ T_ASSERT(bcache_write_bytes(f->cache, f->di, byte_b, byte_e - byte_b, buffer));
+ free(buffer);
+}
+
+static void _do_zero(struct fixture *f, uint64_t byte_b, uint64_t byte_e)
+{
+ T_ASSERT(bcache_zero_bytes(f->cache, f->di, byte_b, byte_e - byte_b));
+}
+
+static void _do_set(struct fixture *f, uint64_t byte_b, uint64_t byte_e, uint8_t val)
+{
+ T_ASSERT(bcache_set_bytes(f->cache, f->di, byte_b, byte_e - byte_b, val));
+}
+
+static void _reopen(struct fixture *f)
+{
+ struct io_engine *engine;
+
+ bcache_destroy(f->cache);
+ engine = create_async_io_engine();
+ T_ASSERT(engine);
+
+ f->cache = bcache_create(T_BLOCK_SIZE / 512, NR_BLOCKS, engine);
+ T_ASSERT(f->cache);
+
+ f->di = bcache_set_fd(f->fd);
+}
+
+//----------------------------------------------------------------
+
+static uint8_t _random_pattern(void)
+{
+ /* coverity[dont_call] don't care */
+ return random();
+}
+
+static uint64_t _max_byte(void)
+{
+ return T_BLOCK_SIZE * NR_BLOCKS;
+}
+
+static void _rwv_cycle(struct fixture *f, uint64_t b, uint64_t e)
+{
+ uint8_t pat = _random_pattern();
+
+ _verify(f, b, e, INIT_PATTERN);
+ _do_write(f, b, e, pat);
+ _reopen(f);
+ _verify(f, b < 128 ? 0 : b - 128, b, INIT_PATTERN);
+ _verify(f, b, e, pat);
+ _verify(f, e, _min(e + 128, _max_byte()), INIT_PATTERN);
+}
+
+static void _test_rw_first_block(void *fixture)
+{
+ _rwv_cycle(fixture, byte(0, 0), byte(0, T_BLOCK_SIZE));
+}
+
+static void _test_rw_last_block(void *fixture)
+{
+ uint64_t last_block = NR_BLOCKS - 1;
+ _rwv_cycle(fixture, byte(last_block, 0),
+ byte(last_block, T_BLOCK_SIZE));
+}
+
+static void _test_rw_several_whole_blocks(void *fixture)
+{
+ _rwv_cycle(fixture, byte(5, 0), byte(10, 0));
+}
+
+static void _test_rw_within_single_block(void *fixture)
+{
+ _rwv_cycle(fixture, byte(7, 3), byte(7, T_BLOCK_SIZE / 2));
+}
+
+static void _test_rw_cross_one_boundary(void *fixture)
+{
+ _rwv_cycle(fixture, byte(13, 43), byte(14, 43));
+}
+
+static void _test_rw_many_boundaries(void *fixture)
+{
+ _rwv_cycle(fixture, byte(13, 13), byte(23, 13));
+}
+
+//----------------------------------------------------------------
+
+static void _zero_cycle(struct fixture *f, uint64_t b, uint64_t e)
+{
+ _verify(f, b, e, INIT_PATTERN);
+ _do_zero(f, b, e);
+ _reopen(f);
+ _verify(f, b < 128 ? 0 : b - 128, b, INIT_PATTERN);
+ _verify_zeroes(f, b, e);
+ _verify(f, e, _min(e + 128, _max_byte()), INIT_PATTERN);
+}
+
+static void _test_zero_first_block(void *fixture)
+{
+ _zero_cycle(fixture, byte(0, 0), byte(0, T_BLOCK_SIZE));
+}
+
+static void _test_zero_last_block(void *fixture)
+{
+ uint64_t last_block = NR_BLOCKS - 1;
+ _zero_cycle(fixture, byte(last_block, 0), byte(last_block, T_BLOCK_SIZE));
+}
+
+static void _test_zero_several_whole_blocks(void *fixture)
+{
+ _zero_cycle(fixture, byte(5, 0), byte(10, 0));
+}
+
+static void _test_zero_within_single_block(void *fixture)
+{
+ _zero_cycle(fixture, byte(7, 3), byte(7, T_BLOCK_SIZE / 2));
+}
+
+static void _test_zero_cross_one_boundary(void *fixture)
+{
+ _zero_cycle(fixture, byte(13, 43), byte(14, 43));
+}
+
+static void _test_zero_many_boundaries(void *fixture)
+{
+ _zero_cycle(fixture, byte(13, 13), byte(23, 13));
+}
+
+//----------------------------------------------------------------
+
+static void _set_cycle(struct fixture *f, uint64_t b, uint64_t e)
+{
+ uint8_t val = _random_pattern();
+
+ _verify(f, b, e, INIT_PATTERN);
+ _do_set(f, b, e, val);
+ _reopen(f);
+ _verify(f, b < 128 ? 0 : b - 128, b, INIT_PATTERN);
+ _verify_set(f, b, e, val);
+ _verify(f, e, _min(e + 128, _max_byte()), INIT_PATTERN);
+}
+
+static void _test_set_first_block(void *fixture)
+{
+ _set_cycle(fixture, byte(0, 0), byte(0, T_BLOCK_SIZE));
+}
+
+static void _test_set_last_block(void *fixture)
+{
+ uint64_t last_block = NR_BLOCKS - 1;
+ _set_cycle(fixture, byte(last_block, 0), byte(last_block, T_BLOCK_SIZE));
+}
+
+static void _test_set_several_whole_blocks(void *fixture)
+{
+ _set_cycle(fixture, byte(5, 0), byte(10, 0));
+}
+
+static void _test_set_within_single_block(void *fixture)
+{
+ _set_cycle(fixture, byte(7, 3), byte(7, T_BLOCK_SIZE / 2));
+}
+
+static void _test_set_cross_one_boundary(void *fixture)
+{
+ _set_cycle(fixture, byte(13, 43), byte(14, 43));
+}
+
+static void _test_set_many_boundaries(void *fixture)
+{
+ _set_cycle(fixture, byte(13, 13), byte(23, 13));
+}
+
+//----------------------------------------------------------------
+
+#define T(path, desc, fn) register_test(ts, "/base/device/bcache/utils/async/" path, desc, fn)
+
+static struct test_suite *_async_tests(void)
+{
+ struct test_suite *ts = test_suite_create(_async_init, _fix_exit);
+ if (!ts) {
+ fprintf(stderr, "out of memory\n");
+ exit(1);
+ }
+
+#define T(path, desc, fn) register_test(ts, "/base/device/bcache/utils/async/" path, desc, fn)
+ T("rw-first-block", "read/write/verify the first block", _test_rw_first_block);
+ T("rw-last-block", "read/write/verify the last block", _test_rw_last_block);
+ T("rw-several-blocks", "read/write/verify several whole blocks", _test_rw_several_whole_blocks);
+ T("rw-within-single-block", "read/write/verify within single block", _test_rw_within_single_block);
+ T("rw-cross-one-boundary", "read/write/verify across one boundary", _test_rw_cross_one_boundary);
+ T("rw-many-boundaries", "read/write/verify many boundaries", _test_rw_many_boundaries);
+
+ T("zero-first-block", "zero the first block", _test_zero_first_block);
+ T("zero-last-block", "zero the last block", _test_zero_last_block);
+ T("zero-several-blocks", "zero several whole blocks", _test_zero_several_whole_blocks);
+ T("zero-within-single-block", "zero within single block", _test_zero_within_single_block);
+ T("zero-cross-one-boundary", "zero across one boundary", _test_zero_cross_one_boundary);
+ T("zero-many-boundaries", "zero many boundaries", _test_zero_many_boundaries);
+
+ T("set-first-block", "set the first block", _test_set_first_block);
+ T("set-last-block", "set the last block", _test_set_last_block);
+ T("set-several-blocks", "set several whole blocks", _test_set_several_whole_blocks);
+ T("set-within-single-block", "set within single block", _test_set_within_single_block);
+ T("set-cross-one-boundary", "set across one boundary", _test_set_cross_one_boundary);
+ T("set-many-boundaries", "set many boundaries", _test_set_many_boundaries);
+#undef T
+
+ return ts;
+}
+
+
+static struct test_suite *_sync_tests(void)
+{
+ struct test_suite *ts = test_suite_create(_sync_init, _fix_exit);
+ if (!ts) {
+ fprintf(stderr, "out of memory\n");
+ exit(1);
+ }
+
+#define T(path, desc, fn) register_test(ts, "/base/device/bcache/utils/sync/" path, desc, fn)
+ T("rw-first-block", "read/write/verify the first block", _test_rw_first_block);
+ T("rw-last-block", "read/write/verify the last block", _test_rw_last_block);
+ T("rw-several-blocks", "read/write/verify several whole blocks", _test_rw_several_whole_blocks);
+ T("rw-within-single-block", "read/write/verify within single block", _test_rw_within_single_block);
+ T("rw-cross-one-boundary", "read/write/verify across one boundary", _test_rw_cross_one_boundary);
+ T("rw-many-boundaries", "read/write/verify many boundaries", _test_rw_many_boundaries);
+
+ T("zero-first-block", "zero the first block", _test_zero_first_block);
+ T("zero-last-block", "zero the last block", _test_zero_last_block);
+ T("zero-several-blocks", "zero several whole blocks", _test_zero_several_whole_blocks);
+ T("zero-within-single-block", "zero within single block", _test_zero_within_single_block);
+ T("zero-cross-one-boundary", "zero across one boundary", _test_zero_cross_one_boundary);
+ T("zero-many-boundaries", "zero many boundaries", _test_zero_many_boundaries);
+
+ T("set-first-block", "set the first block", _test_set_first_block);
+ T("set-last-block", "set the last block", _test_set_last_block);
+ T("set-several-blocks", "set several whole blocks", _test_set_several_whole_blocks);
+ T("set-within-single-block", "set within single block", _test_set_within_single_block);
+ T("set-cross-one-boundary", "set across one boundary", _test_set_cross_one_boundary);
+ T("set-many-boundaries", "set many boundaries", _test_set_many_boundaries);
+#undef T
+
+ return ts;
+}
+
+void bcache_utils_tests(struct dm_list *all_tests)
+{
+ dm_list_add(all_tests, &_async_tests()->list);
+ dm_list_add(all_tests, &_sync_tests()->list);
+}
+
diff --git a/test/unit/bitset_t.c b/test/unit/bitset_t.c
index 499de32..1e74e12 100644
--- a/test/unit/bitset_t.c
+++ b/test/unit/bitset_t.c
@@ -9,38 +9,43 @@
*
* 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
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
-#include "libdevmapper.h"
-#include <CUnit/CUnit.h>
-
-int bitset_init(void);
-int bitset_fini(void);
+#include "units.h"
+#include "device_mapper/all.h"
enum {
NR_BITS = 137
};
-static struct dm_pool *mem;
+static void *_mem_init(void) {
+ struct dm_pool *mem = dm_pool_create("bitset test", 1024);
+ if (!mem) {
+ fprintf(stderr, "out of memory\n");
+ exit(1);
+ }
-int bitset_init(void) {
- mem = dm_pool_create("bitset test", 1024);
- return mem == NULL;
+ return mem;
}
-int bitset_fini(void) {
- dm_pool_destroy(mem);
- return 0;
+static void _mem_exit(void *mem)
+{
+ if (mem)
+ dm_pool_destroy(mem);
}
-static void test_get_next(void)
+static void test_get_next(void *fixture)
{
+ struct dm_pool *mem = fixture;
+
int i, j, last = 0, first;
dm_bitset_t bs = dm_bitset_create(mem, NR_BITS);
+ T_ASSERT(bs);
+
for (i = 0; i < NR_BITS; i++)
- CU_ASSERT(!dm_bit(bs, i));
+ T_ASSERT(!dm_bit(bs, i));
for (i = 0, j = 1; i < NR_BITS; i += j, j++)
dm_bit_set(bs, i);
@@ -53,10 +58,10 @@ static void test_get_next(void)
} else
last = dm_bit_get_next(bs, last);
- CU_ASSERT(last == i);
+ T_ASSERT(last == i);
}
- CU_ASSERT(dm_bit_get_next(bs, last) == -1);
+ T_ASSERT(dm_bit_get_next(bs, last) == -1);
}
static void bit_flip(dm_bitset_t bs, int bit)
@@ -68,37 +73,48 @@ static void bit_flip(dm_bitset_t bs, int bit)
dm_bit_set(bs, bit);
}
-static void test_equal(void)
+static void test_equal(void *fixture)
{
+ struct dm_pool *mem = fixture;
dm_bitset_t bs1 = dm_bitset_create(mem, NR_BITS);
dm_bitset_t bs2 = dm_bitset_create(mem, NR_BITS);
- int i, j;
+ int i, j;
+
+ T_ASSERT(bs1);
+ T_ASSERT(bs2);
+
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));
+ T_ASSERT(dm_bitset_equal(bs1, bs2));
+ T_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));
+ T_ASSERT(!dm_bitset_equal(bs1, bs2));
+ T_ASSERT(!dm_bitset_equal(bs2, bs1));
- CU_ASSERT(dm_bitset_equal(bs1, bs1)); /* comparing with self */
+ T_ASSERT(dm_bitset_equal(bs1, bs1)); /* comparing with self */
bit_flip(bs1, i);
}
}
-static void test_and(void)
+static void test_and(void *fixture)
{
+ struct dm_pool *mem = fixture;
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;
+ int i, j;
+
+ T_ASSERT(bs1);
+ T_ASSERT(bs2);
+ T_ASSERT(bs3);
+
for (i = 0, j = 1; i < NR_BITS; i += j, j++) {
dm_bit_set(bs1, i);
dm_bit_set(bs2, i);
@@ -106,9 +122,9 @@ static void test_and(void)
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));
+ T_ASSERT(dm_bitset_equal(bs1, bs2));
+ T_ASSERT(dm_bitset_equal(bs1, bs3));
+ T_ASSERT(dm_bitset_equal(bs2, bs3));
dm_bit_clear_all(bs1);
dm_bit_clear_all(bs2);
@@ -122,12 +138,23 @@ static void test_and(void)
dm_bit_and(bs3, bs1, bs2);
for (i = 0; i < NR_BITS; i++)
- CU_ASSERT(!dm_bit(bs3, i));
+ T_ASSERT(!dm_bit(bs3, i));
+}
+
+#define T(path, desc, fn) register_test(ts, "/base/data-struct/bitset/" path, desc, fn)
+
+void bitset_tests(struct dm_list *all_tests)
+{
+ struct test_suite *ts = test_suite_create(_mem_init, _mem_exit);
+ if (!ts) {
+ fprintf(stderr, "out of memory\n");
+ exit(1);
+ }
+
+ T("get_next", "get next set bit", test_get_next);
+ T("equal", "equality", test_equal);
+ T("and", "and all bits", test_and);
+
+ dm_list_add(all_tests, &ts->list);
}
-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
index 9a8b693..cd539ab 100644
--- a/test/unit/config_t.c
+++ b/test/unit/config_t.c
@@ -9,25 +9,26 @@
*
* 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
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
-#include "libdevmapper.h"
-#include <CUnit/CUnit.h>
+#include "units.h"
+#include "device_mapper/all.h"
-int config_init(void);
-int config_fini(void);
-
-static struct dm_pool *mem;
+static void *_mem_init(void)
+{
+ struct dm_pool *mem = dm_pool_create("config test", 1024);
+ if (!mem) {
+ fprintf(stderr, "out of memory\n");
+ exit(1);
+ }
-int config_init(void) {
- mem = dm_pool_create("config test", 1024);
- return mem == NULL;
+ return mem;
}
-int config_fini(void) {
+static void _mem_exit(void *mem)
+{
dm_pool_destroy(mem);
- return 0;
}
static const char *conf =
@@ -60,97 +61,120 @@ static const char *overlay =
" }\n"
"}\n";
-static void test_parse(void)
+static void test_parse(void *fixture)
{
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"));
+ T_ASSERT((long) tree);
+ T_ASSERT(dm_config_has_node(tree->root, "id"));
+ T_ASSERT(dm_config_has_node(tree->root, "physical_volumes"));
+ T_ASSERT(dm_config_has_node(tree->root, "physical_volumes/pv0"));
+ T_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"));
+ T_ASSERT(!strcmp(dm_config_find_str(tree->root, "id", "foo"), "yada-yada"));
+ T_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"));
+ T_ASSERT(!strcmp(dm_config_find_str(tree->root, "physical_volumes/pv0/bb", "foo"), "foo"));
+ T_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));
+ T_ASSERT(!dm_config_get_uint32(tree->root, "id", NULL));
+ T_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));
+ // T_ASSERT(!dm_config_get_list(tree->root, "id", NULL));
+ // T_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 */
+ T_ASSERT(dm_config_get_list(tree->root, "flags", &value));
+ T_ASSERT(value->next == NULL); /* an empty list */
+ T_ASSERT(dm_config_get_list(tree->root, "status", &value));
+ T_ASSERT(value->next != NULL); /* a non-empty list */
dm_config_destroy(tree);
}
-static void test_clone(void)
+static void test_clone(void *fixture)
{
struct dm_config_tree *tree = dm_config_from_string(conf);
- struct dm_config_node *n = dm_config_clone_node(tree, tree->root, 1);
+ struct dm_config_node *n;
const struct dm_config_value *value;
+ T_ASSERT(tree);
+
+ n = dm_config_clone_node(tree, tree->root, 1);
+
+ T_ASSERT(n);
+
/* 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"));
+ T_ASSERT(n != tree->root);
+ T_ASSERT(n->sib != tree->root->sib);
+ T_ASSERT(dm_config_find_node(n, "physical_volumes") != NULL);
+ T_ASSERT(dm_config_find_node(tree->root, "physical_volumes") != NULL);
+ T_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"));
+ T_ASSERT(dm_config_has_node(n, "id"));
+ T_ASSERT(dm_config_has_node(n, "physical_volumes"));
+ T_ASSERT(dm_config_has_node(n, "physical_volumes/pv0"));
+ T_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"));
+ T_ASSERT(!strcmp(dm_config_find_str(n, "id", "foo"), "yada-yada"));
+ T_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"));
+ T_ASSERT(!strcmp(dm_config_find_str(n, "physical_volumes/pv0/bb", "foo"), "foo"));
+ T_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));
+ T_ASSERT(!dm_config_get_uint32(n, "id", NULL));
+ T_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));
+ // T_ASSERT(!dm_config_get_list(tree->root, "id", NULL));
+ // T_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 */
+ T_ASSERT(dm_config_get_list(n, "flags", &value));
+ T_ASSERT(value->next == NULL); /* an empty list */
+ T_ASSERT(dm_config_get_list(n, "status", &value));
+ T_ASSERT(value->next != NULL); /* a non-empty list */
dm_config_destroy(tree);
}
-static void test_cascade(void)
+static void test_cascade(void *fixture)
{
struct dm_config_tree *t1 = dm_config_from_string(conf),
*t2 = dm_config_from_string(overlay),
- *tree = dm_config_insert_cascaded_tree(t2, t1);
+ *tree;
+
+ T_ASSERT(t1);
+ T_ASSERT(t2);
- 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"));
+ tree = dm_config_insert_cascaded_tree(t2, t1);
- 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"));
+ T_ASSERT(tree);
+
+ T_ASSERT(!strcmp(dm_config_tree_find_str(tree, "id", "foo"), "yoda-soda"));
+ T_ASSERT(!strcmp(dm_config_tree_find_str(tree, "idt", "foo"), "foo"));
+
+ T_ASSERT(!strcmp(dm_config_tree_find_str(tree, "physical_volumes/pv0/bb", "foo"), "foo"));
+ T_ASSERT(!strcmp(dm_config_tree_find_str(tree, "physical_volumes/pv1/id", "foo"), "hgfe-dcba"));
+ T_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
+#define T(path, desc, fn) register_test(ts, "/metadata/config/" path, desc, fn)
+
+void config_tests(struct dm_list *all_tests)
+{
+ struct test_suite *ts = test_suite_create(_mem_init, _mem_exit);
+ if (!ts) {
+ fprintf(stderr, "out of memory\n");
+ exit(1);
+ }
+
+ T("parse", "parsing various", test_parse);
+ T("clone", "duplicating a config tree", test_clone);
+ T("cascade", "cascade", test_cascade);
+
+ dm_list_add(all_tests, &ts->list);
};
diff --git a/test/unit/dmlist_t.c b/test/unit/dmlist_t.c
new file mode 100644
index 0000000..0e33385
--- /dev/null
+++ b/test/unit/dmlist_t.c
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2015 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "units.h"
+#include "device_mapper/all.h"
+
+static void test_dmlist_splice(void *fixture)
+{
+ unsigned i;
+ struct dm_list a[10];
+ struct dm_list list1;
+ struct dm_list list2;
+
+ dm_list_init(&list1);
+ dm_list_init(&list2);
+
+ for (i = 0; i < DM_ARRAY_SIZE(a); i++)
+ dm_list_add(&list1, &a[i]);
+
+ dm_list_splice(&list2, &list1);
+ T_ASSERT(dm_list_size(&list1) == 0);
+ T_ASSERT(dm_list_size(&list2) == 10);
+}
+
+#define T(path, desc, fn) register_test(ts, "/base/data-struct/list/" path, desc, fn)
+
+void dm_list_tests(struct dm_list *all_tests)
+{
+ struct test_suite *ts = test_suite_create(NULL, NULL);
+ if (!ts) {
+ fprintf(stderr, "out of memory\n");
+ exit(1);
+ }
+
+ T("splice", "joining lists together", test_dmlist_splice);
+
+ dm_list_add(all_tests, &ts->list);
+}
diff --git a/test/unit/dmstatus_t.c b/test/unit/dmstatus_t.c
new file mode 100644
index 0000000..ac2015e
--- /dev/null
+++ b/test/unit/dmstatus_t.c
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2015 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "units.h"
+#include "device_mapper/all.h"
+
+static void *_mem_init(void)
+{
+ struct dm_pool *mem = dm_pool_create("dmstatus test", 1024);
+ if (!mem) {
+ fprintf(stderr, "out of memory\n");
+ exit(1);
+ }
+
+ return mem;
+}
+
+static void _mem_exit(void *mem)
+{
+ dm_pool_destroy(mem);
+}
+
+static void _test_mirror_status(void *fixture)
+{
+ struct dm_pool *mem = fixture;
+ struct dm_status_mirror *s = NULL;
+
+ T_ASSERT(dm_get_status_mirror(mem,
+ "2 253:1 253:2 80/81 1 AD 3 disk 253:0 A",
+ &s));
+ if (s) {
+ T_ASSERT_EQUAL(s->total_regions, 81);
+ T_ASSERT_EQUAL(s->insync_regions, 80);
+ T_ASSERT_EQUAL(s->dev_count, 2);
+ T_ASSERT_EQUAL(s->devs[0].health, 'A');
+ T_ASSERT_EQUAL(s->devs[0].major, 253);
+ T_ASSERT_EQUAL(s->devs[0].minor, 1);
+ T_ASSERT_EQUAL(s->devs[1].health, 'D');
+ T_ASSERT_EQUAL(s->devs[1].major, 253);
+ T_ASSERT_EQUAL(s->devs[1].minor, 2);
+ T_ASSERT_EQUAL(s->log_count, 1);
+ T_ASSERT_EQUAL(s->logs[0].major, 253);
+ T_ASSERT_EQUAL(s->logs[0].minor, 0);
+ T_ASSERT_EQUAL(s->logs[0].health, 'A');
+ T_ASSERT(!strcmp(s->log_type, "disk"));
+ }
+
+ T_ASSERT(dm_get_status_mirror(mem,
+ "4 253:1 253:2 253:3 253:4 10/10 1 ADFF 1 core",
+ &s));
+ if (s) {
+ T_ASSERT_EQUAL(s->total_regions, 10);
+ T_ASSERT_EQUAL(s->insync_regions, 10);
+ T_ASSERT_EQUAL(s->dev_count, 4);
+ T_ASSERT_EQUAL(s->devs[3].minor, 4);
+ T_ASSERT_EQUAL(s->devs[3].health, 'F');
+ T_ASSERT_EQUAL(s->log_count, 0);
+ T_ASSERT(!strcmp(s->log_type, "core"));
+ }
+}
+
+void dm_status_tests(struct dm_list *all_tests)
+{
+ struct test_suite *ts = test_suite_create(_mem_init, _mem_exit);
+ if (!ts) {
+ fprintf(stderr, "out of memory\n");
+ exit(1);
+ }
+
+ register_test(ts, "/device-mapper/mirror/status", "parsing mirror status", _test_mirror_status);
+ dm_list_add(all_tests, &ts->list);
+}
+
diff --git a/test/unit/framework.c b/test/unit/framework.c
new file mode 100644
index 0000000..de9a8b1
--- /dev/null
+++ b/test/unit/framework.c
@@ -0,0 +1,66 @@
+#include "framework.h"
+
+/*----------------------------------------------------------------
+ * Assertions
+ *--------------------------------------------------------------*/
+
+jmp_buf test_k;
+#define TEST_FAILED 1
+
+void test_fail(const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ vfprintf(stderr, fmt, ap);
+ va_end(ap);
+ fprintf(stderr, "\n");
+
+ longjmp(test_k, TEST_FAILED);
+}
+
+struct test_suite *test_suite_create(void *(*fixture_init)(void),
+ void (*fixture_exit)(void *))
+{
+ struct test_suite *ts = malloc(sizeof(*ts));
+ if (ts) {
+ ts->fixture_init = fixture_init;
+ ts->fixture_exit = fixture_exit;
+ dm_list_init(&ts->tests);
+ }
+
+ return ts;
+}
+
+void test_suite_destroy(struct test_suite *ts)
+{
+ struct test_details *td, *tmp;
+
+ dm_list_iterate_items_safe (td, tmp, &ts->tests) {
+ dm_list_del(&td->list);
+ free(td);
+ }
+
+ free(ts);
+}
+
+bool register_test(struct test_suite *ts,
+ const char *path, const char *desc,
+ void (*fn)(void *))
+{
+ struct test_details *t = malloc(sizeof(*t));
+ if (!t) {
+ fprintf(stderr, "out of memory\n");
+ return false;
+ }
+
+ t->parent = ts;
+ t->path = path;
+ t->desc = desc;
+ t->fn = fn;
+ dm_list_add(&ts->tests, &t->list);
+
+ return true;
+}
+
+//-----------------------------------------------------------------
diff --git a/test/unit/framework.h b/test/unit/framework.h
new file mode 100644
index 0000000..f7f5b5b
--- /dev/null
+++ b/test/unit/framework.h
@@ -0,0 +1,51 @@
+#ifndef TEST_UNIT_FRAMEWORK_H
+#define TEST_UNIT_FRAMEWORK_H
+
+#include "device_mapper/all.h"
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <setjmp.h>
+
+//-----------------------------------------------------------------
+
+// A test suite gathers a set of tests with a common fixture together.
+struct test_suite {
+ struct dm_list list;
+
+ void *(*fixture_init)(void);
+ void (*fixture_exit)(void *);
+ struct dm_list tests;
+};
+
+struct test_details {
+ struct test_suite *parent;
+ struct dm_list list;
+
+ const char *path;
+ const char *desc;
+ void (*fn)(void *);
+};
+
+struct test_suite *test_suite_create(void *(*fixture_init)(void),
+ void (*fixture_exit)(void *));
+void test_suite_destroy(struct test_suite *ts);
+
+bool register_test(struct test_suite *ts,
+ const char *path, const char *desc, void (*fn)(void *));
+
+void test_fail(const char *fmt, ...)
+ __attribute__((noreturn, format (printf, 1, 2)));
+
+#define T_ASSERT(e) do {if (!(e)) {test_fail("assertion failed: '%s'", # e);} } while(0)
+#define T_ASSERT_EQUAL(x, y) T_ASSERT((x) == (y))
+#define T_ASSERT_NOT_EQUAL(x, y) T_ASSERT((x) != (y))
+
+extern jmp_buf test_k;
+#define TEST_FAILED 1
+
+#define PAGE_SIZE ({ int ps = sysconf(_SC_PAGESIZE); (ps > 0) ? ps : 4096 ; })
+
+//-----------------------------------------------------------------
+
+#endif
diff --git a/test/unit/io_engine_t.c b/test/unit/io_engine_t.c
new file mode 100644
index 0000000..2f6ea5b
--- /dev/null
+++ b/test/unit/io_engine_t.c
@@ -0,0 +1,229 @@
+/*
+ * Copyright (C) 2018 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "units.h"
+#include "lib/device/bcache.h"
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+//----------------------------------------------------------------
+
+#define SECTOR_SHIFT 9
+#define SECTOR_SIZE 512
+#define BLOCK_SIZE_SECTORS 8
+#define PAGE_SIZE_SECTORS ((PAGE_SIZE) >> SECTOR_SHIFT)
+#define NR_BLOCKS 64
+
+struct fixture {
+ struct io_engine *e;
+ uint8_t *data;
+
+ char fname[64];
+ int fd;
+ int di;
+};
+
+static void _fill_buffer(uint8_t *buffer, uint8_t seed, size_t count)
+{
+ unsigned i;
+ uint8_t b = seed;
+
+ for (i = 0; i < count; i++) {
+ buffer[i] = b;
+ b = ((b << 5) + b) + i;
+ }
+}
+
+static void _check_buffer(uint8_t *buffer, uint8_t seed, size_t count)
+{
+ unsigned i;
+ uint8_t b = seed;
+
+ for (i = 0; i < count; i++) {
+ T_ASSERT_EQUAL(buffer[i], b);
+ b = ((b << 5) + b) + i;
+ }
+}
+
+static void _print_buffer(const char *name, uint8_t *buffer, size_t count)
+{
+ unsigned col;
+
+ fprintf(stderr, "%s:\n", name);
+ while (count) {
+ for (col = 0; count && col < 20; col++) {
+ fprintf(stderr, "%x, ", (unsigned) *buffer);
+ col++;
+ buffer++;
+ count--;
+ }
+ fprintf(stderr, "\n");
+ }
+}
+
+static void *_fix_init(void)
+{
+ struct fixture *f = malloc(sizeof(*f));
+
+ T_ASSERT(f);
+ f->e = create_async_io_engine();
+ T_ASSERT(f->e);
+ if (posix_memalign((void **) &f->data, PAGE_SIZE, SECTOR_SIZE * BLOCK_SIZE_SECTORS))
+ test_fail("posix_memalign failed");
+
+ snprintf(f->fname, sizeof(f->fname), "unit-test-XXXXXX");
+ /* coverity[secure_temp] don't care */
+ f->fd = mkstemp(f->fname);
+ T_ASSERT(f->fd >= 0);
+
+ _fill_buffer(f->data, 123, SECTOR_SIZE * BLOCK_SIZE_SECTORS);
+
+ T_ASSERT(write(f->fd, f->data, SECTOR_SIZE * BLOCK_SIZE_SECTORS) > 0);
+ T_ASSERT(lseek(f->fd, 0, SEEK_SET) != -1);
+
+ return f;
+}
+
+static void _fix_exit(void *fixture)
+{
+ struct fixture *f = fixture;
+
+ if (f) {
+ (void) close(f->fd);
+ bcache_clear_fd(f->di);
+ (void) unlink(f->fname);
+ free(f->data);
+ if (f->e)
+ f->e->destroy(f->e);
+ free(f);
+ }
+}
+
+static void _test_create(void *fixture)
+{
+ // empty
+}
+
+struct io {
+ bool completed;
+ int error;
+};
+
+static void _io_init(struct io *io)
+{
+ io->completed = false;
+ io->error = 0;
+}
+
+static void _complete_io(void *context, int io_error)
+{
+ struct io *io = context;
+ io->completed = true;
+ io->error = io_error;
+}
+
+static void _test_read(void *fixture)
+{
+ struct fixture *f = fixture;
+ struct io io;
+ struct bcache *cache = bcache_create(PAGE_SIZE_SECTORS, BLOCK_SIZE_SECTORS, f->e);
+ T_ASSERT(cache);
+
+ f->di = bcache_set_fd(f->fd);
+
+ T_ASSERT(f->di >= 0);
+
+ _io_init(&io);
+ T_ASSERT(f->e->issue(f->e, DIR_READ, f->di, 0, BLOCK_SIZE_SECTORS, f->data, &io));
+ T_ASSERT(f->e->wait(f->e, _complete_io));
+ T_ASSERT(io.completed);
+ T_ASSERT(!io.error);
+
+ _check_buffer(f->data, 123, SECTOR_SIZE * BLOCK_SIZE_SECTORS);
+}
+
+static void _test_write(void *fixture)
+{
+ struct fixture *f = fixture;
+ struct io io;
+ struct bcache *cache = bcache_create(PAGE_SIZE_SECTORS, BLOCK_SIZE_SECTORS, f->e);
+ T_ASSERT(cache);
+
+ f->di = bcache_set_fd(f->fd);
+
+ T_ASSERT(f->di >= 0);
+
+ _io_init(&io);
+ T_ASSERT(f->e->issue(f->e, DIR_WRITE, f->di, 0, BLOCK_SIZE_SECTORS, f->data, &io));
+ T_ASSERT(f->e->wait(f->e, _complete_io));
+ T_ASSERT(io.completed);
+ T_ASSERT(!io.error);
+}
+
+static void _test_write_bytes(void *fixture)
+{
+ struct fixture *f = fixture;
+
+ unsigned offset = 345;
+ char buf_out[32];
+ char buf_in[32];
+ struct bcache *cache = bcache_create(PAGE_SIZE_SECTORS, BLOCK_SIZE_SECTORS, f->e);
+ T_ASSERT(cache);
+
+ f->di = bcache_set_fd(f->fd);
+
+ // T_ASSERT(bcache_read_bytes(cache, f->di, offset, sizeof(buf_in), buf_in));
+ _fill_buffer((uint8_t *) buf_out, 234, sizeof(buf_out));
+ T_ASSERT(bcache_write_bytes(cache, f->di, offset, sizeof(buf_out), buf_out));
+ T_ASSERT(bcache_read_bytes(cache, f->di, offset, sizeof(buf_in), buf_in));
+
+ _print_buffer("buf_out", (uint8_t *) buf_out, sizeof(buf_out));
+ _print_buffer("buf_in", (uint8_t *) buf_in, sizeof(buf_in));
+ T_ASSERT(!memcmp(buf_out, buf_in, sizeof(buf_out)));
+
+ bcache_destroy(cache);
+ f->e = NULL; // already destroyed
+}
+
+//----------------------------------------------------------------
+
+#define T(path, desc, fn) register_test(ts, "/base/device/bcache/io-engine/" path, desc, fn)
+
+static struct test_suite *_tests(void)
+{
+ struct test_suite *ts = test_suite_create(_fix_init, _fix_exit);
+ if (!ts) {
+ fprintf(stderr, "out of memory\n");
+ exit(1);
+ }
+
+ T("create-destroy", "simple create/destroy", _test_create);
+ T("read", "read sanity check", _test_read);
+ T("write", "write sanity check", _test_write);
+ T("bcache-write-bytes", "test the utility fns", _test_write_bytes);
+
+ return ts;
+}
+
+void io_engine_tests(struct dm_list *all_tests)
+{
+ dm_list_add(all_tests, &_tests()->list);
+}
+
diff --git a/test/unit/matcher_t.c b/test/unit/matcher_t.c
index 7331a82..89b2988 100644
--- a/test/unit/matcher_t.c
+++ b/test/unit/matcher_t.c
@@ -10,76 +10,120 @@
*
* 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
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
-#include "libdevmapper.h"
-#include "log.h"
+#include "units.h"
+#include "device_mapper/all.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;
+static void *_mem_init(void)
+{
+ struct dm_pool *mem = dm_pool_create("bitset test", 1024);
+ if (!mem) {
+ fprintf(stderr, "out of memory");
+ exit(1);
+ }
-int regex_init(void) {
- mem = dm_pool_create("bitset test", 1024);
- return mem == NULL;
+ return mem;
}
-int regex_fini(void) {
+static void _mem_exit(void *mem)
+{
dm_pool_destroy(mem);
- return 0;
}
-static struct dm_regex *make_scanner(const char **rx)
+static struct dm_regex *make_scanner(struct dm_pool *mem, 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);
+ T_ASSERT(scanner != NULL);
return scanner;
}
-static void test_fingerprints(void) {
+static void test_fingerprints(void *fixture)
+{
+ struct dm_pool *mem = fixture;
struct dm_regex *scanner;
- scanner = make_scanner(dev_patterns);
- CU_ASSERT_EQUAL(dm_regex_fingerprint(scanner), 0x7f556c09);
+ scanner = make_scanner(mem, dev_patterns);
+ T_ASSERT_EQUAL(dm_regex_fingerprint(scanner), 0x7f556c09);
- scanner = make_scanner(random_patterns);
- CU_ASSERT_EQUAL(dm_regex_fingerprint(scanner), 0x9f11076c);
+ scanner = make_scanner(mem, random_patterns);
+ T_ASSERT_EQUAL(dm_regex_fingerprint(scanner), 0x9f11076c);
}
-static void test_matching(void) {
+static void test_matching(void *fixture)
+{
+ struct dm_pool *mem = fixture;
struct dm_regex *scanner;
int i;
- scanner = make_scanner(dev_patterns);
+ scanner = make_scanner(mem, dev_patterns);
for (i = 0; devices[i].str; ++i)
- CU_ASSERT_EQUAL(dm_regex_match(scanner, devices[i].str), devices[i].expected - 1);
+ T_ASSERT_EQUAL(dm_regex_match(scanner, devices[i].str), devices[i].expected - 1);
- scanner = make_scanner(nonprint_patterns);
+ scanner = make_scanner(mem, nonprint_patterns);
for (i = 0; nonprint[i].str; ++i)
- CU_ASSERT_EQUAL(dm_regex_match(scanner, nonprint[i].str), nonprint[i].expected - 1);
+ T_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
-};
+static void test_kabi_query(void *fixture)
+{
+ // Remember, matches regexes from last to first.
+ static const char *_patterns[] = {
+ ".*", ".*/dev/md.*", "loop"
+ };
+
+ static struct {
+ const char *input;
+ int r;
+ } _cases[] = {
+ {"foo", 0},
+ {"/dev/mapper/vg-lvol1", 0},
+ {"/dev/mapper/vglvol1", 0},
+ {"/dev/md1", 1},
+ {"loop", 2},
+ };
+
+ int r;
+ unsigned i;
+ struct dm_pool *mem = fixture;
+ struct dm_regex *scanner;
+
+ scanner = dm_regex_create(mem, _patterns, DM_ARRAY_SIZE(_patterns));
+ T_ASSERT(scanner != NULL);
+
+ for (i = 0; i < DM_ARRAY_SIZE(_cases); i++) {
+ r = dm_regex_match(scanner, _cases[i].input);
+ if (r != _cases[i].r) {
+ test_fail("'%s' expected to match '%s', but matched %s",
+ _cases[i].input,
+ _cases[i].r >= DM_ARRAY_SIZE(_patterns) ? "<nothing>" : _patterns[_cases[i].r],
+ r >= DM_ARRAY_SIZE(_patterns) ? "<nothing>" : _patterns[r]);
+ }
+ }
+
+}
+
+#define T(path, desc, fn) register_test(ts, "/base/regex/" path, desc, fn)
+
+void regex_tests(struct dm_list *all_tests)
+{
+ struct test_suite *ts = test_suite_create(_mem_init, _mem_exit);
+ if (!ts) {
+ fprintf(stderr, "out of memory\n");
+ exit(1);
+ }
+
+ T("fingerprints", "not sure", test_fingerprints);
+ T("matching", "test the matcher with a variety of regexes", test_matching);
+ T("kabi-query", "test the matcher with some specific patterns", test_kabi_query);
+
+ dm_list_add(all_tests, &ts->list);
+}
diff --git a/test/unit/percent_t.c b/test/unit/percent_t.c
new file mode 100644
index 0000000..3575e12
--- /dev/null
+++ b/test/unit/percent_t.c
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2017 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "units.h"
+#include "device_mapper/all.h"
+
+#include <stdio.h>
+#include <string.h>
+
+static void test_percent_100(void *fixture)
+{
+ char buf[32];
+
+ /* Check 100% is shown only for DM_PERCENT_100*/
+ dm_percent_t p_100 = dm_make_percent(100, 100);
+ dm_percent_t p1_100 = dm_make_percent(100000, 100000);
+ dm_percent_t n_100 = dm_make_percent(999999, 1000000);
+
+ T_ASSERT_EQUAL(p_100, DM_PERCENT_100);
+ T_ASSERT_EQUAL(p1_100, DM_PERCENT_100);
+ T_ASSERT_NOT_EQUAL(n_100, DM_PERCENT_100);
+
+ (void) dm_snprintf(buf, sizeof(buf), "%.2f", dm_percent_to_float(p_100));
+ T_ASSERT_EQUAL(strcmp(buf, "100.00"), 0);
+
+ (void) dm_snprintf(buf, sizeof(buf), "%.2f", dm_percent_to_float(p1_100));
+ T_ASSERT_EQUAL(strcmp(buf, "100.00"), 0);
+
+ (void) dm_snprintf(buf, sizeof(buf), "%.2f", dm_percent_to_float(n_100));
+ T_ASSERT_NOT_EQUAL(strcmp(buf, "99.99"), 0); /* Would like to gett */
+
+ (void) dm_snprintf(buf, sizeof(buf), "%.2f", dm_percent_to_round_float(n_100, 2));
+ T_ASSERT_EQUAL(strcmp(buf, "99.99"), 0);
+
+ (void) dm_snprintf(buf, sizeof(buf), "%.3f", dm_percent_to_round_float(n_100, 3));
+ T_ASSERT_EQUAL(strcmp(buf, "99.999"), 0);
+
+ (void) dm_snprintf(buf, sizeof(buf), "%.4f", dm_percent_to_round_float(n_100, 4));
+ T_ASSERT_EQUAL(strcmp(buf, "99.9999"), 0);
+
+ (void) dm_snprintf(buf, sizeof(buf), "%d", (int)dm_percent_to_round_float(n_100, 0));
+ T_ASSERT_EQUAL(strcmp(buf, "99"), 0);
+}
+
+static void test_percent_0(void *fixture)
+{
+ char buf[32];
+
+ /* Check 0% is shown only for DM_PERCENT_0 */
+ dm_percent_t p_0 = dm_make_percent(0, 100);
+ dm_percent_t p1_0 = dm_make_percent(0, 100000);
+ dm_percent_t n_0 = dm_make_percent(1, 1000000);
+
+ T_ASSERT_EQUAL(p_0, DM_PERCENT_0);
+ T_ASSERT_EQUAL(p1_0, DM_PERCENT_0);
+ T_ASSERT_NOT_EQUAL(n_0, DM_PERCENT_0);
+
+ (void) dm_snprintf(buf, sizeof(buf), "%.2f", dm_percent_to_float(p_0));
+ T_ASSERT_EQUAL(strcmp(buf, "0.00"), 0);
+
+ (void) dm_snprintf(buf, sizeof(buf), "%.2f", dm_percent_to_float(p1_0));
+ T_ASSERT_EQUAL(strcmp(buf, "0.00"), 0);
+
+ (void) dm_snprintf(buf, sizeof(buf), "%.2f", dm_percent_to_float(n_0));
+ T_ASSERT_NOT_EQUAL(strcmp(buf, "0.01"), 0);
+
+ (void) dm_snprintf(buf, sizeof(buf), "%.2f", dm_percent_to_round_float(n_0, 2));
+ T_ASSERT_EQUAL(strcmp(buf, "0.01"), 0);
+
+ (void) dm_snprintf(buf, sizeof(buf), "%.3f", dm_percent_to_round_float(n_0, 3));
+ T_ASSERT_EQUAL(strcmp(buf, "0.001"), 0);
+
+ (void) dm_snprintf(buf, sizeof(buf), "%d", (int)dm_percent_to_round_float(n_0, 0));
+ T_ASSERT_EQUAL(strcmp(buf, "1"), 0);
+}
+
+#define T(path, desc, fn) register_test(ts, "/base/formatting/percent/" path, desc, fn)
+
+void percent_tests(struct dm_list *all_tests)
+{
+ struct test_suite *ts = test_suite_create(NULL, NULL);
+ if (!ts) {
+ fprintf(stderr, "out of memory\n");
+ exit(1);
+ }
+
+ T("100", "Pretty printing of percentages near 100%", test_percent_100);
+ T("0", "Pretty printing of percentages near 0%", test_percent_0);
+
+ dm_list_add(all_tests, &ts->list);
+}
diff --git a/test/unit/radix_tree_t.c b/test/unit/radix_tree_t.c
new file mode 100644
index 0000000..b80e4f8
--- /dev/null
+++ b/test/unit/radix_tree_t.c
@@ -0,0 +1,852 @@
+// Copyright (C) 2018 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+#include "units.h"
+#include "base/data-struct/radix-tree.h"
+#include "base/memory/container_of.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+//----------------------------------------------------------------
+
+static void *rt_init(void)
+{
+ struct radix_tree *rt = radix_tree_create(NULL, NULL);
+ T_ASSERT(rt);
+ return rt;
+}
+
+static void rt_exit(void *fixture)
+{
+ if (fixture)
+ radix_tree_destroy(fixture);
+}
+
+static void test_create_destroy(void *fixture)
+{
+ T_ASSERT(fixture);
+}
+
+static void test_insert_one(void *fixture)
+{
+ struct radix_tree *rt = fixture;
+ union radix_value v;
+ unsigned char k = 'a';
+ v.n = 65;
+ T_ASSERT(radix_tree_insert(rt, &k, &k + 1, v));
+ T_ASSERT(radix_tree_is_well_formed(rt));
+ v.n = 0;
+ T_ASSERT(radix_tree_lookup(rt, &k, &k + 1, &v));
+ T_ASSERT_EQUAL(v.n, 65);
+}
+
+static void test_single_byte_keys(void *fixture)
+{
+ unsigned i, count = 256;
+ struct radix_tree *rt = fixture;
+ union radix_value v;
+ uint8_t k;
+
+ for (i = 0; i < count; i++) {
+ k = i;
+ v.n = 100 + i;
+ T_ASSERT(radix_tree_insert(rt, &k, &k + 1, v));
+ }
+
+ T_ASSERT(radix_tree_is_well_formed(rt));
+
+ for (i = 0; i < count; i++) {
+ k = i;
+ T_ASSERT(radix_tree_lookup(rt, &k, &k + 1, &v));
+ T_ASSERT_EQUAL(v.n, 100 + i);
+ }
+}
+
+static void test_overwrite_single_byte_keys(void *fixture)
+{
+ unsigned i, count = 256;
+ struct radix_tree *rt = fixture;
+ union radix_value v;
+ uint8_t k;
+
+ for (i = 0; i < count; i++) {
+ k = i;
+ v.n = 100 + i;
+ T_ASSERT(radix_tree_insert(rt, &k, &k + 1, v));
+ }
+
+ T_ASSERT(radix_tree_is_well_formed(rt));
+
+ for (i = 0; i < count; i++) {
+ k = i;
+ v.n = 1000 + i;
+ T_ASSERT(radix_tree_insert(rt, &k, &k + 1, v));
+ }
+
+ T_ASSERT(radix_tree_is_well_formed(rt));
+
+ for (i = 0; i < count; i++) {
+ k = i;
+ T_ASSERT(radix_tree_lookup(rt, &k, &k + 1, &v));
+ T_ASSERT_EQUAL(v.n, 1000 + i);
+ }
+}
+
+static void test_16_bit_keys(void *fixture)
+{
+ unsigned i, count = 1 << 16;
+ struct radix_tree *rt = fixture;
+ union radix_value v;
+ uint8_t k[2];
+
+ for (i = 0; i < count; i++) {
+ k[0] = i / 256;
+ k[1] = i % 256;
+ v.n = 100 + i;
+ T_ASSERT(radix_tree_insert(rt, k, k + sizeof(k), v));
+ }
+
+ T_ASSERT(radix_tree_is_well_formed(rt));
+
+ for (i = 0; i < count; i++) {
+ k[0] = i / 256;
+ k[1] = i % 256;
+ T_ASSERT(radix_tree_lookup(rt, k, k + sizeof(k), &v));
+ T_ASSERT_EQUAL(v.n, 100 + i);
+ }
+}
+
+static void test_prefix_keys(void *fixture)
+{
+ struct radix_tree *rt = fixture;
+ union radix_value v;
+ uint8_t k[2];
+
+ k[0] = 100;
+ k[1] = 200;
+ v.n = 1024;
+ T_ASSERT(radix_tree_insert(rt, k, k + 1, v));
+ T_ASSERT(radix_tree_is_well_formed(rt));
+ v.n = 2345;
+ T_ASSERT(radix_tree_insert(rt, k, k + 2, v));
+ T_ASSERT(radix_tree_is_well_formed(rt));
+ T_ASSERT(radix_tree_lookup(rt, k, k + 1, &v));
+ T_ASSERT_EQUAL(v.n, 1024);
+ T_ASSERT(radix_tree_lookup(rt, k, k + 2, &v));
+ T_ASSERT_EQUAL(v.n, 2345);
+}
+
+static void test_prefix_keys_reversed(void *fixture)
+{
+ struct radix_tree *rt = fixture;
+ union radix_value v;
+ uint8_t k[2];
+
+ k[0] = 100;
+ k[1] = 200;
+ v.n = 1024;
+ T_ASSERT(radix_tree_insert(rt, k, k + 2, v));
+ T_ASSERT(radix_tree_is_well_formed(rt));
+ v.n = 2345;
+ T_ASSERT(radix_tree_insert(rt, k, k + 1, v));
+ T_ASSERT(radix_tree_is_well_formed(rt));
+ T_ASSERT(radix_tree_lookup(rt, k, k + 2, &v));
+ T_ASSERT_EQUAL(v.n, 1024);
+ T_ASSERT(radix_tree_lookup(rt, k, k + 1, &v));
+ T_ASSERT_EQUAL(v.n, 2345);
+}
+
+static void _gen_key(uint8_t *b, uint8_t *e)
+{
+ for (; b != e; b++)
+ /* coverity[dont_call] don't care */
+ *b = rand() % 256;
+}
+
+static void test_sparse_keys(void *fixture)
+{
+ unsigned n;
+ struct radix_tree *rt = fixture;
+ union radix_value v;
+ uint8_t k[32];
+
+ for (n = 0; n < 100000; n++) {
+ _gen_key(k, k + sizeof(k));
+ v.n = 1234;
+ T_ASSERT(radix_tree_insert(rt, k, k + 32, v));
+ // FIXME: remove
+ //T_ASSERT(radix_tree_is_well_formed(rt));
+ }
+ T_ASSERT(radix_tree_is_well_formed(rt));
+}
+
+static void test_remove_one(void *fixture)
+{
+ struct radix_tree *rt = fixture;
+ uint8_t k[4];
+ union radix_value v;
+
+ _gen_key(k, k + sizeof(k));
+ v.n = 1234;
+ T_ASSERT(radix_tree_insert(rt, k, k + sizeof(k), v));
+ T_ASSERT(radix_tree_is_well_formed(rt));
+ T_ASSERT(radix_tree_remove(rt, k, k + sizeof(k)));
+ T_ASSERT(radix_tree_is_well_formed(rt));
+ T_ASSERT(!radix_tree_lookup(rt, k, k + sizeof(k), &v));
+}
+
+static void test_remove_one_byte_keys(void *fixture)
+{
+ struct radix_tree *rt = fixture;
+ unsigned i, j;
+ uint8_t k[1];
+ union radix_value v;
+
+ for (i = 0; i < 256; i++) {
+ k[0] = i;
+ v.n = i + 1000;
+ T_ASSERT(radix_tree_insert(rt, k, k + 1, v));
+ }
+
+ T_ASSERT(radix_tree_is_well_formed(rt));
+ for (i = 0; i < 256; i++) {
+ k[0] = i;
+ T_ASSERT(radix_tree_remove(rt, k, k + 1));
+ T_ASSERT(radix_tree_is_well_formed(rt));
+
+ for (j = i + 1; j < 256; j++) {
+ k[0] = j;
+ T_ASSERT(radix_tree_lookup(rt, k, k + 1, &v));
+ if (v.n != j + 1000)
+ test_fail("v.n (%u) != j + 1000 (%u)\n",
+ (unsigned) v.n,
+ (unsigned) j + 1000);
+ }
+ }
+
+ for (i = 0; i < 256; i++) {
+ k[0] = i;
+ T_ASSERT(!radix_tree_lookup(rt, k, k + 1, &v));
+ }
+}
+
+static void test_remove_one_byte_keys_reversed(void *fixture)
+{
+ struct radix_tree *rt = fixture;
+ unsigned i, j;
+ uint8_t k[1];
+ union radix_value v;
+
+ for (i = 0; i < 256; i++) {
+ k[0] = i;
+ v.n = i + 1000;
+ T_ASSERT(radix_tree_insert(rt, k, k + 1, v));
+ }
+
+ T_ASSERT(radix_tree_is_well_formed(rt));
+ for (i = 256; i; i--) {
+ k[0] = i - 1;
+ T_ASSERT(radix_tree_remove(rt, k, k + 1));
+ T_ASSERT(radix_tree_is_well_formed(rt));
+
+ for (j = 0; j < i - 1; j++) {
+ k[0] = j;
+ T_ASSERT(radix_tree_lookup(rt, k, k + 1, &v));
+ if (v.n != j + 1000)
+ test_fail("v.n (%u) != j + 1000 (%u)\n",
+ (unsigned) v.n,
+ (unsigned) j + 1000);
+ }
+ }
+
+ for (i = 0; i < 256; i++) {
+ k[0] = i;
+ T_ASSERT(!radix_tree_lookup(rt, k, k + 1, &v));
+ }
+}
+static void test_remove_prefix_keys(void *fixture)
+{
+ struct radix_tree *rt = fixture;
+ unsigned i, j;
+ uint8_t k[32];
+ union radix_value v;
+
+ _gen_key(k, k + sizeof(k));
+
+ for (i = 0; i < 32; i++) {
+ v.n = i;
+ T_ASSERT(radix_tree_insert(rt, k, k + i, v));
+ }
+
+ T_ASSERT(radix_tree_is_well_formed(rt));
+ for (i = 0; i < 32; i++) {
+ T_ASSERT(radix_tree_remove(rt, k, k + i));
+ T_ASSERT(radix_tree_is_well_formed(rt));
+ for (j = i + 1; j < 32; j++) {
+ T_ASSERT(radix_tree_lookup(rt, k, k + j, &v));
+ T_ASSERT_EQUAL(v.n, j);
+ }
+ }
+
+ for (i = 0; i < 32; i++)
+ T_ASSERT(!radix_tree_lookup(rt, k, k + i, &v));
+}
+
+static void test_remove_prefix_keys_reversed(void *fixture)
+{
+ struct radix_tree *rt = fixture;
+ unsigned i, j;
+ uint8_t k[32];
+ union radix_value v;
+
+ _gen_key(k, k + sizeof(k));
+
+ for (i = 0; i < 32; i++) {
+ v.n = i;
+ T_ASSERT(radix_tree_insert(rt, k, k + i, v));
+ }
+
+ T_ASSERT(radix_tree_is_well_formed(rt));
+ for (i = 0; i < 32; i++) {
+ T_ASSERT(radix_tree_remove(rt, k, k + (31 - i)));
+ T_ASSERT(radix_tree_is_well_formed(rt));
+ for (j = 0; j < 31 - i; j++) {
+ T_ASSERT(radix_tree_lookup(rt, k, k + j, &v));
+ T_ASSERT_EQUAL(v.n, j);
+ }
+ }
+
+ for (i = 0; i < 32; i++)
+ T_ASSERT(!radix_tree_lookup(rt, k, k + i, &v));
+}
+
+static void test_remove_prefix(void *fixture)
+{
+ struct radix_tree *rt = fixture;
+ unsigned i, count = 0;
+ uint8_t k[4];
+ union radix_value v;
+
+ // populate some random 32bit keys
+ for (i = 0; i < 100000; i++) {
+ _gen_key(k, k + sizeof(k));
+ if (k[0] == 21)
+ count++;
+ v.n = i;
+ T_ASSERT(radix_tree_insert(rt, k, k + sizeof(k), v));
+ }
+
+ T_ASSERT(radix_tree_is_well_formed(rt));
+
+ // remove keys in a sub range
+ k[0] = 21;
+ T_ASSERT_EQUAL(radix_tree_remove_prefix(rt, k, k + 1), count);
+ T_ASSERT(radix_tree_is_well_formed(rt));
+}
+
+static void test_remove_prefix_single(void *fixture)
+{
+ struct radix_tree *rt = fixture;
+ uint8_t k[4];
+ union radix_value v;
+
+ _gen_key(k, k + sizeof(k));
+ v.n = 1234;
+ T_ASSERT(radix_tree_insert(rt, k, k + sizeof(k), v));
+ T_ASSERT(radix_tree_is_well_formed(rt));
+ T_ASSERT_EQUAL(radix_tree_remove_prefix(rt, k, k + 2), 1);
+ T_ASSERT(radix_tree_is_well_formed(rt));
+}
+
+static void test_size(void *fixture)
+{
+ struct radix_tree *rt = fixture;
+ unsigned i, dup_count = 0;
+ uint8_t k[2];
+ union radix_value v;
+
+ // populate some random 16bit keys
+ for (i = 0; i < 10000; i++) {
+ _gen_key(k, k + sizeof(k));
+ if (radix_tree_lookup(rt, k, k + sizeof(k), &v))
+ dup_count++;
+ v.n = i;
+ T_ASSERT(radix_tree_insert(rt, k, k + sizeof(k), v));
+ }
+
+ T_ASSERT_EQUAL(radix_tree_size(rt), 10000 - dup_count);
+ T_ASSERT(radix_tree_is_well_formed(rt));
+}
+
+struct visitor {
+ struct radix_tree_iterator it;
+ unsigned count;
+};
+
+static bool _visit(struct radix_tree_iterator *it,
+ uint8_t *kb, uint8_t *ke, union radix_value v)
+{
+ struct visitor *vt = container_of(it, struct visitor, it);
+ vt->count++;
+ return true;
+}
+
+static void test_iterate_all(void *fixture)
+{
+ struct radix_tree *rt = fixture;
+ unsigned i;
+ uint8_t k[4];
+ union radix_value v;
+ struct visitor vt;
+
+ // populate some random 32bit keys
+ for (i = 0; i < 100000; i++) {
+ _gen_key(k, k + sizeof(k));
+ v.n = i;
+ T_ASSERT(radix_tree_insert(rt, k, k + sizeof(k), v));
+ }
+
+ T_ASSERT(radix_tree_is_well_formed(rt));
+ vt.count = 0;
+ vt.it.visit = _visit;
+ radix_tree_iterate(rt, NULL, NULL, &vt.it);
+ T_ASSERT_EQUAL(vt.count, radix_tree_size(rt));
+}
+
+static void test_iterate_subset(void *fixture)
+{
+ struct radix_tree *rt = fixture;
+ unsigned i, subset_count = 0;
+ uint8_t k[3];
+ union radix_value v;
+ struct visitor vt;
+
+ // populate some random 32bit keys
+ for (i = 0; i < 100000; i++) {
+ _gen_key(k, k + sizeof(k));
+ if (k[0] == 21 && k[1] == 12)
+ subset_count++;
+ v.n = i;
+ T_ASSERT(radix_tree_insert(rt, k, k + sizeof(k), v));
+ }
+
+ T_ASSERT(radix_tree_is_well_formed(rt));
+ vt.count = 0;
+ vt.it.visit = _visit;
+ k[0] = 21;
+ k[1] = 12;
+ radix_tree_iterate(rt, k, k + 2, &vt.it);
+ T_ASSERT_EQUAL(vt.count, subset_count);
+}
+
+static void test_iterate_single(void *fixture)
+{
+ struct radix_tree *rt = fixture;
+ uint8_t k[6];
+ union radix_value v;
+ struct visitor vt;
+
+ _gen_key(k, k + sizeof(k));
+ v.n = 1234;
+ T_ASSERT(radix_tree_insert(rt, k, k + sizeof(k), v));
+
+ T_ASSERT(radix_tree_is_well_formed(rt));
+ vt.count = 0;
+ vt.it.visit = _visit;
+ radix_tree_iterate(rt, k, k + 3, &vt.it);
+ T_ASSERT_EQUAL(vt.count, 1);
+}
+
+static void test_iterate_vary_middle(void *fixture)
+{
+ struct radix_tree *rt = fixture;
+ unsigned i;
+ uint8_t k[6];
+ union radix_value v;
+ struct visitor vt;
+
+ _gen_key(k, k + sizeof(k));
+ for (i = 0; i < 16; i++) {
+ k[3] = i;
+ v.n = i;
+ T_ASSERT(radix_tree_insert(rt, k, k + sizeof(k), v));
+ }
+
+ T_ASSERT(radix_tree_is_well_formed(rt));
+ vt.it.visit = _visit;
+ for (i = 0; i < 16; i++) {
+ vt.count = 0;
+ k[3] = i;
+ radix_tree_iterate(rt, k, k + 4, &vt.it);
+ T_ASSERT_EQUAL(vt.count, 1);
+ }
+}
+
+//----------------------------------------------------------------
+
+#define DTR_COUNT 100
+
+struct counter {
+ unsigned c;
+ uint8_t present[DTR_COUNT];
+};
+
+static void _counting_dtr(void *context, union radix_value v)
+{
+ struct counter *c = context;
+ c->c++;
+ T_ASSERT(v.n < DTR_COUNT);
+ c->present[v.n] = 0;
+}
+
+static void test_remove_calls_dtr(void *fixture)
+{
+ struct counter c;
+ struct radix_tree *rt = radix_tree_create(_counting_dtr, &c);
+ T_ASSERT(rt);
+
+ // Bug hunting, so I need the keys to be deterministic
+ srand(0);
+
+ c.c = 0;
+ memset(c.present, 1, sizeof(c.present));
+
+ {
+ unsigned i;
+ uint8_t keys[DTR_COUNT * 3];
+ union radix_value v;
+
+ // generate and insert a lot of keys
+ for (i = 0; i < DTR_COUNT; i++) {
+ bool found = false;
+ do {
+ v.n = i;
+ uint8_t *k = keys + (i * 3);
+ _gen_key(k, k + 3);
+ if (!radix_tree_lookup(rt, k, k + 3, &v)) {
+ T_ASSERT(radix_tree_insert(rt, k, k + 3, v));
+ found = true;
+ }
+
+ } while (!found);
+ }
+
+ T_ASSERT(radix_tree_is_well_formed(rt));
+
+ // double check
+ for (i = 0; i < DTR_COUNT; i++) {
+ uint8_t *k = keys + (i * 3);
+ T_ASSERT(radix_tree_lookup(rt, k, k + 3, &v));
+ }
+
+ for (i = 0; i < DTR_COUNT; i++) {
+ uint8_t *k = keys + (i * 3);
+ // FIXME: check the values get passed to the dtr
+ T_ASSERT(radix_tree_remove(rt, k, k + 3));
+ }
+
+ T_ASSERT(c.c == DTR_COUNT);
+ for (i = 0; i < DTR_COUNT; i++)
+ T_ASSERT(!c.present[i]);
+ }
+
+ radix_tree_destroy(rt);
+}
+
+static void test_destroy_calls_dtr(void *fixture)
+{
+ unsigned i;
+ struct counter c;
+ struct radix_tree *rt = radix_tree_create(_counting_dtr, &c);
+ T_ASSERT(rt);
+
+ // Bug hunting, so I need the keys to be deterministic
+ srand(0);
+
+ c.c = 0;
+ memset(c.present, 1, sizeof(c.present));
+
+ {
+ uint8_t keys[DTR_COUNT * 3];
+ union radix_value v;
+
+ // generate and insert a lot of keys
+ for (i = 0; i < DTR_COUNT; i++) {
+ bool found = false;
+ do {
+ v.n = i;
+ uint8_t *k = keys + (i * 3);
+ _gen_key(k, k + 3);
+ if (!radix_tree_lookup(rt, k, k + 3, &v)) {
+ T_ASSERT(radix_tree_insert(rt, k, k + 3, v));
+ found = true;
+ }
+
+ } while (!found);
+ }
+
+ T_ASSERT(radix_tree_is_well_formed(rt));
+ }
+
+ radix_tree_destroy(rt);
+ T_ASSERT(c.c == DTR_COUNT);
+ for (i = 0; i < DTR_COUNT; i++)
+ T_ASSERT(!c.present[i]);
+}
+
+//----------------------------------------------------------------
+
+static void test_bcache_scenario(void *fixture)
+{
+ struct radix_tree *rt = fixture;
+
+ unsigned i;
+ uint8_t k[6];
+ union radix_value v;
+
+ memset(k, 0, sizeof(k));
+
+ for (i = 0; i < 3; i++) {
+ // it has to be the 4th byte that varies to
+ // trigger the bug.
+ k[4] = i;
+ v.n = i;
+ T_ASSERT(radix_tree_insert(rt, k, k + sizeof(k), v));
+ }
+ T_ASSERT(radix_tree_is_well_formed(rt));
+
+ k[4] = 0;
+ T_ASSERT(radix_tree_remove(rt, k, k + sizeof(k)));
+ T_ASSERT(radix_tree_is_well_formed(rt));
+
+ k[4] = i;
+ v.n = i;
+ T_ASSERT(radix_tree_insert(rt, k, k + sizeof(k), v));
+ T_ASSERT(radix_tree_is_well_formed(rt));
+}
+
+//----------------------------------------------------------------
+
+static void _bcs2_step1(struct radix_tree *rt)
+{
+ unsigned i;
+ uint8_t k[12];
+ union radix_value v;
+
+ memset(k, 0, sizeof(k));
+ for (i = 0x6; i < 0x69; i++) {
+ k[0] = i;
+ v.n = i;
+ T_ASSERT(radix_tree_insert(rt, k, k + sizeof(k), v));
+ }
+ T_ASSERT(radix_tree_is_well_formed(rt));
+}
+
+static void _bcs2_step2(struct radix_tree *rt)
+{
+ unsigned i;
+ uint8_t k[12];
+
+ memset(k, 0, sizeof(k));
+ for (i = 0x6; i < 0x69; i++) {
+ k[0] = i;
+ radix_tree_remove_prefix(rt, k, k + 4);
+ }
+ T_ASSERT(radix_tree_is_well_formed(rt));
+}
+
+static void test_bcache_scenario2(void *fixture)
+{
+ unsigned i;
+ struct radix_tree *rt = fixture;
+ uint8_t k[12];
+ union radix_value v;
+
+ _bcs2_step1(rt);
+ _bcs2_step2(rt);
+
+ memset(k, 0, sizeof(k));
+ for (i = 0; i < 50; i++) {
+ k[0] = 0x6;
+ v.n = 0x6;
+ T_ASSERT(radix_tree_insert(rt, k, k + sizeof(k), v));
+ radix_tree_remove_prefix(rt, k, k + 4);
+ }
+ T_ASSERT(radix_tree_is_well_formed(rt));
+
+ _bcs2_step1(rt);
+ _bcs2_step2(rt);
+ _bcs2_step1(rt);
+ _bcs2_step2(rt);
+
+ memset(k, 0, sizeof(k));
+ for(i = 0x6; i < 0x37; i++) {
+ k[0] = i;
+ k[4] = 0xf;
+ k[5] = 0x1;
+ T_ASSERT(radix_tree_insert(rt, k, k + sizeof(k), v));
+ k[4] = 0;
+ k[5] = 0;
+ T_ASSERT(radix_tree_insert(rt, k, k + sizeof(k), v));
+ }
+ T_ASSERT(radix_tree_is_well_formed(rt));
+
+ memset(k, 0, sizeof(k));
+ for (i = 0x38; i < 0x69; i++) {
+ k[0] = i - 0x32;
+ k[4] = 0xf;
+ k[5] = 1;
+ T_ASSERT(radix_tree_remove(rt, k, k + sizeof(k)));
+
+ k[0] = i;
+ T_ASSERT(radix_tree_insert(rt, k, k + sizeof(k), v));
+
+ k[0] = i - 0x32;
+ k[4] = 0;
+ k[5] = 0;
+ T_ASSERT(radix_tree_remove(rt, k, k + sizeof(k)));
+
+ k[0] = i;
+ T_ASSERT(radix_tree_insert(rt, k, k + sizeof(k), v));
+ }
+ T_ASSERT(radix_tree_is_well_formed(rt));
+
+ memset(k, 0, sizeof(k));
+ k[0] = 0x6;
+ radix_tree_remove_prefix(rt, k, k + 4);
+ T_ASSERT(radix_tree_is_well_formed(rt));
+
+ k[0] = 0x38;
+ k[4] = 0xf;
+ k[5] = 0x1;
+ T_ASSERT(radix_tree_remove(rt, k, k + sizeof(k)));
+ T_ASSERT(radix_tree_is_well_formed(rt));
+
+ memset(k, 0, sizeof(k));
+ k[0] = 0x6;
+ T_ASSERT(radix_tree_insert(rt, k, k + sizeof(k), v));
+ T_ASSERT(radix_tree_is_well_formed(rt));
+
+ k[0] = 0x7;
+ radix_tree_remove_prefix(rt, k, k + 4);
+ T_ASSERT(radix_tree_is_well_formed(rt));
+
+ k[0] = 0x38;
+ T_ASSERT(radix_tree_remove(rt, k, k + sizeof(k)));
+ T_ASSERT(radix_tree_is_well_formed(rt));
+
+ k[0] = 7;
+ T_ASSERT(radix_tree_insert(rt, k, k + sizeof(k), v));
+ T_ASSERT(radix_tree_is_well_formed(rt));
+}
+
+//----------------------------------------------------------------
+
+struct key_parts {
+ uint32_t fd;
+ uint64_t b;
+} __attribute__ ((packed));
+
+union key {
+ struct key_parts parts;
+ uint8_t bytes[12];
+};
+
+static void __lookup_matches(struct radix_tree *rt, int fd, uint64_t b, uint64_t expected)
+{
+ union key k;
+ union radix_value v;
+
+ k.parts.fd = fd;
+ k.parts.b = b;
+ T_ASSERT(radix_tree_lookup(rt, k.bytes, k.bytes + sizeof(k.bytes), &v));
+ T_ASSERT(v.n == expected);
+}
+
+static void __lookup_fails(struct radix_tree *rt, int fd, uint64_t b)
+{
+ union key k;
+ union radix_value v;
+
+ k.parts.fd = fd;
+ k.parts.b = b;
+ T_ASSERT(!radix_tree_lookup(rt, k.bytes, k.bytes + sizeof(k.bytes), &v));
+}
+
+static void __insert(struct radix_tree *rt, int fd, uint64_t b, uint64_t n)
+{
+ union key k;
+ union radix_value v;
+
+ k.parts.fd = fd;
+ k.parts.b = b;
+ v.n = n;
+ T_ASSERT(radix_tree_insert(rt, k.bytes, k.bytes + sizeof(k.bytes), v));
+}
+
+static void __invalidate(struct radix_tree *rt, int fd)
+{
+ union key k;
+
+ k.parts.fd = fd;
+ radix_tree_remove_prefix(rt, k.bytes, k.bytes + sizeof(k.parts.fd));
+ T_ASSERT(radix_tree_is_well_formed(rt));
+}
+
+static void test_bcache_scenario3(void *fixture)
+{
+ struct radix_tree *rt = fixture;
+
+ #include "test/unit/rt_case1.c"
+}
+
+//----------------------------------------------------------------
+#define T(path, desc, fn) register_test(ts, "/base/data-struct/radix-tree/" path, desc, fn)
+
+void radix_tree_tests(struct dm_list *all_tests)
+{
+ struct test_suite *ts = test_suite_create(rt_init, rt_exit);
+ if (!ts) {
+ fprintf(stderr, "out of memory\n");
+ exit(1);
+ }
+
+ T("create-destroy", "create and destroy an empty tree", test_create_destroy);
+ T("insert-one", "insert one trivial trivial key", test_insert_one);
+ T("insert-single-byte-keys", "inserts many single byte keys", test_single_byte_keys);
+ T("overwrite-single-byte-keys", "overwrite many single byte keys", test_overwrite_single_byte_keys);
+ T("insert-16-bit-keys", "insert many 16bit keys", test_16_bit_keys);
+ T("prefix-keys", "prefixes of other keys are valid keys", test_prefix_keys);
+ T("prefix-keys-reversed", "prefixes of other keys are valid keys", test_prefix_keys_reversed);
+ T("sparse-keys", "see what the memory usage is for sparsely distributed keys", test_sparse_keys);
+ T("remove-one", "remove one entry", test_remove_one);
+ T("remove-one-byte-keys", "remove many one byte keys", test_remove_one_byte_keys);
+ T("remove-one-byte-keys-reversed", "remove many one byte keys reversed", test_remove_one_byte_keys_reversed);
+ T("remove-prefix-keys", "remove a set of keys that have common prefixes", test_remove_prefix_keys);
+ T("remove-prefix-keys-reversed", "remove a set of keys that have common prefixes (reversed)", test_remove_prefix_keys_reversed);
+ T("remove-prefix", "remove a subrange", test_remove_prefix);
+ T("remove-prefix-single", "remove a subrange with a single entry", test_remove_prefix_single);
+ T("size-spots-duplicates", "duplicate entries aren't counted twice", test_size);
+ T("iterate-all", "iterate all entries in tree", test_iterate_all);
+ T("iterate-subset", "iterate a subset of entries in tree", test_iterate_subset);
+ T("iterate-single", "iterate a subset that contains a single entry", test_iterate_single);
+ T("iterate-vary-middle", "iterate keys that vary in the middle", test_iterate_vary_middle);
+ T("remove-calls-dtr", "remove should call the dtr for the value", test_remove_calls_dtr);
+ T("destroy-calls-dtr", "destroy should call the dtr for all values", test_destroy_calls_dtr);
+ T("bcache-scenario", "A specific series of keys from a bcache scenario", test_bcache_scenario);
+ T("bcache-scenario-2", "A second series of keys from a bcache scenario", test_bcache_scenario2);
+ T("bcache-scenario-3", "A third series of keys from a bcache scenario", test_bcache_scenario3);
+
+ dm_list_add(all_tests, &ts->list);
+}
+//----------------------------------------------------------------
diff --git a/test/unit/rt_case1.c b/test/unit/rt_case1.c
new file mode 100644
index 0000000..c1677d1
--- /dev/null
+++ b/test/unit/rt_case1.c
@@ -0,0 +1,1669 @@
+ __lookup_fails(rt, 6, 0);
+ __insert(rt, 6, 0, 0);
+ __lookup_fails(rt, 7, 0);
+ __insert(rt, 7, 0, 1);
+ __lookup_fails(rt, 8, 0);
+ __insert(rt, 8, 0, 2);
+ __lookup_fails(rt, 9, 0);
+ __insert(rt, 9, 0, 3);
+ __lookup_fails(rt, 10, 0);
+ __insert(rt, 10, 0, 4);
+ __lookup_fails(rt, 11, 0);
+ __insert(rt, 11, 0, 5);
+ __lookup_fails(rt, 12, 0);
+ __insert(rt, 12, 0, 6);
+ __lookup_fails(rt, 13, 0);
+ __insert(rt, 13, 0, 7);
+ __lookup_fails(rt, 14, 0);
+ __insert(rt, 14, 0, 8);
+ __lookup_fails(rt, 15, 0);
+ __insert(rt, 15, 0, 9);
+ __lookup_fails(rt, 16, 0);
+ __insert(rt, 16, 0, 10);
+ __lookup_fails(rt, 17, 0);
+ __insert(rt, 17, 0, 11);
+ __lookup_fails(rt, 18, 0);
+ __insert(rt, 18, 0, 12);
+ __lookup_fails(rt, 19, 0);
+ __insert(rt, 19, 0, 13);
+ __lookup_fails(rt, 20, 0);
+ __insert(rt, 20, 0, 14);
+ __lookup_fails(rt, 21, 0);
+ __insert(rt, 21, 0, 15);
+ __lookup_fails(rt, 22, 0);
+ __insert(rt, 22, 0, 16);
+ __lookup_fails(rt, 23, 0);
+ __insert(rt, 23, 0, 17);
+ __lookup_fails(rt, 24, 0);
+ __insert(rt, 24, 0, 18);
+ __lookup_fails(rt, 25, 0);
+ __insert(rt, 25, 0, 19);
+ __lookup_fails(rt, 26, 0);
+ __insert(rt, 26, 0, 20);
+ __lookup_fails(rt, 27, 0);
+ __insert(rt, 27, 0, 21);
+ __lookup_fails(rt, 28, 0);
+ __insert(rt, 28, 0, 22);
+ __lookup_fails(rt, 29, 0);
+ __insert(rt, 29, 0, 23);
+ __lookup_fails(rt, 30, 0);
+ __insert(rt, 30, 0, 24);
+ __lookup_fails(rt, 31, 0);
+ __insert(rt, 31, 0, 25);
+ __lookup_fails(rt, 32, 0);
+ __insert(rt, 32, 0, 26);
+ __lookup_fails(rt, 33, 0);
+ __insert(rt, 33, 0, 27);
+ __lookup_fails(rt, 34, 0);
+ __insert(rt, 34, 0, 28);
+ __lookup_fails(rt, 35, 0);
+ __insert(rt, 35, 0, 29);
+ __lookup_fails(rt, 36, 0);
+ __insert(rt, 36, 0, 30);
+ __lookup_fails(rt, 37, 0);
+ __insert(rt, 37, 0, 31);
+ __lookup_fails(rt, 38, 0);
+ __insert(rt, 38, 0, 32);
+ __lookup_fails(rt, 39, 0);
+ __insert(rt, 39, 0, 33);
+ __lookup_fails(rt, 40, 0);
+ __insert(rt, 40, 0, 34);
+ __lookup_fails(rt, 41, 0);
+ __insert(rt, 41, 0, 35);
+ __lookup_fails(rt, 42, 0);
+ __insert(rt, 42, 0, 36);
+ __lookup_fails(rt, 43, 0);
+ __insert(rt, 43, 0, 37);
+ __lookup_fails(rt, 44, 0);
+ __insert(rt, 44, 0, 38);
+ __lookup_fails(rt, 45, 0);
+ __insert(rt, 45, 0, 39);
+ __lookup_fails(rt, 46, 0);
+ __insert(rt, 46, 0, 40);
+ __lookup_fails(rt, 47, 0);
+ __insert(rt, 47, 0, 41);
+ __lookup_fails(rt, 48, 0);
+ __insert(rt, 48, 0, 42);
+ __lookup_fails(rt, 49, 0);
+ __insert(rt, 49, 0, 43);
+ __lookup_fails(rt, 50, 0);
+ __insert(rt, 50, 0, 44);
+ __lookup_fails(rt, 51, 0);
+ __insert(rt, 51, 0, 45);
+ __lookup_fails(rt, 52, 0);
+ __insert(rt, 52, 0, 46);
+ __lookup_fails(rt, 53, 0);
+ __insert(rt, 53, 0, 47);
+ __lookup_fails(rt, 54, 0);
+ __insert(rt, 54, 0, 48);
+ __lookup_fails(rt, 55, 0);
+ __insert(rt, 55, 0, 49);
+ __lookup_fails(rt, 56, 0);
+ __insert(rt, 56, 0, 50);
+ __lookup_fails(rt, 57, 0);
+ __insert(rt, 57, 0, 51);
+ __lookup_fails(rt, 58, 0);
+ __insert(rt, 58, 0, 52);
+ __lookup_fails(rt, 59, 0);
+ __insert(rt, 59, 0, 53);
+ __lookup_fails(rt, 60, 0);
+ __insert(rt, 60, 0, 54);
+ __lookup_fails(rt, 61, 0);
+ __insert(rt, 61, 0, 55);
+ __lookup_fails(rt, 62, 0);
+ __insert(rt, 62, 0, 56);
+ __lookup_fails(rt, 63, 0);
+ __insert(rt, 63, 0, 57);
+ __lookup_fails(rt, 64, 0);
+ __insert(rt, 64, 0, 58);
+ __lookup_fails(rt, 65, 0);
+ __insert(rt, 65, 0, 59);
+ __lookup_fails(rt, 66, 0);
+ __insert(rt, 66, 0, 60);
+ __lookup_fails(rt, 67, 0);
+ __insert(rt, 67, 0, 61);
+ __lookup_fails(rt, 68, 0);
+ __insert(rt, 68, 0, 62);
+ __lookup_fails(rt, 69, 0);
+ __insert(rt, 69, 0, 63);
+ __lookup_fails(rt, 70, 0);
+ __insert(rt, 70, 0, 64);
+ __lookup_fails(rt, 71, 0);
+ __insert(rt, 71, 0, 65);
+ __lookup_fails(rt, 72, 0);
+ __insert(rt, 72, 0, 66);
+ __lookup_fails(rt, 73, 0);
+ __insert(rt, 73, 0, 67);
+ __lookup_fails(rt, 74, 0);
+ __insert(rt, 74, 0, 68);
+ __lookup_fails(rt, 75, 0);
+ __insert(rt, 75, 0, 69);
+ __lookup_fails(rt, 76, 0);
+ __insert(rt, 76, 0, 70);
+ __lookup_fails(rt, 77, 0);
+ __insert(rt, 77, 0, 71);
+ __lookup_fails(rt, 78, 0);
+ __insert(rt, 78, 0, 72);
+ __lookup_fails(rt, 79, 0);
+ __insert(rt, 79, 0, 73);
+ __lookup_fails(rt, 80, 0);
+ __insert(rt, 80, 0, 74);
+ __lookup_fails(rt, 81, 0);
+ __insert(rt, 81, 0, 75);
+ __lookup_fails(rt, 82, 0);
+ __insert(rt, 82, 0, 76);
+ __lookup_fails(rt, 83, 0);
+ __insert(rt, 83, 0, 77);
+ __lookup_fails(rt, 84, 0);
+ __insert(rt, 84, 0, 78);
+ __lookup_fails(rt, 85, 0);
+ __insert(rt, 85, 0, 79);
+ __lookup_fails(rt, 86, 0);
+ __insert(rt, 86, 0, 80);
+ __lookup_fails(rt, 87, 0);
+ __insert(rt, 87, 0, 81);
+ __lookup_fails(rt, 88, 0);
+ __insert(rt, 88, 0, 82);
+ __lookup_fails(rt, 89, 0);
+ __insert(rt, 89, 0, 83);
+ __lookup_fails(rt, 90, 0);
+ __insert(rt, 90, 0, 84);
+ __lookup_fails(rt, 91, 0);
+ __insert(rt, 91, 0, 85);
+ __lookup_fails(rt, 92, 0);
+ __insert(rt, 92, 0, 86);
+ __lookup_fails(rt, 93, 0);
+ __insert(rt, 93, 0, 87);
+ __lookup_fails(rt, 94, 0);
+ __insert(rt, 94, 0, 88);
+ __lookup_fails(rt, 95, 0);
+ __insert(rt, 95, 0, 89);
+ __lookup_fails(rt, 96, 0);
+ __insert(rt, 96, 0, 90);
+ __lookup_fails(rt, 97, 0);
+ __insert(rt, 97, 0, 91);
+ __lookup_fails(rt, 98, 0);
+ __insert(rt, 98, 0, 92);
+ __lookup_fails(rt, 99, 0);
+ __insert(rt, 99, 0, 93);
+ __lookup_fails(rt, 100, 0);
+ __insert(rt, 100, 0, 94);
+ __lookup_fails(rt, 101, 0);
+ __insert(rt, 101, 0, 95);
+ __lookup_fails(rt, 102, 0);
+ __insert(rt, 102, 0, 96);
+ __lookup_fails(rt, 103, 0);
+ __insert(rt, 103, 0, 97);
+ __lookup_fails(rt, 104, 0);
+ __insert(rt, 104, 0, 98);
+ __lookup_fails(rt, 105, 0);
+ __insert(rt, 105, 0, 99);
+ __lookup_fails(rt, 106, 0);
+ __insert(rt, 106, 0, 100);
+ __lookup_fails(rt, 107, 0);
+ __insert(rt, 107, 0, 101);
+ __lookup_fails(rt, 108, 0);
+ __insert(rt, 108, 0, 102);
+ __lookup_fails(rt, 109, 0);
+ __insert(rt, 109, 0, 103);
+ __lookup_fails(rt, 110, 0);
+ __insert(rt, 110, 0, 104);
+ __lookup_fails(rt, 111, 0);
+ __insert(rt, 111, 0, 105);
+ __lookup_fails(rt, 112, 0);
+ __insert(rt, 112, 0, 106);
+ __lookup_fails(rt, 113, 0);
+ __insert(rt, 113, 0, 107);
+ __lookup_fails(rt, 114, 0);
+ __insert(rt, 114, 0, 108);
+ __lookup_fails(rt, 115, 0);
+ __insert(rt, 115, 0, 109);
+ __lookup_fails(rt, 116, 0);
+ __insert(rt, 116, 0, 110);
+ __lookup_fails(rt, 117, 0);
+ __insert(rt, 117, 0, 111);
+ __lookup_fails(rt, 118, 0);
+ __insert(rt, 118, 0, 112);
+ __lookup_fails(rt, 119, 0);
+ __insert(rt, 119, 0, 113);
+ __lookup_fails(rt, 120, 0);
+ __insert(rt, 120, 0, 114);
+ __lookup_fails(rt, 121, 0);
+ __insert(rt, 121, 0, 115);
+ __lookup_fails(rt, 122, 0);
+ __insert(rt, 122, 0, 116);
+ __lookup_fails(rt, 123, 0);
+ __insert(rt, 123, 0, 117);
+ __lookup_fails(rt, 124, 0);
+ __insert(rt, 124, 0, 118);
+ __lookup_fails(rt, 125, 0);
+ __insert(rt, 125, 0, 119);
+ __lookup_fails(rt, 126, 0);
+ __insert(rt, 126, 0, 120);
+ __lookup_fails(rt, 127, 0);
+ __insert(rt, 127, 0, 121);
+ __lookup_fails(rt, 128, 0);
+ __insert(rt, 128, 0, 122);
+ __lookup_fails(rt, 129, 0);
+ __insert(rt, 129, 0, 123);
+ __lookup_fails(rt, 130, 0);
+ __insert(rt, 130, 0, 124);
+ __lookup_fails(rt, 131, 0);
+ __insert(rt, 131, 0, 125);
+ __lookup_fails(rt, 132, 0);
+ __insert(rt, 132, 0, 126);
+ __lookup_fails(rt, 133, 0);
+ __insert(rt, 133, 0, 127);
+ __lookup_fails(rt, 134, 0);
+ __insert(rt, 134, 0, 128);
+ __lookup_fails(rt, 135, 0);
+ __insert(rt, 135, 0, 129);
+ __lookup_fails(rt, 136, 0);
+ __insert(rt, 136, 0, 130);
+ __lookup_fails(rt, 137, 0);
+ __insert(rt, 137, 0, 131);
+ __lookup_fails(rt, 138, 0);
+ __insert(rt, 138, 0, 132);
+ __lookup_fails(rt, 139, 0);
+ __insert(rt, 139, 0, 133);
+ __lookup_fails(rt, 140, 0);
+ __insert(rt, 140, 0, 134);
+ __lookup_fails(rt, 141, 0);
+ __insert(rt, 141, 0, 135);
+ __lookup_fails(rt, 142, 0);
+ __insert(rt, 142, 0, 136);
+ __lookup_fails(rt, 143, 0);
+ __insert(rt, 143, 0, 137);
+ __lookup_fails(rt, 144, 0);
+ __insert(rt, 144, 0, 138);
+ __lookup_fails(rt, 145, 0);
+ __insert(rt, 145, 0, 139);
+ __lookup_fails(rt, 146, 0);
+ __insert(rt, 146, 0, 140);
+ __lookup_fails(rt, 147, 0);
+ __insert(rt, 147, 0, 141);
+ __lookup_fails(rt, 148, 0);
+ __insert(rt, 148, 0, 142);
+ __lookup_fails(rt, 149, 0);
+ __insert(rt, 149, 0, 143);
+ __lookup_fails(rt, 150, 0);
+ __insert(rt, 150, 0, 144);
+ __lookup_fails(rt, 151, 0);
+ __insert(rt, 151, 0, 145);
+ __lookup_fails(rt, 152, 0);
+ __insert(rt, 152, 0, 146);
+ __lookup_fails(rt, 153, 0);
+ __insert(rt, 153, 0, 147);
+ __lookup_fails(rt, 154, 0);
+ __insert(rt, 154, 0, 148);
+ __lookup_fails(rt, 155, 0);
+ __insert(rt, 155, 0, 149);
+ __lookup_fails(rt, 156, 0);
+ __insert(rt, 156, 0, 150);
+ __lookup_fails(rt, 157, 0);
+ __insert(rt, 157, 0, 151);
+ __lookup_fails(rt, 158, 0);
+ __insert(rt, 158, 0, 152);
+ __lookup_fails(rt, 159, 0);
+ __insert(rt, 159, 0, 153);
+ __lookup_fails(rt, 160, 0);
+ __insert(rt, 160, 0, 154);
+ __lookup_fails(rt, 161, 0);
+ __insert(rt, 161, 0, 155);
+ __lookup_fails(rt, 162, 0);
+ __insert(rt, 162, 0, 156);
+ __lookup_fails(rt, 163, 0);
+ __insert(rt, 163, 0, 157);
+ __lookup_fails(rt, 164, 0);
+ __insert(rt, 164, 0, 158);
+ __lookup_fails(rt, 165, 0);
+ __insert(rt, 165, 0, 159);
+ __lookup_fails(rt, 166, 0);
+ __insert(rt, 166, 0, 160);
+ __lookup_fails(rt, 167, 0);
+ __insert(rt, 167, 0, 161);
+ __lookup_fails(rt, 168, 0);
+ __insert(rt, 168, 0, 162);
+ __lookup_fails(rt, 169, 0);
+ __insert(rt, 169, 0, 163);
+ __lookup_fails(rt, 170, 0);
+ __insert(rt, 170, 0, 164);
+ __lookup_fails(rt, 171, 0);
+ __insert(rt, 171, 0, 165);
+ __lookup_fails(rt, 172, 0);
+ __insert(rt, 172, 0, 166);
+ __lookup_fails(rt, 173, 0);
+ __insert(rt, 173, 0, 167);
+ __lookup_fails(rt, 174, 0);
+ __insert(rt, 174, 0, 168);
+ __lookup_fails(rt, 175, 0);
+ __insert(rt, 175, 0, 169);
+ __lookup_fails(rt, 176, 0);
+ __insert(rt, 176, 0, 170);
+ __lookup_fails(rt, 177, 0);
+ __insert(rt, 177, 0, 171);
+ __lookup_fails(rt, 178, 0);
+ __insert(rt, 178, 0, 172);
+ __lookup_fails(rt, 179, 0);
+ __insert(rt, 179, 0, 173);
+ __lookup_fails(rt, 180, 0);
+ __insert(rt, 180, 0, 174);
+ __lookup_fails(rt, 181, 0);
+ __insert(rt, 181, 0, 175);
+ __lookup_fails(rt, 182, 0);
+ __insert(rt, 182, 0, 176);
+ __lookup_fails(rt, 183, 0);
+ __insert(rt, 183, 0, 177);
+ __lookup_fails(rt, 184, 0);
+ __insert(rt, 184, 0, 178);
+ __lookup_fails(rt, 185, 0);
+ __insert(rt, 185, 0, 179);
+ __lookup_fails(rt, 186, 0);
+ __insert(rt, 186, 0, 180);
+ __lookup_fails(rt, 187, 0);
+ __insert(rt, 187, 0, 181);
+ __lookup_fails(rt, 188, 0);
+ __insert(rt, 188, 0, 182);
+ __lookup_fails(rt, 189, 0);
+ __insert(rt, 189, 0, 183);
+ __lookup_fails(rt, 190, 0);
+ __insert(rt, 190, 0, 184);
+ __lookup_fails(rt, 191, 0);
+ __insert(rt, 191, 0, 185);
+ __lookup_fails(rt, 192, 0);
+ __insert(rt, 192, 0, 186);
+ __lookup_fails(rt, 193, 0);
+ __insert(rt, 193, 0, 187);
+ __lookup_fails(rt, 194, 0);
+ __insert(rt, 194, 0, 188);
+ __lookup_fails(rt, 195, 0);
+ __insert(rt, 195, 0, 189);
+ __lookup_fails(rt, 196, 0);
+ __insert(rt, 196, 0, 190);
+ __lookup_fails(rt, 197, 0);
+ __insert(rt, 197, 0, 191);
+ __lookup_fails(rt, 198, 0);
+ __insert(rt, 198, 0, 192);
+ __lookup_fails(rt, 199, 0);
+ __insert(rt, 199, 0, 193);
+ __lookup_fails(rt, 200, 0);
+ __insert(rt, 200, 0, 194);
+ __lookup_fails(rt, 201, 0);
+ __insert(rt, 201, 0, 195);
+ __lookup_fails(rt, 202, 0);
+ __insert(rt, 202, 0, 196);
+ __lookup_fails(rt, 203, 0);
+ __insert(rt, 203, 0, 197);
+ __lookup_fails(rt, 204, 0);
+ __insert(rt, 204, 0, 198);
+ __lookup_fails(rt, 205, 0);
+ __insert(rt, 205, 0, 199);
+ __lookup_matches(rt, 6, 0, 0);
+ __invalidate(rt, 6);
+ __lookup_matches(rt, 7, 0, 1);
+ __invalidate(rt, 7);
+ __lookup_matches(rt, 8, 0, 2);
+ __invalidate(rt, 8);
+ __lookup_matches(rt, 9, 0, 3);
+ __invalidate(rt, 9);
+ __lookup_matches(rt, 10, 0, 4);
+ __invalidate(rt, 10);
+ __lookup_matches(rt, 11, 0, 5);
+ __invalidate(rt, 11);
+ __lookup_matches(rt, 12, 0, 6);
+ __lookup_matches(rt, 13, 0, 7);
+ __invalidate(rt, 13);
+ __lookup_matches(rt, 14, 0, 8);
+ __invalidate(rt, 14);
+ __lookup_matches(rt, 15, 0, 9);
+ __invalidate(rt, 15);
+ __lookup_matches(rt, 16, 0, 10);
+ __invalidate(rt, 16);
+ __lookup_matches(rt, 17, 0, 11);
+ __invalidate(rt, 17);
+ __lookup_matches(rt, 18, 0, 12);
+ __invalidate(rt, 18);
+ __lookup_matches(rt, 19, 0, 13);
+ __invalidate(rt, 19);
+ __lookup_matches(rt, 20, 0, 14);
+ __invalidate(rt, 20);
+ __lookup_matches(rt, 21, 0, 15);
+ __invalidate(rt, 21);
+ __lookup_matches(rt, 22, 0, 16);
+ __invalidate(rt, 22);
+ __lookup_matches(rt, 23, 0, 17);
+ __invalidate(rt, 23);
+ __lookup_matches(rt, 24, 0, 18);
+ __invalidate(rt, 24);
+ __lookup_matches(rt, 25, 0, 19);
+ __invalidate(rt, 25);
+ __lookup_matches(rt, 26, 0, 20);
+ __invalidate(rt, 26);
+ __lookup_matches(rt, 27, 0, 21);
+ __invalidate(rt, 27);
+ __lookup_matches(rt, 28, 0, 22);
+ __invalidate(rt, 28);
+ __lookup_matches(rt, 29, 0, 23);
+ __invalidate(rt, 29);
+ __lookup_matches(rt, 30, 0, 24);
+ __invalidate(rt, 30);
+ __lookup_matches(rt, 31, 0, 25);
+ __invalidate(rt, 31);
+ __lookup_matches(rt, 32, 0, 26);
+ __invalidate(rt, 32);
+ __lookup_matches(rt, 33, 0, 27);
+ __invalidate(rt, 33);
+ __lookup_matches(rt, 34, 0, 28);
+ __invalidate(rt, 34);
+ __lookup_matches(rt, 35, 0, 29);
+ __invalidate(rt, 35);
+ __lookup_matches(rt, 36, 0, 30);
+ __invalidate(rt, 36);
+ __lookup_matches(rt, 37, 0, 31);
+ __invalidate(rt, 37);
+ __lookup_matches(rt, 38, 0, 32);
+ __invalidate(rt, 38);
+ __lookup_matches(rt, 39, 0, 33);
+ __invalidate(rt, 39);
+ __lookup_matches(rt, 40, 0, 34);
+ __invalidate(rt, 40);
+ __lookup_matches(rt, 41, 0, 35);
+ __invalidate(rt, 41);
+ __lookup_matches(rt, 42, 0, 36);
+ __invalidate(rt, 42);
+ __lookup_matches(rt, 43, 0, 37);
+ __invalidate(rt, 43);
+ __lookup_matches(rt, 44, 0, 38);
+ __invalidate(rt, 44);
+ __lookup_matches(rt, 45, 0, 39);
+ __invalidate(rt, 45);
+ __lookup_matches(rt, 46, 0, 40);
+ __lookup_fails(rt, 46, 5);
+ __insert(rt, 46, 5, 200);
+ __lookup_matches(rt, 46, 5, 200);
+ __lookup_fails(rt, 46, 6);
+ __insert(rt, 46, 6, 201);
+ __lookup_fails(rt, 46, 7);
+ __insert(rt, 46, 7, 202);
+ __lookup_fails(rt, 46, 8);
+ __insert(rt, 46, 8, 203);
+ __lookup_matches(rt, 46, 5, 200);
+ __lookup_matches(rt, 46, 6, 201);
+ __lookup_matches(rt, 46, 7, 202);
+ __lookup_matches(rt, 46, 8, 203);
+ __lookup_matches(rt, 47, 0, 41);
+ __invalidate(rt, 47);
+ __lookup_matches(rt, 48, 0, 42);
+ __invalidate(rt, 48);
+ __lookup_matches(rt, 49, 0, 43);
+ __invalidate(rt, 49);
+ __lookup_matches(rt, 50, 0, 44);
+ __invalidate(rt, 50);
+ __lookup_matches(rt, 51, 0, 45);
+ __invalidate(rt, 51);
+ __lookup_matches(rt, 52, 0, 46);
+ __invalidate(rt, 52);
+ __lookup_matches(rt, 53, 0, 47);
+ __invalidate(rt, 53);
+ __lookup_matches(rt, 54, 0, 48);
+ __invalidate(rt, 54);
+ __lookup_matches(rt, 55, 0, 49);
+ __invalidate(rt, 55);
+ __lookup_matches(rt, 56, 0, 50);
+ __invalidate(rt, 56);
+ __lookup_matches(rt, 57, 0, 51);
+ __invalidate(rt, 57);
+ __lookup_matches(rt, 58, 0, 52);
+ __invalidate(rt, 58);
+ __lookup_matches(rt, 59, 0, 53);
+ __invalidate(rt, 59);
+ __lookup_matches(rt, 60, 0, 54);
+ __invalidate(rt, 60);
+ __lookup_matches(rt, 61, 0, 55);
+ __invalidate(rt, 61);
+ __lookup_matches(rt, 62, 0, 56);
+ __invalidate(rt, 62);
+ __lookup_matches(rt, 63, 0, 57);
+ __invalidate(rt, 63);
+ __lookup_matches(rt, 64, 0, 58);
+ __invalidate(rt, 64);
+ __lookup_matches(rt, 65, 0, 59);
+ __lookup_fails(rt, 65, 1);
+ __insert(rt, 65, 1, 204);
+ __lookup_fails(rt, 65, 2);
+ __insert(rt, 65, 2, 205);
+ __lookup_fails(rt, 65, 3);
+ __insert(rt, 65, 3, 206);
+ __lookup_fails(rt, 65, 4);
+ __insert(rt, 65, 4, 207);
+ __lookup_matches(rt, 65, 0, 59);
+ __lookup_matches(rt, 65, 1, 204);
+ __lookup_matches(rt, 65, 2, 205);
+ __lookup_matches(rt, 65, 3, 206);
+ __lookup_matches(rt, 65, 4, 207);
+ __lookup_matches(rt, 66, 0, 60);
+ __invalidate(rt, 66);
+ __lookup_matches(rt, 67, 0, 61);
+ __invalidate(rt, 67);
+ __lookup_matches(rt, 68, 0, 62);
+ __invalidate(rt, 68);
+ __lookup_matches(rt, 69, 0, 63);
+ __invalidate(rt, 69);
+ __lookup_matches(rt, 70, 0, 64);
+ __invalidate(rt, 70);
+ __lookup_matches(rt, 71, 0, 65);
+ __invalidate(rt, 71);
+ __lookup_matches(rt, 72, 0, 66);
+ __invalidate(rt, 72);
+ __lookup_matches(rt, 73, 0, 67);
+ __invalidate(rt, 73);
+ __lookup_matches(rt, 74, 0, 68);
+ __invalidate(rt, 74);
+ __lookup_matches(rt, 75, 0, 69);
+ __invalidate(rt, 75);
+ __lookup_matches(rt, 76, 0, 70);
+ __invalidate(rt, 76);
+ __lookup_matches(rt, 77, 0, 71);
+ __invalidate(rt, 77);
+ __lookup_matches(rt, 78, 0, 72);
+ __invalidate(rt, 78);
+ __lookup_matches(rt, 79, 0, 73);
+ __invalidate(rt, 79);
+ __lookup_matches(rt, 80, 0, 74);
+ __invalidate(rt, 80);
+ __lookup_matches(rt, 81, 0, 75);
+ __invalidate(rt, 81);
+ __lookup_matches(rt, 82, 0, 76);
+ __invalidate(rt, 82);
+ __lookup_matches(rt, 83, 0, 77);
+ __invalidate(rt, 83);
+ __lookup_matches(rt, 84, 0, 78);
+ __invalidate(rt, 84);
+ __lookup_matches(rt, 85, 0, 79);
+ __invalidate(rt, 85);
+ __lookup_matches(rt, 86, 0, 80);
+ __invalidate(rt, 86);
+ __lookup_matches(rt, 87, 0, 81);
+ __invalidate(rt, 87);
+ __lookup_matches(rt, 88, 0, 82);
+ __invalidate(rt, 88);
+ __lookup_matches(rt, 89, 0, 83);
+ __invalidate(rt, 89);
+ __lookup_matches(rt, 90, 0, 84);
+ __invalidate(rt, 90);
+ __lookup_matches(rt, 91, 0, 85);
+ __invalidate(rt, 91);
+ __lookup_matches(rt, 92, 0, 86);
+ __invalidate(rt, 92);
+ __lookup_matches(rt, 93, 0, 87);
+ __invalidate(rt, 93);
+ __lookup_matches(rt, 94, 0, 88);
+ __invalidate(rt, 94);
+ __lookup_matches(rt, 95, 0, 89);
+ __invalidate(rt, 95);
+ __lookup_matches(rt, 96, 0, 90);
+ __lookup_matches(rt, 97, 0, 91);
+ __invalidate(rt, 97);
+ __lookup_matches(rt, 98, 0, 92);
+ __invalidate(rt, 98);
+ __lookup_matches(rt, 99, 0, 93);
+ __invalidate(rt, 99);
+ __lookup_matches(rt, 100, 0, 94);
+ __invalidate(rt, 100);
+ __lookup_matches(rt, 101, 0, 95);
+ __invalidate(rt, 101);
+ __lookup_matches(rt, 102, 0, 96);
+ __invalidate(rt, 102);
+ __lookup_matches(rt, 103, 0, 97);
+ __invalidate(rt, 103);
+ __lookup_matches(rt, 104, 0, 98);
+ __invalidate(rt, 104);
+ __lookup_matches(rt, 105, 0, 99);
+ __invalidate(rt, 105);
+ __lookup_matches(rt, 106, 0, 100);
+ __invalidate(rt, 106);
+ __lookup_matches(rt, 107, 0, 101);
+ __invalidate(rt, 107);
+ __lookup_matches(rt, 108, 0, 102);
+ __invalidate(rt, 108);
+ __lookup_matches(rt, 109, 0, 103);
+ __invalidate(rt, 109);
+ __lookup_matches(rt, 110, 0, 104);
+ __invalidate(rt, 110);
+ __lookup_matches(rt, 111, 0, 105);
+ __invalidate(rt, 111);
+ __lookup_matches(rt, 112, 0, 106);
+ __invalidate(rt, 112);
+ __lookup_matches(rt, 113, 0, 107);
+ __invalidate(rt, 113);
+ __lookup_matches(rt, 114, 0, 108);
+ __invalidate(rt, 114);
+ __lookup_matches(rt, 115, 0, 109);
+ __invalidate(rt, 115);
+ __lookup_matches(rt, 116, 0, 110);
+ __invalidate(rt, 116);
+ __lookup_matches(rt, 117, 0, 111);
+ __invalidate(rt, 117);
+ __lookup_matches(rt, 118, 0, 112);
+ __invalidate(rt, 118);
+ __lookup_matches(rt, 119, 0, 113);
+ __invalidate(rt, 119);
+ __lookup_matches(rt, 120, 0, 114);
+ __invalidate(rt, 120);
+ __lookup_matches(rt, 121, 0, 115);
+ __invalidate(rt, 121);
+ __lookup_matches(rt, 122, 0, 116);
+ __invalidate(rt, 122);
+ __lookup_matches(rt, 123, 0, 117);
+ __invalidate(rt, 123);
+ __lookup_matches(rt, 124, 0, 118);
+ __invalidate(rt, 124);
+ __lookup_matches(rt, 125, 0, 119);
+ __invalidate(rt, 125);
+ __lookup_matches(rt, 126, 0, 120);
+ __invalidate(rt, 126);
+ __lookup_matches(rt, 127, 0, 121);
+ __invalidate(rt, 127);
+ __lookup_matches(rt, 128, 0, 122);
+ __invalidate(rt, 128);
+ __lookup_matches(rt, 129, 0, 123);
+ __invalidate(rt, 129);
+ __lookup_matches(rt, 130, 0, 124);
+ __invalidate(rt, 130);
+ __lookup_matches(rt, 131, 0, 125);
+ __invalidate(rt, 131);
+ __lookup_matches(rt, 132, 0, 126);
+ __invalidate(rt, 132);
+ __lookup_matches(rt, 133, 0, 127);
+ __invalidate(rt, 133);
+ __lookup_matches(rt, 134, 0, 128);
+ __invalidate(rt, 134);
+ __lookup_matches(rt, 135, 0, 129);
+ __invalidate(rt, 135);
+ __lookup_matches(rt, 136, 0, 130);
+ __invalidate(rt, 136);
+ __lookup_matches(rt, 137, 0, 131);
+ __invalidate(rt, 137);
+ __lookup_matches(rt, 138, 0, 132);
+ __invalidate(rt, 138);
+ __lookup_matches(rt, 139, 0, 133);
+ __invalidate(rt, 139);
+ __lookup_matches(rt, 140, 0, 134);
+ __invalidate(rt, 140);
+ __lookup_matches(rt, 141, 0, 135);
+ __invalidate(rt, 141);
+ __lookup_matches(rt, 142, 0, 136);
+ __invalidate(rt, 142);
+ __lookup_matches(rt, 143, 0, 137);
+ __invalidate(rt, 143);
+ __lookup_matches(rt, 144, 0, 138);
+ __invalidate(rt, 144);
+ __lookup_matches(rt, 145, 0, 139);
+ __invalidate(rt, 145);
+ __lookup_matches(rt, 146, 0, 140);
+ __invalidate(rt, 146);
+ __lookup_matches(rt, 147, 0, 141);
+ __invalidate(rt, 147);
+ __lookup_matches(rt, 148, 0, 142);
+ __invalidate(rt, 148);
+ __lookup_matches(rt, 149, 0, 143);
+ __invalidate(rt, 149);
+ __lookup_matches(rt, 150, 0, 144);
+ __invalidate(rt, 150);
+ __lookup_matches(rt, 151, 0, 145);
+ __invalidate(rt, 151);
+ __lookup_matches(rt, 152, 0, 146);
+ __invalidate(rt, 152);
+ __lookup_matches(rt, 153, 0, 147);
+ __invalidate(rt, 153);
+ __lookup_matches(rt, 154, 0, 148);
+ __invalidate(rt, 154);
+ __lookup_matches(rt, 155, 0, 149);
+ __invalidate(rt, 155);
+ __lookup_matches(rt, 156, 0, 150);
+ __invalidate(rt, 156);
+ __lookup_matches(rt, 157, 0, 151);
+ __invalidate(rt, 157);
+ __lookup_matches(rt, 158, 0, 152);
+ __invalidate(rt, 158);
+ __lookup_matches(rt, 159, 0, 153);
+ __invalidate(rt, 159);
+ __lookup_matches(rt, 160, 0, 154);
+ __invalidate(rt, 160);
+ __lookup_matches(rt, 161, 0, 155);
+ __invalidate(rt, 161);
+ __lookup_matches(rt, 162, 0, 156);
+ __invalidate(rt, 162);
+ __lookup_matches(rt, 163, 0, 157);
+ __lookup_matches(rt, 164, 0, 158);
+ __invalidate(rt, 164);
+ __lookup_matches(rt, 165, 0, 159);
+ __invalidate(rt, 165);
+ __lookup_matches(rt, 166, 0, 160);
+ __invalidate(rt, 166);
+ __lookup_matches(rt, 167, 0, 161);
+ __invalidate(rt, 167);
+ __lookup_matches(rt, 168, 0, 162);
+ __invalidate(rt, 168);
+ __lookup_matches(rt, 169, 0, 163);
+ __invalidate(rt, 169);
+ __lookup_matches(rt, 170, 0, 164);
+ __invalidate(rt, 170);
+ __lookup_matches(rt, 171, 0, 165);
+ __invalidate(rt, 171);
+ __lookup_matches(rt, 172, 0, 166);
+ __invalidate(rt, 172);
+ __lookup_matches(rt, 173, 0, 167);
+ __invalidate(rt, 173);
+ __lookup_matches(rt, 174, 0, 168);
+ __invalidate(rt, 174);
+ __lookup_matches(rt, 175, 0, 169);
+ __invalidate(rt, 175);
+ __lookup_matches(rt, 176, 0, 170);
+ __invalidate(rt, 176);
+ __lookup_matches(rt, 177, 0, 171);
+ __invalidate(rt, 177);
+ __lookup_matches(rt, 178, 0, 172);
+ __invalidate(rt, 178);
+ __lookup_matches(rt, 179, 0, 173);
+ __invalidate(rt, 179);
+ __lookup_matches(rt, 180, 0, 174);
+ __invalidate(rt, 180);
+ __lookup_matches(rt, 181, 0, 175);
+ __invalidate(rt, 181);
+ __lookup_matches(rt, 182, 0, 176);
+ __invalidate(rt, 182);
+ __lookup_matches(rt, 183, 0, 177);
+ __invalidate(rt, 183);
+ __lookup_matches(rt, 184, 0, 178);
+ __invalidate(rt, 184);
+ __lookup_matches(rt, 185, 0, 179);
+ __invalidate(rt, 185);
+ __lookup_matches(rt, 186, 0, 180);
+ __invalidate(rt, 186);
+ __lookup_matches(rt, 187, 0, 181);
+ __invalidate(rt, 187);
+ __lookup_matches(rt, 188, 0, 182);
+ __invalidate(rt, 188);
+ __lookup_matches(rt, 189, 0, 183);
+ __invalidate(rt, 189);
+ __lookup_matches(rt, 190, 0, 184);
+ __invalidate(rt, 190);
+ __lookup_matches(rt, 191, 0, 185);
+ __invalidate(rt, 191);
+ __lookup_matches(rt, 192, 0, 186);
+ __invalidate(rt, 192);
+ __lookup_matches(rt, 193, 0, 187);
+ __invalidate(rt, 193);
+ __lookup_matches(rt, 194, 0, 188);
+ __invalidate(rt, 194);
+ __lookup_matches(rt, 195, 0, 189);
+ __invalidate(rt, 195);
+ __lookup_matches(rt, 196, 0, 190);
+ __invalidate(rt, 196);
+ __lookup_matches(rt, 197, 0, 191);
+ __invalidate(rt, 197);
+ __lookup_matches(rt, 198, 0, 192);
+ __invalidate(rt, 198);
+ __lookup_matches(rt, 199, 0, 193);
+ __invalidate(rt, 199);
+ __lookup_matches(rt, 200, 0, 194);
+ __invalidate(rt, 200);
+ __lookup_matches(rt, 201, 0, 195);
+ __invalidate(rt, 201);
+ __lookup_matches(rt, 202, 0, 196);
+ __invalidate(rt, 202);
+ __lookup_matches(rt, 203, 0, 197);
+ __invalidate(rt, 203);
+ __lookup_matches(rt, 204, 0, 198);
+ __invalidate(rt, 204);
+ __lookup_matches(rt, 205, 0, 199);
+ __invalidate(rt, 205);
+ __lookup_fails(rt, 6, 0);
+ __insert(rt, 6, 0, 208);
+ __lookup_fails(rt, 7, 0);
+ __insert(rt, 7, 0, 209);
+ __lookup_fails(rt, 8, 0);
+ __insert(rt, 8, 0, 210);
+ __lookup_fails(rt, 9, 0);
+ __insert(rt, 9, 0, 211);
+ __lookup_fails(rt, 10, 0);
+ __insert(rt, 10, 0, 212);
+ __lookup_fails(rt, 11, 0);
+ __insert(rt, 11, 0, 213);
+ __lookup_fails(rt, 13, 0);
+ __insert(rt, 13, 0, 214);
+ __lookup_fails(rt, 14, 0);
+ __insert(rt, 14, 0, 215);
+ __lookup_fails(rt, 15, 0);
+ __insert(rt, 15, 0, 216);
+ __lookup_fails(rt, 16, 0);
+ __insert(rt, 16, 0, 217);
+ __lookup_fails(rt, 17, 0);
+ __insert(rt, 17, 0, 218);
+ __lookup_fails(rt, 18, 0);
+ __insert(rt, 18, 0, 219);
+ __lookup_fails(rt, 19, 0);
+ __insert(rt, 19, 0, 220);
+ __lookup_fails(rt, 20, 0);
+ __insert(rt, 20, 0, 221);
+ __lookup_fails(rt, 21, 0);
+ __insert(rt, 21, 0, 222);
+ __lookup_fails(rt, 22, 0);
+ __insert(rt, 22, 0, 223);
+ __lookup_fails(rt, 23, 0);
+ __insert(rt, 23, 0, 224);
+ __lookup_fails(rt, 24, 0);
+ __insert(rt, 24, 0, 225);
+ __lookup_fails(rt, 25, 0);
+ __insert(rt, 25, 0, 226);
+ __lookup_fails(rt, 26, 0);
+ __insert(rt, 26, 0, 227);
+ __lookup_fails(rt, 27, 0);
+ __insert(rt, 27, 0, 228);
+ __lookup_fails(rt, 28, 0);
+ __insert(rt, 28, 0, 229);
+ __lookup_fails(rt, 29, 0);
+ __insert(rt, 29, 0, 230);
+ __lookup_fails(rt, 30, 0);
+ __insert(rt, 30, 0, 231);
+ __lookup_fails(rt, 31, 0);
+ __insert(rt, 31, 0, 232);
+ __lookup_fails(rt, 32, 0);
+ __insert(rt, 32, 0, 233);
+ __lookup_fails(rt, 33, 0);
+ __insert(rt, 33, 0, 234);
+ __lookup_fails(rt, 34, 0);
+ __insert(rt, 34, 0, 235);
+ __lookup_fails(rt, 35, 0);
+ __insert(rt, 35, 0, 236);
+ __lookup_fails(rt, 36, 0);
+ __insert(rt, 36, 0, 237);
+ __lookup_fails(rt, 37, 0);
+ __insert(rt, 37, 0, 238);
+ __lookup_fails(rt, 38, 0);
+ __insert(rt, 38, 0, 239);
+ __lookup_fails(rt, 39, 0);
+ __insert(rt, 39, 0, 240);
+ __lookup_fails(rt, 40, 0);
+ __insert(rt, 40, 0, 241);
+ __lookup_fails(rt, 41, 0);
+ __insert(rt, 41, 0, 242);
+ __lookup_fails(rt, 42, 0);
+ __insert(rt, 42, 0, 243);
+ __lookup_fails(rt, 43, 0);
+ __insert(rt, 43, 0, 244);
+ __lookup_fails(rt, 44, 0);
+ __insert(rt, 44, 0, 245);
+ __lookup_fails(rt, 45, 0);
+ __insert(rt, 45, 0, 246);
+ __lookup_fails(rt, 47, 0);
+ __insert(rt, 47, 0, 247);
+ __lookup_fails(rt, 48, 0);
+ __insert(rt, 48, 0, 248);
+ __lookup_fails(rt, 49, 0);
+ __insert(rt, 49, 0, 249);
+ __lookup_fails(rt, 50, 0);
+ __insert(rt, 50, 0, 250);
+ __lookup_fails(rt, 51, 0);
+ __insert(rt, 51, 0, 251);
+ __lookup_fails(rt, 52, 0);
+ __insert(rt, 52, 0, 252);
+ __lookup_fails(rt, 53, 0);
+ __insert(rt, 53, 0, 253);
+ __lookup_fails(rt, 54, 0);
+ __insert(rt, 54, 0, 254);
+ __lookup_fails(rt, 55, 0);
+ __insert(rt, 55, 0, 255);
+ __lookup_fails(rt, 56, 0);
+ __insert(rt, 56, 0, 256);
+ __lookup_fails(rt, 57, 0);
+ __insert(rt, 57, 0, 257);
+ __lookup_fails(rt, 58, 0);
+ __insert(rt, 58, 0, 258);
+ __lookup_fails(rt, 59, 0);
+ __insert(rt, 59, 0, 259);
+ __lookup_fails(rt, 60, 0);
+ __insert(rt, 60, 0, 260);
+ __lookup_fails(rt, 61, 0);
+ __insert(rt, 61, 0, 261);
+ __lookup_fails(rt, 62, 0);
+ __insert(rt, 62, 0, 262);
+ __lookup_fails(rt, 63, 0);
+ __insert(rt, 63, 0, 263);
+ __lookup_fails(rt, 64, 0);
+ __insert(rt, 64, 0, 264);
+ __lookup_fails(rt, 66, 0);
+ __insert(rt, 66, 0, 265);
+ __lookup_fails(rt, 67, 0);
+ __insert(rt, 67, 0, 266);
+ __lookup_fails(rt, 68, 0);
+ __insert(rt, 68, 0, 267);
+ __lookup_fails(rt, 69, 0);
+ __insert(rt, 69, 0, 268);
+ __lookup_fails(rt, 70, 0);
+ __insert(rt, 70, 0, 269);
+ __lookup_fails(rt, 71, 0);
+ __insert(rt, 71, 0, 270);
+ __lookup_fails(rt, 72, 0);
+ __insert(rt, 72, 0, 271);
+ __lookup_fails(rt, 73, 0);
+ __insert(rt, 73, 0, 272);
+ __lookup_fails(rt, 74, 0);
+ __insert(rt, 74, 0, 273);
+ __lookup_fails(rt, 75, 0);
+ __insert(rt, 75, 0, 274);
+ __lookup_fails(rt, 76, 0);
+ __insert(rt, 76, 0, 275);
+ __lookup_fails(rt, 77, 0);
+ __insert(rt, 77, 0, 276);
+ __lookup_fails(rt, 78, 0);
+ __insert(rt, 78, 0, 277);
+ __lookup_fails(rt, 79, 0);
+ __insert(rt, 79, 0, 278);
+ __lookup_fails(rt, 80, 0);
+ __insert(rt, 80, 0, 279);
+ __lookup_fails(rt, 81, 0);
+ __insert(rt, 81, 0, 280);
+ __lookup_fails(rt, 82, 0);
+ __insert(rt, 82, 0, 281);
+ __lookup_fails(rt, 83, 0);
+ __insert(rt, 83, 0, 282);
+ __lookup_fails(rt, 84, 0);
+ __insert(rt, 84, 0, 283);
+ __lookup_fails(rt, 85, 0);
+ __insert(rt, 85, 0, 284);
+ __lookup_fails(rt, 86, 0);
+ __insert(rt, 86, 0, 285);
+ __lookup_fails(rt, 87, 0);
+ __insert(rt, 87, 0, 286);
+ __lookup_fails(rt, 88, 0);
+ __insert(rt, 88, 0, 287);
+ __lookup_fails(rt, 89, 0);
+ __insert(rt, 89, 0, 288);
+ __lookup_fails(rt, 90, 0);
+ __insert(rt, 90, 0, 289);
+ __lookup_fails(rt, 91, 0);
+ __insert(rt, 91, 0, 290);
+ __lookup_fails(rt, 92, 0);
+ __insert(rt, 92, 0, 291);
+ __lookup_fails(rt, 93, 0);
+ __insert(rt, 93, 0, 292);
+ __lookup_fails(rt, 94, 0);
+ __insert(rt, 94, 0, 293);
+ __lookup_fails(rt, 95, 0);
+ __insert(rt, 95, 0, 294);
+ __lookup_fails(rt, 97, 0);
+ __insert(rt, 97, 0, 295);
+ __lookup_fails(rt, 98, 0);
+ __insert(rt, 98, 0, 296);
+ __lookup_fails(rt, 99, 0);
+ __insert(rt, 99, 0, 297);
+ __lookup_fails(rt, 100, 0);
+ __insert(rt, 100, 0, 298);
+ __lookup_fails(rt, 101, 0);
+ __insert(rt, 101, 0, 299);
+ __lookup_fails(rt, 102, 0);
+ __insert(rt, 102, 0, 300);
+ __lookup_fails(rt, 103, 0);
+ __insert(rt, 103, 0, 301);
+ __lookup_fails(rt, 104, 0);
+ __insert(rt, 104, 0, 302);
+ __lookup_fails(rt, 105, 0);
+ __insert(rt, 105, 0, 303);
+ __lookup_fails(rt, 106, 0);
+ __insert(rt, 106, 0, 304);
+ __lookup_fails(rt, 107, 0);
+ __insert(rt, 107, 0, 305);
+ __lookup_fails(rt, 108, 0);
+ __insert(rt, 108, 0, 306);
+ __lookup_fails(rt, 109, 0);
+ __insert(rt, 109, 0, 307);
+ __lookup_fails(rt, 110, 0);
+ __insert(rt, 110, 0, 308);
+ __lookup_fails(rt, 111, 0);
+ __insert(rt, 111, 0, 309);
+ __lookup_fails(rt, 112, 0);
+ __insert(rt, 112, 0, 310);
+ __lookup_fails(rt, 113, 0);
+ __insert(rt, 113, 0, 311);
+ __lookup_fails(rt, 114, 0);
+ __insert(rt, 114, 0, 312);
+ __lookup_fails(rt, 115, 0);
+ __insert(rt, 115, 0, 313);
+ __lookup_fails(rt, 116, 0);
+ __insert(rt, 116, 0, 314);
+ __lookup_fails(rt, 117, 0);
+ __insert(rt, 117, 0, 315);
+ __lookup_fails(rt, 118, 0);
+ __insert(rt, 118, 0, 316);
+ __lookup_fails(rt, 119, 0);
+ __insert(rt, 119, 0, 317);
+ __lookup_fails(rt, 120, 0);
+ __insert(rt, 120, 0, 318);
+ __lookup_fails(rt, 121, 0);
+ __insert(rt, 121, 0, 319);
+ __lookup_fails(rt, 122, 0);
+ __insert(rt, 122, 0, 320);
+ __lookup_fails(rt, 123, 0);
+ __insert(rt, 123, 0, 321);
+ __lookup_fails(rt, 124, 0);
+ __insert(rt, 124, 0, 322);
+ __lookup_fails(rt, 125, 0);
+ __insert(rt, 125, 0, 323);
+ __lookup_fails(rt, 126, 0);
+ __insert(rt, 126, 0, 324);
+ __lookup_fails(rt, 127, 0);
+ __insert(rt, 127, 0, 325);
+ __lookup_fails(rt, 128, 0);
+ __insert(rt, 128, 0, 326);
+ __lookup_fails(rt, 129, 0);
+ __insert(rt, 129, 0, 327);
+ __lookup_fails(rt, 130, 0);
+ __insert(rt, 130, 0, 328);
+ __lookup_fails(rt, 131, 0);
+ __insert(rt, 131, 0, 329);
+ __lookup_fails(rt, 132, 0);
+ __insert(rt, 132, 0, 330);
+ __lookup_fails(rt, 133, 0);
+ __insert(rt, 133, 0, 331);
+ __lookup_fails(rt, 134, 0);
+ __insert(rt, 134, 0, 332);
+ __lookup_fails(rt, 135, 0);
+ __insert(rt, 135, 0, 333);
+ __lookup_fails(rt, 136, 0);
+ __insert(rt, 136, 0, 334);
+ __lookup_fails(rt, 137, 0);
+ __insert(rt, 137, 0, 335);
+ __lookup_fails(rt, 138, 0);
+ __insert(rt, 138, 0, 336);
+ __lookup_fails(rt, 139, 0);
+ __insert(rt, 139, 0, 337);
+ __lookup_fails(rt, 140, 0);
+ __insert(rt, 140, 0, 338);
+ __lookup_fails(rt, 141, 0);
+ __insert(rt, 141, 0, 339);
+ __lookup_fails(rt, 142, 0);
+ __insert(rt, 142, 0, 340);
+ __lookup_fails(rt, 143, 0);
+ __insert(rt, 143, 0, 341);
+ __lookup_fails(rt, 144, 0);
+ __insert(rt, 144, 0, 342);
+ __lookup_fails(rt, 145, 0);
+ __insert(rt, 145, 0, 343);
+ __lookup_fails(rt, 146, 0);
+ __insert(rt, 146, 0, 344);
+ __lookup_fails(rt, 147, 0);
+ __insert(rt, 147, 0, 345);
+ __lookup_fails(rt, 148, 0);
+ __insert(rt, 148, 0, 346);
+ __lookup_fails(rt, 149, 0);
+ __insert(rt, 149, 0, 347);
+ __lookup_fails(rt, 150, 0);
+ __insert(rt, 150, 0, 348);
+ __lookup_fails(rt, 151, 0);
+ __insert(rt, 151, 0, 349);
+ __lookup_fails(rt, 152, 0);
+ __insert(rt, 152, 0, 350);
+ __lookup_fails(rt, 153, 0);
+ __insert(rt, 153, 0, 351);
+ __lookup_fails(rt, 154, 0);
+ __insert(rt, 154, 0, 352);
+ __lookup_fails(rt, 155, 0);
+ __insert(rt, 155, 0, 353);
+ __lookup_fails(rt, 156, 0);
+ __insert(rt, 156, 0, 354);
+ __lookup_fails(rt, 157, 0);
+ __insert(rt, 157, 0, 355);
+ __lookup_fails(rt, 158, 0);
+ __insert(rt, 158, 0, 356);
+ __lookup_fails(rt, 159, 0);
+ __insert(rt, 159, 0, 357);
+ __lookup_fails(rt, 160, 0);
+ __insert(rt, 160, 0, 358);
+ __lookup_fails(rt, 161, 0);
+ __insert(rt, 161, 0, 359);
+ __lookup_fails(rt, 162, 0);
+ __insert(rt, 162, 0, 360);
+ __lookup_fails(rt, 164, 0);
+ __insert(rt, 164, 0, 361);
+ __lookup_fails(rt, 165, 0);
+ __insert(rt, 165, 0, 362);
+ __lookup_fails(rt, 166, 0);
+ __insert(rt, 166, 0, 363);
+ __lookup_fails(rt, 167, 0);
+ __insert(rt, 167, 0, 364);
+ __lookup_fails(rt, 168, 0);
+ __insert(rt, 168, 0, 365);
+ __lookup_fails(rt, 169, 0);
+ __insert(rt, 169, 0, 366);
+ __lookup_fails(rt, 170, 0);
+ __insert(rt, 170, 0, 367);
+ __lookup_fails(rt, 171, 0);
+ __insert(rt, 171, 0, 368);
+ __lookup_fails(rt, 172, 0);
+ __insert(rt, 172, 0, 369);
+ __lookup_fails(rt, 173, 0);
+ __insert(rt, 173, 0, 370);
+ __lookup_fails(rt, 174, 0);
+ __insert(rt, 174, 0, 371);
+ __lookup_fails(rt, 175, 0);
+ __insert(rt, 175, 0, 372);
+ __lookup_fails(rt, 176, 0);
+ __insert(rt, 176, 0, 373);
+ __lookup_fails(rt, 177, 0);
+ __insert(rt, 177, 0, 374);
+ __lookup_fails(rt, 178, 0);
+ __insert(rt, 178, 0, 375);
+ __lookup_fails(rt, 179, 0);
+ __insert(rt, 179, 0, 376);
+ __lookup_fails(rt, 180, 0);
+ __insert(rt, 180, 0, 377);
+ __lookup_fails(rt, 181, 0);
+ __insert(rt, 181, 0, 378);
+ __lookup_fails(rt, 182, 0);
+ __insert(rt, 182, 0, 379);
+ __lookup_fails(rt, 183, 0);
+ __insert(rt, 183, 0, 380);
+ __lookup_fails(rt, 184, 0);
+ __insert(rt, 184, 0, 381);
+ __lookup_fails(rt, 185, 0);
+ __insert(rt, 185, 0, 382);
+ __lookup_fails(rt, 186, 0);
+ __insert(rt, 186, 0, 383);
+ __lookup_fails(rt, 187, 0);
+ __insert(rt, 187, 0, 384);
+ __lookup_fails(rt, 188, 0);
+ __insert(rt, 188, 0, 385);
+ __lookup_fails(rt, 189, 0);
+ __insert(rt, 189, 0, 386);
+ __lookup_fails(rt, 190, 0);
+ __insert(rt, 190, 0, 387);
+ __lookup_fails(rt, 191, 0);
+ __insert(rt, 191, 0, 388);
+ __lookup_fails(rt, 192, 0);
+ __insert(rt, 192, 0, 389);
+ __lookup_fails(rt, 193, 0);
+ __insert(rt, 193, 0, 390);
+ __lookup_fails(rt, 194, 0);
+ __insert(rt, 194, 0, 391);
+ __lookup_fails(rt, 195, 0);
+ __insert(rt, 195, 0, 392);
+ __lookup_fails(rt, 196, 0);
+ __insert(rt, 196, 0, 393);
+ __lookup_fails(rt, 197, 0);
+ __insert(rt, 197, 0, 394);
+ __lookup_fails(rt, 198, 0);
+ __insert(rt, 198, 0, 395);
+ __lookup_fails(rt, 199, 0);
+ __insert(rt, 199, 0, 396);
+ __lookup_fails(rt, 200, 0);
+ __insert(rt, 200, 0, 397);
+ __lookup_fails(rt, 201, 0);
+ __insert(rt, 201, 0, 398);
+ __lookup_fails(rt, 202, 0);
+ __insert(rt, 202, 0, 399);
+ __lookup_fails(rt, 203, 0);
+ __insert(rt, 203, 0, 400);
+ __lookup_fails(rt, 204, 0);
+ __insert(rt, 204, 0, 401);
+ __lookup_fails(rt, 205, 0);
+ __insert(rt, 205, 0, 402);
+ __lookup_fails(rt, 206, 0);
+ __insert(rt, 206, 0, 403);
+ __lookup_fails(rt, 207, 0);
+ __insert(rt, 207, 0, 404);
+ __lookup_fails(rt, 208, 0);
+ __insert(rt, 208, 0, 405);
+ __lookup_fails(rt, 209, 0);
+ __insert(rt, 209, 0, 406);
+ __lookup_fails(rt, 210, 0);
+ __insert(rt, 210, 0, 407);
+ __lookup_matches(rt, 6, 0, 208);
+ __invalidate(rt, 6);
+ __lookup_matches(rt, 7, 0, 209);
+ __invalidate(rt, 7);
+ __lookup_matches(rt, 8, 0, 210);
+ __invalidate(rt, 8);
+ __lookup_matches(rt, 9, 0, 211);
+ __invalidate(rt, 9);
+ __lookup_matches(rt, 10, 0, 212);
+ __invalidate(rt, 10);
+ __lookup_matches(rt, 11, 0, 213);
+ __invalidate(rt, 11);
+ __lookup_matches(rt, 13, 0, 214);
+ __invalidate(rt, 13);
+ __lookup_matches(rt, 14, 0, 215);
+ __invalidate(rt, 14);
+ __lookup_matches(rt, 15, 0, 216);
+ __invalidate(rt, 15);
+ __lookup_matches(rt, 16, 0, 217);
+ __invalidate(rt, 16);
+ __lookup_matches(rt, 17, 0, 218);
+ __invalidate(rt, 17);
+ __lookup_matches(rt, 18, 0, 219);
+ __invalidate(rt, 18);
+ __lookup_matches(rt, 19, 0, 220);
+ __invalidate(rt, 19);
+ __lookup_matches(rt, 20, 0, 221);
+ __invalidate(rt, 20);
+ __lookup_matches(rt, 21, 0, 222);
+ __invalidate(rt, 21);
+ __lookup_matches(rt, 22, 0, 223);
+ __invalidate(rt, 22);
+ __lookup_matches(rt, 23, 0, 224);
+ __invalidate(rt, 23);
+ __lookup_matches(rt, 24, 0, 225);
+ __invalidate(rt, 24);
+ __lookup_matches(rt, 25, 0, 226);
+ __invalidate(rt, 25);
+ __lookup_matches(rt, 26, 0, 227);
+ __invalidate(rt, 26);
+ __lookup_matches(rt, 27, 0, 228);
+ __invalidate(rt, 27);
+ __lookup_matches(rt, 28, 0, 229);
+ __invalidate(rt, 28);
+ __lookup_matches(rt, 29, 0, 230);
+ __invalidate(rt, 29);
+ __lookup_matches(rt, 30, 0, 231);
+ __invalidate(rt, 30);
+ __lookup_matches(rt, 31, 0, 232);
+ __invalidate(rt, 31);
+ __lookup_matches(rt, 32, 0, 233);
+ __invalidate(rt, 32);
+ __lookup_matches(rt, 33, 0, 234);
+ __invalidate(rt, 33);
+ __lookup_matches(rt, 34, 0, 235);
+ __invalidate(rt, 34);
+ __lookup_matches(rt, 35, 0, 236);
+ __invalidate(rt, 35);
+ __lookup_matches(rt, 36, 0, 237);
+ __invalidate(rt, 36);
+ __lookup_matches(rt, 37, 0, 238);
+ __invalidate(rt, 37);
+ __lookup_matches(rt, 38, 0, 239);
+ __invalidate(rt, 38);
+ __lookup_matches(rt, 39, 0, 240);
+ __invalidate(rt, 39);
+ __lookup_matches(rt, 40, 0, 241);
+ __invalidate(rt, 40);
+ __lookup_matches(rt, 41, 0, 242);
+ __invalidate(rt, 41);
+ __lookup_matches(rt, 42, 0, 243);
+ __invalidate(rt, 42);
+ __lookup_matches(rt, 43, 0, 244);
+ __invalidate(rt, 43);
+ __lookup_matches(rt, 44, 0, 245);
+ __invalidate(rt, 44);
+ __lookup_matches(rt, 45, 0, 246);
+ __invalidate(rt, 45);
+ __lookup_matches(rt, 47, 0, 247);
+ __invalidate(rt, 47);
+ __lookup_matches(rt, 48, 0, 248);
+ __invalidate(rt, 48);
+ __lookup_matches(rt, 49, 0, 249);
+ __invalidate(rt, 49);
+ __lookup_matches(rt, 50, 0, 250);
+ __invalidate(rt, 50);
+ __lookup_matches(rt, 51, 0, 251);
+ __invalidate(rt, 51);
+ __lookup_matches(rt, 52, 0, 252);
+ __invalidate(rt, 52);
+ __lookup_matches(rt, 53, 0, 253);
+ __invalidate(rt, 53);
+ __lookup_matches(rt, 54, 0, 254);
+ __invalidate(rt, 54);
+ __lookup_matches(rt, 55, 0, 255);
+ __invalidate(rt, 55);
+ __lookup_matches(rt, 56, 0, 256);
+ __invalidate(rt, 56);
+ __lookup_matches(rt, 57, 0, 257);
+ __invalidate(rt, 57);
+ __lookup_matches(rt, 58, 0, 258);
+ __invalidate(rt, 58);
+ __lookup_matches(rt, 59, 0, 259);
+ __invalidate(rt, 59);
+ __lookup_matches(rt, 60, 0, 260);
+ __invalidate(rt, 60);
+ __lookup_matches(rt, 61, 0, 261);
+ __invalidate(rt, 61);
+ __lookup_matches(rt, 62, 0, 262);
+ __invalidate(rt, 62);
+ __lookup_matches(rt, 63, 0, 263);
+ __invalidate(rt, 63);
+ __lookup_matches(rt, 64, 0, 264);
+ __invalidate(rt, 64);
+ __lookup_matches(rt, 66, 0, 265);
+ __invalidate(rt, 66);
+ __lookup_matches(rt, 67, 0, 266);
+ __invalidate(rt, 67);
+ __lookup_matches(rt, 68, 0, 267);
+ __invalidate(rt, 68);
+ __lookup_matches(rt, 69, 0, 268);
+ __invalidate(rt, 69);
+ __lookup_matches(rt, 70, 0, 269);
+ __invalidate(rt, 70);
+ __lookup_matches(rt, 71, 0, 270);
+ __invalidate(rt, 71);
+ __lookup_matches(rt, 72, 0, 271);
+ __invalidate(rt, 72);
+ __lookup_matches(rt, 73, 0, 272);
+ __lookup_matches(rt, 74, 0, 273);
+ __invalidate(rt, 74);
+ __lookup_matches(rt, 75, 0, 274);
+ __invalidate(rt, 75);
+ __lookup_matches(rt, 76, 0, 275);
+ __invalidate(rt, 76);
+ __lookup_matches(rt, 77, 0, 276);
+ __invalidate(rt, 77);
+ __lookup_matches(rt, 78, 0, 277);
+ __invalidate(rt, 78);
+ __lookup_matches(rt, 79, 0, 278);
+ __invalidate(rt, 79);
+ __lookup_matches(rt, 80, 0, 279);
+ __invalidate(rt, 80);
+ __lookup_matches(rt, 81, 0, 280);
+ __invalidate(rt, 81);
+ __lookup_matches(rt, 82, 0, 281);
+ __invalidate(rt, 82);
+ __lookup_matches(rt, 83, 0, 282);
+ __invalidate(rt, 83);
+ __lookup_matches(rt, 84, 0, 283);
+ __invalidate(rt, 84);
+ __lookup_matches(rt, 85, 0, 284);
+ __invalidate(rt, 85);
+ __lookup_matches(rt, 86, 0, 285);
+ __invalidate(rt, 86);
+ __lookup_matches(rt, 87, 0, 286);
+ __invalidate(rt, 87);
+ __lookup_matches(rt, 88, 0, 287);
+ __invalidate(rt, 88);
+ __lookup_matches(rt, 89, 0, 288);
+ __invalidate(rt, 89);
+ __lookup_matches(rt, 90, 0, 289);
+ __invalidate(rt, 90);
+ __lookup_matches(rt, 91, 0, 290);
+ __invalidate(rt, 91);
+ __lookup_matches(rt, 92, 0, 291);
+ __invalidate(rt, 92);
+ __lookup_matches(rt, 93, 0, 292);
+ __invalidate(rt, 93);
+ __lookup_matches(rt, 94, 0, 293);
+ __invalidate(rt, 94);
+ __lookup_matches(rt, 95, 0, 294);
+ __invalidate(rt, 95);
+ __lookup_matches(rt, 97, 0, 295);
+ __invalidate(rt, 97);
+ __lookup_matches(rt, 98, 0, 296);
+ __invalidate(rt, 98);
+ __lookup_matches(rt, 99, 0, 297);
+ __invalidate(rt, 99);
+ __lookup_matches(rt, 100, 0, 298);
+ __invalidate(rt, 100);
+ __lookup_matches(rt, 101, 0, 299);
+ __invalidate(rt, 101);
+ __lookup_matches(rt, 102, 0, 300);
+ __invalidate(rt, 102);
+ __lookup_matches(rt, 103, 0, 301);
+ __invalidate(rt, 103);
+ __lookup_matches(rt, 104, 0, 302);
+ __invalidate(rt, 104);
+ __lookup_matches(rt, 105, 0, 303);
+ __invalidate(rt, 105);
+ __lookup_matches(rt, 106, 0, 304);
+ __invalidate(rt, 106);
+ __lookup_matches(rt, 107, 0, 305);
+ __invalidate(rt, 107);
+ __lookup_matches(rt, 108, 0, 306);
+ __invalidate(rt, 108);
+ __lookup_matches(rt, 109, 0, 307);
+ __invalidate(rt, 109);
+ __lookup_matches(rt, 110, 0, 308);
+ __invalidate(rt, 110);
+ __lookup_matches(rt, 111, 0, 309);
+ __invalidate(rt, 111);
+ __lookup_matches(rt, 112, 0, 310);
+ __invalidate(rt, 112);
+ __lookup_matches(rt, 113, 0, 311);
+ __invalidate(rt, 113);
+ __lookup_matches(rt, 114, 0, 312);
+ __invalidate(rt, 114);
+ __lookup_matches(rt, 115, 0, 313);
+ __invalidate(rt, 115);
+ __lookup_matches(rt, 116, 0, 314);
+ __invalidate(rt, 116);
+ __lookup_matches(rt, 117, 0, 315);
+ __invalidate(rt, 117);
+ __lookup_matches(rt, 118, 0, 316);
+ __invalidate(rt, 118);
+ __lookup_matches(rt, 119, 0, 317);
+ __invalidate(rt, 119);
+ __lookup_matches(rt, 120, 0, 318);
+ __invalidate(rt, 120);
+ __lookup_matches(rt, 121, 0, 319);
+ __invalidate(rt, 121);
+ __lookup_matches(rt, 122, 0, 320);
+ __invalidate(rt, 122);
+ __lookup_matches(rt, 123, 0, 321);
+ __invalidate(rt, 123);
+ __lookup_matches(rt, 124, 0, 322);
+ __invalidate(rt, 124);
+ __lookup_matches(rt, 125, 0, 323);
+ __invalidate(rt, 125);
+ __lookup_matches(rt, 126, 0, 324);
+ __invalidate(rt, 126);
+ __lookup_matches(rt, 127, 0, 325);
+ __invalidate(rt, 127);
+ __lookup_matches(rt, 128, 0, 326);
+ __invalidate(rt, 128);
+ __lookup_matches(rt, 129, 0, 327);
+ __invalidate(rt, 129);
+ __lookup_matches(rt, 130, 0, 328);
+ __invalidate(rt, 130);
+ __lookup_matches(rt, 131, 0, 329);
+ __invalidate(rt, 131);
+ __lookup_matches(rt, 132, 0, 330);
+ __invalidate(rt, 132);
+ __lookup_matches(rt, 133, 0, 331);
+ __invalidate(rt, 133);
+ __lookup_matches(rt, 134, 0, 332);
+ __invalidate(rt, 134);
+ __lookup_matches(rt, 135, 0, 333);
+ __invalidate(rt, 135);
+ __lookup_matches(rt, 136, 0, 334);
+ __invalidate(rt, 136);
+ __lookup_matches(rt, 137, 0, 335);
+ __invalidate(rt, 137);
+ __lookup_matches(rt, 138, 0, 336);
+ __invalidate(rt, 138);
+ __lookup_matches(rt, 139, 0, 337);
+ __invalidate(rt, 139);
+ __lookup_matches(rt, 140, 0, 338);
+ __invalidate(rt, 140);
+ __lookup_matches(rt, 141, 0, 339);
+ __invalidate(rt, 141);
+ __lookup_matches(rt, 142, 0, 340);
+ __invalidate(rt, 142);
+ __lookup_matches(rt, 143, 0, 341);
+ __invalidate(rt, 143);
+ __lookup_matches(rt, 144, 0, 342);
+ __invalidate(rt, 144);
+ __lookup_matches(rt, 145, 0, 343);
+ __invalidate(rt, 145);
+ __lookup_matches(rt, 146, 0, 344);
+ __invalidate(rt, 146);
+ __lookup_matches(rt, 147, 0, 345);
+ __invalidate(rt, 147);
+ __lookup_matches(rt, 148, 0, 346);
+ __invalidate(rt, 148);
+ __lookup_matches(rt, 149, 0, 347);
+ __invalidate(rt, 149);
+ __lookup_matches(rt, 150, 0, 348);
+ __invalidate(rt, 150);
+ __lookup_matches(rt, 151, 0, 349);
+ __invalidate(rt, 151);
+ __lookup_matches(rt, 152, 0, 350);
+ __invalidate(rt, 152);
+ __lookup_matches(rt, 153, 0, 351);
+ __invalidate(rt, 153);
+ __lookup_matches(rt, 154, 0, 352);
+ __invalidate(rt, 154);
+ __lookup_matches(rt, 155, 0, 353);
+ __invalidate(rt, 155);
+ __lookup_matches(rt, 156, 0, 354);
+ __invalidate(rt, 156);
+ __lookup_matches(rt, 157, 0, 355);
+ __invalidate(rt, 157);
+ __lookup_matches(rt, 158, 0, 356);
+ __invalidate(rt, 158);
+ __lookup_matches(rt, 159, 0, 357);
+ __invalidate(rt, 159);
+ __lookup_matches(rt, 160, 0, 358);
+ __invalidate(rt, 160);
+ __lookup_matches(rt, 161, 0, 359);
+ __invalidate(rt, 161);
+ __lookup_matches(rt, 162, 0, 360);
+ __invalidate(rt, 162);
+ __lookup_matches(rt, 164, 0, 361);
+ __invalidate(rt, 164);
+ __lookup_matches(rt, 165, 0, 362);
+ __invalidate(rt, 165);
+ __lookup_matches(rt, 166, 0, 363);
+ __invalidate(rt, 166);
+ __lookup_matches(rt, 167, 0, 364);
+ __invalidate(rt, 167);
+ __lookup_matches(rt, 168, 0, 365);
+ __invalidate(rt, 168);
+ __lookup_matches(rt, 169, 0, 366);
+ __invalidate(rt, 169);
+ __lookup_matches(rt, 170, 0, 367);
+ __invalidate(rt, 170);
+ __lookup_matches(rt, 171, 0, 368);
+ __invalidate(rt, 171);
+ __lookup_matches(rt, 172, 0, 369);
+ __invalidate(rt, 172);
+ __lookup_matches(rt, 173, 0, 370);
+ __invalidate(rt, 173);
+ __lookup_matches(rt, 174, 0, 371);
+ __invalidate(rt, 174);
+ __lookup_matches(rt, 175, 0, 372);
+ __invalidate(rt, 175);
+ __lookup_matches(rt, 176, 0, 373);
+ __invalidate(rt, 176);
+ __lookup_matches(rt, 177, 0, 374);
+ __invalidate(rt, 177);
+ __lookup_matches(rt, 178, 0, 375);
+ __invalidate(rt, 178);
+ __lookup_matches(rt, 179, 0, 376);
+ __invalidate(rt, 179);
+ __lookup_matches(rt, 180, 0, 377);
+ __invalidate(rt, 180);
+ __lookup_matches(rt, 181, 0, 378);
+ __invalidate(rt, 181);
+ __lookup_matches(rt, 182, 0, 379);
+ __invalidate(rt, 182);
+ __lookup_matches(rt, 183, 0, 380);
+ __invalidate(rt, 183);
+ __lookup_matches(rt, 184, 0, 381);
+ __invalidate(rt, 184);
+ __lookup_matches(rt, 185, 0, 382);
+ __invalidate(rt, 185);
+ __lookup_matches(rt, 186, 0, 383);
+ __invalidate(rt, 186);
+ __lookup_matches(rt, 187, 0, 384);
+ __invalidate(rt, 187);
+ __lookup_matches(rt, 188, 0, 385);
+ __invalidate(rt, 188);
+ __lookup_matches(rt, 189, 0, 386);
+ __invalidate(rt, 189);
+ __lookup_matches(rt, 190, 0, 387);
+ __invalidate(rt, 190);
+ __lookup_matches(rt, 191, 0, 388);
+ __invalidate(rt, 191);
+ __lookup_matches(rt, 192, 0, 389);
+ __invalidate(rt, 192);
+ __lookup_matches(rt, 193, 0, 390);
+ __invalidate(rt, 193);
+ __lookup_matches(rt, 194, 0, 391);
+ __invalidate(rt, 194);
+ __lookup_matches(rt, 195, 0, 392);
+ __invalidate(rt, 195);
+ __lookup_matches(rt, 196, 0, 393);
+ __invalidate(rt, 196);
+ __lookup_matches(rt, 197, 0, 394);
+ __invalidate(rt, 197);
+ __lookup_matches(rt, 198, 0, 395);
+ __invalidate(rt, 198);
+ __lookup_matches(rt, 199, 0, 396);
+ __invalidate(rt, 199);
+ __lookup_matches(rt, 200, 0, 397);
+ __invalidate(rt, 200);
+ __lookup_matches(rt, 201, 0, 398);
+ __invalidate(rt, 201);
+ __lookup_matches(rt, 202, 0, 399);
+ __invalidate(rt, 202);
+ __lookup_matches(rt, 203, 0, 400);
+ __invalidate(rt, 203);
+ __lookup_matches(rt, 204, 0, 401);
+ __invalidate(rt, 204);
+ __lookup_matches(rt, 205, 0, 402);
+ __invalidate(rt, 205);
+ __lookup_matches(rt, 206, 0, 403);
+ __invalidate(rt, 206);
+ __lookup_matches(rt, 207, 0, 404);
+ __invalidate(rt, 207);
+ __lookup_matches(rt, 208, 0, 405);
+ __invalidate(rt, 208);
+ __lookup_matches(rt, 209, 0, 406);
+ __invalidate(rt, 209);
+ __lookup_matches(rt, 210, 0, 407);
+ __invalidate(rt, 210);
+ __lookup_fails(rt, 6, 0);
+ __insert(rt, 6, 0, 408);
+ __lookup_fails(rt, 7, 0);
+ __insert(rt, 7, 0, 409);
+ __lookup_fails(rt, 8, 0);
+ __insert(rt, 8, 0, 410);
+ __lookup_fails(rt, 9, 0);
+ __insert(rt, 9, 0, 411);
+ __lookup_fails(rt, 10, 0);
+ __insert(rt, 10, 0, 412);
+ __lookup_fails(rt, 11, 0);
+ __insert(rt, 11, 0, 413);
+ __lookup_fails(rt, 13, 0);
+ __insert(rt, 13, 0, 414);
+ __lookup_fails(rt, 14, 0);
+ __insert(rt, 14, 0, 415);
+ __lookup_fails(rt, 15, 0);
+ __insert(rt, 15, 0, 416);
+ __lookup_fails(rt, 16, 0);
+ __insert(rt, 16, 0, 417);
+ __lookup_fails(rt, 17, 0);
+ __insert(rt, 17, 0, 418);
+ __lookup_fails(rt, 18, 0);
+ __insert(rt, 18, 0, 419);
+ __lookup_fails(rt, 19, 0);
+ __insert(rt, 19, 0, 420);
+ __lookup_fails(rt, 20, 0);
+ __insert(rt, 20, 0, 421);
+ __lookup_fails(rt, 21, 0);
+ __insert(rt, 21, 0, 422);
+ __lookup_fails(rt, 22, 0);
+ __insert(rt, 22, 0, 423);
+ __lookup_fails(rt, 23, 0);
+ __insert(rt, 23, 0, 424);
+ __lookup_matches(rt, 6, 0, 408);
+ __invalidate(rt, 6);
+ __lookup_matches(rt, 7, 0, 409);
+ __invalidate(rt, 7);
+ __lookup_matches(rt, 8, 0, 410);
+ __invalidate(rt, 8);
+ __lookup_matches(rt, 9, 0, 411);
+ __invalidate(rt, 9);
+ __lookup_matches(rt, 10, 0, 412);
+ __invalidate(rt, 10);
+ __lookup_matches(rt, 11, 0, 413);
+ __invalidate(rt, 11);
+ __lookup_matches(rt, 13, 0, 414);
+ __invalidate(rt, 13);
+ __lookup_matches(rt, 14, 0, 415);
diff --git a/test/unit/run.c b/test/unit/run.c
index 482498a..84b867b 100644
--- a/test/unit/run.c
+++ b/test/unit/run.c
@@ -1,29 +1,312 @@
-#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
+#include "units.h"
+
+#include <getopt.h>
+#include <regex.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <setjmp.h>
+#include <unistd.h>
+
+//-----------------------------------------------------------------
+
+#define MAX_COMPONENTS 16
+
+struct token {
+ const char *b, *e;
};
-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;
+static bool _pop_component(const char *path, struct token *result)
+{
+ const char *b, *e;
+
+ while (*path && *path == '/')
+ path++;
+
+ b = path;
+ while (*path && (*path != '/'))
+ path++;
+ e = path;
+
+ if (b == e)
+ return false;
+
+ result->b = b;
+ result->e = e;
+ return true;
+}
+
+static unsigned _split_components(const char *path, struct token *toks, unsigned len)
+{
+ unsigned count = 0;
+ struct token tok;
+ tok.e = path;
+
+ while (len && _pop_component(tok.e, &tok)) {
+ *toks = tok;
+ toks++;
+ count++;
+ len--;
+ }
+
+ return count;
+}
+
+static void _indent(FILE *stream, unsigned count)
+{
+ unsigned i;
+
+ for (i = 0; i < count; i++)
+ fprintf(stream, " ");
+}
+
+static void _print_token(FILE *stream, struct token *t)
+{
+ const char *ptr;
+
+ for (ptr = t->b; ptr != t->e; ptr++)
+ fprintf(stream, "%c", *ptr);
+}
+
+static int _char_cmp(char l, char r)
+{
+ if (l < r)
+ return -1;
+
+ else if (r < l)
+ return 1;
+
+ else
+ return 0;
+}
+
+static int _tok_cmp(struct token *lhs, struct token *rhs)
+{
+ const char *l = lhs->b, *le = lhs->e;
+ const char *r = rhs->b, *re = rhs->e;
+
+ while ((l != le) && (r != re) && (*l == *r)) {
+ l++;
+ r++;
+ }
+
+ if ((l != le) && (r != re))
+ return _char_cmp(*l, *r);
+
+ else if (r != re)
+ return -1;
+
+ else if (l != le)
+ return 1;
+
+ else
+ return 0;
+}
+
+static void _print_path_delta(FILE *stream,
+ struct token *old, unsigned old_len,
+ struct token *new, unsigned new_len,
+ const char *desc)
+{
+ unsigned i, common_prefix = 0, len, d;
+ unsigned max_prefix = old_len < new_len ? old_len : new_len;
+
+ for (i = 0; i < max_prefix; i++) {
+ if (_tok_cmp(old + i, new + i))
+ break;
+ else
+ common_prefix++;
+ }
+
+ for (; i < new_len; i++) {
+ _indent(stream, common_prefix);
+ _print_token(stream, new + i);
+ common_prefix++;
+ if (i < new_len - 1)
+ fprintf(stream, "\n");
+ }
+
+ len = (new_len > 0) ? common_prefix * 2 + (new[new_len - 1].e - new[new_len - 1].b) : 0;
+
+ fprintf(stream, " ");
+ for (d = len; d < 60; d++)
+ fprintf(stream, ".");
+ fprintf(stream, " ");
+ fprintf(stream, "%s", desc);
+ fprintf(stream, "\n");
+}
+
+typedef struct token comp_t[MAX_COMPONENTS];
+
+static void _list_tests(struct test_details **tests, unsigned nr)
+{
+ unsigned i, current = 0, current_len, last_len = 0;
+
+ comp_t components[2];
+
+ for (i = 0; i < nr; i++) {
+ struct test_details *t = tests[i];
+ current_len = _split_components(t->path, components[current], MAX_COMPONENTS);
+ _print_path_delta(stderr, components[!current], last_len,
+ components[current], current_len, t->desc);
+
+ last_len = current_len;
+ current = !current;
+ }
+}
+
+static void _destroy_tests(struct dm_list *suites)
+{
+ struct test_suite *ts, *tmp;
+
+ dm_list_iterate_items_safe (ts, tmp, suites)
+ test_suite_destroy(ts);
+}
+
+static const char *red(bool c)
+{
+ return c ? "\x1B[31m" : "";
+}
+
+static const char *green(bool c)
+{
+ return c ? "\x1B[32m" : "";
+}
+
+static const char *normal(bool c)
+{
+ return c ? "\x1B[0m" : "";
+}
+
+static void _run_test(struct test_details *t, bool use_colour, unsigned *passed, unsigned *total)
+{
+ void *fixture;
+ struct test_suite *ts = t->parent;
+ fprintf(stderr, "[RUN ] %s\n", t->path);
+
+ (*total)++;
+ if (setjmp(test_k))
+ fprintf(stderr, "%s[ FAIL]%s %s\n", red(use_colour), normal(use_colour), t->path);
+ else {
+ if (ts->fixture_init)
+ fixture = ts->fixture_init();
+ else
+ fixture = NULL;
+
+ t->fn(fixture);
+
+ if (ts->fixture_exit)
+ ts->fixture_exit(fixture);
+
+ (*passed)++;
+ fprintf(stderr, "%s[ OK]%s\n", green(use_colour), normal(use_colour));
+ /* coverity[leaked_storage] fixture released by fixture_exit */
+ }
}
+
+static bool _run_tests(struct test_details **tests, unsigned nr)
+{
+ bool use_colour = isatty(fileno(stderr));
+ unsigned i, passed = 0, total = 0;
+
+ for (i = 0; i < nr; i++)
+ _run_test(tests[i], use_colour, &passed, &total);
+
+ fprintf(stderr, "\n%u/%u tests passed\n", passed, total);
+
+ return passed == total;
+}
+
+static void _usage(void)
+{
+ fprintf(stderr, "Usage: unit-test <list|run> [pattern]\n");
+}
+
+static int _cmp_paths(const void *lhs, const void *rhs)
+{
+ struct test_details *l = *((struct test_details **) lhs);
+ struct test_details *r = *((struct test_details **) rhs);
+
+ return strcmp(l->path, r->path);
+}
+
+static unsigned _filter(const char *pattern, struct test_details **tests, unsigned nr)
+{
+ unsigned i, found = 0;
+ regex_t rx;
+
+ if (regcomp(&rx, pattern, 0)) {
+ fprintf(stderr, "couldn't compile regex '%s'\n", pattern);
+ exit(1);
+ }
+
+ for (i = 0; i < nr; i++)
+ if (tests[i] && !regexec(&rx, tests[i]->path, 0, NULL, 0))
+ tests[found++] = tests[i];
+
+ regfree(&rx);
+
+ return found;
+}
+
+int main(int argc, char **argv)
+{
+ int r;
+ unsigned i, nr_tests;
+ struct test_suite *ts;
+ struct test_details *t, **t_array;
+ struct dm_list suites;
+
+ dm_list_init(&suites);
+ register_all_tests(&suites);
+
+ // count all tests
+ nr_tests = 0;
+ dm_list_iterate_items (ts, &suites)
+ dm_list_iterate_items (t, &ts->tests)
+ nr_tests++;
+
+ // stick them in an array
+ t_array = malloc(sizeof(*t_array) * nr_tests);
+ if (!t_array) {
+ fprintf(stderr, "out of memory\n");
+ exit(1);
+ }
+ memset(t_array, 0, sizeof(*t_array) * nr_tests);
+
+ i = 0;
+ dm_list_iterate_items (ts, &suites)
+ dm_list_iterate_items (t, &ts->tests)
+ t_array[i++] = t;
+
+ // filter
+ if (argc == 3)
+ nr_tests = _filter(argv[2], t_array, nr_tests);
+
+ // sort
+ qsort(t_array, nr_tests, sizeof(*t_array), _cmp_paths);
+
+ // run or list them
+ if (argc == 1)
+ r = !_run_tests(t_array, nr_tests);
+ else {
+ const char *cmd = argv[1];
+ if (!strcmp(cmd, "run"))
+ r = !_run_tests(t_array, nr_tests);
+
+ else if (!strcmp(cmd, "list")) {
+ _list_tests(t_array, nr_tests);
+ r = 0;
+
+ } else {
+ _usage();
+ r = 1;
+ }
+ }
+
+ free(t_array);
+ _destroy_tests(&suites);
+
+ return r;
+}
+
+//-----------------------------------------------------------------
diff --git a/test/unit/string_t.c b/test/unit/string_t.c
index df72505..82c6448 100644
--- a/test/unit/string_t.c
+++ b/test/unit/string_t.c
@@ -9,50 +9,48 @@
*
* 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
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
-#include "libdevmapper.h"
+#include "units.h"
+#include "device_mapper/all.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)
+#if 0
+static int _mem_init(void)
{
- mem = dm_pool_create("string test", 1024);
+ struct dm_pool *mem = dm_pool_create("string test", 1024);
+ if (!mem) {
+ fprintf(stderr, "out of memory\n");
+ exit(1);
+ }
- return (mem == NULL);
+ return mem;
}
-int string_fini(void)
+static void _mem_exit(void *mem)
{
dm_pool_destroy(mem);
-
- return 0;
}
/* TODO: Add more string unit tests here */
+#endif
-static void test_strncpy(void)
+static void test_strncpy(void *fixture)
{
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);
+ T_ASSERT_EQUAL(dm_strncpy(buf, st, sizeof(buf)), 1);
+ T_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);
+ T_ASSERT_EQUAL(dm_strncpy(buf, st, sizeof(buf) - 1), 0);
+ T_ASSERT_EQUAL(strlen(buf) + 1, sizeof(buf) - 1);
}
-static void test_asprint(void)
+static void test_asprint(void *fixture)
{
const char st0[] = "";
const char st1[] = "12345678901";
@@ -61,23 +59,33 @@ static void test_asprint(void)
int a;
a = dm_asprintf(&buf, "%s", st0);
- CU_ASSERT_EQUAL(strcmp(buf, st0), 0);
- CU_ASSERT_EQUAL(a, sizeof(st0));
+ T_ASSERT_EQUAL(strcmp(buf, st0), 0);
+ T_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));
+ T_ASSERT_EQUAL(strcmp(buf, st1), 0);
+ T_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);
+ T_ASSERT_EQUAL(a, sizeof(st2));
+ T_ASSERT_EQUAL(strcmp(buf, st2), 0);
free(buf);
}
-CU_TestInfo string_list[] = {
- { (char*)"asprint", test_asprint },
- { (char*)"strncpy", test_strncpy },
- CU_TEST_INFO_NULL
-};
+#define T(path, desc, fn) register_test(ts, "/base/data-struct/string/" path, desc, fn)
+
+void string_tests(struct dm_list *all_tests)
+{
+ struct test_suite *ts = test_suite_create(NULL, NULL);
+ if (!ts) {
+ fprintf(stderr, "out of memory\n");
+ exit(1);
+ }
+
+ T("asprint", "tests asprint", test_asprint);
+ T("strncpy", "tests string copying", test_strncpy);
+
+ dm_list_add(all_tests, &ts->list);
+}
diff --git a/test/api/pe_start.sh b/test/unit/unit-test.sh
index 20ba8ec..f545f14 100644
--- a/test/api/pe_start.sh
+++ b/test/unit/unit-test.sh
@@ -1,5 +1,5 @@
#!/bin/sh
-# Copyright (C) 2011 Red Hat, Inc. All rights reserved.
+# Copyright (C) 2018 Red Hat, Inc. All rights reserved.
#
# This file is part of LVM2.
#
@@ -9,13 +9,13 @@
#
# 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
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
-. lib/test
+SKIP_WITH_LVMLOCKD=1
+SKIP_WITH_LVMPOLLD=1
-aux prepare_devs 2
+SKIP_ROOT_DM_CHECK=1
-aux apitest pe_start test_vg $dev1
+. lib/inittest
-not vgs test_vg
-not pvs $dev1
+aux unittest run
diff --git a/test/unit/units.h b/test/unit/units.h
new file mode 100644
index 0000000..d7ac6ad
--- /dev/null
+++ b/test/unit/units.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2018 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef TEST_UNIT_UNITS_H
+#define TEST_UNIT_UNITS_H
+
+#include "framework.h"
+
+//-----------------------------------------------------------------
+
+// Declare the function that adds tests suites here ...
+void bcache_tests(struct dm_list *suites);
+void bcache_utils_tests(struct dm_list *suites);
+void bitset_tests(struct dm_list *suites);
+void config_tests(struct dm_list *suites);
+void dm_list_tests(struct dm_list *suites);
+void dm_status_tests(struct dm_list *suites);
+void io_engine_tests(struct dm_list *suites);
+void percent_tests(struct dm_list *suites);
+void radix_tree_tests(struct dm_list *suites);
+void regex_tests(struct dm_list *suites);
+void string_tests(struct dm_list *suites);
+void vdo_tests(struct dm_list *suites);
+
+// ... and call it in here.
+static inline void register_all_tests(struct dm_list *suites)
+{
+ bcache_tests(suites);
+ bcache_utils_tests(suites);
+ bitset_tests(suites);
+ config_tests(suites);
+ dm_list_tests(suites);
+ dm_status_tests(suites);
+ io_engine_tests(suites);
+ percent_tests(suites);
+ radix_tree_tests(suites);
+ regex_tests(suites);
+ string_tests(suites);
+ vdo_tests(suites);
+}
+
+//-----------------------------------------------------------------
+
+#endif
diff --git a/test/unit/vdo_t.c b/test/unit/vdo_t.c
new file mode 100644
index 0000000..27ad26b
--- /dev/null
+++ b/test/unit/vdo_t.c
@@ -0,0 +1,325 @@
+/*
+ * Copyright (C) 2018 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "units.h"
+#include "device_mapper/vdo/target.h"
+
+//----------------------------------------------------------------
+
+static bool _status_eq(struct dm_vdo_status *lhs, struct dm_vdo_status *rhs)
+{
+ return !strcmp(lhs->device, rhs->device) &&
+ (lhs->operating_mode == rhs->operating_mode) &&
+ (lhs->recovering == rhs->recovering) &&
+ (lhs->index_state == rhs->index_state) &&
+ (lhs->compression_state == rhs->compression_state) &&
+ (lhs->used_blocks == rhs->used_blocks) &&
+ (lhs->total_blocks == rhs->total_blocks);
+}
+
+#if 0
+static const char *_op_mode(enum dm_vdo_operating_mode m)
+{
+ switch (m) {
+ case DM_VDO_MODE_RECOVERING:
+ return "recovering";
+ case DM_VDO_MODE_READ_ONLY:
+ return "read-only";
+ case DM_VDO_MODE_NORMAL:
+ return "normal";
+ }
+
+ return "<unknown>";
+}
+
+static const char *_index_state(enum dm_vdo_index_state is)
+{
+ switch (is) {
+ case DM_VDO_INDEX_ERROR:
+ return "error";
+ case DM_VDO_INDEX_CLOSED:
+ return "closed";
+ case DM_VDO_INDEX_OPENING:
+ return "opening";
+ case DM_VDO_INDEX_CLOSING:
+ return "closing";
+ case DM_VDO_INDEX_OFFLINE:
+ return "offline";
+ case DM_VDO_INDEX_ONLINE:
+ return "online";
+ case DM_VDO_INDEX_UNKNOWN:
+ return "unknown";
+ }
+
+ return "<unknown>";
+}
+
+static void _print_status(FILE *stream, struct dm_vdo_status *s)
+{
+ fprintf(stream, "<status| %s ", s->device);
+ fprintf(stream, "%s ", _op_mode(s->operating_mode));
+ fprintf(stream, "%s ", s->recovering ? "recovering" : "-");
+ fprintf(stream, "%s ", _index_state(s->index_state));
+ fprintf(stream, "%s ", s->compression_state == DM_VDO_COMPRESSION_ONLINE ? "online" : "offline");
+ fprintf(stream, "%llu ", (unsigned long long) s->used_blocks);
+ fprintf(stream, "%llu", (unsigned long long) s->total_blocks);
+ fprintf(stream, ">");
+}
+#endif
+
+struct example_good {
+ const char *input;
+ struct dm_vdo_status status;
+};
+
+static void _check_good(struct example_good *es, unsigned count)
+{
+ unsigned i;
+
+ for (i = 0; i < count; i++) {
+ struct example_good *e = es + i;
+ struct dm_vdo_status_parse_result pr;
+
+ T_ASSERT(dm_vdo_status_parse(NULL, e->input, &pr));
+#if 0
+ _print_status(stderr, pr.status);
+ fprintf(stderr, "\n");
+ _print_status(stderr, &e->status);
+ fprintf(stderr, "\n");
+#endif
+ T_ASSERT(_status_eq(&e->status, pr.status));
+ free(pr.status);
+ }
+}
+
+struct example_bad {
+ const char *input;
+ const char *reason;
+};
+
+static void _check_bad(struct example_bad *es, unsigned count)
+{
+ unsigned i;
+
+ for (i = 0; i < count; i++) {
+ struct example_bad *e = es + i;
+ struct dm_vdo_status_parse_result pr;
+
+ T_ASSERT(!dm_vdo_status_parse(NULL, e->input, &pr));
+ T_ASSERT(!strcmp(e->reason, pr.error));
+ }
+}
+
+static void _test_device_names_good(void *fixture)
+{
+ static struct example_good _es[] = {
+ {"foo1234 read-only - error online 0 1234",
+ {(char *) "foo1234", DM_VDO_MODE_READ_ONLY, false, DM_VDO_INDEX_ERROR, DM_VDO_COMPRESSION_ONLINE, 0, 1234}},
+ {"f read-only - error online 0 1234",
+ {(char *) "f", DM_VDO_MODE_READ_ONLY, false, DM_VDO_INDEX_ERROR, DM_VDO_COMPRESSION_ONLINE, 0, 1234}},
+ };
+
+ _check_good(_es, DM_ARRAY_SIZE(_es));
+}
+
+static void _test_operating_mode_good(void *fixture)
+{
+ static struct example_good _es[] = {
+ {"device-name recovering - error online 0 1234",
+ {(char *) "device-name", DM_VDO_MODE_RECOVERING, false, DM_VDO_INDEX_ERROR, DM_VDO_COMPRESSION_ONLINE, 0, 1234}},
+ {"device-name read-only - error online 0 1234",
+ {(char *) "device-name", DM_VDO_MODE_READ_ONLY, false, DM_VDO_INDEX_ERROR, DM_VDO_COMPRESSION_ONLINE, 0, 1234}},
+ {"device-name normal - error online 0 1234",
+ {(char *) "device-name", DM_VDO_MODE_NORMAL, false, DM_VDO_INDEX_ERROR, DM_VDO_COMPRESSION_ONLINE, 0, 1234}},
+ };
+
+ _check_good(_es, DM_ARRAY_SIZE(_es));
+}
+
+static void _test_operating_mode_bad(void *fixture)
+{
+ static struct example_bad _es[] = {
+ {"device-name investigating - error online 0 1234",
+ "couldn't parse 'operating mode'"}};
+
+ _check_bad(_es, DM_ARRAY_SIZE(_es));
+}
+
+static void _test_recovering_good(void *fixture)
+{
+ static struct example_good _es[] = {
+ {"device-name recovering - error online 0 1234",
+ {(char *) "device-name", DM_VDO_MODE_RECOVERING, false, DM_VDO_INDEX_ERROR, DM_VDO_COMPRESSION_ONLINE, 0, 1234}},
+ {"device-name read-only recovering error online 0 1234",
+ {(char *) "device-name", DM_VDO_MODE_READ_ONLY, true, DM_VDO_INDEX_ERROR, DM_VDO_COMPRESSION_ONLINE, 0, 1234}},
+ };
+
+ _check_good(_es, DM_ARRAY_SIZE(_es));
+}
+
+static void _test_recovering_bad(void *fixture)
+{
+ static struct example_bad _es[] = {
+ {"device-name normal fish error online 0 1234",
+ "couldn't parse 'recovering'"}};
+
+ _check_bad(_es, DM_ARRAY_SIZE(_es));
+}
+
+static void _test_index_state_good(void *fixture)
+{
+ static struct example_good _es[] = {
+ {"device-name recovering - error online 0 1234",
+ {(char *) "device-name", DM_VDO_MODE_RECOVERING, false, DM_VDO_INDEX_ERROR, DM_VDO_COMPRESSION_ONLINE, 0, 1234}},
+ {"device-name recovering - closed online 0 1234",
+ {(char *) "device-name", DM_VDO_MODE_RECOVERING, false, DM_VDO_INDEX_CLOSED, DM_VDO_COMPRESSION_ONLINE, 0, 1234}},
+ {"device-name recovering - opening online 0 1234",
+ {(char *) "device-name", DM_VDO_MODE_RECOVERING, false, DM_VDO_INDEX_OPENING, DM_VDO_COMPRESSION_ONLINE, 0, 1234}},
+ {"device-name recovering - closing online 0 1234",
+ {(char *) "device-name", DM_VDO_MODE_RECOVERING, false, DM_VDO_INDEX_CLOSING, DM_VDO_COMPRESSION_ONLINE, 0, 1234}},
+ {"device-name recovering - offline online 0 1234",
+ {(char *) "device-name", DM_VDO_MODE_RECOVERING, false, DM_VDO_INDEX_OFFLINE, DM_VDO_COMPRESSION_ONLINE, 0, 1234}},
+ {"device-name recovering - online online 0 1234",
+ {(char *) "device-name", DM_VDO_MODE_RECOVERING, false, DM_VDO_INDEX_ONLINE, DM_VDO_COMPRESSION_ONLINE, 0, 1234}},
+ {"device-name recovering - unknown online 0 1234",
+ {(char *) "device-name", DM_VDO_MODE_RECOVERING, false, DM_VDO_INDEX_UNKNOWN, DM_VDO_COMPRESSION_ONLINE, 0, 1234}},
+ };
+
+ _check_good(_es, DM_ARRAY_SIZE(_es));
+}
+
+static void _test_index_state_bad(void *fixture)
+{
+ static struct example_bad _es[] = {
+ {"device-name normal - fish online 0 1234",
+ "couldn't parse 'index state'"}};
+
+ _check_bad(_es, DM_ARRAY_SIZE(_es));
+}
+
+static void _test_compression_state_good(void *fixture)
+{
+ static struct example_good _es[] = {
+ {"device-name recovering - error online 0 1234",
+ {(char *) "device-name", DM_VDO_MODE_RECOVERING, false, DM_VDO_INDEX_ERROR, DM_VDO_COMPRESSION_ONLINE, 0, 1234}},
+ {"device-name read-only - error offline 0 1234",
+ {(char *) "device-name", DM_VDO_MODE_READ_ONLY, false, DM_VDO_INDEX_ERROR, DM_VDO_COMPRESSION_OFFLINE, 0, 1234}},
+ };
+
+ _check_good(_es, DM_ARRAY_SIZE(_es));
+}
+
+static void _test_compression_state_bad(void *fixture)
+{
+ static struct example_bad _es[] = {
+ {"device-name normal - error fish 0 1234",
+ "couldn't parse 'compression state'"}};
+
+ _check_bad(_es, DM_ARRAY_SIZE(_es));
+}
+
+static void _test_used_blocks_good(void *fixture)
+{
+ static struct example_good _es[] = {
+ {"device-name recovering - error online 0 1234",
+ {(char *) "device-name", DM_VDO_MODE_RECOVERING, false, DM_VDO_INDEX_ERROR, DM_VDO_COMPRESSION_ONLINE, 0, 1234}},
+ {"device-name read-only - error offline 1 1234",
+ {(char *) "device-name", DM_VDO_MODE_READ_ONLY, false, DM_VDO_INDEX_ERROR, DM_VDO_COMPRESSION_OFFLINE, 1, 1234}},
+ {"device-name read-only - error offline 12 1234",
+ {(char *) "device-name", DM_VDO_MODE_READ_ONLY, false, DM_VDO_INDEX_ERROR, DM_VDO_COMPRESSION_OFFLINE, 12, 1234}},
+ {"device-name read-only - error offline 3456 1234",
+ {(char *) "device-name", DM_VDO_MODE_READ_ONLY, false, DM_VDO_INDEX_ERROR, DM_VDO_COMPRESSION_OFFLINE, 3456, 1234}},
+ };
+
+ _check_good(_es, DM_ARRAY_SIZE(_es));
+}
+
+static void _test_used_blocks_bad(void *fixture)
+{
+ static struct example_bad _es[] = {
+ {"device-name normal - error online fish 1234",
+ "couldn't parse 'used blocks'"}};
+
+ _check_bad(_es, DM_ARRAY_SIZE(_es));
+}
+
+static void _test_total_blocks_good(void *fixture)
+{
+ static struct example_good _es[] = {
+ {"device-name recovering - error online 0 1234",
+ {(char *) "device-name", DM_VDO_MODE_RECOVERING, false, DM_VDO_INDEX_ERROR, DM_VDO_COMPRESSION_ONLINE, 0, 1234}},
+ {"device-name recovering - error online 0 1",
+ {(char *) "device-name", DM_VDO_MODE_RECOVERING, false, DM_VDO_INDEX_ERROR, DM_VDO_COMPRESSION_ONLINE, 0, 1}},
+ {"device-name recovering - error online 0 0",
+ {(char *) "device-name", DM_VDO_MODE_RECOVERING, false, DM_VDO_INDEX_ERROR, DM_VDO_COMPRESSION_ONLINE, 0, 0}},
+ };
+
+ _check_good(_es, DM_ARRAY_SIZE(_es));
+}
+
+static void _test_total_blocks_bad(void *fixture)
+{
+ static struct example_bad _es[] = {
+ {"device-name normal - error online 0 fish",
+ "couldn't parse 'total blocks'"}};
+
+ _check_bad(_es, DM_ARRAY_SIZE(_es));
+}
+
+static void _test_status_bad(void *fixture)
+{
+ struct example_bad _bad[] = {
+ {"", "couldn't get token for device"},
+ {"device-name read-only - error online 0 1000 lksd", "too many tokens"}
+ };
+
+ _check_bad(_bad, DM_ARRAY_SIZE(_bad));
+}
+
+//----------------------------------------------------------------
+
+#define T(path, desc, fn) register_test(ts, "/device-mapper/vdo/status/" path, desc, fn)
+
+static struct test_suite *_tests(void)
+{
+ struct test_suite *ts = test_suite_create(NULL, NULL);
+ if (!ts) {
+ fprintf(stderr, "out of memory\n");
+ exit(1);
+ };
+
+ T("device-names", "parse various device names", _test_device_names_good);
+ T("operating-mode-good", "operating mode, good examples", _test_operating_mode_good);
+ T("operating-mode-bad", "operating mode, bad examples", _test_operating_mode_bad);
+ T("recovering-good", "recovering, good examples", _test_recovering_good);
+ T("recovering-bad", "recovering, bad examples", _test_recovering_bad);
+ T("index-state-good", "index state, good examples", _test_index_state_good);
+ T("index-state-bad", "index state, bad examples", _test_index_state_bad);
+ T("compression-state-good", "compression state, good examples", _test_compression_state_good);
+ T("compression-state-bad", "compression state, bad examples", _test_compression_state_bad);
+ T("used-blocks-good", "used blocks, good examples", _test_used_blocks_good);
+ T("used-blocks-bad", "used blocks, bad examples", _test_used_blocks_bad);
+ T("total-blocks-good", "total blocks, good examples", _test_total_blocks_good);
+ T("total-blocks-bad", "total blocks, bad examples", _test_total_blocks_bad);
+ T("bad", "parse various badly formed vdo status lines", _test_status_bad);
+
+ return ts;
+}
+
+void vdo_tests(struct dm_list *all_tests)
+{
+ dm_list_add(all_tests, &_tests()->list);
+}
+
+//----------------------------------------------------------------