💽

Level 8 of 24

Storage & LVM

Disks, partitions, filesystems, and Logical Volume Management end to end.

Disks don't become usable storage on their own — they need partitioning, a filesystem, and a mount point, and production systems almost always add LVM as a flexible layer in between. This level builds that chain from raw disk to resizable, mounted storage.

Prerequisites

  • • Level 3: Filesystem

By the end of this level, you can

  • ✓ Explain the chain from raw disk to mounted, usable storage
  • ✓ List and inspect disks, partitions, and mounted filesystems
  • ✓ Explain LVM's physical volume → volume group → logical volume architecture
  • ✓ Extend a logical volume's size without data loss

Disks, partitions, filesystems, and mounting

The full chain from a raw block device to something you can read and write files on. · 11 min

A block device (`/dev/sda`, `/dev/nvme0n1`) represents a raw disk as the kernel sees it — unusable for files directly until it's partitioned and formatted. Partitioning divides a disk into logical sections, recorded in a partition table using one of two schemes: the older MBR (Master Boot Record, limited to 4 primary partitions and 2TB disks) or the modern GPT (GUID Partition Table, supporting far larger disks and more partitions) — GPT is the standard choice for any new system today.

A filesystem then formats a partition (or an LVM logical volume) with a structure for actually organizing files and directories — ext4 is the long-standing, reliable default on most Linux distributions; XFS is common on RHEL-family systems and excels with very large files and filesystems; Btrfs offers built-in snapshots and checksumming at the cost of more complexity. Creating a filesystem (`mkfs`) is what turns an empty partition into something `mount` can actually attach to the directory tree.

Mounting attaches a filesystem to a specific point in the existing directory tree, making its contents accessible at that path — `mount /dev/sdb1 /mnt/data` makes that partition's files appear under `/mnt/data`. A mount performed manually like this doesn't survive a reboot; `/etc/fstab` is the file that defines mounts to be applied automatically at boot, referencing each filesystem by its UUID (a stable identifier, preferred over a device name like `/dev/sdb1` which can shift if disks are added or removed) rather than a device path that isn't guaranteed stable across reboots.

CommandPurposeExample
lsblkList block devices and their partitions/mount points in a tree view—
blkidShow filesystem type and UUID for each block device—
fdisk / gdiskCreate, delete, and inspect partitions (fdisk for MBR, gdisk for GPT — both interactive)—
partedAlternative partitioning tool supporting both MBR and GPT, scriptable—
mkfs.ext4 / mkfs.xfsCreate a filesystem on a partitionsudo mkfs.ext4 /dev/sdb1
mount / umountAttach or detach a filesystem at a directorysudo mount /dev/sdb1 /mnt/data
df -hShow disk space usage per mounted filesystem—
du -shShow total size of a specific directorydu -sh /var/log

Common Mistakes

  • ⚠ Referencing a mount by device name (`/dev/sdb1`) in `/etc/fstab` instead of UUID — device names can shift if disks are added, removed, or the boot order changes
  • ⚠ Running `mkfs` on the wrong device and destroying existing data — always double- and triple-check the device path with `lsblk` first
  • ⚠ Forgetting that a manual `mount` command doesn't survive a reboot without a corresponding `/etc/fstab` entry

Takeaway: The chain is always disk → partition → filesystem → mount point — and `/etc/fstab` referenced by UUID, not device name, is what makes a mount survive a reboot.

LVM: physical volumes, volume groups, and logical volumes

Why almost every production Linux server uses LVM instead of raw partitions directly. · 13 min

Logical Volume Management (LVM) adds a flexible layer between raw disks and filesystems, solving a real limitation of plain partitions: a plain partition's size is essentially fixed at creation and awkward to resize, especially to grow across what used to be free space on a different disk entirely. LVM's architecture has three layers: a Physical Volume (PV) is a disk or partition initialized for LVM use; a Volume Group (VG) pools one or more PVs together into a single unit of available storage, regardless of how many physical disks back it; a Logical Volume (LV) is then carved out of a VG's pooled space, and it's the LV that actually gets formatted with a filesystem and mounted — behaving, from the filesystem's perspective, just like a regular partition would.

The payoff is flexibility: you can extend a Volume Group by simply adding another Physical Volume (another disk) to it, and then extend a Logical Volume to use that newly available space — growing storage without needing to have predicted the exact right size upfront, and often without unmounting anything (ext4 and XFS both support online, live resizing when growing, though shrinking is more restrictive and filesystem-dependent).

The complete build chain: `pvcreate` initializes a disk/partition as a PV. `vgcreate` creates a VG from one or more PVs. `lvcreate` carves out an LV from the VG's free space. `mkfs` formats the LV with a filesystem exactly as you would a plain partition. `mount` attaches it. To later grow it: `lvextend` grows the LV's size within the VG's available space, and then a filesystem-specific resize command (`resize2fs` for ext4, `xfs_growfs` for XFS) extends the filesystem itself to actually use that newly available space — extending the LV alone does not automatically grow the filesystem sitting on top of it.

CommandPurposeExample
pvcreate /dev/sdb1Initialize a partition/disk as a Physical Volume—
pvsList Physical Volumes—
vgcreate myvg /dev/sdb1Create a Volume Group from one or more Physical Volumes—
vgsList Volume Groups—
lvcreate -L 10G -n mylv myvgCreate a 10GB Logical Volume named "mylv" in Volume Group "myvg"—
lvsList Logical Volumes—
lvextend -L +5G /dev/myvg/mylvGrow a Logical Volume by 5GB—
resize2fs /dev/myvg/mylvGrow an ext4 filesystem to fill its Logical Volume after lvextend—

Physical Volume → Volume Group → Logical Volume → Filesystem

/dev/sdb (disk)
  ↓ pvcreate
Physical Volume
  ↓ vgcreate
Volume Group (pools one or more PVs)
  ↓ lvcreate
Logical Volume (carved from the VG's free space)
  ↓ mkfs.ext4
Filesystem
  ↓ mount
Usable, mounted storage
🧪

Hands-On Lab

Build and extend LVM storage from scratch

Objectives

  • ✓ Build the full chain: Physical Volume → Volume Group → Logical Volume → filesystem → mount
  • ✓ Write a test file and confirm it persists
  • ✓ Extend the Logical Volume and grow the filesystem to use the new space
⚠️ Warning: This lab involves destructive disk operations (pvcreate, mkfs) — only run this against a disposable VM's extra virtual disk, never against a disk containing real data.

Instructions

  1. Attach a second, empty virtual disk to your VM (e.g. 5GB) and confirm it appears as `/dev/sdb` via `lsblk`.
  2. Initialize it as a Physical Volume: `sudo pvcreate /dev/sdb`.
  3. Create a Volume Group: `sudo vgcreate labvg /dev/sdb`.
  4. Create a 3GB Logical Volume: `sudo lvcreate -L 3G -n labvol labvg`.
  5. Format it: `sudo mkfs.ext4 /dev/labvg/labvol`.
  6. Mount it: `sudo mkdir -p /mnt/lab && sudo mount /dev/labvg/labvol /mnt/lab`, then create a test file inside it.
  7. Extend the Logical Volume to use the remaining free space: `sudo lvextend -l +100%FREE /dev/labvg/labvol`.
  8. Grow the filesystem to match: `sudo resize2fs /dev/labvg/labvol`, then confirm the new size with `df -h /mnt/lab`.
Hints (2)
  • If `pvcreate` fails, confirm you're targeting the correct, genuinely empty disk with `lsblk` — never run it against a disk holding data you need.
  • The extend step is two commands, not one — `lvextend` grows the logical volume, `resize2fs` (or `xfs_growfs` for XFS) grows the filesystem sitting on top of it.

Quick Check

After running `lvextend -L +5G` on a logical volume, the filesystem on it still shows the old, smaller size in `df -h`. What step was missed?

Takeaway: Extending storage under LVM is always two steps, not one: `lvextend` grows the logical volume, and a separate filesystem-specific resize command grows the filesystem to actually use that new space.

Sponsor / Advertisement