shrink_lv/scripts/pvsqueeze.sh
2025-03-20 15:26:02 -04:00

74 lines
2.2 KiB
Bash

#!/bin/bash
#
# pvsqueeze - Squeeze linear extents into free holes
#
# This script iteratively moves linear (allocated to LV) extents to fill in
# free holes found in a PV segment map. The end result is that all free
# extents are at the end of the PV. Use this script in anger as required!
#
# The script outputs the PV segment map before moving anything, then iterates
# stuffing extents in each free hole until there are no more except for the
# last one, and finally outputs the PV segment map again showing the changes.
#
# Usage
if [[ ! $1 =~ ^/dev/ ]]; then
echo "Usage: $0 PV"
exit 1
fi
# Set some vars
pvdev=$1
pvsargs='--noheadings --nameprefixes --segments -o pvseg_start,pvseg_size,segtype'
# Show current segment map
echo 'PV segment map before squeeze:'
pvs "$pvdev" --segments -o lvname,pvseg_start,pvseg_size,seg_le_ranges
if [[ $? -ne 0 ]]; then
echo "$0: Fatal error getting PV info"
exit 1
fi
# Iterate stuffing PEs in each free hole
while true; do
# Find first free segment
LVM2_PVSEG_START=
eval $(pvs "$pvdev" $pvsargs | grep SEGTYPE=.free. | head -1)
if [[ -z $LVM2_PVSEG_START ]]; then
echo "$0: No free segments found"
exit 1
fi
free_start=$LVM2_PVSEG_START
free_size=$LVM2_PVSEG_SIZE
# Find the last linear segment
LVM2_PVSEG_START=
eval $(pvs "$pvdev" $pvsargs | grep SEGTYPE=.linear. | tail -1)
if [[ -z $LVM2_PVSEG_START ]]; then
echo "$0: No linear segments found"
exit 1
fi
move_start=$LVM2_PVSEG_START
move_size=$LVM2_PVSEG_SIZE
# We're done when first free is after the last linear
[[ $free_start -gt $move_start ]] && break
# Move last linear PEs to the free segment
[[ $free_size -gt $move_size ]] && free_size=$move_size
from_range="$pvdev:$((move_start+move_size-free_size))-$((move_start+move_size-1))"
to_range="$pvdev:$((free_start))-$((free_start+free_size))"
echo "Moving $from_range to $to_range..."
pvmove --atomic --alloc anywhere "$from_range" "$to_range"
if [[ $? -ne 0 ]]; then
echo "$0: Fatal error doing pvmove"
exit 1
fi
done
# Show squeezed segment map
echo 'PV segment map after squeeze:'
pvs "$pvdev" --segments -o lvname,pvseg_start,pvseg_size,seg_le_ranges
exit 0