A practical reference for Linux Logical Volume Manager (LVM) covering PV → VG → LV layers.
LVM Architecture
# Disk → Partition → PV → VG → LV → mkfs → mount
# PE (Physical Extent): smallest allocatable unit (default 4 MiB)
# Device paths:
/dev/mapper/vg-name-lv-name # Device mapper path
/dev/vg-name/lv-name # Alternative symlink
# Config:
/etc/lvm/lvm.conf # LVM configuration
/etc/lvm/archive/ # Auto metadata archives
/etc/lvm/backup/ # Manual metadata backupsPhysical Volume (PV)
Create
pvcreate /dev/sdb # PV on whole disk
pvcreate /dev/sdc1 # PV on partition
pvcreate /dev/sdd /dev/sde # Multiple at once
pvcreate --dataalignment 1M /dev/sdf # Align for 4K sectorsDisplay & Scan
pvdisplay # Detailed PV info
pvdisplay -m # Show PE allocation
pvs # Compact summary
pvs -o pv_name,pv_size,pv_free --units g # Custom columns
pvscan # Scan for PVsRemove
pvremove /dev/sdb # Remove PV label
pvremove -ff /dev/sdb # Force removalVolume Group (VG)
Create & Extend
vgcreate vg_data /dev/sdb # Create VG
vgcreate -s 16M vg_data /dev/sdd # Custom PE size
vgextend vg_data /dev/sdc # Add PV to VG
vgextend vg_data /dev/sdd /dev/sde # Add multiple PVsDisplay & Reduce
vgdisplay vg_data # Detailed VG info
vgs # Compact summary
vgs -o vg_name,vg_size,vg_free # Custom columns
vgscan # Scan for VGs
vgreduce vg_data /dev/sdc # Remove PV from VG
vgreduce --removemissing vg_data # Remove missing PVsActivate & Rename
vgchange -a y vg_data # Activate all LVs
vgchange -a n vg_data # Deactivate all LVs
vgrename vg_data vg_prod # Rename VG
vgremove vg_data # Remove VG (no LVs)Backup
vgcfgbackup vg_data # Backup metadata
vgcfgbackup -f /tmp/vg.bak vg_data # Save to file
vgcfgrestore vg_data -f /tmp/vg.bak # Restore from fileLogical Volume (LV)
Create
lvcreate -L 100G -n lv_data vg_data # 100GB LV
lvcreate -l 100%FREE -n lv_home vg_data # All remaining space
lvcreate -l 50%VG -n lv_apps vg_data # 50% of VG
lvcreate -L 50G -n lv_fast vg_data /dev/sdd # Specific PVDisplay
lvdisplay vg_data/lv_data # Detailed LV info
lvs # Compact summary
lvs -a # Show all (incl. internal)
lvs -o lv_name,lv_size,lv_attr # Custom columns
lvscan # Scan for LVsExtend & Reduce
lvextend -L +50G vg_data/lv_data # Grow by 50GB
lvextend -L 200G vg_data/lv_data # Grow to 200GB
lvextend -l +100%FREE vg_data/lv_data # Fill VG
lvextend -r vg_data/lv_data # Extend + resize fs
# Shrink: fs first, then LV
lvreduce -L -20G vg_data/lv_data # Shrink by 20GB
lvreduce --fsck -r -L -10G vg_data/lv_data # Check + shrinkResize (Grow/Shrink)
lvresize -L +50G vg_data/lv_data # Grow
lvresize -L 150G vg_data/lv_data # Exact size
lvresize -r -L -20G vg_data/lv_data # Shrink with fsRemove & Rename
lvremove vg_data/lv_data # Remove LV
lvremove -f vg_data/lv_data # Force
lvrename vg_data lv_data lv_storage # Rename
lvchange -a y vg_data/lv_data # Activate
lvchange -a n vg_data/lv_data # DeactivateFilesystem Resize
XFS (grow only)
lvextend -L +50G vg_data/lv_data # 1. Extend LV
xfs_growfs /mount/point # 2. Grow XFS to fillext4 (grow and shrink)
# Grow:
lvextend -L +50G vg_data/lv_data # 1. Extend LV
resize2fs /dev/vg_data/lv_data # 2. Grow filesystem
# Shrink:
e2fsck -f /dev/vg_data/lv_data # 1. Force fsck
resize2fs /dev/vg_data/lv_data 80G # 2. Shrink fs to 80G
lvreduce -L 80G vg_data/lv_data # 3. Reduce LVSnapshots
Create Snapshot
lvcreate -L 10G -s -n lv_root_snap /dev/vg_data/lv_root
# -L = COW storage size (estimate changes × duration)
# Too small = snapshot invalidates (100% used)Monitor & Extend
lvs -a -o lv_name,lv_size,origin,snap_percent
# snap_percent = COW space used (100% = invalid)
lvextend -L +5G vg_data/lv_root_snap # Extend COW storageMerge & Remove
lvconvert --merge vg_data/lv_root_snap # Restore to original
# Merge completes when LV is deactivated next
lvremove vg_data/lv_root_snap # Delete snapshotThin Snapshots
# Require thin pool — instant and space-efficient
lvcreate -s -n thin_snap vg_data/lv_thin_vol
# No -L needed — shares data blocksThin Provisioning
Create Thin Pool
lvcreate -L 500G --thinpool vg_data/thinpool # Auto metadata
lvcreate --size 5G --thinpool vg_data/thinpool # Custom metadataCreate Thin Volumes
lvcreate -V 50G --thin -n lv_thin_vol vg_data/thinpool # 50GB virtual
lvcreate -V 100%FREE --thin -n lv_max vg_data/thinpoolMonitor & Auto-extend
lvs -a -o lv_name,data_percent,metadata_percent
# data_percent = pool usage, metadata_percent = metadata usage
# Auto-extend in /etc/lvm/lvm.conf:
thin_pool_autoextend_threshold = 80 # % full to trigger
thin_pool_autoextend_percent = 20 # % to extend byDiscard
mount -o discard /dev/vg_data/lv_thin_vol /mnt # Online discard
fstrim -v /mnt # Manual discardCaching
Setup Cache (SSD + HDD)
# One-liner: create cache pool and attach
lvcreate -L 50G -n lv_cache_pool vg_ssd
lvconvert --type cache --cachepool vg_ssd/lv_cache_pool \
vg_hdd/lv_slow_dataCache Modes
lvchange --cachemode writeback vg_hdd/lv_slow_data # Fast, risk on crash
lvchange --cachemode writethrough vg_hdd/lv_slow_data # Safe, slower writesMonitor & Detach
lvs -a -o+cache_read_hits,cache_read_misses
dmsetup status vg_hdd-lv_slow_data-cache
lvconvert --splitcache vg_hdd/lv_slow_data # Detach cacheStriping & RAID
Striped (RAID 0)
lvcreate -L 100G -i 2 -I 64 -n lv_striped vg_data
# -i 2 = 2 stripes (2+ PVs), -I 64 = 64KB stripe sizeRAID 1 (Mirror)
lvcreate -L 100G -m1 -n lv_mirror vg_data # 1 mirror = 2 copies
lvcreate -L 100G -m2 -n lv_mirror2 vg_data # 2 mirrors = 3 copiesRAID 5/6/10
lvcreate -L 200G --type raid5 -i 3 -n lv_raid5 vg_data # 3+ PVs
lvcreate -L 200G --type raid6 -i 4 -n lv_raid6 vg_data # 4+ PVs
lvcreate -L 200G --type raid10 -i 2 -n lv_raid10 vg_data # 4+ PVsMonitor & Repair
lvs -a -o lv_name,lv_health_status,raid_sync_action
# health_status: healthy / partial / failed
# Replace failed disk:
pvcreate /dev/sdf && vgextend vg_data /dev/sdf
lvconvert --repair vg_data/lv_raid5
vgreduce vg_data /dev/sdc # Remove failed PVLVM Tags & Automation
pvchange --addtag ssd /dev/sdb # Tag PV
vgchange --addtag production vg_data # Tag VG
lvchange --addtag critical vg_data/lv_db # Tag LV
systemctl enable lvm2-monitor # Auto-activate LVs
# Configure: /etc/lvm/lvm.conf → auto_activation_volume_listpvmove (Online Migration)
pvmove /dev/sdb # Move all data off PV
pvmove /dev/sdb /dev/sde # To specific target
pvmove -n vg_data/lv_data /dev/sdb # Move only one LV
pvmove -b /dev/sdb # Background mode
pvmove -i 5 /dev/sdb # Report every 5 sec
pvmove --abort # Cancel migrationTroubleshooting
Full VG
vgs vg_data # Check free space
# Solutions:
pvcreate /dev/sdf && vgextend vg_data /dev/sdf # Add PV
lvextend -L +100G vg_data/thinpool_tdata # Extend pool
lvremove vg_data/old_snap # Remove snapshotsMissing PV / Failed Disk
vgs -o+missing_pv_count # Check missing PVs
vgreduce --removemissing vg_data # Remove missing PV
# Partial recovery:
vgchange -a y --activationmode partial vg_dataRecover with pvck & vgcfgrestore
pvck /dev/sdb # Scan for metadata
# Restore from backup:
vgcfgrestore --list vg_data # List available backups
vgcfgrestore vg_data -f /etc/lvm/archive/vg_data_000123.vgMetadata Corruption
vgscan --cache # Refresh cache
vgck vg_data # Check VG metadata
vgcfgrestore vg_data # Restore latest backup
vgscan --mknodes # Recreate device nodesThin Pool Overflow
lvextend -L +50G vg_data/thinpool_tdata # Extend data
lvextend -L +1G vg_data/thinpool_tmeta # Extend metadata
systemctl enable lvm2-monitor # Enable auto-extendSplit Brain (Duplicate VG Names)
vgs -o+vg_uuid # Show UUIDs
vgrename VDpp5C-XXXX-XXXX vg_imported # Rename by UUID