#!/bin/bash # # pvsqueeze - Squeeze PEs into free holes # # This script iteratively moves linear (allocated to LV) PEs to fill in free # holes found in a PV segement map. The end result is that all free PEs are # at the end of the PV. Use this script as required in anger! # # 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 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