Skip to content
Commitpedia
Log in Join & edit

Extend an LVM logical volume and filesystem online (safe script)

A bash script that grows the LVM volume behind a mount point, checks the filesystem type and free space first, and runs as a dry run unless you pass --yes.

Edit history of Extend an LVM logical volume and filesystem online (safe script): 1 recorded edit
Edit history · 1 edit
Type
Script
Edits
1
Editors
1
First issued
15 Oct 2026
Last edit
15 Oct 2026
Language
bash
Licence
CC0-1.0

Growing an LVM volume is one command, lvextend --resizefs, but under pressure (a disk is full, the app is down) it is easy to target the wrong volume or ask for more than the volume group has. This script takes the mount point you care about, works out which logical volume is behind it, checks everything it can, shows what it will do, and only changes something when you add --yes.

The script

Check before you run this

  • Runs with administrator rights. Make sure you understand every line.
#!/usr/bin/env bash
set -Eeuo pipefail

usage() {
  cat <<USAGE
Usage: $(basename "$0") [--yes] <mount-point> <+SIZE | 100%FREE>

Grow the LVM logical volume behind <mount-point> and its ext4 or XFS
filesystem while it stays mounted.

  <mount-point>  for example /var or /srv/data
  +SIZE          amount to add, for example +5G or +500M
  100%FREE       use all free space left in the volume group
  --yes          really make the change (default is a dry run)

Examples:
  $(basename "$0") /srv/data +10G
  $(basename "$0") --yes /srv/data +10G
USAGE
}

die() { echo "ERROR: $*" >&2; exit 1; }

APPLY=0
if [[ ${1:-} == "--yes" ]]; then APPLY=1; shift; fi
[[ ${1:-} == "-h" || ${1:-} == "--help" ]] && { usage; exit 0; }
[[ $# -eq 2 ]] || { usage >&2; exit 2; }

MOUNT=$1
SIZE=$2

[[ $EUID -eq 0 ]] || die "run as root (sudo)"
for cmd in findmnt lvs vgs lvextend numfmt df; do
  command -v "$cmd" >/dev/null 2>&1 || die "missing command: $cmd"
done

findmnt --mountpoint "$MOUNT" >/dev/null || die "$MOUNT is not a mount point"
SOURCE=$(findmnt --noheadings --output SOURCE --mountpoint "$MOUNT")
FSTYPE=$(findmnt --noheadings --output FSTYPE --mountpoint "$MOUNT")

case "$FSTYPE" in
  ext4|xfs) ;;
  *) die "filesystem on $MOUNT is $FSTYPE; this script only handles ext4 and xfs" ;;
esac

SOURCE_REAL=$(readlink -f "$SOURCE")
VG="" LV="" LV_SIZE="" VG_FREE=""
while IFS='|' read -r path vg lv lvsize vgfree; do
  path=${path// /}
  [[ -n $path ]] || continue
  if [[ $(readlink -f "$path") == "$SOURCE_REAL" ]]; then
    VG=${vg// /} LV=${lv// /} LV_SIZE=${lvsize// /} VG_FREE=${vgfree// /}
    break
  fi
done < <(lvs --noheadings --separator '|' --units b --nosuffix -o lv_path,vg_name,lv_name,lv_size,vg_free)
[[ -n $VG && -n $LV ]] || die "$SOURCE is not an LVM logical volume"

human() { numfmt --to=iec --suffix=B "$1"; }

if [[ $SIZE == "100%FREE" ]]; then
  (( VG_FREE > 0 )) || die "volume group $VG has no free space; add a disk (pvcreate + vgextend) first"
  ADD_BYTES=$VG_FREE
  LVEXTEND_ARGS=(-l +100%FREE)
elif [[ $SIZE =~ ^\+([0-9]+)([KMGT])$ ]]; then
  ADD_BYTES=$(numfmt --from=iec "${BASH_REMATCH[1]}${BASH_REMATCH[2]}")
  (( ADD_BYTES <= VG_FREE )) || die "asked for $(human "$ADD_BYTES") but $VG has only $(human "$VG_FREE") free"
  LVEXTEND_ARGS=(-L "$SIZE")
else
  die "size must look like +10G, +500M or 100%FREE (got: $SIZE)"
fi

echo "Mount point : $MOUNT"
echo "Device      : $SOURCE ($VG/$LV, $FSTYPE)"
echo "LV size now : $(human "$LV_SIZE")"
echo "VG free     : $(human "$VG_FREE")"
echo "Will add    : $(human "$ADD_BYTES")"
echo "Command     : lvextend ${LVEXTEND_ARGS[*]} --resizefs $VG/$LV"
echo

echo "Filesystem before:"
df -h "$MOUNT"
echo

if (( APPLY == 0 )); then
  echo "Dry run only. LVM test mode says:"
  lvextend --test "${LVEXTEND_ARGS[@]}" "$VG/$LV" || die "lvextend test failed"
  echo
  echo "Nothing was changed. Re-run with --yes to apply."
  exit 0
fi

lvextend "${LVEXTEND_ARGS[@]}" --resizefs "$VG/$LV"

echo
echo "Filesystem after:"
df -h "$MOUNT"
lvs "$VG/$LV"

Usage

Check before you run this

  • Runs with administrator rights. Make sure you understand every line.
sudo install -m 755 extend-lv.sh /usr/local/sbin/extend-lv

sudo extend-lv /srv/data +10G          # dry run: shows the plan, runs lvextend --test
sudo extend-lv --yes /srv/data +10G    # really grow it
sudo extend-lv --yes /var 100%FREE     # give /var all free space in its VG

What it checks before changing anything

  1. It runs as root and all needed tools exist.
  2. The path is a real mount point (findmnt), not just a directory on the root filesystem.
  3. The filesystem is ext4 or XFS, the two types that can grow online while mounted.
  4. The device behind the mount point is an LVM logical volume. It compares resolved device paths, so /dev/mapper/vg-lv and /dev/vg/lv both match.
  5. The volume group has enough free space for the requested size.
  6. In dry-run mode, lvextend --test runs the request through LVM without writing metadata.

With --yes it runs lvextend ... --resizefs, which grows the volume and then the filesystem (using resize2fs for ext4 or xfs_growfs for XFS), and prints df before and after.

When the volume group is full

If the script says the VG has no free space, add capacity first. Warning: pvcreate overwrites the start of the device; confirm with lsblk -f and sudo wipefs /dev/sdX that the disk is the new, empty one.

Check before you run this

  • Runs with administrator rights. Make sure you understand every line.
lsblk -f
sudo pvcreate /dev/sdc
sudo vgextend datavg /dev/sdc
sudo vgs

For a virtual disk that was enlarged in the hypervisor, run sudo pvresize /dev/sdX instead (after growing the partition, if the PV sits on one).

Notes

  • Growing is safe online; there is no matching shrink option on purpose. XFS cannot shrink at all, and shrinking ext4 requires unmounting.
  • Take a backup or VM snapshot before storage changes on important servers, even safe ones.
  • Sizes use binary units: +10G means 10 GiB.

Official documentation

See also

  • 0102 Proxmox VE storage types: local, LVM-thin, ZFS, NFS and Ceph Proxmox VE stores disks, ISOs, templates and backups in storage pools defined in /etc/pve/storage.cfg. Learn the main storage types, what local and… Intermediate · Concept · Linux Article Disks, LVM & filesystems · Storage 15 Oct 2026
  • 0168 Server health check script: disk, memory and failed units A dependency-free bash script that checks disk and inode usage, available memory, load, failed systemd units and pending reboots, and exits non-zero… Intermediate · Reference · Linux Script Disks, LVM & filesystems · Services & systemd 15 Oct 2026
  • 0169 Add a new disk: partition, format and mount it by UUID Find a new disk with lsblk, partition it with parted, create an ext4 or XFS filesystem and mount it permanently through /etc/fstab… Intermediate · How-to · Linux Article Disks, LVM & filesystems 15 Oct 2026
  • 0170 LVM explained: physical volumes, volume groups and logical volumes LVM puts a flexible layer between disks and filesystems, so you can grow volumes, add disks and take snapshots without repartitioning. Intermediate · Concept · Linux Article Disks, LVM & filesystems 15 Oct 2026
  • 0172 Fix: No space left on device Writes fail because a filesystem is full, out of inodes, or holding space for deleted files that are still open. Find which… Beginner · Fix · Linux Article Disks, LVM & filesystems 15 Oct 2026

History

Every saved edit is kept. The plot on the sleeve draws one line per edit. Open any edit to see exactly what changed.

  1. commitpedia-admin +5,945 chars

Report a problem

Something wrong, unsafe or copied? Tell the editors.
What is wrong?