Linux LVM (Logical Volume Manager)
LVM is the standard logical volume manager for Linux. It abstracts physical storage into flexible pools from which virtual block devices (logical volumes) can be allocated, resized, snapshotted, and mirrored without regard for underlying physical disk boundaries.
LVM architecture
LVM uses a three-layer abstraction built on the kernel's device-mapper subsystem:
| Layer | Abbreviation | Role |
|---|---|---|
| Physical Volume | PV | A disk or partition initialized with an LVM header. The smallest unit LVM recognizes. |
| Volume Group | VG | A pool of storage assembled from one or more PVs. Allocations are made from here. |
| Logical Volume | LV | A virtual block device carved from a VG. Filesystems are created on LVs. |
The stack reads bottom-to-top:
Physical Disks / Partitions
↓
Physical Volumes (PV) ← pvcreate
↓
Volume Group (VG) ← vgcreate
↓
Logical Volumes (LV) ← lvcreate
↓
Filesystems (ext4, XFS, Btrfs…)Device paths
Three device path formats exist for each LV. Only the first is stable and recommended for /etc/fstab and scripts:
| Path format | Example | Use |
|---|---|---|
/dev/VGNAME/LVNAME | /dev/myvg/mylv | Preferred: persistent symlink created by udev |
/dev/mapper/VGNAME-LVNAME | /dev/mapper/myvg-mylv | Internal format, may change between releases |
/dev/dm-N | /dev/dm-3 | Kernel device node, dynamically assigned. Never use in fstab. |
Physical Volume operations
Initializing a PV
# Initialize a partition
pvcreate /dev/sdb1
# Initialize multiple devices at once
pvcreate /dev/sdb1 /dev/sdc1 /dev/sdd1
# vgcreate can auto-initialize PVs, so this step is optional:
vgcreate myvg /dev/sdb1 /dev/sdc1 # PVs created implicitlyPV metadata location
The LVM disk label sits at byte offset 512 from the start of the device. The metadata area follows at the page-size offset (typically 4 KiB) and holds a circular text buffer with VG metadata. The first Physical Extent (PE) begins at the 1 MiB mark by default, leaving roughly 1020 KiB for metadata.
# Check metadata area size and first PE location
pvs -o pv_name,pe_start,mda_size /dev/sdb1Other PV commands
# Display detailed PV info
pvdisplay /dev/sdb1
# Scan for all PVs
pvscan
# Remove LVM label (PV must not be in a VG)
pvremove /dev/sdb1
# Move all extents off a PV (for removal)
pvmove /dev/sdb1
pvmove -n mylv /dev/sdb1 # move only extents belonging to mylv
pvmove /dev/sdb1 /dev/sdc1 # move to a specific destination PV
pvmove --abort # abort an in-progress pvmoveVolume Group operations
# Create VG with default 4 MiB PE size
vgcreate myvg /dev/sdb1 /dev/sdc1
# Create VG with custom PE size (must be a power of 2, minimum 1 KiB)
vgcreate -s 8M myvg /dev/sdb1
# Display VG info
vgdisplay myvg
# Add a PV to an existing VG
vgextend myvg /dev/sdd1
# Remove an unused PV from a VG
vgreduce myvg /dev/sdb1
# Remove all unused PVs
vgreduce -a myvg
# Remove missing PVs (after disk failure)
vgreduce --removemissing myvg
# Rename a VG
vgrename myvg newvg
# Remove a VG entirely
vgremove myvgThe Physical Extent size is set at VG creation time and is difficult to change afterward. The default 4 MiB is fine for most workloads. For multi-terabyte volumes, a larger PE (8 or 16 MiB) reduces snapshot metadata overhead. PE size has no impact on I/O performance, device-mapper is unaware of PE boundaries.
Logical Volume operations
Creating LVs
# Linear LV (default)
lvcreate -L 20G -n mylv myvg
# Use all remaining free space
lvcreate -l 100%FREE -n mylv myvg
# Striped LV across 3 PVs (stripe size 64 KiB)
lvcreate -i 3 -I 64 -L 30G -n mylv myvg
# 2-way mirror (RAID1)
lvcreate --type raid1 -m 1 -L 10G -n mymir myvg
# RAID5 (3 data stripes + 1 parity)
lvcreate --type raid5 -i 3 -L 30G -n myr5 myvg
# RAID10 (2 stripes, 1 mirror)
lvcreate --type raid10 -i 2 -m 1 -L 40G -n myr10 myvgDisplay and scan
lvdisplay /dev/myvg/mylv
lvdisplay -m /dev/myvg/mylv # show mapping (which PVs hold the data)
lvs # compact table
lvscanResizing logical volumes
Growing (online)
# Extend by 5 GiB and resize the filesystem in one step
lvextend -L +5G -r /dev/myvg/mylv
# Extend to use all free space
lvextend -l +100%FREE -r /dev/myvg/mylv
# Two-step (manual filesystem resize)
lvextend -L +5G /dev/myvg/mylv
resize2fs /dev/myvg/mylv # ext4
xfs_growfs /mnt/data # XFS, use mount point, not deviceShrinking (ext4 only, XFS cannot shrink)
Always resize the filesystem to a size smaller than the target LV size first, then reduce the LV. Reducing the LV while the filesystem still spans the full size destroys data.
# Safe shrink procedure (ext4)
umount /mnt/data
e2fsck -f /dev/myvg/mylv
resize2fs /dev/myvg/mylv 15G
lvreduce -L 15G /dev/myvg/mylv
mount /dev/myvg/mylv /mnt/data
# One-step with --resizefs (handles both)
lvreduce -L 15G -r /dev/myvg/mylvSnapshots
LVM snapshots use copy-on-write (COW). When the snapshot is created it is empty and shares all data blocks with the origin. When a block in the origin is overwritten, the old data is copied into the snapshot's exception store first. The snapshot only grows as the origin changes.
Thick (COW) snapshots
# Create a 2 GiB snapshot
lvcreate -L 2G -s -n mysnap myvg/mylv
# If the snapshot fills up it becomes invalid, extend it
lvextend -L +1G /dev/myvg/mysnapSize the snapshot to hold the expected write volume during its lifetime. 15-25% of the origin size is typical for short-lived backup snapshots.
Thin snapshots (no size needed)
# Thin snapshot of a thin LV
lvcreate -s -n mythinsnap myvg/mythinlv
# Merge a snapshot back into origin
lvconvert --merge myvg/mysnapFor the root filesystem, merge is deferred until the next reboot because the origin cannot be closed while active.
Thin provisioning
# Create a thin pool
lvcreate -L 10G -T myvg/mythinpool
# Create a thin LV with a virtual size larger than the pool
lvcreate -V 100G --thinpool mythinpool -n mythinlv myvgIf the pool fills up, every thin LV using it will fail with I/O errors. Monitor pool usage with lvs and grow the pool before it is exhausted. Set --errorwhenfull y to fail writes cleanly rather than corrupting data.
LVM RAID vs mdadm
LVM RAID uses the same kernel MD driver as mdadm but is managed through lvcreate and lvconvert. It creates hidden sub-LVs for data (_rimage_0, _rimage_1, …) and metadata (_rmeta_0, _rmeta_1, …). View them with lvs -a.
| Feature | mdadm | LVM RAID |
|---|---|---|
| Maturity | Very mature, widely deployed | Good, Red Hat default for new installs |
| Snapshots on RAID | No (need LVM on top) | Yes: native |
| Resizing | mdadm --grow (reshaping) | lvextend / lvreduce |
| Tooling | Standalone mdadm | Integrated with LVM commands |
LVM cache (dm-cache / dm-writecache)
# Create a cache pool on a fast NVMe device
lvcreate --type cache-pool -L 10G --cachemode writeback \
-n fast_pool myvg /dev/nvme0n1p1
# Attach the cache pool to an existing LV
lvconvert --type cache --cachepool fast_pool myvg/main_lv
# Simpler: use a cache volume directly
lvcreate -L 10G -n fast_vol myvg /dev/nvme0n1p1
lvconvert --type cache --cachevol fast_vol myvg/main_lv
# Remove cache
lvconvert --splitcache myvg/main_lv| Cache mode | Behavior |
|---|---|
writethrough | Writes go to both cache and origin. Safer: no data loss on cache failure. |
writeback | Writes go to cache only, flushed later. Faster but risk of data loss on cache device failure. |
passthrough | Cache disabled, I/O passes through to origin. |
LVM on LUKS vs LUKS on LVM
| Layout | Pros | Cons |
|---|---|---|
| LVM on LUKS (recommended) Disk → LUKS → LVM → FS | Single passphrase, VG metadata encrypted, Red Hat/Fedora/Ubuntu default | Cannot encrypt individual LVs with different keys |
| LUKS on LVM Disk → LVM → LUKS per LV → FS | Per-LV encryption keys, mix encrypted and unencrypted | Multiple passphrases, LVM metadata exposed, slower boot |
Moving VGs between hosts
# On source host:
vgchange -an myvg # deactivate
vgexport myvg # export (clears system ID)
# Physically move disks to new host
# On destination host:
vgimport myvg # import (sets system ID to this host)
vgchange -ay myvg # activateMetadata backup and recovery
LVM automatically backs up VG metadata on every configuration change. Current metadata lives in /etc/lvm/backup/ and historical archives in /etc/lvm/archive/.
# Manual backup
vgcfgbackup myvg
vgcfgbackup -f /root/myvg.conf myvg
# List available archives
vgcfgrestore --list myvg
# Dry-run restore
vgcfgrestore --test --file /etc/lvm/archive/myvg_00003-xxx.vg myvg
# Actual restore
vgcfgrestore --file /etc/lvm/archive/myvg_00003-xxx.vg myvgvgcfgbackup only saves LVM configuration (PV/VG/LV layout, sizes, mappings). It does not back up filesystem data.
Autoactivation and systemd
Modern LVM uses event-based autoactivation driven by udev. When a device appears, pvscan --cache -aay runs via a systemd service, records the PV as online, and activates the VG if all its PVs are present.
# Disable autoactivation for a VG
vgchange --setautoactivation n myvg
# Control via lvm.conf
# auto_activation_volume_list = [ "vg1", "vg2/lv1" ] # only these
# auto_activation_volume_list = [] # noneThe lvmetad daemon is deprecated and removed in newer LVM versions. Native async disk scanning has replaced it.
Full stack walkthrough
# 1. Partition the disk (type 8E for MBR, or 8e00 for GPT)
fdisk /dev/sdb
# 2. Initialize PV (or let vgcreate do it)
pvcreate /dev/sdb1
# 3. Create VG
vgcreate myvg /dev/sdb1
# 4. Create LV
lvcreate -L 20G -n mylv myvg
# 5. Create filesystem
mkfs.ext4 /dev/myvg/mylv
# 6. Mount and add to fstab
mkdir /mnt/data
mount /dev/myvg/mylv /mnt/data
echo "/dev/myvg/mylv /mnt/data ext4 defaults 0 2" >> /etc/fstabCommand quick reference
| Operation | Command |
|---|---|
| Create PV | pvcreate /dev/sdb1 |
| Create VG | vgcreate myvg /dev/sdb1 |
| Create LV | lvcreate -L 10G -n mylv myvg |
| Extend LV + FS | lvextend -L +5G -r /dev/myvg/mylv |
| Snapshot | lvcreate -L 2G -s -n snap myvg/mylv |
| Merge snapshot | lvconvert --merge myvg/snap |
| Thin pool | lvcreate -L 10G -T myvg/pool |
| Thin LV | lvcreate -V 100G --thinpool pool -n thin myvg |
| Metadata backup | vgcfgbackup myvg |
| Metadata restore | vgcfgrestore --file <archive> myvg |
| Export VG | vgexport myvg |
| Import VG | vgimport myvg |