Post

LVM

LVM Cheat Sheet: Complete Guide from Basics to Advanced Techniques

Logical Volume Manager (LVM) is a powerful storage management solution that provides flexibility and advanced features beyond traditional disk partitioning. Whether you’re managing a single server or an enterprise infrastructure, understanding LVM is essential for modern system administration.

Table of Contents


What is LVM?

LVM adds a layer of abstraction between your physical storage and the filesystem. Instead of dealing with fixed partitions, you can dynamically allocate, resize, and manage storage space.

Key Benefits:

  • Flexibility: Resize volumes without unmounting
  • Snapshot capability: Create point-in-time copies for backups
  • Thin provisioning: Allocate space on-demand
  • Storage pooling: Combine multiple disks into a single pool
  • Live migration: Move data while the system is running
  • RAID functionality: Software RAID without hardware requirements

LVM Architecture

LVM uses a three-layer architecture:

flowchart TD
    subgraph "Physical Layer"
        PV1["Physical Volume<br/>/dev/sda1"]
        PV2["Physical Volume<br/>/dev/sdb1"]
        PV3["Physical Volume<br/>/dev/nvme0n1p1"]
    end
    
    subgraph "Volume Group Layer"
        VG["Volume Group<br/>vg_data"]
    end
    
    subgraph "Logical Volume Layer"
        LV1["Logical Volume<br/>/dev/vg_data/root<br/>ext4/xfs"]
        LV2["Logical Volume<br/>/dev/vg_data/home<br/>ext4"]
        LV3["Logical Volume<br/>/dev/vg_data/db<br/>xfs"]
    end
    
    FS1["/"]
    FS2["/home"]
    FS3["/var/lib/mysql"]

    PV1 -->|"extend"| VG
    PV2 -->|"extend"| VG
    PV3 -->|"extend"| VG
    
    VG -->|"allocate"| LV1
    VG -->|"allocate"| LV2
    VG -->|"allocate"| LV3
    
    LV1 -->|"mount"| FS1
    LV2 -->|"mount"| FS2
    LV3 -->|"mount"| FS3

Layer Breakdown:

  1. Physical Volume (PV): The actual disk or partition (e.g., /dev/sda1)
  2. Volume Group (VG): A pool of storage created from one or more PVs
  3. Logical Volume (LV): Virtual partitions carved out of the VG

Basic LVM Operations

Physical Volumes (PV)

Create a Physical Volume

1
2
3
4
5
6
7
8
# Initialize a disk/partition for LVM use
pvcreate /dev/sdb1

# Initialize entire disk (no partition table)
pvcreate /dev/sdc

# Initialize multiple devices
pvcreate /dev/sdd1 /dev/sde1 /dev/sdf1

View Physical Volumes

1
2
3
4
5
6
7
8
9
10
11
# Display all PVs
pvdisplay

# Compact display
pvs

# Show specific PV
pvdisplay /dev/sdb1

# Show PV size in human-readable format
pvs --units g

Remove a Physical Volume

1
2
3
4
5
6
7
8
# First, ensure all data is moved off the PV
pvmove /dev/sdb1

# Then remove from VG
vgreduce <volume-group-name> /dev/sdb1

# Finally, wipe LVM metadata
pvremove /dev/sdb1

Volume Groups (VG)

Create a Volume Group

1
2
3
4
5
6
7
8
# Create VG from one or more PVs
vgcreate <vg-name> /dev/sdb1 /dev/sdc1

# Specify PE (Physical Extent) size (default 4MB)
vgcreate -s 8M <vg-name> /dev/sdb1

# Example
vgcreate vg_data /dev/sdb1 /dev/sdc1

View Volume Groups

1
2
3
4
5
6
7
8
9
10
11
# Display all VGs
vgdisplay

# Compact display
vgs

# Show free space in VG
vgs --units g -o +vg_free

# Show specific VG
vgdisplay vg_data

Extend a Volume Group

1
2
3
4
5
# Add a new PV to existing VG
vgextend vg_data /dev/sdd1

# Verify extension
vgs vg_data

Reduce a Volume Group

1
2
3
4
5
# Ensure no LVs are using the PV
pvmove /dev/sdb1

# Remove PV from VG
vgreduce vg_data /dev/sdb1

Remove a Volume Group

1
2
3
4
5
# First, deactivate and remove all LVs
lvremove /dev/vg_data/<lv-name>

# Then remove VG
vgremove vg_data

Logical Volumes (LV)

Create a Logical Volume

1
2
3
4
5
6
7
8
9
10
11
12
# Create LV with specific size
lvcreate -L 10G -n lv_name vg_name

# Create LV using percentage of VG free space
lvcreate -l 100%FREE -n lv_name vg_name
lvcreate -l 50%VG -n lv_name vg_name

# Create LV with specific number of extents
lvcreate -l 100 -n lv_name vg_name

# Example
lvcreate -L 20G -n root vg_data

View Logical Volumes

1
2
3
4
5
6
7
8
9
10
11
# Display all LVs
lvdisplay

# Compact display
lvs

# Show specific LV
lvdisplay /dev/vg_data/root

# Show LV with path
lvs -o +lv_path

Remove a Logical Volume

1
2
3
4
5
# WARNING: This deletes all data in LV!
lvremove /dev/vg_data/lv_name

# Or use VG and LV name
lvremove vg_data/lv_name

Common Tasks

Extending Logical Volumes

Scenario: Increase filesystem size without downtime

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# Step 1: Extend the logical volume
# Option A: Add specific size
lvextend -L +5G /dev/vg_data/root

# Option B: Use all free space
lvextend -l +100%FREE /dev/vg_data/root

# Option C: Extend to specific size
lvextend -L 30G /dev/vg_data/root

# Step 2: Resize the filesystem
# For ext4 (online resize)
resize2fs /dev/vg_data/root

# For xfs (online resize)
xfs_growfs /mount/point

# For btrfs (online resize)
btrfs filesystem resize max /mount/point

# Step 3: Verify
df -h

Complete Example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# Check current size
lvs vg_data/root
Filesystem             Size  Origin Snap%  Move Log Cpy%Sync Convert

# Extend LV by 10GB
lvextend -L +10G vg_data/root
  Size of logical volume vg_data/root changed from 20.00 GiB to 30.00 GiB.

# Resize ext4 filesystem
resize2fs /dev/vg_data/root
resize2fs 1.47.0 (5-Feb-2023)
Filesystem at /dev/vg_data/root is mounted on /; on-line resizing required
old_desc_blocks = 4, new_desc_blocks = 6
The filesystem on /dev/vg_data/root is now 7864320 (4k) blocks long.

# Verify
df -h /dev/vg_data/root
Filesystem             Size  Used Avail Use% Mounted on
/dev/mapper/vg_data-root  30G   12G   17G  42% /

Reducing Logical Volumes

⚠️ WARNING: Always backup data before reducing. Filesystem must be unmounted or mounted read-only.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# Step 1: Check filesystem
# For ext4: unmount first or use read-only
umount /mount/point

# Check filesystem integrity
e2fsck -f /dev/vg_data/lv_name

# Step 2: Reduce filesystem size (shrink filesystem first!)
# For ext4: reduce to 15GB
resize2fs /dev/vg_data/lv_name 15G

# Step 3: Reduce logical volume
lvreduce -L 15G /dev/vg_data/lv_name

# Confirm reduction (type 'y')
lvreduce -L 15G /dev/vg_data/lv_name
  WARNING: Reducing active logical volume to 15.00 GiB.
  THIS MAY DESTROY YOUR DATA (filesystem may be damaged)
  Do you really want to reduce vg_data/lv_name? [y/n]: y
  Size of logical volume vg_data/lv_name changed from 20.00 GiB to 15.00 GiB.

# Step 4: Remount and verify
mount /dev/vg_data/lv_name /mount/point
df -h

Moving Data Between Disks

Scenario: Replace old disk with new, larger disk

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# Step 1: Add new PV to VG
pvcreate /dev/sdd1
vgextend vg_data /dev/sdd1

# Step 2: Move data from old PV to new PV
pvmove /dev/sdb1

# This may take time depending on data size
# Monitor progress:
watch -n 5 pvs

# Step 3: Remove old PV from VG
vgreduce vg_data /dev/sdb1

# Step 4: (Optional) Remove PV metadata
pvremove /dev/sdb1

Move specific LV to specific PV:

1
2
# Move only lv_home to /dev/sdd1
pvmove -n lv_home /dev/sdb1 /dev/sdd1

Advanced LVM Features

LVM Snapshots

Snapshots provide point-in-time copies of logical volumes using copy-on-write (COW).

flowchart LR
    subgraph "Original LV"
        A[Block 1<br/>Data A]
        B[Block 2<br/>Data B]
        C[Block 3<br/>Data C]
        D[Block 4<br/>Data D]
    end
    
    subgraph "Snapshot LV"
        A2[Block 1<br/>Data A]
        B2[Block 2<br/>Data B]
        C2[Block 3<br/>Data C]
        D2[Block 4<br/>Data D]
    end
    
    subgraph "Changes After Snapshot"
        C3[Block 3<br/>Data C_new]
        D3[Block 4<br/>Data D_new]
    end
    
    A --> A2
    B --> B2
    C --> C2
    D --> D2
    
    C2 -.->|"COW: Original<br/>block preserved"| C3
    D2 -.->|"COW: Original<br/>block preserved"| D3

Create a Snapshot

1
2
3
4
5
6
7
8
# Create snapshot with 10% of original LV size
lvcreate -s -n snap_name -L 10G /dev/vg_data/lv_original

# Create snapshot using percentage of LV size
lvcreate -s -n snap_name -l 20%ORIGIN /dev/vg_data/lv_original

# Example
lvcreate -s -n root_snap -L 5G vg_data/root

Mount and Use Snapshot

1
2
3
4
5
6
7
8
# Mount snapshot (read-only recommended)
mount -o ro /dev/vg_data/root_snap /mnt/snapshot

# Access files from snapshot
ls /mnt/snapshot/home/

# Unmount when done
umount /mnt/snapshot

Merge Snapshot (Rollback)

1
2
3
4
5
6
7
8
9
10
11
# Merge snapshot back to original (requires lvm2 >= 2.02.89)
lvconvert --merge vg_data/root_snap

# If LV is active, reboot required or deactivate first
lvconvert --merge vg_data/root_snap
# Reboot to complete merge

# Or merge while active (if supported)
umount /dev/vg_data/root
lvconvert --merge vg_data/root_snap
mount /dev/vg_data/root /

Remove Snapshot

1
2
3
4
5
# First unmount if mounted
umount /dev/vg_data/root_snap

# Remove snapshot LV
lvremove vg_data/root_snap

Snapshot Use Cases:

  • Backups: Create snapshot, backup from snapshot while LV remains active
  • Testing: Test changes, rollback if needed
  • Consistent Data: Quiesce database, create snapshot, backup

Snapshot Limitations:

  • Snapshot size limits number of changes before full copy
  • Performance overhead on write-heavy workloads
  • Cannot resize snapshot independently
  • Requires sufficient free space in VG

Thin Provisioning

Thin provisioning allows overcommitting storage - allocate virtual space larger than physical space.

flowchart TD
    subgraph "Thin Pool"
        TP[Thin Pool<br/>Physical: 100GB]
    end
    
    subgraph "Thin Volumes"
        TV1[Thin LV 1<br/>Virtual: 50GB<br/>Actual: 10GB]
        TV2[Thin LV 2<br/>Virtual: 80GB<br/>Actual: 25GB]
        TV3[Thin LV 3<br/>Virtual: 100GB<br/>Actual: 40GB]
    end
    
    TP --> TV1
    TP --> TV2
    TP --> TV3
    
    TV1 -.->|"Uses 10GB"| TP
    TV2 -.->|"Uses 25GB"| TP
    TV3 -.->|"Uses 40GB"| TP

Create Thin Pool

1
2
3
4
5
6
7
8
9
10
11
12
13
# Step 1: Create thin pool LV (metadata + data)
# Create metadata LV (usually 1% of pool size)
lvcreate -L 1G -n thinpool_meta vg_data

# Create data LV (remaining space)
lvcreate -L 99G -n thinpool_data vg_data

# Step 2: Convert to thin pool
lvconvert -y --zero n -c 512K --thinpool vg_data/thinpool_data \
          --poolmetadata vg_data/thinpool_meta vg_data/thinpool_data

# Or create thin pool in one command (lvm2 >= 2.02.115)
lvcreate -L 100G -T vg_data/thinpool

Create Thin Volume

1
2
3
4
5
6
7
8
9
# Create thin volume from thin pool
lvcreate -V 500G -T vg_data/thinpool -n thin_vol1

# -V specifies virtual size (can exceed pool size)
# Actual space allocated on-demand

# Create multiple thin volumes
lvcreate -V 200G -T vg_data/thinpool -n thin_vol2
lvcreate -V 300G -T vg_data/thinpool -n thin_vol3

View Thin Pool Status

1
2
3
4
5
6
7
8
9
10
11
12
# Show thin pool metadata usage
lvs -o +data_percent,metadata_percent,thin_pool

# Example output:
# LV         VG      Attr       LSize   Data%  Meta%  Move Log Cpy%Sync Convert
# thinpool   vg_data twi-aotz-- 100.00g  45.20  12.50

# Check thin volume usage
lvs -o +thin_percent

# Monitor thin pool
lvs -a -o +seg_monitor

Extend Thin Pool

1
2
3
4
5
# Add more space to thin pool
lvextend -L +50G vg_data/thinpool

# Extend metadata if needed
lvextend -L +1G vg_data/thinpool_meta

Thin Pool Auto-Extension

1
2
3
4
5
6
7
# Configure automatic extension when pool reaches threshold
lvm.conf setting:
thin_pool_autoextend_threshold = 80
thin_pool_autoextend_percent = 20

# Or use command:
lvchange --autoextend y --poolmetadataspare 1 vg_data/thinpool

Thin Snapshot

1
2
3
4
# Create snapshot of thin volume (very efficient)
lvcreate -s -n thin_snap -V 10G vg_data/thin_vol1

# Snapshot size is virtual, actual depends on changes

Thin Provisioning Best Practices:

  • Monitor pool usage closely (Data% approaching 100% = out of space)
  • Keep metadata < 50% used (Meta% threshold)
  • Use separate metadata LV for performance
  • Set up alerts for pool capacity
  • Consider overcommit ratio based on workload

LVM Mirroring (RAID 1)

LVM provides software mirroring for redundancy.

flowchart LR
    subgraph "Mirror LV"
        M1[Mirror Segment<br/>/dev/sdb1]
        M2[Mirror Segment<br/>/dev/sdc1]
    end
    
    M1 -->|"Synchronous<br/>Write"| Mirror[Logical Volume<br/>/dev/vg_data/mirror_lv]
    M2 -->|"Synchronous<br/>Write"| Mirror

Create Mirrored LV

1
2
3
4
5
6
7
8
# Create mirrored LV with 2 copies
lvcreate -m 1 -L 20G -n mirror_lv vg_data

# -m 1 means 1 mirror (2 total copies: original + 1 mirror)
# -m 2 would mean 2 mirrors (3 total copies)

# Specify which PVs to use
lvcreate -m 1 -L 20G -n mirror_lv vg_data /dev/sdb1 /dev/sdc1

View Mirror Status

1
2
3
4
5
6
7
8
9
# Show mirror sync status
lvs -o +mirror_seg,raid_sync_status

# Example:
# LV        VG      Attr       LSize   Cpy%Sync Convert
# mirror_lv vg_data mwi-aom--- 20.00g  100.00

# Detailed mirror information
lvdisplay -m /dev/vg_data/mirror_lv

Repair a Failed Mirror

1
2
3
4
5
6
7
# If a disk fails, remove it from mirror
lvconvert --repair vg_data/mirror_lv

# Replace failed disk and add to mirror
pvcreate /dev/sdd1
vgextend vg_data /dev/sdd1
lvconvert -m vg_data/mirror_lv /dev/sdd1

Convert Linear LV to Mirrored

1
2
3
4
5
# Add mirror to existing LV
lvconvert -m 1 vg_data/linear_lv

# Specify devices
lvconvert -m 1 vg_data/linear_lv /dev/sdb1 /dev/sdc1

Remove Mirror

1
2
# Remove one mirror copy (reduce to linear)
lvconvert -m 0 vg_data/mirror_lv

Mirror Considerations:

  • Requires at least 2 PVs for redundancy
  • Write performance overhead (synchronous writes)
  • Automatic resync after failure/replacement
  • Monitor sync progress with lvs

LVM Caching

LVM can use fast SSDs to cache slower HDDs using dm-cache.

flowchart TD
    subgraph "Origin LV<br/>(Slow HDD)"
        O1[Block 1]
        O2[Block 2]
        O3[Block 3]
        O4[Block 4]
    end
    
    subgraph "Cache LV<br/>(Fast SSD)"
        C1[Block 1<br/>Cached]
        C2[Block 2<br/>Cached]
    end
    
    O1 -->|"Cache Hit"| C1
    O2 -->|"Cache Hit"| C2
    O3 -->|"Cache Miss"| O3
    O4 -->|"Cache Miss"| O4

Create Cached LV

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# Step 1: Create origin LV on slow storage
lvcreate -L 100G -n origin_lv vg_data /dev/sdb1

# Step 2: Create cache metadata LV (small, on SSD)
lvcreate -L 1G -n cache_meta vg_data /dev/nvme0n1p1

# Step 3: Create cache data LV (larger, on SSD)
lvcreate -L 20G -n cache_data vg_data /dev/nvme0n1p1

# Step 4: Convert to cache pool
lvconvert -y --type cache-pool \
          vg_data/cache_data \
          --poolmetadata vg_data/cache_meta

# Step 5: Attach cache to origin LV
lvconvert -y --type cache \
          --cachepool vg_data/cache_data \
          vg_data/origin_lv

View Cache Status

1
2
3
4
5
6
7
8
9
# Show cache statistics
lvs -o +cache_policy,cache_settings

# Check cache hits/misses
dmsetup status /dev/vg_data/origin_lv-cache

# Example output:
# 0 20971520 cache 0 0 1 1 0 0 0 0 0 0 0 0 0 0
# (reads: hits misses, writes: hits misses)

Cache Policies

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# Set cache policy (default: smq)
lvchange --cachepolicy smq vg_data/origin_lv

# Available policies:
# - smq: Stochastic Multi-Queue (default, good for most workloads)
# - mq: Multi-Queue (better for high queue depth)
# - cleaner: Write-through (flush dirty blocks)

# Set cache mode
lvchange --cachemode writeback vg_data/origin_lv
# Modes: writethrough, writeback, passthrough

# Set cache parameters
lvchange --cachesettings 'smq_threshold=8192' vg_data/origin_lv

Remove Cache

1
2
3
4
# Detach cache (data remains on origin)
lvconvert --uncache vg_data/origin_lv

# This may take time to flush dirty blocks

Caching Best Practices:

  • Cache metadata LV should be on reliable storage
  • Cache size: 10-20% of origin size typically
  • Monitor cache hit ratio
  • Use writeback mode for performance, writethrough for safety
  • Consider workload characteristics (random vs sequential)

LVM Encryption

LVM integrates with LUKS for disk encryption.

flowchart TD
    subgraph "Physical Layer"
        PV[Physical Volume<br/>/dev/sdb1]
    end
    
    subgraph "LUKS Layer"
        LUKS[LUKS Container<br/>/dev/mapper/crypt_lv]
    end
    
    subgraph "LVM Layer"
        VG[Volume Group<br/>vg_encrypted]
        LV[Logical Volume<br/>/dev/vg_encrypted/secret_data]
    end
    
    PV -->|"Encrypted"| LUKS
    LUKS -->|"Decrypted"| VG
    VG --> LV

Encrypt a Logical Volume

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# Method 1: Encrypt LV directly (lvm2 >= 2.03.07)
lvcreate -L 10G -n secret_lv vg_data
lvconvert --type encrypt --cipher aes-xts-plain64 \
          --key-size 256 --hash sha256 \
          --encrypt y vg_data/secret_lv

# Enter passphrase when prompted

# Method 2: LUKS on PV, then PV to VG (more flexible)
cryptsetup luksFormat /dev/sdb1
cryptsetup open /dev/sdb1 crypt_lv
pvcreate /dev/mapper/crypt_lv
vgcreate vg_encrypted /dev/mapper/crypt_lv
lvcreate -L 10G -n data vg_encrypted

Open Encrypted LV

1
2
3
4
5
6
7
8
9
# If using LUKS on PV
cryptsetup open /dev/sdb1 crypt_lv --type luks

# If using LVM encryption
lvchange -ay vg_data/secret_lv
# Prompts for passphrase

# Access decrypted LV
mount /dev/vg_data/secret_lv /mnt/secret

Close Encrypted LV

1
2
3
4
5
6
7
8
# Unmount filesystem
umount /mnt/secret

# Deactivate LV
lvchange -an vg_data/secret_lv

# Or close LUKS container
cryptsetup close crypt_lv

Change Passphrase

1
2
3
4
5
6
# For LUKS on PV
cryptsetup luksChangeKey /dev/sdb1

# For LVM encryption
lvchange --keyfile /dev/vg_data/secret_lv
# Follow prompts

Encryption Considerations:

  • Performance overhead (hardware AES-NI reduces impact)
  • Key management: store keys securely
  • Backup LUKS headers: cryptsetup luksHeaderBackup
  • Consider TPM integration for automated unlocking
  • Use strong ciphers and key sizes

Practical Use Cases

Use Case 1: Dynamic Web Server Storage

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# Create VG for web data
vgcreate vg_web /dev/sdb1 /dev/sdc1

# Create thin pool for flexible growth
lvcreate -L 50G -T vg_web/thinpool

# Create thin volumes for each site
lvcreate -V 20G -T vg_web/thinpool -n site1
lvcreate -V 30G -T vg_web/thinpool -n site2

# Format and mount
mkfs.xfs /dev/vg_web/site1
mkfs.xfs /dev/vg_web/site2

# Add to /etc/fstab
echo "/dev/vg_web/site1 /var/www/site1 xfs defaults 0 0" >> /etc/fstab
echo "/dev/vg_web/site2 /var/www/site2 xfs defaults 0 0" >> /etc/fstab

Use Case 2: Database with Snapshots

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# Create VG for database
vgcreate vg_db /dev/sdd1 /dev/sde1

# Create LV for database
lvcreate -L 100G -n mysql_data vg_db
mkfs.xfs /dev/vg_db/mysql_data

# Mount and configure MySQL
mount /dev/vg_db/mysql_data /var/lib/mysql

# Daily backup using snapshot
lvcreate -s -n mysql_snap -l 100%FREE vg_db/mysql_data
mount -o ro /dev/vg_db/mysql_snap /mnt/backup
# Backup /mnt/backup
umount /mnt/backup
lvremove vg_db/mysql_snap

Use Case 3: Expand Root Filesystem (Proxmox Example)

1
2
3
4
5
6
# From your existing post:
# 1. Resize disk in Proxmox GUI
# 2. Resize partition: parted resizepart 3 100%
# 3. Resize PV: pvresize /dev/sda3
# 4. Extend LV: lvextend -r -l +100%FREE /dev/mapper/pbs-root
# 5. Verify: df -h

Use Case 4: Live Migration to New Storage

1
2
3
4
5
6
7
8
9
10
11
12
# Add new disk
pvcreate /dev/sdf1
vgextend vg_data /dev/sdf1

# Move data from old to new disk
pvmove /dev/sdb1

# Remove old disk
vgreduce vg_data /dev/sdb1
pvremove /dev/sdb1

# Now can physically remove old disk

Troubleshooting

Common Issues and Solutions

Issue 1: “Insufficient free space” when creating LV

1
2
3
4
5
6
7
8
9
10
# Check VG free space
vgs vg_name

# Check PVs in VG
pvs

# Add more space:
# 1. Add new disk: pvcreate /dev/sdd1
# 2. Extend VG: vgextend vg_name /dev/sdd1
# 3. Retry lvcreate

Issue 2: LV won’t reduce - “Filesystem is mounted”

1
2
3
4
5
6
7
# Unmount first
umount /mount/point

# Or use rescue mode if root filesystem
# Boot from live CD, then reduce

# For xfs: cannot shrink, must backup and recreate

Issue 3: Snapshot fills up and LV becomes read-only

1
2
3
4
5
6
7
# Monitor snapshot usage
lvs -o +thin_percent

# Extend snapshot if needed
lvextend -L +5G /dev/vg_data/snap_name

# Or remove and recreate larger snapshot

Issue 4: “Device is busy” when removing PV

1
2
3
4
5
6
7
# Check what's using the PV
pvs -o+pv_used

# Move data off PV
pvmove /dev/sdb1

# Wait for completion, then retry vgreduce

Issue 5: LVM commands not found

1
2
3
4
5
6
7
8
9
10
# Install LVM2
# Debian/Ubuntu:
apt-get install lvm2

# RHEL/CentOS:
yum install lvm2

# Start LVM services
systemctl enable --now lvm2-lvmetad
systemctl enable --now lvm2-lvmpolld

Issue 6: Boot problems after LVM changes

1
2
3
4
5
6
7
8
9
# Check initramfs includes LVM
update-initramfs -u  # Debian/Ubuntu
dracut -f           # RHEL/CentOS

# Verify /etc/fstab uses correct LV paths
cat /etc/fstab

# Test LVM activation
vgchange -ay

Recovery Commands

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# Scan for PVs
pvscan

# Activate all LVs
vgchange -ay

# Deactivate all LVs
vgchange -an

# Check LVM metadata backup
vgcfgrestore -f /etc/lvm/archive/vg_name_*.vg vg_name

# Restore from backup if VG corrupted
vgcfgrestore vg_name

Best Practices

1. Naming Conventions

1
2
3
4
5
6
# Use descriptive names
vg_name: vg_data, vg_root, vg_web
lv_name: lv_mysql, lv_postgres, lv_logs

# Avoid spaces and special characters
# Use underscores or hyphens

2. PE Size Selection

1
2
3
4
5
6
# Default: 4MB (good for most cases)
# For large LVs (>1TB), consider larger PE:
vgcreate -s 8M vg_name /dev/sdb1

# For many small LVs, smaller PE reduces waste:
vgcreate -s 1M vg_name /dev/sdb1

3. Filesystem Choice

1
2
3
4
5
6
7
8
# XFS: Best for large files, high performance, cannot shrink
mkfs.xfs /dev/vg_name/lv_name

# EXT4: Can shrink, journaling, good general purpose
mkfs.ext4 /dev/vg_name/lv_name

# Btrfs: Snapshots, compression, RAID (still experimental)
mkfs.btrfs /dev/vg_name/lv_name

4. Monitoring

1
2
3
4
5
6
7
# Add to crontab for regular monitoring
*/5 * * * * /usr/bin/lvs --units g >> /var/log/lvm_monitor.log

# Set up alerts for thin pool usage
# Alert if Data% > 90%
lvs --noheadings -o vg_name,lv_name,data_percent | \
  awk '$3 > 90 { print "ALERT: " $0 }'

5. Backup LVM Configuration

1
2
3
4
5
6
7
8
# Backup LVM metadata (automatic, but verify)
ls /etc/lvm/archive/

# Manual backup
vgcfgbackup vg_name

# Restore if needed
vgcfgrestore vg_name

6. Performance Tuning

1
2
3
4
5
6
7
8
9
10
# Set I/O scheduler for SSD
echo 'noop' > /sys/block/sdX/queue/scheduler

# For HDD, use 'deadline' or 'cfq'

# Adjust read_ahead
blockdev --setra 256 /dev/mapper/vg_name-lv_name

# Monitor I/O
iostat -x 1

7. Security

1
2
3
4
5
6
7
8
# Restrict LVM commands to root
chmod 700 /usr/sbin/lvm

# Use SELinux/AppArmor for LVM
# Enable LVM encryption for sensitive data

# Audit LVM commands
auditctl -w /usr/sbin/lvcreate -p x -k lvm

8. Documentation

1
2
3
4
5
6
# Document your LVM layout
lvs -o +lv_attr > lvm_layout.txt
pvs >> lvm_layout.txt
vgs >> lvm_layout.txt

# Keep in /root or version control

Quick Reference Commands

Physical Volumes

1
2
3
4
5
pvcreate /dev/sdb1              # Create PV
pvdisplay                      # Show all PVs
pvs                            # Compact PV list
pvremove /dev/sdb1             # Remove PV
pvmove /dev/sdb1               # Move data off PV

Volume Groups

1
2
3
4
5
6
vgcreate vg_data /dev/sdb1     # Create VG
vgextend vg_data /dev/sdc1     # Extend VG
vgdisplay vg_data              # Show VG
vgs                           # Compact VG list
vgreduce vg_data /dev/sdb1     # Remove PV from VG
vgremove vg_data               # Delete VG

Logical Volumes

1
2
3
4
5
6
7
lvcreate -L 10G -n lv_root vg_data    # Create 10GB LV
lvcreate -l 100%FREE -n lv_new vg_data # Use all free space
lvdisplay /dev/vg_data/lv_root        # Show LV
lvs                                  # Compact LV list
lvextend -L +5G /dev/vg_data/lv_root # Extend LV by 5GB
lvreduce -L 15G /dev/vg_data/lv_root # Reduce to 15GB
lvremove /dev/vg_data/lv_root         # Delete LV

Snapshots

1
2
3
4
lvcreate -s -n snap_name -L 5G /dev/vg_data/lv_original  # Create
mount -o ro /dev/vg_data/snap_name /mnt/snap             # Mount
lvconvert --merge vg_data/snap_name                      # Merge
lvremove vg_data/snap_name                               # Delete

Thin Provisioning

1
2
3
4
lvcreate -L 100G -T vg_data/thinpool                    # Create thin pool
lvcreate -V 500G -T vg_data/thinpool -n thin_vol        # Create thin LV
lvs -o +data_percent,thin_percent                       # Check usage
lvextend -L +50G vg_data/thinpool                       # Extend pool

Resizing Filesystems

1
2
3
resize2fs /dev/vg_data/lv_root      # ext4 (online)
xfs_growfs /mount/point             # XFS (online)
btrfs filesystem resize max /mount/point  # Btrfs

Conclusion

LVM is an indispensable tool for modern system administration. From simple disk management to advanced features like thin provisioning, snapshots, and caching, LVM provides the flexibility needed in dynamic environments.

Key Takeaways:

  1. Start with basics: Master PV → VG → LV workflow
  2. Use snapshots: Essential for backups and testing
  3. Consider thin provisioning: Efficient space utilization
  4. Plan for growth: Leave free space in VGs
  5. Monitor regularly: Especially thin pools and mirrors
  6. Document everything: LVM layouts can get complex
  7. Test in lab: Advanced features need practice

Next Steps:

  • Set up a test environment to practice LVM operations
  • Experiment with snapshots and thin provisioning
  • Implement LVM in your infrastructure gradually
  • Monitor performance and adjust configurations
  • Stay updated with LVM2 developments

Additional Resources

  • Man pages: man lvm, man pvcreate, man vgcreate, man lvcreate
  • Official docs: https://sourceware.org/lvm2/
  • Tutorials: https://tldp.org/HOWTO/LVM-HOWTO/
  • Community: https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/

Happy Volume Managing! 🐧

This post is licensed under CC BY 4.0 by the author.