From b4ff8efba3fd22ee8b3ec7e211aa3e6ac9dcbab2 Mon Sep 17 00:00:00 2001 From: Bruce Johnston Date: Tue, 10 Dec 2024 17:31:45 -0500 Subject: [PATCH 1/3] dm vdo test: split thin device into thin and thin pool. The first step to supporting a thin pool device using VDO is to split our current perl/Permabit/BlockDevice/LVM/Thin.pm file (which is a combination of a thin pool device and a single thin device on top) into two separate files, one for just the thin pool and one for thin. This will allow us to test (in a future commit) multiple thin devices on top of a single thin pool using VDO. The thin device can no longer be made without a thin pool device below it in the stack, acting as its storage device. As such, tests that set the deviceType to just thin have been updated to add thinpool underneath. This includes changes to BlockDevice01.pm and DiscardThin.pm BlockDevice01.pm has also been updated to remove two tests that used to have thin above and below vdos. These tests are actually scenarios we do not support. VDOTest.pm has been modified to fix a bug dealing with getting the vdo device for things like stats. Signed-off-by: Bruce Johnston --- src/perl/Permabit/BlockDevice/LVM/Thin.pm | 21 +++- src/perl/Permabit/BlockDevice/LVM/ThinPool.pm | 37 ++++++ src/perl/Permabit/StorageStack.pm | 1 + src/perl/Permabit/VolumeGroup.pm | 105 +++++++++++------- src/perl/vdotest/VDOTest.pm | 4 +- src/perl/vdotest/VDOTest/BlockDevice01.pm | 8 +- src/perl/vdotest/VDOTest/DiscardThin.pm | 2 +- 7 files changed, 127 insertions(+), 51 deletions(-) create mode 100644 src/perl/Permabit/BlockDevice/LVM/ThinPool.pm diff --git a/src/perl/Permabit/BlockDevice/LVM/Thin.pm b/src/perl/Permabit/BlockDevice/LVM/Thin.pm index 59a7a8ae8..5e32a001f 100644 --- a/src/perl/Permabit/BlockDevice/LVM/Thin.pm +++ b/src/perl/Permabit/BlockDevice/LVM/Thin.pm @@ -9,18 +9,33 @@ use strict; use warnings FATAL => qw(all); use English qw(-no_match_vars); use Log::Log4perl; -use Permabit::Assertions qw(assertNumArgs); +use Permabit::Assertions qw(assertNumArgs assertTrue); use base qw(Permabit::BlockDevice::LVM); my $log = Log::Log4perl->get_logger(__PACKAGE__); +######################################################################## +# @inherit +## +sub checkStorageDevice { + my ($self) = assertNumArgs(1, @_); + $self->SUPER::checkStorageDevice(); + # Make sure the storage device is a ThinPool + assertTrue($self->{storageDevice}->isa("Permabit::BlockDevice::LVM::ThinPool")); + # Use the thinpool's volume group + $self->{volumeGroup} = $self->{storageDevice}->{volumeGroup}; + # Use the thinpool's size instead of volume group size which LVM.pm uses + $self->{lvmSize} //= $self->{storageDevice}->getSize(); +} + ######################################################################## # @inherit ## sub setup { my ($self) = assertNumArgs(1, @_); - $self->{volumeGroup}->createThinVolume($self->{deviceName}, + $self->{volumeGroup}->createThinVolume($self->{storageDevice}, + $self->{deviceName}, $self->{lvmSize}); $self->SUPER::setup(); } @@ -31,7 +46,7 @@ sub setup { sub teardown { my ($self) = assertNumArgs(1, @_); $self->SUPER::teardown(); - $self->{volumeGroup}->deleteThinVolume($self->{deviceName}); + $self->{volumeGroup}->deleteLogicalVolume($self->{deviceName}); } 1; diff --git a/src/perl/Permabit/BlockDevice/LVM/ThinPool.pm b/src/perl/Permabit/BlockDevice/LVM/ThinPool.pm new file mode 100644 index 000000000..3ba68a912 --- /dev/null +++ b/src/perl/Permabit/BlockDevice/LVM/ThinPool.pm @@ -0,0 +1,37 @@ +## +# Perl object that represents a Thin pool managed by LVM +# +# $Id$ +## +package Permabit::BlockDevice::LVM::ThinPool; + +use strict; +use warnings FATAL => qw(all); +use English qw(-no_match_vars); +use Log::Log4perl; +use Permabit::Assertions qw(assertNumArgs); + +use base qw(Permabit::BlockDevice::LVM); + +my $log = Log::Log4perl->get_logger(__PACKAGE__); + +######################################################################## +# @inherit +## +sub setup { + my ($self) = assertNumArgs(1, @_); + $self->{volumeGroup}->createThinPool($self->{deviceName}, + $self->{lvmSize}); + $self->SUPER::setup(); +} + +######################################################################## +# @inherit +## +sub teardown { + my ($self) = assertNumArgs(1, @_); + $self->SUPER::teardown(); + $self->{volumeGroup}->deleteLogicalVolume($self->{deviceName}); +} + +1; diff --git a/src/perl/Permabit/StorageStack.pm b/src/perl/Permabit/StorageStack.pm index 3adbe43d1..e42709128 100644 --- a/src/perl/Permabit/StorageStack.pm +++ b/src/perl/Permabit/StorageStack.pm @@ -42,6 +42,7 @@ my %DEVICE_TYPES = ( raw => 'Permabit::BlockDevice::Raw', stripfua => 'Permabit::BlockDevice::TestDevice::StripFua', thin => 'Permabit::BlockDevice::LVM::Thin', + thinpool => 'Permabit::BlockDevice::LVM::ThinPool', tracer => 'Permabit::BlockDevice::TestDevice::Managed::Tracer', upgrade => 'Permabit::BlockDevice::VDO::Upgrade', vdo => 'Permabit::BlockDevice::VDO::Unmanaged', diff --git a/src/perl/Permabit/VolumeGroup.pm b/src/perl/Permabit/VolumeGroup.pm index 1f19e0ab2..7fa02653a 100644 --- a/src/perl/Permabit/VolumeGroup.pm +++ b/src/perl/Permabit/VolumeGroup.pm @@ -18,6 +18,7 @@ use Permabit::Assertions qw( assertEqualNumeric assertMinMaxArgs assertNumArgs + assertTrue assertType ); use Permabit::Constants; @@ -157,40 +158,84 @@ sub createLogicalVolume { } ######################################################################## -# Create a thin volume +# Create a thin pool # -# @param name Thin volume name -# @param size Thin volume size in bytes +# @param name Thin pool name +# @param size Thin pool size in bytes +# @oparam config String of create time lvm.conf overrides ## -sub createThinVolume { - my ($self, $name, $size) = assertNumArgs(3, @_); +sub createThinPool { + my ($self, $name, $size, $config) = assertMinMaxArgs([""], 3, 4, @_); my $machine = $self->{storageDevice}->getMachine(); assertEqualNumeric(0, $size % $KB, "size must be a multiple of 1KB"); - my $config = $self->getLVMOptions(); + $config = $self->getLVMOptions($config); $self->createVolumeGroup($machine, $config); my $ksize = int($size / $KB); my $kfree = int($self->getFreeBytes() / $KB); - if ($ksize > $kfree) { - $log->info("requested size ${ksize}K is too large, using ${kfree}K"); - $ksize = $kfree; + + # The first time a thin pool is created, lvm will create both a metadata device + # and a spare metadata LV in the VG. The spare device behavior can be controlled with + # the option --poolmetadataspare y|n. Unfortunately, if we try to create a pool using + # --poolmetadataspare n, the output will still generate a WARNING to stderr, thus + # causing our perl code to fail. + # + # As such, we have to take in account the size of both the metadata device and the + # spare metadata device when calculating how much space the pool takes as it doesn't + # take that into account itself. So we take the overall size asked and add the size + # needed for both the metadata and spare metadata devices. Then we see if the VG + # has sufficient space. Currently that space is 30 extents for each device. + my $metaDataSize = (60 * $self->{physicalExtentSize}) / $KB; + my $fullSize = $ksize + $metaDataSize; + + if ($fullSize > $kfree) { + my $newSize = $kfree - $metaDataSize; + $log->info("requested size ${ksize}K plus metadata is too large for VG, using ${newSize}K"); + $ksize = $newSize; } - # Create a thin volume in an existing volume group. This is a two step - # process where we create a thin pool first, then a thin volume. - # If lvcreate asks for a yes/no on whether to wipeout a filesystem - # signature (it does on RHEL7), the input redirection will cause the - # answer to be "no". The volume is not immediately enabled. - $machine->runSystemCmd("sudo lvcreate --name $name-pool --type=thin-pool" - . " --extents 100\%FREE --yes $config" + # Create a thin pool in an existing volume group. The pool is not + # immediately enabled. + $machine->runSystemCmd("sudo lvcreate --name $name --type=thin-pool" + . " --size ${ksize}K --yes $config" . " $self->{volumeGroup} sendCommand("sudo udevadm settle"); + # XXX As soon as we get rid of Squeeze, on which lvcreate doesn't have the + # -a flag, we can stop doing two separate commands and use lvcreate -an. + $self->disableAutoActivation($name); + $self->disableLogicalVolume($name); + +} +######################################################################## +# Create a thin volume on top of a thin pool +# +# @param pool The thin pool device to create on top of +# @param name Thin volume name +# @param size Thin volume size in bytes +## +sub createThinVolume { + my ($self, $pool, $name, $size) = assertNumArgs(4, @_); + my $machine = $self->{storageDevice}->getMachine(); + my $poolName = $pool->getDeviceName(); + assertEqualNumeric(0, $size % $KB, "size must be a multiple of 1KB"); + assertTrue($pool->isa("Permabit::BlockDevice::LVM::ThinPool")); + assertTrue($self->{_useCount} > 0); + + my $ksize = int($size / $KB); + ++$self->{_useCount}; + + my $config = $self->getLVMOptions(); + # Create a thin volume in an existing thin pool. The volume is not + # immediately enabled. $machine->runSystemCmd("sudo lvcreate --name $name --type=thin" - . " --virtualsize=${ksize}K --thinpool=$name-pool" + . " --virtualsize=${ksize}K --thinpool=$poolName" . " --yes $config $self->{volumeGroup}" . " runSystemCmd("sudo lvcreate $args --yes -ay $config" + $machine->runSystemCmd("sudo lvcreate $args --yes $config" . " $self->{volumeGroup} disableLogicalVolume($name); - # remove a logical volume - my $machine = $self->{storageDevice}->getMachine(); - my $lvPath = "$self->{volumeGroup}/$name"; - my $config = $self->getLVMOptions(); - $machine->runSystemCmd("sudo lvremove --force $config $lvPath"); - $lvPath = "$self->{volumeGroup}/$name-pool"; - $machine->runSystemCmd("sudo lvremove --force $config $lvPath"); - if (--$self->{_useCount} == 0) { - $log->info("Automatically removing VG " . $self->{volumeGroup}); - $self->remove(); - } -} - ######################################################################## # Disable auto activation of logical volume # diff --git a/src/perl/vdotest/VDOTest.pm b/src/perl/vdotest/VDOTest.pm index fc3ccd8d6..48f138094 100644 --- a/src/perl/vdotest/VDOTest.pm +++ b/src/perl/vdotest/VDOTest.pm @@ -704,8 +704,8 @@ sub getVDOStats { ## sub assertVDOStats { my ($self, $expected) = assertNumArgs(2, @_); - my $device = $self->getDevice(); - my $stats = $device->getVDOStats(); + my $device = $self->getVDODevice(); + my $stats = $self->getVDOStats(); $stats->logStats($device->getDevicePath()); foreach my $key (sort(keys(%$expected))) { diff --git a/src/perl/vdotest/VDOTest/BlockDevice01.pm b/src/perl/vdotest/VDOTest/BlockDevice01.pm index fdd911a26..9fff08e56 100644 --- a/src/perl/vdotest/VDOTest/BlockDevice01.pm +++ b/src/perl/vdotest/VDOTest/BlockDevice01.pm @@ -33,7 +33,6 @@ my @deviceTypes = qw( loop lvmvdo raw - thin tracer vdo corruptor-raw @@ -50,7 +49,7 @@ my @deviceTypes = qw( lvmvdo-linear lvmvdo-loop lvmvdo-raw - thin-raw + thin-thinpool tracer-raw vdo-linear vdo-loop @@ -60,8 +59,9 @@ my @deviceTypes = qw( lvmvdo-dory-raw lvmvdo-iscsi-linear lvmvdo-tracer-raw - thin-lvmvdo-thin - thin-vdo-thin + thin-thinpool-raw + thin-thinpool-lvmvdo + thin-thinpool-vdo tracer-corruptor-raw vdo-crypt-raw vdo-dory-raw diff --git a/src/perl/vdotest/VDOTest/DiscardThin.pm b/src/perl/vdotest/VDOTest/DiscardThin.pm index c9b10adad..a733e2fec 100644 --- a/src/perl/vdotest/VDOTest/DiscardThin.pm +++ b/src/perl/vdotest/VDOTest/DiscardThin.pm @@ -21,7 +21,7 @@ my $log = Log::Log4perl->get_logger(__PACKAGE__); our %PROPERTIES = ( # @ple set up a Thin volume on top of VDO for the test - deviceType => "thin-lvmvdo", + deviceType => "thin-thinpool-lvmvdo", # @ple logical (provisioned) size of the exported VDO device logicalSize => "100G", # accept large discards so that thin will pass them down From 2a825d926bd1c221fca569ef9ea11cd8424855c5 Mon Sep 17 00:00:00 2001 From: Bruce Johnston Date: Tue, 10 Dec 2024 17:40:32 -0500 Subject: [PATCH 2/3] dm vdo test: add thin pool using vdo device. The second step to supporting a thin pool device using VDO is to add the new device. This commit takes the current LVMManaged.pm file and puts common LVM VDO code into a base class called LVMVDO.pm. Then an LVMVDO directory is created and what is left of the LVMManaged.pm class is put in a new file called Managed.pm in the LVMVDO directory. Finally, the ThinPool.pm (thin using vdo) class is put in the LVMVDO directory, sharing the LVMVDO.pm features. StorageStack.pm is updated with the new file locations and VolumeGroup.pm is updated to support creating the new vdo thinpool device. VolumeGroup.pm is updated to allow creation of thin pools that use vdo. This is done through the use of an optional parameter. Finally a number of tests are updated to handle the new location of the default vdo device, as it has been renamed and put in the LVMVDO directory. Signed-off-by: Bruce Johnston --- .../VDO/{LVMManaged.pm => LVMVDO.pm} | 145 +++++++-------- .../BlockDevice/VDO/LVMVDO/Managed.pm | 124 +++++++++++++ .../BlockDevice/VDO/LVMVDO/ThinPool.pm | 87 +++++++++ src/perl/Permabit/BlockDevice/VDO/Upgrade.pm | 2 +- src/perl/Permabit/StorageStack.pm | 3 +- src/perl/Permabit/VolumeGroup.pm | 8 +- src/perl/vdotest/VDOTest/DebugTools.pm | 2 +- src/perl/vdotest/VDOTest/GrowPhysical01.pm | 2 +- src/perl/vdotest/VDOTest/RebuildBase.pm | 4 +- src/perl/vdotest/VDOTest/RebuildDuration.pm | 2 +- src/perl/vdotest/VDOTest/RebuildStress03.pm | 4 +- src/perl/vdotest/VDOTest/ThinVDO.pm | 168 ++++++++++++++++++ src/perl/vdotest/VDOTest/Vdorecover.pm | 2 +- 13 files changed, 457 insertions(+), 96 deletions(-) rename src/perl/Permabit/BlockDevice/VDO/{LVMManaged.pm => LVMVDO.pm} (79%) create mode 100644 src/perl/Permabit/BlockDevice/VDO/LVMVDO/Managed.pm create mode 100644 src/perl/Permabit/BlockDevice/VDO/LVMVDO/ThinPool.pm create mode 100644 src/perl/vdotest/VDOTest/ThinVDO.pm diff --git a/src/perl/Permabit/BlockDevice/VDO/LVMManaged.pm b/src/perl/Permabit/BlockDevice/VDO/LVMVDO.pm similarity index 79% rename from src/perl/Permabit/BlockDevice/VDO/LVMManaged.pm rename to src/perl/Permabit/BlockDevice/VDO/LVMVDO.pm index 6ecf168e6..571c34d98 100644 --- a/src/perl/Permabit/BlockDevice/VDO/LVMManaged.pm +++ b/src/perl/Permabit/BlockDevice/VDO/LVMVDO.pm @@ -1,9 +1,9 @@ ## -# Perl object that represents a VDO Volume managed by LVM +# Base Perl object that represents a VDO Volume managed by LVM # # $Id$ ## -package Permabit::BlockDevice::VDO::LVMManaged; +package Permabit::BlockDevice::VDO::LVMVDO; use strict; use warnings FATAL => qw(all); @@ -137,27 +137,6 @@ sub makeLVMConfigString { return join(" ", @values); } -######################################################################## -# @inherit -## -sub setup { - my ($self) = assertNumArgs(1, @_); - - # Get the location of the vdoformat binary for use by LVM. - $self->{vdoformat} = $self->getMachine()->findNamedExecutable("vdoformat"), - - # This will create two devices at once; the vdo pool and the - # volume on top of it. - my $config = $self->makeLVMConfigString(); - my $totalSize = $self->getTotalSize($self->{physicalSize}); - $self->{volumeGroup}->createVDOVolume($self->{deviceName}, - "$self->{deviceName}pool", - $totalSize, - $self->{logicalSize}, - $config); - $self->Permabit::BlockDevice::VDO::setup(); -} - ######################################################################## # @inherit ## @@ -187,13 +166,7 @@ sub installModule { ## sub growLogical { my ($self, $logicalSize) = assertNumArgs(2, @_); - - # resize the vdo logical volume - my $name = "$self->{deviceName}"; - - my $newSize = $self->{volumeGroup}->alignToExtent($logicalSize); - $self->{volumeGroup}->resizeLogicalVolume($name, $newSize); - $self->{logicalSize} = $newSize; + confess("Failed to override the growLogical method"); } ######################################################################## @@ -201,22 +174,57 @@ sub growLogical { ## sub growPhysical { my ($self, $physicalSize) = assertNumArgs(2, @_); + confess("Failed to override the growPhysical method"); +} - # resize the vdo pool - my $name = "$self->{deviceName}pool"; +######################################################################## +# Get the lvm name of the device on top of VDO. Implemented in inheriting +# classes. +## +sub getLVMName { + my ($self) = assertNumArgs(1, @_); + confess("Failed to override the getLVMPoolName method"); +} - my $newSize = $self->{metadataSize} + $physicalSize; - $newSize = $self->{volumeGroup}->alignToExtent($newSize); - $self->{volumeGroup}->resizeLogicalVolume($name, $newSize); - $self->{physicalSize} = $newSize - $self->{metadataSize}; +######################################################################## +# Get the lvm name of the vdo device. Implemented in inheriting classes. +## +sub getLVMVDOName { + my ($self) = assertNumArgs(1, @_); + confess("Failed to override the getLVMPoolName method"); +} + +######################################################################## +# Get the lvm name of the vdo storage device. Implemented in inheriting +# classes. +## +sub getLVMStorageName { + my ($self) = assertNumArgs(1, @_); + confess("Failed to override the getLVMStorageName method"); +} + +######################################################################## +# Get the name of the vdo storage device. Implemented in inheriting +# classes. +## +sub getVDOStorageName { + my ($self) = assertNumArgs(1, @_); + confess("Failed to override the getVDOStorageName method"); } ######################################################################## # @inherit ## -sub getLogicalMetadataSize { +sub getVDOStoragePath { my ($self) = assertNumArgs(1, @_); - return $MB; + if (defined($self->{volumeGroup})) { + my $vgName = $self->{volumeGroup}->getName(); + my $storageName = "$vgName-" . $self->getLVMStorageName(); + my $path = makeFullPath($self->{deviceRootDir}, $storageName); + + return $self->_resolveSymlink($path); + } + return $self->getStoragePath(); } ######################################################################## @@ -237,11 +245,7 @@ sub resizeStorageDevice { ## sub renameVDO { my ($self, $newName) = assertNumArgs(2, @_); - my $name = "$self->{deviceName}"; - my $pool = "$self->{deviceName}pool"; - $self->{volumeGroup}->renameLogicalVolume($name, $newName); - $self->{volumeGroup}->renameLogicalVolume($pool, $newName . "pool"); - $self->setDeviceName($newName); + confess("Failed to override the renameVDO method"); } ######################################################################## @@ -288,9 +292,9 @@ sub migrate { ## sub disableWritableStorage { my ($self) = assertNumArgs(1, @_); - my $deviceName = "$self->{deviceName}pool_vdata"; + my $storageName = $self->getLVMStorageName(); my $vgName = $self->{volumeGroup}->getName(); - my $fullName = "$vgName-$deviceName"; + my $fullName = "$vgName-$storageName"; $self->runOnHost("sudo dmsetup remove $fullName"); $self->SUPER::disableWritableStorage(); @@ -301,15 +305,15 @@ sub disableWritableStorage { ## sub enableWritableStorage { my ($self) = assertNumArgs(1, @_); - my $deviceName = "$self->{deviceName}pool_vdata"; + my $storageName = $self->getLVMStorageName(); - $self->{volumeGroup}->enableLogicalVolume($deviceName); + $self->{volumeGroup}->enableLogicalVolume($storageName); my $vgName = $self->{volumeGroup}->getName(); - my $fullName = "$vgName-$deviceName"; + my $fullName = "$vgName-$storageName"; my $table = $self->runOnHost("sudo dmsetup table $fullName"); - $self->{volumeGroup}->disableLogicalVolume($deviceName); + $self->{volumeGroup}->disableLogicalVolume($storageName); $self->runOnHost("sudo dmsetup create $fullName --table '$table'"); $self->SUPER::enableWritableStorage(); @@ -320,7 +324,8 @@ sub enableWritableStorage { ## sub disableReadableStorage { my ($self) = assertNumArgs(1, @_); - $self->{volumeGroup}->disableLogicalVolume("$self->{deviceName}pool_vdata"); + my $storageName = $self->getLVMStorageName(); + $self->{volumeGroup}->disableLogicalVolume($storageName); $self->SUPER::disableReadableStorage(); } @@ -329,48 +334,19 @@ sub disableReadableStorage { ## sub enableReadableStorage { my ($self) = assertNumArgs(1, @_); - $self->{volumeGroup}->enableLogicalVolume("$self->{deviceName}pool_vdata"); + my $storageName = $self->getLVMStorageName(); + $self->{volumeGroup}->enableLogicalVolume($storageName); $self->SUPER::enableReadableStorage(); } -######################################################################## -# @inherit -## -sub getVDOStoragePath { - my ($self) = assertNumArgs(1, @_); - if (defined($self->{volumeGroup})) { - my $vgName = $self->{volumeGroup}->getName(); - my $storageName = "$vgName-$self->{deviceName}pool_vdata"; - my $path = makeFullPath($self->{deviceRootDir}, $storageName); - - return $self->_resolveSymlink($path); - } - return $self->getStoragePath(); -} - -######################################################################## -# @inherit -## -sub setDeviceName { - my ($self, $deviceName) = assertNumArgs(2, @_); - $self->Permabit::BlockDevice::VDO::setDeviceName($deviceName); - # Override the vdo name to point at the VDO pool. - my $vgName = $self->{volumeGroup}->getName(); - $self->{vdoDeviceName} = "$vgName-$self->{deviceName}pool-vpool"; -} - ######################################################################## # @inherit ## sub setSymbolicPath { my ($self) = assertNumArgs(1, @_); - $self->Permabit::BlockDevice::LVM::setSymbolicPath(); - # Override the vdo symbolic path to point at the VDO pool. - my $vgName = $self->{volumeGroup}->getName(); - my $deviceName = "$vgName-$self->{deviceName}pool-vpool"; - $self->{vdoSymbolicPath} - = makeFullPath($self->{deviceRootDir}, $deviceName); + = makeFullPath($self->{deviceRootDir}, $self->{vdoDeviceName}); + $self->Permabit::BlockDevice::LVM::setSymbolicPath(); } ######################################################################## @@ -391,8 +367,7 @@ sub forceRebuild { ## sub _changeVDOSetting { my ($self, $setting) = assertNumArgs(2, @_); - my $name = "$self->{deviceName}pool"; - $self->{volumeGroup}->_changeLogicalVolume($name, $setting); + $self->{volumeGroup}->_changeLogicalVolume($self->getVDODeviceName(), $setting); } ######################################################################## diff --git a/src/perl/Permabit/BlockDevice/VDO/LVMVDO/Managed.pm b/src/perl/Permabit/BlockDevice/VDO/LVMVDO/Managed.pm new file mode 100644 index 000000000..adc179ab9 --- /dev/null +++ b/src/perl/Permabit/BlockDevice/VDO/LVMVDO/Managed.pm @@ -0,0 +1,124 @@ +## +# Perl object that represents a VDO Volume managed by LVM +# +# $Id$ +## +package Permabit::BlockDevice::VDO::LVMVDO::Managed; + +use strict; +use warnings FATAL => qw(all); +use Carp qw(confess); +use English qw(-no_match_vars); +use Log::Log4perl; +use Permabit::Assertions qw( + assertDefined + assertNumArgs + assertType +); +use Permabit::Constants; +use Permabit::ProcessUtils qw(delayFailures); +use Permabit::Utils qw(makeFullPath); + +use base qw(Permabit::BlockDevice::VDO::LVMVDO); + +my $log = Log::Log4perl->get_logger(__PACKAGE__); + +######################################################################## +# @inherit +## +sub setup { + my ($self) = assertNumArgs(1, @_); + + # Get the location of the vdoformat binary for use by LVM. + $self->{vdoformat} = $self->getMachine()->findNamedExecutable("vdoformat"), + + # This will create two devices at once; the vdo pool and the + # volume on top of it. + my $config = $self->makeLVMConfigString(); + my $totalSize = $self->getTotalSize($self->{physicalSize}); + $self->{volumeGroup}->createVDOVolume($self->{deviceName}, + $self->getLVMVDOName(), + $totalSize, + $self->{logicalSize}, + $config); + $self->Permabit::BlockDevice::VDO::setup(); +} + +######################################################################## +# @inherit +## +sub growLogical { + my ($self, $logicalSize) = assertNumArgs(2, @_); + + # resize the device that sits on top of the vdo pool + my $name = $self->{deviceName}; + + my $newSize = $self->{volumeGroup}->alignToExtent($logicalSize); + $self->{volumeGroup}->resizeLogicalVolume($name, $newSize); + $self->{logicalSize} = $newSize; +} + +######################################################################## +# @inherit +## +sub growPhysical { + my ($self, $physicalSize) = assertNumArgs(2, @_); + + # resize the vdo pool + my $name = $self->getLVMVDOName(); + + my $newSize = $self->getMetadataSize() + $physicalSize; + $newSize = $self->{volumeGroup}->alignToExtent($newSize); + $self->{volumeGroup}->resizeLogicalVolume($name, $newSize); + $self->{physicalSize} = $newSize - $self->{metadataSize}; +} + +######################################################################## +# Rename a VDO device. Currently LVM managed devices are the only +# ones that support rename. +# +# @param newName The new name for the VDO device. +## +sub renameVDO { + my ($self, $newName) = assertNumArgs(2, @_); + $self->{volumeGroup}->renameLogicalVolume($self->{deviceName}, $newName); + $self->{volumeGroup}->renameLogicalVolume($self->getLVMVDOName(), $newName . "pool"); + $self->setDeviceName($newName); +} + +######################################################################## +# @inherit +## +sub getLogicalMetadataSize { + my ($self) = assertNumArgs(1, @_); + return $MB; +} + +######################################################################## +# Get the lvm name of the vdo device. +## +sub getLVMVDOName { + my ($self) = assertNumArgs(1, @_); + return "$self->{deviceName}pool"; +} + +######################################################################## +# Get the lvm name of the vdo storage device. +## +sub getLVMStorageName { + my ($self) = assertNumArgs(1, @_); + my $vgName = $self->{volumeGroup}->getName(); + return "$self->{deviceName}pool_vdata"; +} + +######################################################################## +# @inherit +## +sub setDeviceName { + my ($self, $deviceName) = assertNumArgs(2, @_); + my $vgName = $self->{volumeGroup}->getName(); + $self->{vdoDeviceName} = "$vgName-$self->{deviceName}pool-vpool"; + $self->Permabit::BlockDevice::LVM::setDeviceName($deviceName); +} + +1; diff --git a/src/perl/Permabit/BlockDevice/VDO/LVMVDO/ThinPool.pm b/src/perl/Permabit/BlockDevice/VDO/LVMVDO/ThinPool.pm new file mode 100644 index 000000000..3a99723ec --- /dev/null +++ b/src/perl/Permabit/BlockDevice/VDO/LVMVDO/ThinPool.pm @@ -0,0 +1,87 @@ +## +# Perl object that represents an LVM Thin Pool using a VDO as data device +# +# $Id$ +## +package Permabit::BlockDevice::VDO::LVMVDO::ThinPool; + +use strict; +use warnings FATAL => qw(all); +use Carp qw(confess); +use English qw(-no_match_vars); +use Log::Log4perl; +use Permabit::Assertions qw( + assertDefined + assertNumArgs + assertType +); +use Permabit::Constants; +use Permabit::ProcessUtils qw(delayFailures); +use Permabit::Utils qw(makeFullPath); + +use base qw( + Permabit::BlockDevice::VDO::LVMVDO + Permabit::BlockDevice::LVM::ThinPool +); + +my $log = Log::Log4perl->get_logger(__PACKAGE__); + +######################################################################## +# @inherit +## +sub setup { + my ($self) = assertNumArgs(1, @_); + + # Get the location of the vdoformat binary for use by LVM. + $self->{vdoformat} = $self->getMachine()->findNamedExecutable("vdoformat"); + + # This will create a thin pool that has vdo set up to be the data device + my $config = $self->makeLVMConfigString(); + my $totalSize = $self->getTotalSize($self->{physicalSize}); + $self->{volumeGroup}->createThinPool($self->{deviceName}, + $totalSize, + $config, + 1); + $self->Permabit::BlockDevice::VDO::setup(); +} + +######################################################################## +# Rename a VDO device. Currently LVM managed devices are the only +# ones that support rename. +# +# @param newName The new name for the VDO device. +## +sub renameVDO { + my ($self, $newName) = assertNumArgs(2, @_); + my $name = $self->{deviceName}; + $self->{volumeGroup}->renameLogicalVolume($name, $newName); + $self->setDeviceName($newName); +} + +######################################################################## +# Get the lvm name of the vdo device. +## +sub getLVMVDOName { + my ($self) = assertNumArgs(1, @_); + return "$self->{deviceName}_vpool0"; +} + +######################################################################## +# Get the lvm name of the vdo storage device. +## +sub getLVMStorageName { + my ($self) = assertNumArgs(1, @_); + return "$self->{deviceName}_vpool0_vdata"; +} + +######################################################################## +# @inherit +## +sub setDeviceName { + my ($self, $deviceName) = assertNumArgs(2, @_); + my $vgName = $self->{volumeGroup}->getName(); + $self->{vdoDeviceName} = "$vgName-$self->{deviceName}_vpool0-vpool"; + $self->Permabit::BlockDevice::LVM::setDeviceName($deviceName); +} + +1; diff --git a/src/perl/Permabit/BlockDevice/VDO/Upgrade.pm b/src/perl/Permabit/BlockDevice/VDO/Upgrade.pm index fad8025fa..68657fbed 100644 --- a/src/perl/Permabit/BlockDevice/VDO/Upgrade.pm +++ b/src/perl/Permabit/BlockDevice/VDO/Upgrade.pm @@ -23,7 +23,7 @@ use Permabit::Constants qw($GB); use Permabit::Utils qw(makeFullPath); use Permabit::SupportedVersions qw($SUPPORTED_SCENARIOS $SUPPORTED_VERSIONS); -use base qw(Permabit::BlockDevice::VDO::LVMManaged); +use base qw(Permabit::BlockDevice::VDO::LVMVDO::Managed); my $log = Log::Log4perl->get_logger(__PACKAGE__); diff --git a/src/perl/Permabit/StorageStack.pm b/src/perl/Permabit/StorageStack.pm index e42709128..5923eb623 100644 --- a/src/perl/Permabit/StorageStack.pm +++ b/src/perl/Permabit/StorageStack.pm @@ -36,13 +36,14 @@ my %DEVICE_TYPES = ( iscsi => 'Permabit::BlockDevice::ISCSI', linear => 'Permabit::BlockDevice::LVM::Linear', loop => 'Permabit::BlockDevice::Loop', - lvmvdo => 'Permabit::BlockDevice::VDO::LVMManaged', + lvmvdo => 'Permabit::BlockDevice::VDO::LVMVDO::Managed', mostlyzero => 'Permabit::BlockDevice::MostlyZero', raid => 'Permabit::BlockDevice::RAID', raw => 'Permabit::BlockDevice::Raw', stripfua => 'Permabit::BlockDevice::TestDevice::StripFua', thin => 'Permabit::BlockDevice::LVM::Thin', thinpool => 'Permabit::BlockDevice::LVM::ThinPool', + thinpoolvdo => 'Permabit::BlockDevice::VDO::LVMVDO::ThinPool', tracer => 'Permabit::BlockDevice::TestDevice::Managed::Tracer', upgrade => 'Permabit::BlockDevice::VDO::Upgrade', vdo => 'Permabit::BlockDevice::VDO::Unmanaged', diff --git a/src/perl/Permabit/VolumeGroup.pm b/src/perl/Permabit/VolumeGroup.pm index 7fa02653a..954219bd0 100644 --- a/src/perl/Permabit/VolumeGroup.pm +++ b/src/perl/Permabit/VolumeGroup.pm @@ -163,9 +163,10 @@ sub createLogicalVolume { # @param name Thin pool name # @param size Thin pool size in bytes # @oparam config String of create time lvm.conf overrides +# @oparam useVdo Whether the thin pool uses VDO or not ## sub createThinPool { - my ($self, $name, $size, $config) = assertMinMaxArgs([""], 3, 4, @_); + my ($self, $name, $size, $config, $useVdo) = assertMinMaxArgs(["", 0], 3, 5, @_); my $machine = $self->{storageDevice}->getMachine(); assertEqualNumeric(0, $size % $KB, "size must be a multiple of 1KB"); @@ -195,6 +196,11 @@ sub createThinPool { $ksize = $newSize; } + my $dataType = ""; + if ($useVdo) { + $dataType = "--pooldatavdo y"; + } + # Create a thin pool in an existing volume group. The pool is not # immediately enabled. $machine->runSystemCmd("sudo lvcreate --name $name --type=thin-pool" diff --git a/src/perl/vdotest/VDOTest/DebugTools.pm b/src/perl/vdotest/VDOTest/DebugTools.pm index 1bdd18e43..e08abd018 100644 --- a/src/perl/vdotest/VDOTest/DebugTools.pm +++ b/src/perl/vdotest/VDOTest/DebugTools.pm @@ -63,7 +63,7 @@ sub _verifySingleLBNDump { my $storagePath = $device->getVDOStoragePath(); my $lbnOffset = 0; - if ($device->isa("Permabit::BlockDevice::VDO::LVMManaged")) { + if ($device->isa("Permabit::BlockDevice::VDO::LVMVDO::Managed")) { # LVM grabs 512k/128 blocks of metadata space on top of the VDO volume. $lbnOffset = 128; } diff --git a/src/perl/vdotest/VDOTest/GrowPhysical01.pm b/src/perl/vdotest/VDOTest/GrowPhysical01.pm index e2b3bd391..9c7ee91ad 100644 --- a/src/perl/vdotest/VDOTest/GrowPhysical01.pm +++ b/src/perl/vdotest/VDOTest/GrowPhysical01.pm @@ -77,7 +77,7 @@ sub testNoGrowth { eval { $device->growPhysical($self->{physicalSize}); }; - if ($device->isa("Permabit::BlockDevice::VDO::LVMManaged")) { + if ($device->isa("Permabit::BlockDevice::VDO::LVMVDO::Managed")) { # lvresize apparently thinks zero is a negative number assertEvalErrorMatches(qr/Cannot reduce VDO pool data volume/) } else { diff --git a/src/perl/vdotest/VDOTest/RebuildBase.pm b/src/perl/vdotest/VDOTest/RebuildBase.pm index ce1c115b3..bec477adc 100644 --- a/src/perl/vdotest/VDOTest/RebuildBase.pm +++ b/src/perl/vdotest/VDOTest/RebuildBase.pm @@ -345,8 +345,8 @@ sub simpleRecovery { my $newPhysicalThreadCount = $self->{physicalThreadCount} + $zoneDelta; # XXX when LVM adds support for changing thread counts (BZ 2070777), # remove this and implement properly. - if ($device->isa("Permabit::BlockDevice::VDO::LVMManaged")) { - $log->info("Skipping thread count change on LVMManaged"); + if ($device->isa("Permabit::BlockDevice::VDO::LVMVDO::Managed")) { + $log->info("Skipping thread count change on Managed device"); } else { my $modifyArgs = { vdoPhysicalThreads => $newPhysicalThreadCount }; $device->assertVDOCommand("modify", $modifyArgs); diff --git a/src/perl/vdotest/VDOTest/RebuildDuration.pm b/src/perl/vdotest/VDOTest/RebuildDuration.pm index c45a94836..841145ad8 100644 --- a/src/perl/vdotest/VDOTest/RebuildDuration.pm +++ b/src/perl/vdotest/VDOTest/RebuildDuration.pm @@ -290,7 +290,7 @@ sub testRecovery { eval { $vdo->growPhysical($newSize); }; - if ($device->isa("Permabit::BlockDevice::VDO::LVMManaged")) { + if ($device->isa("Permabit::BlockDevice::VDO::LVMVDO::Managed")) { assertEvalErrorMatches(qr/reload ioctl on .* failed/); } else { assertEvalErrorMatches(qr/ERROR\s*[:-] Device.*could not be changed/); diff --git a/src/perl/vdotest/VDOTest/RebuildStress03.pm b/src/perl/vdotest/VDOTest/RebuildStress03.pm index 39507e401..0f0ecd2ff 100644 --- a/src/perl/vdotest/VDOTest/RebuildStress03.pm +++ b/src/perl/vdotest/VDOTest/RebuildStress03.pm @@ -193,8 +193,8 @@ sub doThreadCountChange { # XXX when LVM adds support for changing thread counts (BZ 2070777), remove # this and implement properly at the bottom. - if ($device->isa("Permabit::BlockDevice::VDO::LVMManaged")) { - $log->info("Skipping thread count change on LVMManaged"); + if ($device->isa("Permabit::BlockDevice::VDO::LVMVDO::Managed")) { + $log->info("Skipping thread count change on Managed device"); return; } diff --git a/src/perl/vdotest/VDOTest/ThinVDO.pm b/src/perl/vdotest/VDOTest/ThinVDO.pm new file mode 100644 index 000000000..cf74fccf6 --- /dev/null +++ b/src/perl/vdotest/VDOTest/ThinVDO.pm @@ -0,0 +1,168 @@ +## +# Basic VDO test using block read/write +# +# $Id$ +## +package VDOTest::ThinVDO; + +use strict; +use warnings FATAL => qw(all); +use English qw(-no_match_vars); +use Log::Log4perl; +use Permabit::Assertions qw(assertNumArgs); +use Permabit::Constants; + +use base qw(VDOTest); + +my $log = Log::Log4perl->get_logger(__PACKAGE__); + +######################################################################## +# @paramList{getProperties} +our %PROPERTIES + = ( + # @ple Number of blocks to write + blockCount => 5000, + # @ple Use a VDO device + deviceType => "linear", + # @ple VDO slab bit count + slabBits => $SLAB_BITS_SMALL, + ); +## + +######################################################################## +# Check LVM version. +## +sub doesLVMSupportThinVDO { + my ($self) = assertNumArgs(1, @_); + my $device = $self->getDevice(); + my $machine = $device->getMachine(); + + # Check lvm version. line we want is: 'LVM version: 2.03.26(2) (2024-08-23)' + $machine->runSystemCmd("sudo lvm version | grep 'LVM version:' | awk '{print \$3}'"); + my $stdout = $machine->getStdout(); + my @version = split(/\(/, $stdout); + my ($major, $minor, $patch) = split(/\./, $version[0]); + $log->info("LVM version is " . join(".", ($major, $minor, $patch))); + if (($major > 2) || ($major == 2 && $minor > 3) + || ($major == 2 && $minor == 3 && $patch >= 26)) { + return 1; + } + return 0; +} + +######################################################################## +# Basic VDO testing. +## +sub testBasic { + my ($self) = assertNumArgs(1, @_); + + if (!$self->doesLVMSupportThinVDO()) { + $log->info("LVM version doesn't support thinpool using vdo"); + return; + }; + + $self->createTestDevice("thinpoolvdo"); + $self->createTestDevice("thin"); + + my $device = $self->getDevice(); + + my $expectedStats = { + "data blocks used" => 0, + "dedupe advice valid" => 0, + "dedupe advice stale" => 0, + "dedupe advice timeouts" => 0, + "entries indexed" => 0, + }; + $self->assertVDOStats($expectedStats); + + # Write some blocks, read them back and verify the data have not changed. + my $slice1 = $self->createSlice(blockCount => $self->{blockCount}); + $slice1->write(tag => "Direct1", direct => 1); + $slice1->verify(); + $expectedStats->{"data blocks used"} += $self->{blockCount}; + $expectedStats->{"entries indexed"} += $self->{blockCount}; + $self->assertVDOStats($expectedStats); + + # Write the blocks again, expecting complete dedupe. + my $slice2 = $self->createSlice(blockCount => $self->{blockCount}, + offset => $self->{blockCount},); + $slice2->write(tag => "Direct1", direct => 1); + + $expectedStats->{"dedupe advice valid"} += $self->{blockCount}; + $self->assertVDOStats($expectedStats); + + # Restart the device to verify that data is persistent + $device->restart(); + + # Verify the data have not changed + $slice1->verify(); + $slice2->verify(); +} + +######################################################################## +# VDO testing for Multiple Thin Volumes. +## +sub testMultiple { + my ($self) = assertNumArgs(1, @_); + + if (!$self->doesLVMSupportThinVDO()) { + $log->info("LVM version doesn't support thinpool using vdo"); + return; + }; + + $self->createTestDevice("thinpoolvdo"); + + my $storageDevice = $self->getDevice(); + my $machine = $storageDevice->getMachine(); + + # split the raw device in half and deduct the size of the albireo index + my $storageSize = $storageDevice->getSize() / 2; + # Create the appropriate storage devices for each VDO. + my @parameters = (storageDevice => $storageDevice, + volumeGroup => $storageDevice->{volumeGroup}, + ); + $self->{firstThinLV} + = $self->createTestDevice("thin", + deviceName => "firstThin", + lvmSize => $storageSize, + @parameters); + $self->{secondThinLV} + = $self->createTestDevice("thin", + deviceName => "secondThin", + @parameters); + my $expectedStats = { + "data blocks used" => 0, + "dedupe advice valid" => 0, + "dedupe advice stale" => 0, + "dedupe advice timeouts" => 0, + "entries indexed" => 0, + }; + $self->assertVDOStats($expectedStats); + + # Write some blocks, read them back and verify the data have not changed. + my $slice1 = $self->createSlice(device => $self->{firstThinLV}, + blockCount => $self->{blockCount}); + $slice1->write(tag => "Direct1", direct => 1); + $slice1->verify(); + $expectedStats->{"data blocks used"} += $self->{blockCount}; + $expectedStats->{"entries indexed"} += $self->{blockCount}; + $self->assertVDOStats($expectedStats); + + # Write the blocks again to the other thin lv, expecting complete dedupe. + my $slice2 = $self->createSlice(device => $self->{secondThinLV}, + blockCount => $self->{blockCount}); + $slice2->write(tag => "Direct1", direct => 1); + + $expectedStats->{"dedupe advice valid"} += $self->{blockCount}; + $self->assertVDOStats($expectedStats); + + # Restart the device to verify that data is persistent + $self->{firstThinLV}->restart(); + $self->{secondThinLV}->restart(); + + # Verify the data have not changed + $slice1->verify(); + $slice2->verify(); +} + +1; diff --git a/src/perl/vdotest/VDOTest/Vdorecover.pm b/src/perl/vdotest/VDOTest/Vdorecover.pm index ab1884963..a0da8bfe6 100644 --- a/src/perl/vdotest/VDOTest/Vdorecover.pm +++ b/src/perl/vdotest/VDOTest/Vdorecover.pm @@ -92,7 +92,7 @@ sub _getVDODevicePath { # If LVM creates a vdo with the nominal name of 'vdo0' in 'vg1', the visible # device for a filesystem is named more like 'vg1-vdo0', and the actual VDO # device is named vg1-vdo0pool-vpool, for LVM reasons... - if ($device->isa("Permabit::BlockDevice::VDO::LVMManaged")) { + if ($device->isa("Permabit::BlockDevice::VDO::LVMVDO::Managed")) { my $vgName = $device->{volumeGroup}->getName(); $deviceName = "${vgName}-${deviceName}pool-vpool"; } From b38722229a5d2b4a5302f6eb9994b2bc8e628e71 Mon Sep 17 00:00:00 2001 From: Bruce Johnston Date: Mon, 16 Dec 2024 16:54:05 -0500 Subject: [PATCH 3/3] dm vdo test: use -an and -kn flags for creation This commit replaces the post creation disabling of devices in VolumeGroup.pm with the create flags of -an and -kn now that they work with the lvm version we are using. Signed-off-by: Bruce Johnston --- src/perl/Permabit/VolumeGroup.pm | 39 ++++---------------------------- 1 file changed, 4 insertions(+), 35 deletions(-) diff --git a/src/perl/Permabit/VolumeGroup.pm b/src/perl/Permabit/VolumeGroup.pm index 954219bd0..472f987eb 100644 --- a/src/perl/Permabit/VolumeGroup.pm +++ b/src/perl/Permabit/VolumeGroup.pm @@ -146,15 +146,8 @@ sub createLogicalVolume { # a yes/no on whether to wipeout a filesystem signature (it does on RHEL7), # the input redirection will cause the answer to be "no". The volume is not # immediately enabled. - $machine->runSystemCmd("sudo lvcreate --name $name --size ${ksize}K --yes" + $machine->runSystemCmd("sudo lvcreate --name $name -an --size ${ksize}K --yes" . " $config $self->{volumeGroup} sendCommand("sudo udevadm settle"); - # XXX As soon as we get rid of Squeeze, on which lvcreate doesn't have the - # -a flag, we can stop doing two separate commands and use lvcreate -an. - $self->disableLogicalVolume($name); } ######################################################################## @@ -204,17 +197,8 @@ sub createThinPool { # Create a thin pool in an existing volume group. The pool is not # immediately enabled. $machine->runSystemCmd("sudo lvcreate --name $name --type=thin-pool" - . " --size ${ksize}K --yes $config" + . " --size ${ksize}K -an -kn --yes $config" . " $self->{volumeGroup} sendCommand("sudo udevadm settle"); - # XXX As soon as we get rid of Squeeze, on which lvcreate doesn't have the - # -a flag, we can stop doing two separate commands and use lvcreate -an. - $self->disableAutoActivation($name); - $self->disableLogicalVolume($name); - } ######################################################################## @@ -238,17 +222,10 @@ sub createThinVolume { my $config = $self->getLVMOptions(); # Create a thin volume in an existing thin pool. The volume is not # immediately enabled. - $machine->runSystemCmd("sudo lvcreate --name $name --type=thin" + $machine->runSystemCmd("sudo lvcreate --name $name -an --type=thin" . " --virtualsize=${ksize}K --thinpool=$poolName" . " --yes $config $self->{volumeGroup}" . " sendCommand("sudo udevadm settle"); - # XXX As soon as we get rid of Squeeze, on which lvcreate doesn't have the - # -a flag, we can stop doing two separate commands and use lvcreate -an. - $self->disableLogicalVolume($name); } ######################################################################## @@ -301,16 +278,8 @@ sub createVDOVolume { } my $args = join(' ', map { "--$_ $args{$_}" } keys(%args)); - $machine->runSystemCmd("sudo lvcreate $args --yes $config" + $machine->runSystemCmd("sudo lvcreate $args -an -kn --yes $config" . " $self->{volumeGroup} sendCommand("sudo udevadm settle"); - # XXX As soon as we get rid of Squeeze, on which lvcreate doesn't have the - # -a flag, we can stop doing two separate commands and use lvcreate -an. - $self->disableAutoActivation($name); - $self->disableLogicalVolume($name); } ########################################################################