You will build a flexible LVM storage stack on a server and grow a live filesystem without unmounting it. By the end you will expand capacity with zero downtime, the way production systems add space.

Learning Objectives

  • Assemble physical volumes into a volume group.
  • Carve a logical volume and put a filesystem on it.
  • Extend the volume and filesystem online.
  • Time: ~3 hours · Difficulty: Advanced · Prereqs: a server with two spare disks.

Architecture Overview

Environment Setup

You will need: a Linux server with LVM2 and two empty disks (/dev/sdb, /dev/sdc).

Before you begin: verify the disks are empty with lsblk.

Prerequisites

  • Linux with lvm2 installed and two spare block devices (or loop files).
  • Root or sudo access for all storage operations.
  • The disk management lab for partitioning context (optional but helpful).
  • A filesystem choice: ext4 for this lab (resize2fs shown).

Step-by-Step Execution

01
Initialize physical volumes and a group

This labels the disks for LVM and pools them into one resizable group.

sudo pvcreate /dev/sdb /dev/sdc && sudo vgcreate data /dev/sdb /dev/sdc
[ROOT REQUIRED] Creates PVs and the 'data' volume group.

Expected output:

  Physical volume "/dev/sdb" successfully created.
  Physical volume "/dev/sdc" successfully created.
  Volume group "data" successfully created

What this teaches: pvcreate stamps disks as LVM-managed; vgcreate pools their extents into one resizable volume group named data. Check free space with sudo vgs before carving volumes; the default physical extent size is 4 MiB (adjust with vgcreate -s if you plan many small LVs).

02
Create and format a logical volume

The LV behaves like a partition but can grow across both disks.

sudo lvcreate -L 10G -n srv data && sudo mkfs.ext4 /dev/data/srv

Expected output:

  Logical volume "srv" created.
Creating filesystem with 2621440 4k blocks: done

What this teaches: lvcreate carves a 10G logical volume from the pool; mkfs.ext4 formats the resulting /dev/data/srv device like any partition.

03
Mount it
sudo mkdir -p /srv/store && sudo mount /dev/data/srv /srv/store

Expected output:

(no output on success; verify with: df -h /srv/store)

What this teaches: The LV is a normal block device: mkdir the mountpoint and mount it. From here applications cannot tell it is not a partition.

04
Grow the volume online

Extend the LV, then grow the filesystem, all while it stays mounted and in use.

Expected output:

# lvextend -L +5G /dev/data/srv && resize2fs /dev/data/srv
Size of logical volume data/srv changed from 10.00 GiB (2560 extents) to 15.00 GiB (3840 extents). The filesystem on /dev/data/srv is now 3932160 (4k) blocks long.

What this teaches: lvextend grows the device and resize2fs grows the filesystem, both online. This two-phase growth is the core LVM superpower. Shortcut: lvextend -r (or --resizefs) runs the filesystem grow for you; the manual two steps are shown here so you see both layers. For XFS the second step is xfs_growfs /srv/store instead of resize2fs.

How It Works

LVM decouples logical storage from physical disks through extents: PVs donate fixed-size chunks to the VG pool, and LVs are allocated from the pool regardless of which disk backs them. An LV can therefore span disks, and growing it is an allocation decision, not a repartitioning.

The device-mapper layer in the kernel presents each LV as /dev/VG/LV, translating I/O to the underlying extents. Because this mapping is dynamic, operations like extension, snapshotting, and even migration (pvmove) happen while the filesystem stays mounted and serving.

For servers this means capacity planning becomes reversible: grow volumes as data arrives, add PVs to the VG when the pool runs low, and snapshot before risky changes. Plain partitions offer none of this without downtime.

Progress So Far

Testing & Validation

df -h /srv/store && sudo vgs && sudo lvs && lsblk -f /dev/data/srv

You should see the larger size while the mount stayed active, and lsblk -f confirms the ext4 label on the LV. If so, you grew storage with zero downtime.

Troubleshooting

SymptomLikely causeFix
lvextend succeeded but df unchangedFilesystem not grown after the deviceRun resize2fs for ext4 or xfs_growfs for XFS on the mounted LV
No free extents in VGPool exhaustedvgextend the VG with another PV, then retry
pvcreate: device has existing signaturesOld partition table or filesystem remainsConfirm the disk is expendable, then wipefs -a before pvcreate
LV path missing under /dev/data/Device-mapper did not activate the LVRun vgchange -ay data and check lvscan
Cannot deactivate VG: LVs in useVolumes still mounted or openUnmount all LVs, deactivate snapshots first, then vgchange -an
Filesystem check needed after shrinkShrinking requires offline fsck firstPlan shrinks in maintenance windows; ext4 only, XFS cannot shrink
resize2fs: Bad magic number on the LVTargeted the wrong device (for example the raw disk instead of the LV)Always grow /dev/VG/LV, never /dev/sdX; verify with sudo lvs first
Troubleshooting
  • Filesystem size unchanged: run resize2fs (ext4) or xfs_growfs (xfs) after lvextend.
  • VG out of space: add a disk with pvcreate + vgextend before lvextend.
  • Cannot create PV: the disk has an existing signature; wipe with wipefs after confirming it is empty.

Extension Ideas

Key Results

  • Grew a mounted filesystem from 10GB to 15GB with zero downtime.
  • Pooled two disks into one flexible volume group.
  • Decoupled filesystem size from physical disk limits.
  • Verified capacity changes with df, vgs, and lvs.

Key Takeaways

  • PVs pool extents into a VG; LVs allocate from the pool.
  • LVs appear as normal block devices under /dev/VG/LV.
  • Online growth is two steps: lvextend, then filesystem grow.
  • vgextend adds capacity without touching existing LVs.
  • Snapshots (see fundamentals LVM lab) ride on the same layering.

Practice Challenges

Challenge 1: Pool expansion

Goal: fill the VG to 95%, add a third PV with vgextend, then grow the LV into the new space online.

Hint: vgs shows free extents before and after.

Challenge 2: Migrate off a disk

Goal: use pvmove to evacuate all extents from /dev/sdb onto /dev/sdc while the LV stays mounted, then vgreduce sdb out.

Hint: pvmove is online and shows progress.