LinuxXLVIII · Backup ToolsLVM snapshots
LVM snapshots for backups - the classic Linux approach
What you'll learn
- Create LVM snapshots
- Use snapshots for backup
- Quiesce a database with the PostgreSQL 15+ backup API, or a plain filesystem with fsfreeze
- Recognise the production impact
- Remove snapshots cleanly
Prerequisites
Verified against Ubuntu 24.04 LTS · Debian 12 (Bookworm) · RHEL 9.x · Rocky Linux 9.x · AlmaLinux 9.x · Linux kernel 6.1 LTS / 6.6 LTS · systemd 255+ · OpenSSH 8.7p1 (RHEL 9) / 9.6p1 (Ubuntu 24.04) · nftables 1.0.x · chrony 4.x · Pacemaker 2.1.x · Corosync 3.1.x · 2026-08-09
LVM snapshots are a classic Linux tool for backup. They work with any filesystem on LVM and are instant (copy-on- write). The watch-out: snapshot overflow degrades performance.
Create an LVM snapshot
# Create a snapshot of an LV
lvcreate -L 1G -s -n mydata-snap /dev/vg0/mydata
# Verify
lvs
The -s flag creates a snapshot. -L 1G allocates 1 GB of
COW (copy-on-write) space. The snapshot is instant.
Use the snapshot for backup
# Mount the snapshot
mkdir /mnt/snap
# XFS refuses to mount a filesystem whose UUID is already mounted, and a
# snapshot carries the origin's UUID - so on XFS this needs `nouuid`.
# ext4 has no such restriction.
mount -o ro,nouuid /dev/vg0/mydata-snap /mnt/snap # XFS
# mount -o ro /dev/vg0/mydata-snap /mnt/snap # ext4
# Backup from the snapshot - -aAXH, not -a: ACLs, xattrs and SELinux
# labels are not part of -a, and a restore without them fails at start-up
rsync -aAXH --numeric-ids /mnt/snap/ /backup/mydata/
# Or tar - note -C and the trailing '.'
tar --acls --xattrs --numeric-owner --sparse \
-czf /backup/mydata-$(date +%F).tar.gz -C /mnt/snap .
# Unmount
umount /mnt/snap
The snapshot is read-only mounted. The original LV is unaffected; backup proceeds from the snapshot.
Remove the snapshot
# Remove the snapshot
lvremove /dev/vg0/mydata-snap
Always remove snapshots promptly. An old snapshot accumulates COW data and degrades performance.
Production impact
LVM snapshots are copy-on-write:
- Every write to the original LV allocates a new block in the COW space.
- A snapshot left in place for a long time accumulates COW blocks.
- When COW space is full, the snapshot is “invalid” and cannot be used.
For a busy LV with many writes, a 1 GB snapshot can fill in minutes. Plan accordingly — which means three concrete things, not a resolution to be careful.
Size the COW space from the write rate, not from habit. What
the snapshot must hold is everything written to the origin while
it exists, so the input is bytes-written-per-hour multiplied by
how long the backup takes. 15–20% of the origin is a reasonable
starting point for a nightly backup window; a 1G default on a
100 GB busy volume is not a small snapshot, it is a snapshot that
will be invalid before the backup finishes.
Let LVM grow it. In /etc/lvm/lvm.conf:
snapshot_autoextend_threshold = 70
snapshot_autoextend_percent = 20
At 70% full the snapshot grows by 20%, repeatedly, while the VG
has free extents. This does nothing unless the monitoring daemon
is running — it is dmeventd, started by lvm2-monitor:
systemctl is-active lvm2-monitor # must print: active
sudo lvchange --monitor y /dev/vg0/mydata-snap
The default snapshot_autoextend_threshold is 100, which means
autoextend is off. Setting the percent without lowering the
threshold changes nothing.
Check the fill level, and check it before you trust the
backup. lvs reports it in Data%:
# Watch it during the backup
lvs -o lv_name,origin,lv_size,data_percent,lv_attr vg0
# Gate the backup on the snapshot still being valid afterwards.
# lv_attr character 5 is the State field: 'a' active, 'I' Invalid snapshot,
# 'S' invalid Suspended snapshot (man 8 lvs). Character 1 is the volume
# TYPE - 's' for snapshot - so do not test that one.
ATTR=$(sudo lvs --noheadings -o lv_attr /dev/vg0/mydata-snap | tr -d '[:space:]')
case "${ATTR:4:1}" in
I|S) echo 'snapshot invalidated - COW space exhausted, backup is NOT usable' >&2
exit 1 ;;
esac
That last check is the one most backup scripts omit. An
invalidated snapshot does not make tar or rsync fail; the
reads simply stop returning the data you expect, and the job exits
0 with an archive nobody can restore from.
Application-consistent snapshots
The PostgreSQL backup API is session-scoped. Starting the
backup in one psql -c and stopping it in another does not
work: the first client disconnects, the backup is aborted,
and the snapshot in between carries no backup_label. Run the
whole bracket in one session and let psql fire the
lvcreate from inside it:
set -euo pipefail
psql -v ON_ERROR_STOP=1 <<'SQL'
SELECT pg_backup_start('lvm-snap', fast => true);
\! lvcreate -L 20G -s -n pgdata-snap /dev/vg0/pgdata
SELECT * FROM pg_backup_stop();
SQL
mount -o ro,nouuid /dev/vg0/pgdata-snap /mnt/snap # drop nouuid on ext4
# Backup, then write the label returned by pg_backup_stop()
# into the copy as backup_label
umount /mnt/snap
lvremove -y /dev/vg0/pgdata-snap
set -euo pipefail and -v ON_ERROR_STOP=1 are the load-bearing
part of that script, not boilerplate. Without them a failed
pg_backup_start() still lets lvcreate run, and you end up
holding a crash-consistent snapshot that your runbook calls
application-consistent.
Simpler, and the option to reach for first: pg_basebackup -D /backup/base -Ft -z -Xs -P -c fast does the bracketing and
ships the WAL for you, with no snapshot involved.
Size the COW space for the whole backup window, not just the snapshot instant - the snapshot must survive until the copy finishes.
Quiescing a volume with no backup API
Not every volume holds a database. For a plain filesystem the
generic quiesce is fsfreeze: it flushes dirty pages, blocks
new writes, and leaves the on-disk state consistent for the
instant the snapshot is taken.
# Freeze, snapshot, thaw. The freeze window is milliseconds.
sudo fsfreeze -f /data
sudo lvcreate -L 20G -s -n data-snap /dev/vg0/data
sudo fsfreeze -u /data
Write it so the thaw cannot be skipped:
set -euo pipefail
trap 'sudo fsfreeze -u /data || true' EXIT
sudo fsfreeze -f /data
sudo lvcreate -L 20G -s -n data-snap /dev/vg0/data
When to use
LVM snapshots are best for:
- Hosts with LVM.
- Filesystems on LVM logical volumes.
- Quick, scriptable snapshots.
- Database hosts, when the quiesce is held in one session.
Not best for:
- Non-LVM filesystems.
- Long-term retention (use file backup for that).
- Critical performance hosts (snapshot has overhead).
Knowledge check
Knowledge check · 5 questions
Q1. What happens when an LVM snapshot fills its COW space?
Q2. LVM snapshots are persistent across reboots.
Q3. Which of the following are valid LVM snapshot commands? Select all that apply.
Q4. A nightly script calls psql -c "SELECT pg_start_backup(...)", then lvcreate, then pg_stop_backup. The cluster was upgraded to PostgreSQL 16 a year ago. The job has reported success every night since. What do you actually have?
Q5. A script runs fsfreeze -f /data, the lvcreate that follows fails, and the script exits. What does the operator see?
Passing score: 75%. Answers are checked in this browser.