2024-05-29 19:05:19 +03:00
#!/usr/bin/env bash
# Copyright (C) 2024 Red Hat, Inc. All rights reserved.
#
# This copyrighted material is made available to anyone wishing to use,
# modify, copy, or redistribute it subject to the terms and conditions
# of the GNU General Public License v.2.
#
# You should have received a copy of 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
LVM_SKIP_LARGE_TESTS = 1
SKIP_RESIZE = 0
. lib/inittest
which mkfs.ext4 || skip
[ $SKIP_RESIZE -eq 0 ] && ( which resize2fs || skip )
2024-06-14 13:58:49 +03:00
aux kernel_at_least 6 9 0 || skip
2024-05-29 19:05:19 +03:00
test " $( aux total_mem) " -gt 1048576 || skip "Not enough RAM for this test"
# List of stripes to add or remove
tst_stripes = ""
# Delay on first 'PV' to be able to retrieve status during reshape.
# Needs to be varied depending on layout as they come with different reshape overhead.
ms = 0
# PV numbers and size
npvs = 0
pvsz = 0
function _get_pvs_stripes_and_delay
{
local raid_type = $1
case $LVM_SKIP_LARGE_TESTS in
0)
npvs = 64
pvsz = 32
case $raid_type in
raid[ 45] *)
2024-06-14 13:58:49 +03:00
ms = 30
2024-05-29 19:05:19 +03:00
tst_stripes = "5 4 11 9 15 13 19 18 22 21 25 23 28 30 31 29 33 31 34 33 37 45 41 50 55 60 63 30 15 10 8 3"
; ;
raid6*)
2024-06-14 13:58:49 +03:00
ms = 20
2024-05-29 19:05:19 +03:00
tst_stripes = "5 4 11 9 15 13 19 18 22 21 25 23 28 30 31 29 33 31 34 33 37 45 41 50 55 60 62 30 15 10 8 3"
; ;
raid10*)
2024-06-14 13:58:49 +03:00
ms = 50
2024-05-29 19:05:19 +03:00
tst_stripes = "5 8 9 11 13 14 15 19 20 22 23 25 27 28 29 32"
; ;
esac
; ;
*)
npvs = 20
pvsz = 16
case $raid_type in
raid[ 45] *)
2024-06-14 13:58:49 +03:00
ms = 40
2024-05-29 19:05:19 +03:00
tst_stripes = "5 4 8 7 11 9 15 19 18 10"
; ;
raid6*)
2024-06-14 13:58:49 +03:00
ms = 25
2024-05-29 19:05:19 +03:00
tst_stripes = "5 4 8 7 11 9 15 18 10 5"
; ;
raid10*)
2024-06-14 13:58:49 +03:00
ms = 40
2024-05-29 19:05:19 +03:00
tst_stripes = "5 6 7 8 9 10"
; ;
esac
esac
}
function _get_size
{
local vg = $1
local lv = $2
local data_stripes = $3
local reshape_len rimagesz
# Get any reshape size in sectors
reshape_len = $( lvs --noheadings -aoname,reshapelen --unit s $vg /${ lv } _rimage_0| head -1| cut -d ']' -f2)
reshape_len = $( echo ${ reshape_len /S } | xargs)
# Get rimage size - reshape length
rimagesz = $(( $( blockdev --getsz /dev/mapper/${ vg } -${ lv } _rimage_0) - $reshape_len ))
# Calculate size of LV based on above sizes
echo $(( $rimagesz * $data_stripes ))
}
function _check_size
{
local vg = $1
local lv = $2
local data_stripes = $3
# Compare size of LV with calculated one
[ $( blockdev --getsz /dev/$vg /$lv ) -eq $( _get_size $vg $lv $data_stripes ) ] && echo 0 || echo 1
}
function _total_stripes
{
local raid_type = $1
local data_stripes = $2
case $raid_type in
raid[ 45] *) echo $(( $data_stripes + 1 )) ; ;
raid6*) echo $(( $data_stripes + 2 )) ; ;
raid10*) echo $(( $data_stripes * 2 )) ; ;
esac
}
function _lvcreate
{
local raid_type = $1
local data_stripes = $2
local size = $3
local vg = $4
local lv = $5
shift 5
local opts = " $* "
local stripes = $( _total_stripes $raid_type $data_stripes )
lvcreate -y -aey --type $raid_type -i $data_stripes -L $size -n $lv $vg $opts
check lv_first_seg_field $vg /$lv segtype " $raid_type "
check lv_first_seg_field $vg /$lv datastripes $data_stripes
check lv_first_seg_field $vg /$lv stripes $stripes
mkfs.ext4 " $DM_DEV_DIR / $vg / $lv "
fsck -fy " $DM_DEV_DIR / $vg / $lv "
}
function _reshape_layout
{
local raid_type = $1
local data_stripes = $2
local vg = $3
local lv = $4
local wait_for_reshape = $5
local ignore_a_chars = $6
shift 6
local opts = " $* "
local stripes = $( _total_stripes $raid_type $data_stripes )
# Avoid random udev sync delays causing _check_size to be unreliable
lvconvert -y --noudevsync --ty $raid_type --stripes $data_stripes $opts $vg /$lv
check lv_first_seg_field $vg /$lv1 segtype " $raid_type "
if [ $wait_for_reshape -eq 1 ]
then
aux wait_for_sync $vg $lv $ignore_a_chars
fsck -fn " $DM_DEV_DIR / $vg / $lv "
fi
}
function _add_stripes
{
local raid_type = $1
local vg = $2
local lv = $3
local data_stripes = $4
local stripes = $( _total_stripes $raid_type $data_stripes )
local stripesize = " $(( 16 << ( $data_stripes % 5 )) ).00k " # Stripe size variation
aux delay_dev " $dev1 " $ms 0
_reshape_layout $raid_type $data_stripes $vg $lv 0 1 --stripesize $stripesize
# Size has to be inconsistent until reshape finishes
[ $( _check_size $vg $lv $data_stripes ) -ne 0 ] || die "LV size should be small"
check lv_first_seg_field $vg /$lv stripesize " $stripesize "
check lv_first_seg_field $vg /$lv datastripes $data_stripes
check lv_first_seg_field $vg /$lv stripes $stripes
fsck -fy " $DM_DEV_DIR / $vg / $lv "
aux delay_dev " $dev1 " 0 0
aux wait_for_sync $vg $lv 0
2024-06-14 13:58:49 +03:00
sleep 1
2024-05-29 19:05:19 +03:00
# Now size consistency has to be fine
[ $( _check_size $vg $lv $data_stripes ) -eq 0 ] || die "LV size should be grown"
# Check, use grown capacity for the filesystem and check again
if [ $SKIP_RESIZE -eq 0 ]
then
fsck -fy " $DM_DEV_DIR / $vg / $lv "
resize2fs " $DM_DEV_DIR / $vg / $lv "
fi
fsck -fy " $DM_DEV_DIR / $vg / $lv "
udevadm settle
}
function _remove_stripes
{
local raid_type = $1
local vg = $2
local lv = $3
local data_stripes = $4
local cur_data_stripes = $( get lv_field " $vg / $lv " datastripes -a)
local stripes = $( get lv_field " $vg / $lv " stripes -a)
local stripesize = " $(( 16 << ( $data_stripes % 5 )) ).00k " # Stripe size variation
# Check, shrink hilesystem to the resulting smaller size and check again
if [ $SKIP_RESIZE -eq 0 ]
then
fsck -fy " $DM_DEV_DIR / $vg / $lv "
resize2fs " $DM_DEV_DIR / $vg / $lv " $( _get_size $vg $lv $data_stripes ) s
fsck -fy " $DM_DEV_DIR / $vg / $lv "
fi
aux delay_dev " $dev1 " $ms 0
_reshape_layout $raid_type $data_stripes $vg $lv 0 1 --force --stripesize $stripesize
# Size has to be inconsistent, as to be removed legs still exist
[ $( _check_size $vg $lv $cur_data_stripes ) -ne 0 ] || die "LV size should be reduced but not rimage count"
check lv_first_seg_field $vg /$lv stripesize " $stripesize "
check lv_first_seg_field $vg /$lv datastripes $data_stripes
check lv_first_seg_field $vg /$lv stripes $stripes
fsck -fy " $DM_DEV_DIR / $vg / $lv "
# Have to remove freed legs before another restriping conversion. Will fail while reshaping is ongoing as stripes are still in use
not _reshape_layout $raid_type $(( $data_stripes + 1 )) 0 1 $vg $lv --force
aux delay_dev " $dev1 " 0 0
aux wait_for_sync $vg $lv 1
# Remove freed legs as they are now idle has to succeed without --force
_reshape_layout $raid_type $data_stripes $vg $lv 1 1
check lv_first_seg_field $vg /$lv datastripes $data_stripes
check lv_first_seg_field $vg /$lv stripes $( _total_stripes $raid_type $data_stripes )
2024-06-14 13:58:49 +03:00
sleep 1
2024-05-29 19:05:19 +03:00
# Now size consistency has to be fine
[ $( _check_size $vg $lv $data_stripes ) -eq 0 ] || die "LV size should be completely reduced"
fsck -fy " $DM_DEV_DIR / $vg / $lv "
udevadm settle
}
function _test
{
local vg = $1
local lv = $2
local raid_type = $3
local data_stripes = $4
local cur_data_stripes
_get_pvs_stripes_and_delay $raid_type
aux prepare_pvs $npvs $pvsz
get_devs
vgcreate $SHARED -s 1M " $vg " " ${ DEVICES [@] } "
# Calculate maximum rimage size in MiB and subtract 3 extents to leave room for rounding
rimagesz = $(( $( blockdev --getsz " $dev1 " ) / 2048 - 3 ))
# Create (data_stripes+1)-way striped $raid_type
_lvcreate $raid_type $data_stripes $(( $data_stripes * ${ rimagesz } )) M $vg $lv --stripesize 128k
[ $( _check_size $vg $lv $data_stripes ) -eq 0 ] || die "LV size bogus"
check lv_first_seg_field $vg /$lv stripesize "128.00k"
aux wait_for_sync $vg $lv 0
# Delay its first 'PV' so that size can be evaluated before reshape finished too quick.
aux delay_dev " $dev1 " $ms 0
# Reshape it to one more stripe and 256K stripe size
_reshape_layout $raid_type $(( $data_stripes + 1 )) $vg $lv 0 0 --stripesize 256K
[ $( _check_size $vg $lv $(( $data_stripes + 1 )) ) -ne 0 ] || die "LV size should still be small"
fsck -fy " $DM_DEV_DIR / $vg / $lv "
# Reset delay
aux delay_dev " $dev1 " 0 0
# Wait for sync to finish to check frow extended LV size
aux wait_for_sync $vg $lv 0
[ $( _check_size $vg $lv $(( $data_stripes + 1 )) ) -eq 0 ] || die "LV size should be grown"
fsck -fy " $DM_DEV_DIR / $vg / $lv "
udevadm settle
# Loop adding stripes and check size consistency on each iteration
for data_stripes in $tst_stripes
do
cur_data_stripes = $( get lv_field " $vg / $lv " datastripes -a)
[ $cur_data_stripes -lt $data_stripes ] && _add_stripes $raid_type $vg $lv $data_stripes \
|| _remove_stripes $raid_type $vg $lv $data_stripes
done
vgremove -ff $vg
aux remove_dm_devs " ${ DEVICES [@] } "
}
# Test all respective RAID levels
_test $vg $lv1 raid4 2
_test $vg $lv1 raid5_ra 2
_test $vg $lv1 raid6_nc 3
_test $vg $lv1 raid10 2