Thin Provisioning & Snapshots
Allocate on demand, snapshot at scale
Note
Prerequisite: this page assumes the PV / VG / LV model from LVM Fundamentals. Thin volumes and snapshots are built on top of dm-thin — see Device Mapper for the underlying target.
What Thin Provisioning Is
Thin provisioning decouples the size an LV advertises from the capacity it has actually consumed. Multiple thin LVs share a single thin pool; physical blocks are allocated from the pool on first write, not at creation time.
Because the sum of advertised sizes can exceed the pool’s real capacity (over-provisioning), thin provisioning lets you treat workloads statistically: most volumes never come close to their declared size, so a smaller physical pool can back many oversized logical volumes.
- Physical PEs claimed at
lvcreate - Advertised size = allocated size
- No over-provisioning possible
- Snapshots need pre-sized CoW space
- Simple, predictable, never “fills”
- No physical blocks claimed until write
- Advertised (virtual) size ≠ allocated size
- Over-provisioning is the norm
- Instant, cheap, writable snapshots
- Pool can fill — must be monitored
Why thin?
- Efficient utilisation — VMs / containers that declare 100 GB often use 10–20 GB
- Instant snapshots — no pre-allocated CoW area, snapshot is just another thin LV that shares blocks
- Snapshots of snapshots — the dependency graph is a tree, not a single level
- Block-layer analog of qcow2 — same idea (sparse, CoW) but implemented under the filesystem
Thin Pool Anatomy
A thin pool is actually two LVs hidden behind a single logical entity:
mythin1, mythin2, snapshot, snap-of-snap…- Data LV (
pool_tdata) — the physical capacity of the pool. Every first-write-to-an-address in any thin LV allocates a chunk here. - Metadata LV (
pool_tmeta) — a B-tree that maps (thin LV id, logical block) → pool block. Lose this and you lose every thin LV in the pool.
Warning
Metadata is precious. Size it generously at creation time. Rule of thumb:
0.1% of data LV size, minimum 2 MiB, and LVM imposes a 16 GiB hard
max. Metadata can be grown later (lvextend --poolmetadatasize) but avoid the scramble.
Creating a thin pool
root@host:~# # Let LVM pick metadata size
root@host:~# lvcreate --type thin-pool -L 500G -n tpool data
root@host:~# # Or be explicit (recommended for any sizable pool)
root@host:~# lvcreate --type thin-pool -L 500G --poolmetadatasize 512M -n tpool data
Thin pool volume with chunk size 256.00 KiB can address at most 63.25 TiB of data.
Logical volume "tpool" created.
root@host:~# lvs data/tpool
LV VG Attr LSize Pool Data% Meta%
tpool data twi-a-tz-- 500.00g 0.00 0.15Creating thin volumes
root@host:~# # -V = virtual size (may exceed pool size), -T names the backing pool
root@host:~# lvcreate -V 100G -T data/tpool -n mythin
Logical volume "mythin" created.
root@host:~# lvcreate -V 100G -T data/tpool -n mythin2
root@host:~# lvcreate -V 2T -T data/tpool -n fatbutsparse # 2 TiB virtual on 500 GiB pool
root@host:~# lvs -o name,lv_size,data_percent,pool_lv data
LV LSize Data% Pool
tpool 500.00g 0.00
mythin 100.00g 0.00 tpool
mythin2 100.00g 0.00 tpool
fatbutsparse 2.00t 0.00 tpoolOver-provisioning
The sum of virtual sizes in the example above (100+100+2048 = 2248 GiB) is over 4× the pool’s 500 GiB. That’s legal and often desirable. The deal is simple:
- As long as actual usage stays under the pool’s capacity, everything works
- When writes push the pool past 100%, the pool enters the pool-full state and starts failing allocations — see the warning below
Warning
Pool-full is the single most important operational concern with thin pools.
When the data LV fills, in-flight writes to any thin LV in the pool fail with EIO.
The kernel queues further writes for a grace period (configurable no_space_timeout,
default 60 s) and then marks volumes read-only. Filesystems on top may hit a remount-ro state
or corruption — an application writing at the moment of exhaustion can lose that write.
Metadata exhaustion is just as fatal and has no early warning from the FS side.
Autoextend: Growing the Pool Automatically
LVM can watch pool usage via dmeventd and extend the pool when a configured
threshold is crossed — assuming the VG has free PEs available. Configured per-host in
/etc/lvm/lvm.conf:
root@host:~# grep -E 'thin_pool_autoextend' /etc/lvm/lvm.conf
thin_pool_autoextend_threshold = 80
thin_pool_autoextend_percent = 20Pool writes
Thin LVs receive writes, pool data usage climbs
Threshold hit
Pool data usage crosses 80%
dmeventd fires
Monitored by
lvm2-monitor.servicelvextend +20%
Pool grows if VG has free PEs
Back to watching
Loop continues until VG is empty
Warning
Autoextend is a safety net, not a strategy. It requires free PEs in the VG. If the VG is full, autoextend cannot help and you are right back at pool-full risk. Treat autoextend as “buy me time to provision more physical capacity,” and alert long before the VG itself runs out.
Monitoring
There are two independent usage values to watch per pool: data_percent and
metadata_percent. Alert on both.
root@host:~# lvs -o name,lv_size,data_percent,metadata_percent,pool_lv,lv_attr
LV LSize Data% Meta% Pool Attr
tpool 500.00g 72.41 3.04 twi-aotz--
mythin 100.00g 18.12 tpool Vwi-a-tz--
mythin2 100.00g 6.51 tpool Vwi-a-tz--
root@host:~# # Low-level: dmsetup status shows live counters
root@host:~# dmsetup status data-tpool
0 1048576000 thin-pool 234 1560/131072 921600/2000000 ...
^^^^ ^^^^^^^ ^^^^^^^^^^^^^^^
meta used/total data used/total (in chunks)Alert thresholds worth codifying
data_percent > 80— warning (autoextend should have triggered; investigate why if not)data_percent > 90— criticalmetadata_percent > 80— warning; grow_tmetawithlvextend --poolmetadatasize +- VG
VFreelow — autoextend won’t save you anymore
Thin Snapshots
A thin snapshot is a new thin LV that shares all existing blocks with the origin by pointing at the same pool addresses in the metadata B-tree. On first write to a shared block (from either origin or snapshot) a new pool block is allocated and the mapping is updated — true copy-on-write at the thin-pool level.
root@host:~# lvcreate --snapshot -n mythin_snap data/mythin
Logical volume "mythin_snap" created.
root@host:~# # snapshots are writable by default
root@host:~# mount /dev/data/mythin_snap /mnt/snap
root@host:~# # snapshots-of-snapshots work the same way
root@host:~# lvcreate --snapshot -n mythin_snap2 data/mythin_snapThin vs. traditional snapshots
| Property | Traditional (dm-snapshot) | Thin (dm-thin) |
|---|---|---|
| Pre-allocated space | Yes — fixed-size CoW store per snapshot | No — shares the pool |
| Creation cost | Small but non-zero (allocate CoW LV) | Instant — only metadata is written |
| Origin write overhead | Read-modify-write on first change per block | Single CoW allocation in the pool, negligible |
| Writable | Read-only by default | Writable by default |
| Snapshot-of-snapshot | No (or emulated with significant cost) | Native, unlimited depth |
| Scale | A handful, short-lived | Hundreds or thousands, long-lived |
| Failure mode if space exhausted | Snapshot invalidated & dropped (origin fine) | Pool-full affects all LVs in the pool |
Common use cases
- Consistent backups —
fsfreezethe origin filesystem,lvcreate --snapshot,fsfreeze -u, back up the snapshot while the origin keeps serving writes. Remove the snapshot when done. - Pre-upgrade rollback — snapshot the root LV, run the upgrade, keep
the snapshot for a day, remove on success. If something is broken,
lvconvert --mergerolls the origin back to the snapshot on next boot. - Cheap dev / test clones — spin up dozens of snapshots of a production copy for QA without paying full storage cost.
root@host:~# # freeze → snap → thaw pattern
root@host:~# fsfreeze -f /data
root@host:~# lvcreate --snapshot -n data_backup data/mythin
root@host:~# fsfreeze -u /data
root@host:~# mount -o ro,nouuid /dev/data/data_backup /mnt/snap # nouuid for xfs
root@host:~# rsync -aHAX /mnt/snap/ backup-host:/srv/backups/data/
root@host:~# umount /mnt/snap && lvremove -f /dev/data/data_backupPool Repair
If metadata is suspected corrupt (pool won’t activate, lvchange errors about
bad references) the thin_* tools (from thin-provisioning-tools)
can check, export, and rebuild the B-tree. Run on a deactivated pool.
root@host:~# vgchange -a n data
root@host:~# thin_check /dev/mapper/data-tpool_tmeta
examining superblock
examining devices tree
examining mapping tree
checking space map counts
root@host:~# # Export metadata to XML for inspection or rebuild
root@host:~# thin_dump /dev/mapper/data-tpool_tmeta -o /tmp/thin.xml
root@host:~# # Restore onto a fresh metadata LV
root@host:~# thin_restore -i /tmp/thin.xml -o /dev/mapper/data-tpool_tmeta_newTip
LVM’s own lvconvert --repair data/tpool wraps this workflow end to end:
it snapshots the metadata, runs thin_check, and swaps in the repaired copy.
Prefer it unless you need to hand-edit the XML.
Cache LVs (dm-cache)
A cache LV puts an SSD in front of a slower (HDD) LV transparently. dm-cache sits between the filesystem and the origin LV; hot blocks live on the fast device, cold blocks on the slow one. Promotion / demotion is policy-driven.
root@host:~# # VG "data" contains both the slow HDD PV and the fast SSD PV
root@host:~# # Create a cache pool on the SSD
root@host:~# lvcreate --type cache-pool -L 50G --cachemode writeback \
-n cpool data /dev/nvme0n1
root@host:~# # Attach the cache pool to the slow LV
root@host:~# lvconvert --type cache --cachepool data/cpool data/slowlv
root@host:~# lvs -o name,cache_mode,cache_policy,cache_settings,data_percent
LV CacheMode Policy Settings Data%
slowlv writeback smq 12.34- Every write hits cache and origin synchronously
- Read acceleration only — write latency is HDD-bound
- Cache device can fail without data loss
- Safe default when in doubt
- Writes acknowledged once they land on the SSD
- Full read and write acceleration
- SSD failure = data loss for dirty blocks
- Use mirrored/RAID1 cache devices for safety
VDO — Dedup & Compression
VDO (Virtual Data Optimizer) is Red Hat’s kernel layer that adds
inline deduplication, compression, and thin provisioning
below the filesystem. A VDO volume appears as /dev/mapper/<name> and is
typically used as the block device under a filesystem or as an LVM PV.
root@host:~# # On RHEL/Alma/Rocky
root@host:~# dnf install vdo kmod-kvdo
root@host:~# vdo create --name=vdo0 --device=/dev/data/backing --vdoLogicalSize=10T
root@host:~# mkfs.xfs -K /dev/mapper/vdo0 # -K avoids fstrim of the sparse device
root@host:~# mount -o discard /dev/mapper/vdo0 /backup
root@host:~# vdostats --human-readable
Device Size Used Available Use% Space saving%
/dev/mapper/vdo0 5.0T 1.2T 3.8T 24% 67%When VDO earns its keep
- Backup targets — full backups dedupe heavily across generations
- VM storage with many similar guest images
- Container registries / image caches — large duplication between layers
Note
Kernel module status: VDO is distributed as an out-of-tree module
(kmod-kvdo) on RHEL-family distros. It is not in mainline Linux
as of 2024. On Debian/Ubuntu you’re on your own; consider ZFS with compression/dedup
or btrfs with compression instead.
Thin LVM vs. ZFS
ZFS has thin volumes (zvols), unlimited instant snapshots, and send/receive built into the same filesystem. If you can run ZFS, you almost always will. LVM-thin stays relevant when ZFS isn’t an option or you want to keep a traditional filesystem stack.
- Mainline kernel, no licensing concerns
- Works with any Linux filesystem on top
- No block-level checksums — bit rot undetectable
- No send/receive equivalent (use filesystem-level tools)
- Pool management is imperative, manual
- Proxmox, RHEL, Ubuntu defaults and ecosystem
- CDDL license — out-of-tree on Linux (OpenZFS DKMS)
- Integrated filesystem + volume manager + RAID
- End-to-end checksums and self-healing on redundant vdevs
- Native
zfs send/zfs receivesnapshots stream - ARC / L2ARC / SLOG for caching — RAM-hungry
- TrueNAS, FreeBSD, Proxmox (optional) ecosystem
Tip
Pragmatic rule: if you need data integrity guarantees (bit-rot detection, self-healing), reach for ZFS or btrfs — LVM-thin does not checksum. If you just want flexibility and instant snapshots on top of a traditional stack, LVM-thin is the simplest and most universally available option.