Skip to content

Instantly share code, notes, and snippets.

@MrZoidberg
Created February 28, 2026 11:53
Show Gist options
  • Select an option

  • Save MrZoidberg/8f11a1ba09403a9f5524eaddb6903c07 to your computer and use it in GitHub Desktop.

Select an option

Save MrZoidberg/8f11a1ba09403a9f5524eaddb6903c07 to your computer and use it in GitHub Desktop.
Enlarge disk size inside debian/ubuntu VM
#!/usr/bin/env bash
set -euo pipefail
# Simple helper to print info
log() { echo -e "\e[1;34m[INFO]\e[0m $*"; }
warn() { echo -e "\e[1;33m[WARN]\e[0m $*"; }
err() { echo -e "\e[1;31m[ERR]\e[0m $*" >&2; }
if [[ $EUID -ne 0 ]]; then
err "This script must be run as root."
exit 1
fi
# Check for required tools
for cmd in lsblk findmnt parted growpart; do
if ! command -v "$cmd" &>/dev/null; then
err "Required command '$cmd' not found. Install it and re-run."
if [[ "$cmd" == "growpart" ]]; then
echo " On Ubuntu: apt update && apt install -y cloud-guest-utils"
fi
exit 1
fi
done
# ---- Detect root mount ----
root_src=$(findmnt -n -o SOURCE /)
root_fstype=$(findmnt -n -o FSTYPE /)
log "Root filesystem: $root_src (type: $root_fstype)"
is_lvm=false
if [[ "$root_src" == /dev/mapper/* ]]; then
is_lvm=true
fi
# ---- Helper to grow a partition to end of disk ----
grow_partition() {
local part_dev="$1"
# Underlying disk (e.g. sda for sda3, nvme0n1 for nvme0n1p3)
local disk_name
disk_name=$(lsblk -no PKNAME "$part_dev")
local disk_dev="/dev/${disk_name}"
# Partition name relative to disk (e.g. sda3 -> 3, nvme0n1p3 -> 3)
local part_name
part_name=$(basename "$part_dev")
# Extract numeric partition index (handle sdX#, vdX#, nvmeXnYp#)
local part_num
part_num=$(echo "$part_name" | sed 's/[^0-9]*//g')
if [[ -z "$part_num" ]]; then
err "Could not determine partition number for $part_dev"
exit 1
fi
log "Disk device: $disk_dev"
log "Partition dev: $part_dev (partition #$part_num)"
log "Growing partition $part_dev to fill $disk_dev using growpart..."
growpart "$disk_dev" "$part_num"
log "Partition growth completed."
}
# ---- Non-LVM root case ----
resize_plain_root() {
local part_dev="$1"
local fstype="$2"
grow_partition "$part_dev"
case "$fstype" in
ext4|ext3)
log "Resizing ext filesystem on $part_dev with resize2fs..."
resize2fs "$part_dev"
;;
xfs)
# xfs_growfs works on the mounted filesystem, use the mountpoint
if ! command -v xfs_growfs &>/dev/null; then
err "xfs_growfs not found, install xfsprogs (apt install -y xfsprogs)."
exit 1
fi
log "Resizing XFS filesystem on / with xfs_growfs..."
xfs_growfs /
;;
*)
err "Unsupported filesystem type '$fstype' for plain root. Aborting."
exit 1
;;
esac
log "Plain root filesystem resize completed."
}
# ---- LVM root case ----
resize_lvm_root() {
local lv_dev="$1"
# Find the PV backing this LV (assume single PV)
local pv_dev
pv_dev=$(pvs --noheadings -o pv_name "$lv_dev" 2>/dev/null | awk '{$1=$1};1' | head -n1 || true)
if [[ -z "$pv_dev" ]]; then
err "Could not determine PV for LV $lv_dev. Is LVM set up normally?"
exit 1
fi
log "Detected PV for root LV: $pv_dev"
# Grow the underlying partition
grow_partition "$pv_dev"
# Resize PV to take new space
log "Resizing PV $pv_dev with pvresize..."
pvresize "$pv_dev"
# Extend LV to use all free space, and grow filesystem in-place (-r)
log "Extending LV $lv_dev to use all free space (lvextend -r -l +100%FREE)..."
lvextend -r -l +100%FREE "$lv_dev"
log "LVM root resize completed."
}
# ---- Main logic ----
if [[ "$is_lvm" == false ]]; then
log "Detected non-LVM root."
if [[ "$root_src" != /dev/* ]]; then
err "Unexpected root source: $root_src (not a /dev device). Aborting."
exit 1
fi
resize_plain_root "$root_src" "$root_fstype"
else
log "Detected LVM root: $root_src"
if ! command -v pvs &>/dev/null || ! command -v lvextend &>/dev/null; then
err "LVM tools not found. Install lvm2 (apt install -y lvm2) and retry."
exit 1
fi
resize_lvm_root "$root_src"
fi
log "All done. Current block devices:"
lsblk
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment