An LVM snapshot is neither a copy nor a reflink: it is a fixed-size copy-on-write exception store attached to an origin logical volume. lvcreate -s -L 5G -n snap vg/data allocates 5 GiB from the volume group, and the device-mapper snapshot target records the original contents of each origin chunk the first time it is written. Creation is instant whatever the origin’s size, because nothing is copied.

That size is the whole safety margin, and it is the parameter people get wrong. A store sized for a quiet week is exhausted in an hour by a database checkpoint or an rsync, and when it fills the snapshot does not degrade — it becomes invalid and returns I/O errors. The recovery point disappears exactly when you needed it, which is why the store’s free space belongs on a dashboard, not in a runbook.

An exception store, not a copy

A classic LVM snapshot uses two device-mapper targets: the origin is re-mapped as snapshot-origin, and a new snapshot device combines it with a COW device. Reads of unchanged chunks go straight to the origin; the first write to a chunk copies the old chunk into the COW device, then writes the new data. So consumption tracks the number of distinct chunks that changed, not the number of writes: the simulation writes a million times to sixteen hot chunks and consumes fifteen exceptions, about 60 KiB.

Watch it with lvs -a -o lv_name,lv_attr,origin,data_percent,lv_size. A classic snapshot’s lv_attr reads swi-a-s--- — s for snapshot, w writable, and a state character that becomes I when the store is exhausted. data_percent is the store’s fill, and that is the number to alert on, at 70 or 80 percent; 100 percent is not a warning, it is an obituary. lvextend grows the COW device while the snapshot is still valid; lvchange --monitor y lets dmeventd do it automatically.

Exhaustion is invalidation

The kernel documentation is blunt: the COW device will often be smaller than the origin, and if it fills up the snapshot becomes useless and is disabled, returning errors. LVM’s guidance is to plan for expected writes — often 20 percent of the origin — and extend before it fills. A small slice of the store holds the COW block map, so usable data capacity is a little under the -L value.

The blast radius is narrow but the timing is cruel: the origin keeps running normally, so nothing looks wrong until the backup that reads the snapshot fails or the rollback is unavailable. There is no partial mode: at 100 percent, the snapshot never existed.

Merging, and why thin changes the failure

lvconvert --merge vg/snap rolls the snapshot’s changed chunks back into the origin, and it runs in the background while the origin stays usable — writes to chunks not yet merged are deferred. The constraint is on the origin: it must be inactive when the merge is set up, so unmount it, or schedule the merge and activate the origin afterwards. Merging consumes the snapshot, so copy out anything you need first.

Thin snapshots change the failure mode rather than removing it. A thin snapshot is created when the origin is a thin LV and no size is given; it shares blocks in the thin pool instead of owning a store, so its own divergence cannot invalidate it. The pool is the shared resource now: when it runs out, the damage is not one dead snapshot but every thin volume in the pool, which LVM warns may be damaged and hard to repair. thin_pool_autoextend_threshold and dmeventd exist precisely because pool exhaustion is a pool-wide outage.

When it breaks

The classic failure is a backup that silently stops being a backup. The job mounts the snapshot, copies for longer than the store can cover, and the store reaches 100 percent; the snapshot goes invalid and the copy fails — or worse, monitoring watches only the exit code while the job reads a stale mount. Check data_percent on every snapshot LV, alert at 70 percent, and size for the busiest hour in the retention window.

The second failure is the merge that cannot happen when you need it. lvconvert --merge requires the origin closed, and teams discover that during the incident. Rehearse the merge on a disposable volume, keep a real backup independent of the snapshot, and remember that a snapshot whose store is full cannot be merged.

Check it quickly

Look at the store’s fill before trusting the snapshot:

lvs -a -o lv_name,vg_name,lv_attr,origin,data_percent,lv_size
lvs -a -o lv_name,data_percent,metadata_percent vg/thinpool
dmsetup status vg-snap
lvextend -L +2G vg/snap

data_percent is the COW store’s fill and should sit well under 100; a state character of I in lv_attr means the snapshot is already invalid. For a thin snapshot, data_percent and metadata_percent on the pool are the numbers that matter; dmsetup status shows allocated sectors against the total so you can watch a merge drain.

Sources

  • lvcreate(8), documents -s/--snapshot, COW versus thin snapshots and the sizing guidance, checked 2026-09-16.
  • lvs(8), defines the lv_attr state characters including invalid snapshot, checked 2026-09-16.
  • Device-mapper snapshot support, the exception store, invalidation and lvconvert --merge behaviour, checked 2026-09-16.
  • lvmthin(7), thin snapshots, pool exhaustion and automatic extension, checked 2026-09-16.