LVM offers two snapshot mechanisms that look similar from the command line but fail in fundamentally different ways. The choice between them is about which failure mode you inherit when something goes wrong.

Old-style COW (copy-on-write) snapshots allocate a fixed exception store at creation time. When that store fills to 100%, the snapshot is invalidated permanently and silently. The origin volume continues running. You lose the snapshot and whatever backup or rollback point it represented, but production keeps going.

Thin snapshots share the thin pool and have no separate exception store. When the pool runs out of data or metadata space, every thin volume in the pool freezes at once. That includes the origin, every snapshot, and every other thin LV sharing the pool. The blast radius is wider, recovery is harder, and metadata exhaustion can corrupt the pool in ways that are not always recoverable.

How each snapshot type works

Old-style COW snapshots are created with --size:

# Create a COW snapshot with a 1 GiB exception store
lvcreate --snapshot --size 1G --name snap1 vg0/origin_lv

The --size argument allocates a fixed exception store from VG free extents. This store holds the original copy of every block overwritten in the origin after snapshot creation. Each write to the origin triggers a three-step copy-on-write operation: read the original block from the origin, write it to the exception store, then write the new data to the origin. This triples I/O per origin write while the snapshot exists.

Multiple snapshots on the same origin compound this overhead. Three snapshots on one origin means every origin write triggers three independent COW operations. Write latency doubles or more, and system I/O throughput drops until the snapshot is removed or invalidated.

Thin snapshots are created without --size:

# Create a thin snapshot (no --size)
lvcreate --snapshot --name snap1 vg0/thin_lv

The snapshot shares the thin pool’s data and metadata space with the origin and all other thin volumes in the pool. There is no separate exception store. Copy-on-write data lands in the same pool as everything else. The snapshot is effectively another thin LV that tracks divergent blocks from its origin.

Thin snapshots avoid the COW write amplification problem entirely. They also support snapshot-of-snapshot chains, since everything shares the same pool. Removing the origin of a thin snapshot does not destroy the snapshot: each snapshot becomes an independent thin-provisioned volume. This is different from old-style snapshots, where the origin cannot be removed while snapshots exist.

flowchart TD
  subgraph COW["Old-style COW snapshot"]
    A1["Write to origin"] --> A2["Copy old block to exception store"]
    A2 --> A3{"Exception store full?"}
    A3 -->|"No"| A4["Snapshot stays valid"]
    A3 -->|"Yes"| A5["Snapshot invalidated - permanent, silent"]
    A5 --> A6["Origin unaffected"]
  end
  subgraph Thin["Thin snapshot"]
    B1["Write to any thin LV"] --> B2["Allocate from shared pool"]
    B2 --> B3{"Pool has space?"}
    B3 -->|"Yes"| B4["All volumes normal"]
    B3 -->|"No data space"| B5["All thin LVs freeze (60s queue, then errors)"]
    B3 -->|"No metadata space"| B6["Pool may corrupt - recovery not guaranteed"]
  end

The failure mode COW snapshots inherit: silent invalidation

When the COW exception store fills to 100%, the snapshot is immediately and irreversibly invalidated. The kernel marks it invalid (the lv_attr field shows I in position 5). The snapshot does not disappear from lvs output; it remains listed but is dead.

Key characteristics:

  • Silent: No error reaches the application. The origin continues serving I/O. The kernel stops tracking changes for that snapshot.
  • Permanent: An invalidated snapshot cannot be repaired, extended, or recovered. The only option is to remove it with lvremove and recreate from scratch.
  • Scoped: Only the single snapshot is lost. Other snapshots on the same origin, the origin itself, and all other LVs in the VG are unaffected.
  • Driven by origin writes: The exception store fills based on writes to the origin, not writes to the snapshot. A snapshot of a quiescent volume can sit at 0% indefinitely. A snapshot of an active database can fill in minutes.

The practical consequence: if a backup process was reading from this snapshot, the backup silently becomes incomplete or corrupt. The backup process may not notice because the origin remains available. The first sign of trouble is often a failed restore months later.

snap_percent is the monitoring signal. It jumps in chunks because exception store allocation happens in blocks, so the value may advance several percent at once. You cannot precisely predict the exact moment of overflow.

The failure mode thin snapshots inherit: pool exhaustion

Thin snapshots do not have a fixed COW area, so they avoid the invalidation problem. But they inherit the thin pool’s exhaustion behavior, which is a different and potentially more severe failure mode.

When the thin pool’s data space fills to 100%, behavior depends on the pool’s “when full” policy:

  • error_if_no_space: writes fail immediately.
  • queue_if_no_space: writes to all thin LVs in the pool are queued for up to 60 seconds, controlled by the kernel no_space_timeout parameter with a default of 60 combined with dm_thin_pool metadata. If space is not freed within that window, writes fail with errors.

You set the policy when creating the pool:

# Create thin pool with error mode (writes fail immediately when full)
lvcreate --type thin-pool --poolmetadatasize 1G --size 100G \
  --discards passdown vg0/thinpool
# Check or change the current policy on an existing pool
# The policy is stored in lvm.conf: activation/thin_pool_autoextend_threshold
# Verify current runtime policy:
dmsetup status vg0-thinpool
# Look for "queue_if_no_space" or "error_if_no_space" in the output

In queue mode, processes doing I/O to any thin LV in the pool enter D state (uninterruptible sleep). The system can appear completely hung. If the root filesystem is on a thin LV in the affected pool, the system may become unresponsive to all interaction, including SSH.

When the thin pool’s metadata space fills to 100%, the situation is worse. The man page warns that metadata space exhaustion can lead to inconsistent thin pool metadata and inconsistent filesystems, and that data from thin LVs may be unrecoverable. Recovery requires deactivation, lvconvert --repair (which uses thin_repair and the pmspare LV), and is not guaranteed to succeed.

Key characteristics:

  • Wide blast radius: Every thin LV in the pool is affected simultaneously. The origin, all snapshots, and all other thin volumes freeze or error together.
  • Two independent exhaustion dimensions: Data space and metadata space can fill independently. Metadata can reach 100% while data usage is under 50%. Operators monitoring only data_percent miss this entirely.
  • Metadata is not reclaimable: Unlike data space, which can be reclaimed via fstrim or discard on thin LV filesystems, metadata space does not decrease through normal operation. Metadata consumption depends on unique block writes, not data volume. High random I/O consumes metadata faster than sequential I/O.
  • Recovery is hard: Extending the pool requires VG free space. If the VG is also full, you need to add a PV first. If metadata exhaustion has already corrupted the pool, lvconvert --repair may fail.

Side-by-side: which failure mode you inherit

DimensionOld-style COW snapshotThin snapshot
What fills upFixed exception store (VG extents)Shared thin pool data and metadata
Failure at 100%Single snapshot invalidated permanentlyAll thin LVs in pool freeze or error
Origin impactNone after invalidationOrigin is in the pool, freezes too
Other LVs affectedNoYes, all thin LVs sharing the pool
RecoverabilitySnapshot is gone, recreate onlyExtend pool if VG has space; metadata corruption may not be repairable
Warning signalsnap_percent approaching 100%data_percent and metadata_percent approaching 100%
Speed of failureInstant invalidation at 100%60s write queue (if queued mode), then errors
Write amplification3x or more per origin write, per snapshotMinimal COW overhead on origin
Snapshot of snapshotNot supportedSupported, shares the same pool
Origin can be removedNo, not while snapshots existYes, snapshots become independent thin LVs

Which to choose

The decision depends on your workload and your tolerance for each failure mode.

Use old-style COW snapshots when:

  • Short-lived backup snapshots: You create, read, and remove within a known window. Size the exception store for the expected write volume during that window.
  • Isolation matters: If the snapshot dies, only the backup or restore point is lost. Production continues without interruption.
  • You can tolerate write amplification: The origin sees 3x or higher write overhead per snapshot during the snapshot’s lifetime.

Use thin snapshots when:

  • Long-lived snapshots: You need rollback points or test environments that persist for hours or days.
  • You already monitor the thin pool: You track both data_percent and metadata_percent and have auto-extend properly configured.
  • You can accept the blast radius: A full pool affects all thin volumes, not just the snapshot.
  • Multiple snapshots on one origin: Thin snapshots do not compound COW overhead the way old-style snapshots do.

Do not mix them unknowingly. The --size trap means a single command can create the wrong type. Verify with lvs what type each snapshot actually is before relying on it.

The creation trap: –size creates a COW snapshot

The most common operator mistake is passing --size when creating a snapshot of a thin LV. The lvmthin(7) man page is explicit: specifying -L or --size when creating a thin snapshot causes an old-style COW snapshot to be created instead.

# Correct: thin snapshot shares the pool, no --size
lvcreate --snapshot --name snap1 vg0/thin_lv

# Wrong: creates an old-style COW snapshot with a fixed exception store
lvcreate --snapshot --size 1G --name snap1 vg0/thin_lv

The wrong command succeeds without error or warning. You end up with a snapshot that has a fixed exception store allocated from VG extents and will be silently invalidated when it fills. You may believe you are using thin snapshots (which share the pool and do not invalidate) when you are actually running old-style snapshots that can die at any moment.

To verify which type you have, check whether the snapshot references a pool:

# Identify snapshot type - pool_lv presence indicates thin snapshot
lvs -o lv_name,origin,seg_type,pool_lv,snap_percent

A snapshot with a pool_lv value is a thin snapshot sharing a thin pool. A snapshot with no pool_lv and a seg_type of snapshot is an old-style COW snapshot with a fixed exception store and its own invalidation risk.

Signals to watch in production

SignalApplies toWhy it mattersWarning sign
snap_percentCOW snapshotsApproaches 100% means imminent invalidationAbove 80% on an active origin
lv_attr position 5 = ICOW snapshotsSnapshot already invalidated, backup lostAny I value
data_percent (thin pool)Thin snapshotsApproaches 100% means all thin LVs freezeAbove 85%
metadata_percent (thin pool)Thin snapshotsApproaches 100% means potential pool corruptionAbove 75%
lv_attr position 9 = DThin snapshotsPool out of data space, writes failing or queuedAny D value
lv_attr position 9 = FThin snapshotsPool in failed state, repair neededAny F value
lv_attr position 9 = MThin snapshotsMetadata read-only modeAny M value
Origin LV write latencyBoth (COW mainly)COW overhead from active snapshots2x baseline or higher
vg_free_percentBothLow VG space prevents extension or pool growthBelow 10%
thin_pool_autoextend_thresholdThin snapshotsDefault 100 means auto-extend is disabledVerify value is below 100
dmeventd runningThin snapshotsRequired for auto-extend to fireProcess absent

Two operational notes on these signals.

First, the thin pool auto-extend threshold defaults to 100, which means disabled. Many operators assume their thin pools will auto-grow, but the default configuration does nothing. The first test of auto-extend is usually the production incident. Verify explicitly in /etc/lvm/lvm.conf that thin_pool_autoextend_threshold is set below 100 and that thin_pool_autoextend_percent is greater than 0.

# Check current auto-extend configuration
grep -E 'thin_pool_autoextend' /etc/lvm/lvm.conf

Second, thin pool data usage is updated periodically by the kernel, not on every write. It can be tens of seconds behind actual state. This makes sub-second alerting unreliable for thin pool metrics. Trend-based alerting with rate-of-change calculation is more useful than instantaneous threshold checks for pool exhaustion. For old-style snapshots, snap_percent also jumps in chunks rather than climbing smoothly, because exception store allocation happens in blocks.

How Netdata helps

  • Per-second collection of thin pool data_percent and metadata_percent, giving earlier visibility into growth trends than periodic lvs polling.
  • snap_percent tracking for old-style snapshots with anomaly detection on growth rate, so a write burst on the origin triggers an alert before the exception store fills.
  • LV health attribute monitoring (lv_attr position 9: D, F, M flags) that surfaces pool failure states the moment they appear in kernel device-mapper.
  • Correlation of VG free space with thin pool usage, showing whether auto-extend can actually succeed when it fires.
  • D-state process count and dm device latency correlation, so you can distinguish snapshot COW overhead from thin pool exhaustion during an incident.
  • Kernel log (dmesg) event collection alongside LVM metrics, so invalidation messages and I/O errors appear in the same timeline as the metrics that explain them.