📸 LVM Snapshots

Storage Series: Part 1 — LVM Basics  |  Part 2 — LVM Management  |  Part 3 — LVM Snapshots  |  Part 4 — RAID Overview

What are LVM Snapshots?

An LVM snapshot is a point-in-time copy of a Logical Volume — created instantly, requiring only a small amount of extra space to store changes made after the snapshot was taken. Snapshots are the foundation of consistent online backups, safe system updates, and rapid rollback capability.

LVM uses a Copy-on-Write (CoW) mechanism — when a block is modified in the original LV after the snapshot is taken, the original data is copied to the snapshot space before the new data is written. The snapshot always reflects the state at the moment it was created, while the original LV continues to change normally.

How Copy-on-Write Works

At snapshot creation time:
[ Original LV: /dev/vg_data/lv_home ]  [ Snapshot: lv_home_snap (empty CoW store) ]

After a file is modified in the original:
[ Original LV: block 4 = NEW DATA          ]  [ Snapshot CoW store: block 4 = OLD DATA   ]

Reading snapshot always returns original state:
[ Original LV: reads current data          ]  [ Snapshot: reads CoW store for changed blocks ]
Snapshot space usage grows as original changes — monitor it!
⚠️ Snapshots are NOT backups by themselves. A snapshot lives on the same physical storage as the original LV. If the disk fails, both are lost. Use snapshots to get a consistent point-in-time image to back up to another location — not as the backup itself.

Examples

1
Create a Snapshot — lvcreate -s

Creating a snapshot is instantaneous regardless of LV size:

# Create a snapshot of lv_home with 5GB CoW space
sudo lvcreate -s -L 5G -n lv_home_snap /dev/vg_data/lv_home

# Snapshot naming convention — append date for clarity
sudo lvcreate -s -L 5G \
    -n lv_home_snap_$(date +%Y%m%d) \
    /dev/vg_data/lv_home

# Verify snapshot created
sudo lvs
sudo lvdisplay /dev/vg_data/lv_home_snap
lvs output showing snapshot:
LV VG Attr LSize Pool Origin Data% lv_home vg_data owi-aos--- 100.00g lv_home_snap vg_data swi-a-s--- 5.00g lv_home 0.00
Reading the Attr field: owi-aos on the origin = "origin with snapshot." swi-a-s on the snapshot = "snapshot, writeable, active." The Data% column shows how full the CoW store is — watch this number. If it hits 100% the snapshot becomes invalid.
💡 How much CoW space to allocate? A good rule of thumb: 10–20% of the origin LV size for short-lived backup snapshots. More if the system is busy or the snapshot will exist for a long time. Monitor with lvs and extend if needed.
2
Mount a Snapshot

Mount a snapshot read-only to browse files at the point-in-time state, or read-write for testing changes without touching the original:

# Mount snapshot read-only (safest — preserves snapshot integrity)
sudo mkdir -p /mnt/snapshot
sudo mount -o ro /dev/vg_data/lv_home_snap /mnt/snapshot

# Browse files as they were at snapshot time
ls /mnt/snapshot
diff /mnt/snapshot/etc/passwd /etc/passwd

# Mount snapshot read-write (for testing)
sudo mount /dev/vg_data/lv_home_snap /mnt/snapshot

# XFS snapshots require nouuid option (duplicate UUID issue)
sudo mount -o ro,nouuid /dev/vg_data/lv_home_snap /mnt/snapshot

# Unmount when done
sudo umount /mnt/snapshot
XFS and UUID: XFS embeds the filesystem UUID in the superblock. When you mount a snapshot of an XFS volume, the duplicate UUID causes a mount error. Always add nouuid to the mount options for XFS snapshots.
3
Extend a Snapshot — Prevent Overflow

If a snapshot's CoW store fills up it becomes invalid and is automatically deactivated. Monitor and extend before that happens:

# Check snapshot fill level
sudo lvs | grep snap
sudo lvdisplay /dev/vg_data/lv_home_snap | grep "Allocated"

# Watch snapshot usage live
sudo watch -n10 'sudo lvs | grep snap'

# Extend snapshot CoW space before it fills
sudo lvextend -L +2G /dev/vg_data/lv_home_snap

# Configure LVM to auto-extend snapshots (lvm.conf)
sudo vi /etc/lvm/lvm.conf
# Find and set:
# snapshot_autoextend_threshold = 70  (extend when 70% full)
# snapshot_autoextend_percent = 20    (extend by 20%)
lvdisplay snapshot fill level:
--- Logical volume --- LV snapshot status active destination for lv_home LV Size 100.00 GiB COW-table size 5.00 GiB COW-table I/O size 5.00 GiB Snapshot chunk size 4.00 KiB Allocated to snapshot 34.52% Snapshot merge target No
⚠️ At 100% the snapshot is gone. LVM automatically invalidates and deactivates a snapshot when its CoW store fills completely. The original LV is unaffected but the snapshot is lost. Set up auto-extend in lvm.conf for long-running snapshots.
4
Rollback — Merge Snapshot Back to Origin

Merging a snapshot reverts the original LV to the snapshot's state — useful for undoing a bad system update or failed migration:

# Unmount the origin LV first if possible
sudo umount /home

# Merge snapshot back into origin (schedules the merge)
sudo lvconvert --merge /dev/vg_data/lv_home_snap

# If the LV is in use (e.g., root filesystem), merge happens on next boot
# LVM will automatically complete the merge during next activation
sudo reboot

# After reboot — verify merge completed (snapshot LV will be gone)
sudo lvs
# lv_home_snap should no longer appear
Merge is destructive to the snapshot. After merging, the snapshot LV is removed automatically — the origin LV is restored to the snapshotted state. Any changes made to the origin after the snapshot was taken are permanently lost. This is the rollback — use it intentionally.
💡 Safe update workflow:
  1. Take a snapshot before any major change
  2. Make the change (update, migration, config change)
  3. If it works — remove the snapshot with lvremove
  4. If it fails — merge the snapshot to roll back instantly
5
Remove a Snapshot

When a snapshot is no longer needed, remove it to free the CoW space:

# Unmount first if mounted
sudo umount /mnt/snapshot

# Remove the snapshot LV
sudo lvremove /dev/vg_data/lv_home_snap

# Remove without interactive confirmation (for scripts)
sudo lvremove -f /dev/vg_data/lv_home_snap

# Verify it is gone and space is returned
sudo lvs
sudo vgs   # VFree should increase by the snapshot CoW size
Removing a snapshot does NOT affect the origin LV. The origin LV continues exactly as it was. Only the CoW store (the snapshot's delta) is freed. The original data is always intact regardless of snapshot state.
6
Snapshot-Based Backup Script

The classic use case — take a snapshot, back it up, remove it. Gives you a consistent backup of a live filesystem:

#!/bin/bash
# lvm-snapshot-backup.sh
# Consistent online backup using LVM snapshot

LV_ORIGIN="/dev/vg_data/lv_home"
LV_SNAP="/dev/vg_data/lv_home_snap"
SNAP_SIZE="5G"
SNAP_MOUNT="/mnt/snap_backup"
BACKUP_DEST="/backup/home_$(date +%Y%m%d_%H%M%S).tar.gz"

echo "=== LVM Snapshot Backup ==="
echo "Origin:  $LV_ORIGIN"
echo "Dest:    $BACKUP_DEST"
echo ""

# Step 1: Create snapshot
echo "Creating snapshot..."
sudo lvcreate -s -L "$SNAP_SIZE" -n lv_home_snap "$LV_ORIGIN"

# Step 2: Mount snapshot read-only
sudo mkdir -p "$SNAP_MOUNT"
sudo mount -o ro "$LV_SNAP" "$SNAP_MOUNT"

# Step 3: Backup the snapshot (consistent point-in-time)
echo "Backing up..."
sudo tar -czf "$BACKUP_DEST" -C "$SNAP_MOUNT" .
BACKUP_EXIT=$?

# Step 4: Unmount and remove snapshot (always — even if backup failed)
sudo umount "$SNAP_MOUNT"
sudo lvremove -f "$LV_SNAP"

# Step 5: Report
if [ $BACKUP_EXIT -eq 0 ]; then
    echo "Backup complete: $BACKUP_DEST"
    ls -lh "$BACKUP_DEST"
else
    echo "ERROR: Backup failed (exit code $BACKUP_EXIT)" >&2
    exit 1
fi
💡 Why this works: The snapshot is created in milliseconds, giving you a frozen consistent view of the filesystem. The backup then reads from the snapshot — not the live filesystem — so there are no consistency issues from files changing mid-backup. The live system keeps running normally throughout.
7
Database-Consistent Snapshot

For databases, flush and lock before snapshotting to guarantee a clean, consistent state:

#!/bin/bash
# Database-consistent LVM snapshot for MySQL/MariaDB

DB_USER="root"
DB_PASS="$MYSQL_ROOT_PASSWORD"
LV_ORIGIN="/dev/vg_data/lv_mysql"
SNAP_NAME="lv_mysql_snap_$(date +%Y%m%d)"

echo "Flushing and locking MySQL tables..."

# Step 1: Flush tables and acquire read lock
mysql -u"$DB_USER" -p"$DB_PASS" -e "FLUSH TABLES WITH READ LOCK;"

# Step 2: Create snapshot immediately (while lock is held)
sudo lvcreate -s -L 10G -n "$SNAP_NAME" "$LV_ORIGIN"

# Step 3: Release the lock — DB is fully operational again
mysql -u"$DB_USER" -p"$DB_PASS" -e "UNLOCK TABLES;"

echo "Lock released. Snapshot: $SNAP_NAME"
echo "DB fully operational — backup from snapshot at leisure."

# Step 4: Mount and backup the snapshot
sudo mkdir -p /mnt/dbsnap
sudo mount -o ro /dev/vg_data/"$SNAP_NAME" /mnt/dbsnap
sudo rsync -av /mnt/dbsnap/ /backup/mysql_$(date +%Y%m%d)/

# Step 5: Cleanup
sudo umount /mnt/dbsnap
sudo lvremove -f /dev/vg_data/"$SNAP_NAME"
echo "Done."
The lock window is tiny. The database is locked only for the fraction of a second it takes to create the snapshot. After UNLOCK TABLES the database is fully operational while the backup of the snapshot proceeds at whatever pace is needed. This technique is standard for zero-downtime MySQL/MariaDB backups.
8
Thin Provisioning and Thin Snapshots

Thin-provisioned LVs and their snapshots are more space-efficient for environments with many snapshots of the same origin:

# Create a thin pool LV (the backing store)
sudo lvcreate -L 500G --thinpool tp_pool vg_data

# Create a thin LV from the pool (no fixed size commitment)
sudo lvcreate -V 200G --thin -n lv_thin_home vg_data/tp_pool

# Format and mount as normal
sudo mkfs.xfs /dev/vg_data/lv_thin_home
sudo mount /dev/vg_data/lv_thin_home /home

# Create a thin snapshot (much more efficient than classic snapshots)
sudo lvcreate -s -n lv_thin_home_snap vg_data/lv_thin_home

# Thin snapshots share unchanged blocks — no CoW size needed
sudo lvs
sudo lvs -o name,attr,size,pool_lv,origin,data_percent
lvs showing thin pool and snapshots:
LV VG Attr LSize Pool Origin Data% tp_pool vg_data twi-a-tz-- 500.00g 12.45 lv_thin_home vg_data Vwi-aotz-- 200.00g tp_pool 31.20 lv_thin_home_snap vg_data Vwi---tz-k 200.00g tp_pool lv_thin_home 31.20
Thin vs classic snapshots: Classic snapshots need a pre-allocated CoW store and become invalid if it fills. Thin snapshots share the pool and grow as needed — much better for keeping multiple snapshots long-term. The tradeoff is slightly more complexity in setup.

Quick Reference

CommandWhat it does
lvcreate -s -L 5G -n snap /dev/vg/lvCreate a 5GB snapshot of lv
lvsList LVs — shows snapshot Data% fill level
lvdisplay /dev/vg/snapDetailed snapshot info including fill %
mount -o ro /dev/vg/snap /mnt/snapMount snapshot read-only
mount -o ro,nouuid /dev/vg/snap /mnt/snapMount XFS snapshot (duplicate UUID fix)
umount /mnt/snapUnmount snapshot
lvextend -L +2G /dev/vg/snapExtend snapshot CoW space
lvconvert --merge /dev/vg/snapRollback — merge snapshot to origin
lvremove /dev/vg/snapRemove snapshot (does not affect origin)
lvcreate -s -n snap vg/thin_lvCreate thin snapshot (no size needed)

Snapshot Use Cases

Use CaseApproach
Online filesystem backupSnapshot → mount ro → tar/rsync → remove snapshot
Database backupFLUSH + LOCK → snapshot → UNLOCK → backup snapshot → remove
Safe system updateSnapshot before update → update → if OK remove, if bad merge
Testing config changesSnapshot → make changes → if OK remove, if bad merge
Many long-term snapshotsUse thin provisioning — more space-efficient
Recover deleted fileSnapshot → mount ro → copy file back → unmount → remove

← Back to Storage Index ↑ Back to EXPANDED