open atlas
↑ Back to track
Linux, the operating system LIN · 07 · 02

Growing LVs and LVM snapshots

Growing an LV online requires lvextend (to grow the block device) then resize2fs or xfs_growfs (to grow the filesystem) — order matters. LVM snapshots are copy-on-write point-in-time views ideal for consistent backups. A snapshot that fills up silently becomes invalid.

LIN Senior ◷ 22 min
Level
FoundationsJuniorMiddleSenior

Disk usage on /data hits 90%. With a raw partition you would need to unmount, boot a live disk, use parted to shrink the neighbour partition and grow this one, then resize the filesystem — an offline procedure with multiple ways to destroy data. With LVM you run two commands while the filesystem is mounted and traffic is live.

But there is a catch most documentation glosses over: the order is non-negotiable. Growing the filesystem before the block device is a no-op at best, a corruption at worst if you later shrink. Growing the block device without growing the filesystem wastes the space silently. Get the order right and LVM online resize is one of the safest operations you will do.

Goal

After this lesson you can grow an LVM logical volume and its filesystem online, explain why the order (lvextend then resize) is mandatory, create and use LVM snapshots for consistent backups, and understand when a snapshot becomes invalid.

1

First, check how much space is available in the VG.

Before extending an LV you need to know the VG has free extents. LV space comes from the VG pool — if the VG is full you must either add a PV (vgextend) or shrink another LV first.

# How much is free in the VG?
sudo vgs
#   VG     #PV #LV #SN Attr   VSize    VFree
#   datavg   2   2   0 wz--n- <99.99g  30.00g
# 30 GB free — safe to extend

# More detail: free physical extents
sudo vgdisplay datavg | grep -E 'Free|Total|Alloc'
#   Total PE              25599
#   Alloc PE / Size       18176 / 71.00 GiB
#   Free  PE / Size        7423 / 29.00 GiB

# Which LV do we want to grow?
sudo lvs
#   LV      VG     Attr       LSize
#   appdata datavg -wi-ao---- 30.00g
#   logs    datavg -wi-ao---- 41.00g

# Current filesystem usage (what prompted the alarm)
df -h /mnt/appdata
# Filesystem               Size  Used Avail Use%
# /dev/mapper/datavg-appdata  30G   27G  1.4G  95%
2

Step 1 of growing: extend the logical volume (the block device layer).

# Extend appdata LV by 20 GB (adds to current size)
sudo lvextend -L +20G /dev/datavg/appdata
#   Size of logical volume datavg/appdata changed from 30.00 GiB to 50.00 GiB.
#   Logical volume datavg/appdata successfully resized.

# Or extend to a specific total size
sudo lvextend -L 50G /dev/datavg/appdata

# Or consume all remaining free space in the VG
sudo lvextend -l +100%FREE /dev/datavg/appdata

# After lvextend, the block device is larger but the FILESYSTEM does not know yet:
df -h /mnt/appdata
# Filesystem               Size  Used Avail Use%
# /dev/mapper/datavg-appdata  30G   27G  1.4G  95%
# <-- still shows 30 GB! The filesystem has not been told about the extra space.

lvextend only grows the block device. The filesystem sits on top and has its own size metadata — you must resize it separately.

3

Step 2 of growing: resize the filesystem to fill the LV.

The command differs by filesystem type:

# For ext4: resize2fs (can run on a live, mounted filesystem)
sudo resize2fs /dev/datavg/appdata
# resize2fs 1.47.0 (5-Feb-2023)
# Filesystem at /dev/datavg/appdata is mounted on /mnt/appdata; on-line resizing required
# old_desc_blocks = 4, new_desc_blocks = 7
# The filesystem on /dev/datavg/appdata is now 13107200 (4k) blocks long.

# For xfs: xfs_growfs (requires mount point, NOT device path)
sudo xfs_growfs /mnt/appdata
# meta-data=/dev/mapper/datavg-appdata isize=512    agcount=4, agsize=1966080 blks
# data     =                       bsize=4096   blocks=7864320, imaxpct=25
# ...
# data blocks changed from 7864320 to 13107200

# Verify the filesystem is now larger
df -h /mnt/appdata
# Filesystem               Size  Used Avail Use%
# /dev/mapper/datavg-appdata  50G   27G   21G  57%
# <-- now shows 50 GB

The mandatory order: lvextend first, then filesystem resize. If you try to resize2fs on a device that is smaller than the filesystem expects, it errors. If you run lvextend but forget resize2fs, the filesystem continues using the old size — the extra space exists but is invisible to the OS.

Shortcut: lvextend -r (resize flag) tells LVM to run resize2fs or xfs_growfs automatically after extending:

sudo lvextend -L +20G -r /dev/datavg/appdata
# Extends LV and resizes filesystem in one command
4

LVM snapshots: copy-on-write point-in-time views.

An LVM snapshot creates a point-in-time view of a logical volume. It does not copy the data immediately — instead it uses copy-on-write (COW): blocks are copied to the snapshot only when the original LV changes them. This makes snapshot creation instantaneous.

# Create a 5 GB snapshot of appdata (the COW buffer)
# The snapshot size is NOT the size of the data — it is how much change you expect during backup
sudo lvcreate -s -L 5G -n appdata-snap /dev/datavg/appdata
#   Logical volume "appdata-snap" created.

sudo lvs
#   LV           VG     Attr       LSize Origin  Snap%  Move Log
#   appdata      datavg owi-aos---  50.00g
#   appdata-snap datavg swi-a-s---   5.00g appdata   0.00
# 'o' = origin, 's' = snapshot, Snap% = how full the COW buffer is

# Mount the snapshot read-only for backup
sudo mkdir /mnt/snap
sudo mount -o ro /dev/datavg/appdata-snap /mnt/snap

# Run backup against the consistent snapshot (original LV keeps serving traffic)
sudo rsync -av /mnt/snap/ /backup/appdata-$(date +%Y%m%d)/

# Clean up: unmount and remove the snapshot
sudo umount /mnt/snap
sudo lvremove /dev/datavg/appdata-snap
5

The snapshot fill trap: a full snapshot becomes invalid.

The COW buffer (the size you gave to lvcreate -s) must absorb every block that changes on the origin LV between snapshot creation and removal. If more data changes than the buffer can hold, the snapshot fills up and becomes invalid.

# Watch snapshot utilisation — monitor this during a long backup
sudo lvs /dev/datavg/appdata-snap
#   LV           Snap%
#   appdata-snap 73.41  <-- 73% used, still safe

# If it hits 100%:
#   appdata-snap 100.00  <-- INVALID — data is gone from the snapshot
# Any attempt to read from it will return I/O errors

# Set a monitoring threshold: warn at 80%
# LVM can auto-extend snapshots (add to /etc/lvm/lvm.conf):
# snapshot_autoextend_threshold = 80
# snapshot_autoextend_percent = 20
# (LVM daemon lvmetad/lvmpolld will then extend automatically)

# Size the COW buffer conservatively:
# - For a busy database during a long backup: 20-30% of origin size
# - For a quiet filesystem during a quick rsync: 5-10% is fine
# - When in doubt, bigger is safer — unused COW space is wasted but not harmful
Worked example

Production scenario: growing a PostgreSQL data volume without downtime.

# Situation: /dev/pgvg/pgdata is mounted at /var/lib/postgresql
# df shows 92% usage — need to add 50 GB now, PostgreSQL keeps running

# Step 1: confirm VG has space
sudo vgs pgvg
#   VG   #PV #LV VSize   VFree
#   pgvg   1   1 200.00g 100.00g
# 100 GB free — good

# Step 2: determine filesystem type (matters for the resize command)
findmnt /var/lib/postgresql
# TARGET                 SOURCE                  FSTYPE
# /var/lib/postgresql    /dev/mapper/pgvg-pgdata ext4

# Step 3: extend LV and filesystem in one shot (-r flag)
sudo lvextend -L +50G -r /dev/pgvg/pgdata
# Extending logical volume pgvg/pgdata to 150.00 GiB
# resize2fs 1.47.0: Filesystem at /dev/pgvg/pgdata is mounted on /var/lib/postgresql
# The filesystem on /dev/pgvg/pgdata is now 39321600 (4k) blocks long.

# PostgreSQL never paused. Verify:
df -h /var/lib/postgresql
# Filesystem                  Size  Used Avail Use%
# /dev/mapper/pgvg-pgdata     150G   92G   53G  64%

# Step 4 (good practice): take a snapshot before the next major schema migration
sudo lvcreate -s -L 20G -n pgdata-premigration /dev/pgvg/pgdata
#   Logical volume "pgdata-premigration" created.

# Run the migration. If it goes wrong:
# sudo lvconvert --merge /dev/pgvg/pgdata-premigration
# (merges the snapshot back — effectively a rollback; requires stop + restart of the LV)

# When migration succeeds, drop the snapshot:
sudo lvremove /dev/pgvg/pgdata-premigration
Common mistake

The most dangerous mistake with LVM snapshots: assuming a snapshot is indefinitely safe once created. If the origin LV has heavy write traffic and you run a slow backup, the COW buffer drains fast. At 100% full the snapshot silently becomes invalid — reads from the snapshot return I/O errors, not a clear error message. Always size the COW buffer generously for production volumes, monitor Snap% in lvs during the backup, and configure snapshot_autoextend_threshold in /etc/lvm/lvm.conf so LVM extends the buffer automatically before it fills.

Why this works

Why does xfs_growfs take a mount point while resize2fs takes a device path? XFS locks its metadata through the VFS (virtual filesystem switch) layer and requires the live mount context to issue the grow ioctl. ext4’s resize2fs works at the block level and does not need the mount point — though for a live filesystem it still uses an ioctl internally. The practical consequence: for XFS always use the mount path (/mnt/appdata), never the device; for ext4 you can use either, though the device path is more common in documentation.

Check yourself
Quiz

You run 'sudo lvextend -L +30G /dev/myvg/data' and it succeeds. Then 'df -h /data' still shows the old smaller size. What must you do, and why did lvextend not fix it?

Recap

Growing an LV online requires two steps in order: lvextend first (grows the block device, allocating extents from the VG’s free pool), then resize2fs /dev/vg/lv for ext4 or xfs_growfs /mountpoint for XFS (tells the filesystem to fill the new space). The -r flag on lvextend does both in one command. LVM snapshots are copy-on-write point-in-time views created with lvcreate -s; they capture the state of an origin LV instantly and let you run a backup against the snapshot while the origin keeps serving writes. The snapshot COW buffer absorbs every block changed on the origin since creation — if it fills to 100%, the snapshot silently becomes invalid. Size the buffer generously, monitor Snap% in lvs, and configure snapshot_autoextend_threshold in /etc/lvm/lvm.conf for production volumes.

Practice

Start at the top. Tasks go easiest → hardest: recall a fact, apply it to a case, then a senior-level stretch. Open one, attempt it, then reveal.

recallapplystretch0 of 4 done

Something unclear?

Ask a question about this lesson. Questions are anonymous and go straight to the author to make the lesson better.

shortcuts expand
search
K
prev piece
k
next piece
j
cycle tier
t
this menu
?
sources3
expand
  1. 01
  2. 02
  3. 03

Trademarks belong to their respective owners. Editorial reference only.