LVM (Logical Volume Manager)
Quick Reference
# View current state
pvs # Physical volumes
vgs # Volume groups
lvs # Logical volumes
lsblk # Block devices
# Create basic LVM setup
pvcreate /dev/sdb # Initialize PV
vgcreate vg_data /dev/sdb # Create VG
lvcreate -L 100G -n lv_data vg_data # Create LV
mkfs.ext4 /dev/vg_data/lv_data # Format
# Extend volume
lvextend -L +50G /dev/vg_data/lv_data
resize2fs /dev/vg_data/lv_data # Grow filesystem
# Snapshots
lvcreate -s -L 10G -n snap_data /dev/vg_data/lv_data
Understanding LVM
LVM Architecture
┌─────────────────────────────────────────────────────────────┐
│ Logical Volumes (LV) │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────────────┐ │
│ │ lv_root │ │ lv_home │ │ lv_data │ │
│ │ 50GB │ │ 100GB │ │ 200GB │ │
│ └─────────────┘ └─────────────┘ └─────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ Volume Group (VG) │
│ vg_system │
│ Total: 500GB │
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ Physical Volumes (PV) │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────────────┐ │
│ │ /dev/sda2 │ │ /dev/sdb │ │ /dev/sdc │ │
│ │ 200GB │ │ 150GB │ │ 150GB │ │
│ └─────────────┘ └─────────────┘ └─────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ Physical Disks/Partitions │
│ /dev/sda2 /dev/sdb /dev/sdc │
└─────────────────────────────────────────────────────────────┘
Key Concepts
| Component | Description |
|---|---|
Physical Volume (PV) |
Block device (disk/partition) initialized for LVM. Divided into Physical Extents (PE). |
Volume Group (VG) |
Pool of storage from one or more PVs. Allocates space to Logical Volumes. |
Logical Volume (LV) |
Virtual partition carved from VG. Appears as |
Physical Extent (PE) |
Smallest unit of allocation (default 4MB). VG divides PVs into PEs. |
Logical Extent (LE) |
Maps to PE. LV size = number of LEs × PE size. |
Why Use LVM?
-
Flexible resizing - Grow/shrink volumes without unmounting (for some filesystems)
-
Snapshots - Point-in-time copies for backups
-
Spanning disks - Create volumes larger than single disk
-
Striping - Improve I/O performance
-
Mirroring - Redundancy without hardware RAID
-
Thin provisioning - Overcommit storage
-
Easy migration - Move data between physical disks
Physical Volumes (PV)
View Physical Volumes
# Simple list
pvs
# Output:
# PV VG Fmt Attr PSize PFree
# /dev/sda2 vg_system lvm2 a-- 199.00g 49.00g
# /dev/sdb vg_data lvm2 a-- 500.00g 200.00g
# Detailed view
pvdisplay
# Specific PV
pvdisplay /dev/sda2
# Show PE allocation
pvs -o +pv_used,pv_pe_count,pv_pe_alloc_count
# Scan for PVs
pvscan
Create Physical Volume
# On whole disk (recommended)
pvcreate /dev/sdb
# On partition
pvcreate /dev/sda3
# With specific PE size (default 4MB)
pvcreate --dataalignmentoffset 0 -M2 /dev/sdb
# Multiple disks at once
pvcreate /dev/sdb /dev/sdc /dev/sdd
# Force (wipe existing signatures)
pvcreate -ff /dev/sdb
Volume Groups (VG)
View Volume Groups
# Simple list
vgs
# Output:
# VG #PV #LV #SN Attr VSize VFree
# vg_data 2 3 0 wz--n- 699.99g 199.99g
# vg_system 1 2 0 wz--n- 199.00g 49.00g
# Detailed view
vgdisplay
# Specific VG
vgdisplay vg_data
# Show all attributes
vgs -o +vg_extent_size,vg_extent_count,vg_free_count
# Scan for VGs
vgscan
Create Volume Group
# Basic creation
vgcreate vg_data /dev/sdb
# With multiple PVs
vgcreate vg_data /dev/sdb /dev/sdc
# With specific PE size (must be power of 2, min 1KB)
vgcreate -s 16M vg_data /dev/sdb
# With metadata copies
vgcreate --metadatacopies 2 vg_data /dev/sdb
Extend Volume Group
# Initialize new PV
pvcreate /dev/sdc
# Add to existing VG
vgextend vg_data /dev/sdc
# Verify
vgs vg_data
pvs
Reduce Volume Group
# 1. Move data off the PV being removed
pvmove /dev/sdc
# 2. Remove PV from VG
vgreduce vg_data /dev/sdc
# 3. Optionally remove PV metadata
pvremove /dev/sdc
Rename Volume Group
# Rename VG
vgrename vg_old vg_new
# Update /etc/fstab and regenerate initramfs if root VG
# Update grub config if necessary
Logical Volumes (LV)
View Logical Volumes
# Simple list
lvs
# Output:
# LV VG Attr LSize Pool Origin Data%
# lv_home vg_system -wi-ao---- 100.00g
# lv_root vg_system -wi-ao---- 50.00g
# lv_data vg_data -wi-a----- 200.00g
# Detailed view
lvdisplay
# Specific LV
lvdisplay /dev/vg_data/lv_data
# Show more attributes
lvs -o +lv_layout,lv_role,stripes,stripe_size
# Show device mapper path
ls -la /dev/mapper/
ls -la /dev/vg_data/
Create Logical Volume
# By size
lvcreate -L 100G -n lv_data vg_data
# By percentage of VG
lvcreate -l 50%VG -n lv_data vg_data
# By percentage of free space
lvcreate -l 100%FREE -n lv_data vg_data
# By number of extents
lvcreate -l 1000 -n lv_data vg_data
# On specific PV
lvcreate -L 100G -n lv_data vg_data /dev/sdb
# Striped (performance)
lvcreate -L 100G -n lv_data -i 2 -I 64K vg_data
# Mirrored (redundancy)
lvcreate -L 100G -n lv_data -m 1 vg_data
Extend Logical Volume
# Add specific size
lvextend -L +50G /dev/vg_data/lv_data
# Extend to specific size
lvextend -L 200G /dev/vg_data/lv_data
# Extend by percentage
lvextend -l +50%FREE /dev/vg_data/lv_data
# Use all remaining space
lvextend -l +100%FREE /dev/vg_data/lv_data
# Extend on specific PV
lvextend -L +50G /dev/vg_data/lv_data /dev/sdc
# Extend LV and resize filesystem together
lvextend -r -L +50G /dev/vg_data/lv_data
Resize Filesystem After Extending
# ext4 (online resize)
resize2fs /dev/vg_data/lv_data
# XFS (online resize, grow only)
xfs_growfs /mnt/data
# btrfs
btrfs filesystem resize max /mnt/data
Reduce Logical Volume
| Always backup before reducing. Some filesystems (XFS) cannot shrink. |
# 1. Unmount
umount /mnt/data
# 2. Check filesystem
e2fsck -f /dev/vg_data/lv_data
# 3. Shrink filesystem first
resize2fs /dev/vg_data/lv_data 80G
# 4. Then shrink LV
lvreduce -L 80G /dev/vg_data/lv_data
# OR do both together (safer)
lvreduce -r -L 80G /dev/vg_data/lv_data
# 5. Remount
mount /dev/vg_data/lv_data /mnt/data
Snapshots
Understanding Snapshots
-
Copy-on-write - Only stores changes from original
-
Space efficient - Grows as original changes
-
Consistent backups - Freeze point-in-time state
-
Rollback capability - Revert to snapshot state
Create Snapshot
# Basic snapshot
lvcreate -s -L 10G -n snap_data /dev/vg_data/lv_data
# Parameters:
# -s : snapshot type
# -L 10G : snapshot size (for COW changes)
# -n snap_... : snapshot name
# Snapshot should be ~15-20% of origin size (adjust based on change rate)
# View snapshots
lvs -o +snap_percent
Use Snapshot for Backup
# 1. Create snapshot
lvcreate -s -L 5G -n snap_backup /dev/vg_data/lv_data
# 2. Mount snapshot (read-only recommended)
mkdir -p /mnt/snap_backup
mount -o ro /dev/vg_data/snap_backup /mnt/snap_backup
# 3. Perform backup
rsync -av /mnt/snap_backup/ /backup/destination/
# or
tar czf /backup/data-$(date +%F).tar.gz /mnt/snap_backup/
# 4. Unmount and remove snapshot
umount /mnt/snap_backup
lvremove /dev/vg_data/snap_backup
Revert to Snapshot
# WARNING: This destroys all changes since snapshot
# 1. Unmount original
umount /mnt/data
# 2. Merge snapshot back (reverts original)
lvconvert --merge /dev/vg_data/snap_data
# 3. Reactivate LV (may require reboot for root)
lvchange -an /dev/vg_data/lv_data
lvchange -ay /dev/vg_data/lv_data
# 4. Mount
mount /dev/vg_data/lv_data /mnt/data
Thin Provisioning
Understanding Thin Provisioning
-
Overcommit storage - Allocate more than physically available
-
Space efficient - Only uses space for actual data
-
Thin pool - Shared storage pool for thin volumes
-
Automatic growth - Volumes grow as needed
Create Thin Pool
# Create thin pool
lvcreate -T -L 100G vg_data/thin_pool
# Or with metadata size
lvcreate -T -L 100G --poolmetadatasize 1G vg_data/thin_pool
# View thin pool
lvs -a -o +pool_lv,data_percent,metadata_percent
Create Thin Volume
# Create thin volume (virtual size can exceed pool)
lvcreate -V 500G -T vg_data/thin_pool -n thin_vol1
# Create another from same pool
lvcreate -V 500G -T vg_data/thin_pool -n thin_vol2
# Total virtual: 1TB, actual pool: 100GB (overcommitted)
# Format and use
mkfs.ext4 /dev/vg_data/thin_vol1
mount /dev/vg_data/thin_vol1 /mnt/thin1
Advanced Features
Striping (Performance)
# Create striped LV across multiple PVs
lvcreate -L 100G -n lv_striped -i 3 -I 256K vg_data
# Parameters:
# -i 3 : 3 stripes (requires 3 PVs in VG)
# -I 256K : stripe size (should match workload)
# View stripe configuration
lvs -o +stripes,stripe_size /dev/vg_data/lv_striped
Mirroring (Redundancy)
# Create mirrored LV
lvcreate -L 100G -n lv_mirror -m 1 vg_data
# Parameters:
# -m 1 : 1 mirror (2 copies total)
# RAID1 style mirror
lvcreate --type raid1 -L 100G -n lv_raid1 -m 1 vg_data
# View mirror status
lvs -o +devices,seg_pe_ranges /dev/vg_data/lv_mirror
RAID with LVM
# RAID0 (striping)
lvcreate --type raid0 -L 100G -n lv_raid0 -i 3 vg_data
# RAID1 (mirroring)
lvcreate --type raid1 -L 100G -n lv_raid1 -m 1 vg_data
# RAID5 (stripe with parity)
lvcreate --type raid5 -L 100G -n lv_raid5 -i 3 vg_data
# RAID6 (stripe with double parity)
lvcreate --type raid6 -L 100G -n lv_raid6 -i 4 vg_data
# RAID10 (stripe of mirrors)
lvcreate --type raid10 -L 100G -n lv_raid10 -i 2 -m 1 vg_data
Cache Volumes
# Use SSD as cache for HDD
# 1. Create cache data LV on SSD
lvcreate -L 50G -n cache_data vg_data /dev/ssd
# 2. Create cache metadata LV on SSD
lvcreate -L 1G -n cache_meta vg_data /dev/ssd
# 3. Create cache pool
lvconvert --type cache-pool --cachemode writeback \
--poolmetadata vg_data/cache_meta vg_data/cache_data
# 4. Attach cache to origin LV
lvconvert --type cache --cachepool vg_data/cache_data vg_data/lv_slow
# View cache stats
lvs -o +cache_mode,cache_read_hits,cache_write_hits
LVM on LUKS
Create Encrypted LVM
# 1. Create LUKS container
cryptsetup luksFormat /dev/sdb
# 2. Open LUKS
cryptsetup open /dev/sdb crypt_data
# 3. Create PV on decrypted device
pvcreate /dev/mapper/crypt_data
# 4. Create VG and LV
vgcreate vg_crypt /dev/mapper/crypt_data
lvcreate -l 100%FREE -n lv_secure vg_crypt
# 5. Format and mount
mkfs.ext4 /dev/vg_crypt/lv_secure
mount /dev/vg_crypt/lv_secure /mnt/secure
Troubleshooting
Common Issues
LV Won’t Activate
# Check VG status
vgdisplay vg_data
# Try activating
vgchange -ay vg_data
# If partial, import
vgimportclone /dev/sdb
# Force activation (use with caution)
lvchange -ay --activationmode partial /dev/vg_data/lv_data
Missing PV
# Check what's missing
vgdisplay --partial vg_data
# If PV is truly lost, remove references
vgreduce --removemissing vg_data
# Force if needed
vgreduce --removemissing --force vg_data
Configuration
LVM Configuration File
# Key settings
devices {
# Filter which devices LVM scans
filter = [ "a|/dev/sd.*|", "a|/dev/nvme.*|", "r|.*|" ]
# Metadata backup location
backup_dir = "/etc/lvm/backup"
archive_dir = "/etc/lvm/archive"
}
activation {
# Auto-activate VGs at boot
auto_activation_volume_list = [ "vg_system", "vg_data" ]
}
global {
# Use lvmetad (metadata caching daemon)
use_lvmetad = 1
}
Quick Command Reference
Information Commands
# Summary views
pvs # Physical volumes
vgs # Volume groups
lvs # Logical volumes
# Detailed views
pvdisplay # PV details
vgdisplay # VG details
lvdisplay # LV details
# Scan/refresh
pvscan # Scan PVs
vgscan # Scan VGs
lvscan # Scan LVs
Creation Commands
# Create PV
pvcreate /dev/sdb
# Create VG
vgcreate vg_name /dev/sdb
# Create LV
lvcreate -L 100G -n lv_name vg_name
# Create snapshot
lvcreate -s -L 10G -n snap_name /dev/vg/lv
# Create thin pool
lvcreate -T -L 100G vg_name/pool_name
# Create thin volume
lvcreate -V 500G -T vg_name/pool -n thin_lv
Modification Commands
# Extend VG
vgextend vg_name /dev/sdc
# Extend LV (and resize filesystem)
lvextend -r -L +50G /dev/vg/lv
# Reduce LV (shrink filesystem first!)
lvreduce -r -L 50G /dev/vg/lv
# Move data
pvmove /dev/sdb /dev/sdc
# Activate/deactivate
vgchange -ay vg_name # Activate VG
vgchange -an vg_name # Deactivate VG
lvchange -ay /dev/vg/lv # Activate LV
lvchange -an /dev/vg/lv # Deactivate LV