LVM on Linux: Logical Volume Management for Flexible Disk Storage

LVM changed how I think about disk management. Before LVM, adding storage meant figuring out partitions, worrying about running out of space, and sometimes having to move data around to resize things. With LVM, extending a filesystem is usually a matter of three commands. Shrinking, snapshotting, moving storage between devices — all doable without downtime.

It’s worth understanding even if you’re not immediately going to use it, because a lot of servers come with LVM configured by default.

The Three Layers

LVM has three layers:

Physical Volumes (PVs) — raw block devices: disk partitions, whole disks, or RAID arrays. These are what LVM takes ownership of.

Volume Groups (VGs) — a pool of storage created from one or more PVs. Think of it as a single large virtual disk made from all your PVs combined.

Logical Volumes (LVs) — the partitions you actually format and mount, carved out of a VG. Flexible in size, can span multiple PVs transparently.

Physical devices: /dev/sdb, /dev/sdc, /dev/sdd
        ↓ pvcreate
Physical Volumes (PVs)
        ↓ vgcreate
Volume Group (VG): data_vg (combined storage)
        ↓ lvcreate
Logical Volumes (LVs): /dev/data_vg/db, /dev/data_vg/logs
        ↓ mkfs, mount
Filesystems: ext4, xfs, etc.

Setting Up LVM

Start with a new disk (/dev/sdb in this example):

# Install LVM tools
apt install lvm2

# Create a physical volume
pvcreate /dev/sdb

# Check it
pvdisplay /dev/sdb
pvs

Create a volume group:

vgcreate data_vg /dev/sdb

# Check it
vgdisplay data_vg
vgs

Create logical volumes:

# Create a 50GB volume for database
lvcreate -L 50G -n db data_vg

# Create a 20GB volume for logs
lvcreate -L 20G -n logs data_vg

# Check
lvdisplay
lvs

Format and mount:

mkfs.ext4 /dev/data_vg/db
mkfs.ext4 /dev/data_vg/logs

mkdir -p /mnt/db /mnt/logs
mount /dev/data_vg/db /mnt/db
mount /dev/data_vg/logs /mnt/logs

Add to /etc/fstab for persistent mounts:

/dev/data_vg/db    /mnt/db    ext4    defaults    0 2
/dev/data_vg/logs  /mnt/logs  ext4    defaults    0 2

Extending a Logical Volume

The most common operation — you’re running out of space and need more:

# Extend the LV by 20GB
lvextend -L +20G /dev/data_vg/db

# Or extend to a specific size
lvextend -L 80G /dev/data_vg/db

# Extend to use all remaining free space in the VG
lvextend -l +100%FREE /dev/data_vg/db

Then extend the filesystem to use the new space (while mounted and online):

# ext4
resize2fs /dev/data_vg/db

# xfs (can only grow, not shrink)
xfs_growfs /mnt/db

# Combined: extend LV and resize filesystem in one command
lvextend -L +20G --resizefs /dev/data_vg/db

--resizefs is convenient — it extends the LV and resizes the filesystem in one step, without needing to unmount.

Adding a New Disk to an Existing VG

Over time, you add new drives. Add a new disk to an existing VG:

# Add the disk as a new PV
pvcreate /dev/sdc

# Add to existing VG
vgextend data_vg /dev/sdc

Now the VG has more free space and you can extend existing LVs or create new ones.

Shrinking Logical Volumes

Shrinking is possible with ext4 but riskier and requires unmounting:

# Unmount first
umount /mnt/db

# Check filesystem
e2fsck -f /dev/data_vg/db

# Shrink filesystem (shrink before the LV!)
resize2fs /dev/data_vg/db 40G

# Then shrink the LV
lvreduce -L 40G /dev/data_vg/db

# Remount
mount /dev/data_vg/db /mnt/db

Shrink the filesystem before the LV — if you shrink the LV first, you’ll truncate the filesystem and lose data. And always back up before shrinking. I’ve only had to shrink LVs a handful of times, and I back up every time.

XFS cannot be shrunk. Plan accordingly if you use XFS.

LVM Snapshots

Snapshots are instant, space-efficient copies of an LV at a point in time. Incredibly useful for backups or before risky operations:

# Create a snapshot (10GB initial size for the change log)
lvcreate -s -n db_snap -L 10G /dev/data_vg/db

The snapshot starts empty and grows as the original LV changes. The 10G size limits how much change you can track before the snapshot is invalidated — size it based on how long you need the snapshot and how much data changes.

Mount and back up the snapshot:

mkdir /mnt/db_snap
mount -o ro /dev/data_vg/db_snap /mnt/db_snap
# back up from /mnt/db_snap
rsync -av /mnt/db_snap/ /backup/db/
umount /mnt/db_snap

Remove the snapshot when done:

lvremove /dev/data_vg/db_snap

Moving LV Data Between PVs

Useful when replacing a disk — migrate data from old disk to new disk online:

# Add new disk to VG
pvcreate /dev/sdd
vgextend data_vg /dev/sdd

# Move data from /dev/sdb to /dev/sdd (while the LV is mounted and in use)
pvmove /dev/sdb /dev/sdd

# Check progress
pvmove  # shows status if a move is in progress

# Remove old disk from VG
vgreduce data_vg /dev/sdb

# Release the PV
pvremove /dev/sdb

pvmove works online. It’s slow (moving GB of data takes time), but the filesystem stays mounted and accessible throughout. This is how I replace disks without downtime.

Checking Status

pvs    # Physical volumes summary
vgs    # Volume groups summary
lvs    # Logical volumes summary

# More detail
pvdisplay
vgdisplay data_vg
lvdisplay /dev/data_vg/db

# Full map of everything
lsblk

Thin Provisioning

LVM supports thin provisioning — allocating more storage to LVs than physically exists, with the assumption not all of it will be used at once.

# Create a thin pool
lvcreate -L 100G --thinpool data_pool data_vg

# Create thin LVs (overprovisioned)
lvcreate -V 50G --thin -n vm1 data_vg/data_pool
lvcreate -V 50G --thin -n vm2 data_vg/data_pool
lvcreate -V 50G --thin -n vm3 data_vg/data_pool

Total allocated: 150G from a 100G pool. It works as long as actual usage stays under 100G. Thin LV snapshots are more space-efficient than regular snapshots.

I use thin provisioning in virtual machine environments where VMs don’t all fill their disks simultaneously. For databases and high-IO workloads, I generally don’t — the complexity and the risk of running out of space (thin pool full = disaster) isn’t worth it.

LVM and System Backups

LVM snapshots pair well with backup strategies. Instead of backing up a live database that might be writing during the backup:

  1. Create a snapshot of the database LV
  2. Back up from the snapshot (consistent state)
  3. Remove the snapshot

The backup tool doesn’t need to know anything about LVM — it just backs up from the snapshot mountpoint. For integration with tools like rsync backups or database dumps, LVM snapshots provide a clean, consistent point-in-time source.

Scroll to Top