For this recipe (Ubuntu 22.04 focal), the setup has three SCSI disks that will be combined into a logical volume using LVM. The disks sit at /dev/sda, /dev/sdb, and /dev/sdc. Ignore the OS disk, which we leave untouched.
LVM (the Logical Volume Manager) puts a layer between the physical disks and the filesystems you actually mount. Instead of formatting each disk on its own and juggling three separate mount points, you pool the disks into a single volume group and then carve logical volumes out of that pool. The payoff is flexibility. You can grow a volume later, add a fourth disk to the group without repartitioning, or move data between disks while the system stays online. The trade-off is one extra layer to understand and, if you are pooling disks without redundancy, one more point of failure: lose a physical disk in a linear volume group and you risk the data that lived on it. Plan your backups accordingly, which is partly why one of the volumes below is dedicated to exactly that.
The three layers you will build here, from the bottom up, are physical volumes (the raw disks prepared for LVM), the volume group (the pool), and logical volumes (the usable slices you format and mount). Keep that hierarchy in mind and each command below reads as a step up the stack.
Disk /dev/nvme0n1: 1.76 TiB, 1920383410176 bytes, 3750748848 sectors Disk model: SAMSUNG MZQL21T9HCJR-00A07 Units: sectors of 1 * 512 = 512 bytes Sector size (logical/physical): 512 bytes / 4096 bytes I/O size (minimum/optimal): 131072 bytes / 131072 bytes Disklabel type: dos Disk identifier: 0x0edc49ab Device Boot Start End Sectors Size Id Type /dev/nvme0n1p1 2048 8390655 8388608 4G 82 Linux swap / Solaris /dev/nvme0n1p2 8390656 10487807 2097152 1G 83 Linux /dev/nvme0n1p3 10487808 3750746799 3740258992 1.8T 83 Linux Disk /dev/sda: 7.28 TiB, 8001563222016 bytes, 15628053168 sectors Disk model: HGST HUH721008AL Units: sectors of 1 * 512 = 512 bytes Sector size (logical/physical): 512 bytes / 4096 bytes I/O size (minimum/optimal): 4096 bytes / 4096 bytes Disklabel type: gpt Disk identifier: 5DDAA99D-057D-5A45-90FF-C9DC826FCE7D Disk /dev/sdb: 7.28 TiB, 8001563222016 bytes, 15628053168 sectors Disk model: HGST HUH721008AL Units: sectors of 1 * 512 = 512 bytes Sector size (logical/physical): 512 bytes / 4096 bytes I/O size (minimum/optimal): 4096 bytes / 4096 bytes Disklabel type: gpt Disk identifier: 0A481C8C-79A2-0347-94EA-B2DF6361BF5F Disk /dev/sdc: 14.57 TiB, 16000900661248 bytes, 31251759104 sectors Disk model: ST16000NM003G-2K Units: sectors of 1 * 512 = 512 bytes Sector size (logical/physical): 512 bytes / 4096 bytes I/O size (minimum/optimal): 4096 bytes / 4096 bytes Disklabel type: gpt Disk identifier: E1266E34-E31B-DF45-BC60-9D5565C11BC8
Preparing the disks
First, we clean the drives. Wiping any existing partition tables or filesystem signatures avoids surprises later, since LVM will refuse to touch a disk it thinks is already in use, and stale metadata is a common cause of confusing errors. Be certain you are pointing at the right devices before you run anything destructive. A quick lsblk to confirm sizes and mount points is cheap insurance against wiping the wrong disk.
root@server ~ # wipefs -a /dev/sda /dev/sda: 8 bytes were erased at offset 0x00000200 (gpt): 45 46 49 20 50 41 52 54 /dev/sda: 8 bytes were erased at offset 0x74702555e00 (gpt): 45 46 49 20 50 41 52 54 /dev/sda: 2 bytes were erased at offset 0x000001fe (PMBR): 55 aa /dev/sda: calling ioctl to re-read partition table: Success root@server ~ # wipefs -a /dev/sdb /dev/sdb: 8 bytes were erased at offset 0x00000200 (gpt): 45 46 49 20 50 41 52 54 /dev/sdb: 8 bytes were erased at offset 0x74702555e00 (gpt): 45 46 49 20 50 41 52 54 /dev/sdb: 2 bytes were erased at offset 0x000001fe (PMBR): 55 aa /dev/sdb: calling ioctl to re-read partition table: Success root@server ~ # wipefs -a /dev/sdc /dev/sdc: 8 bytes were erased at offset 0x00000200 (gpt): 45 46 49 20 50 41 52 54 /dev/sdc: 8 bytes were erased at offset 0xe8d7ffffe00 (gpt): 45 46 49 20 50 41 52 54 /dev/sdc: 2 bytes were erased at offset 0x000001fe (PMBR): 55 aa /dev/sdc: calling ioctl to re-read partition table: Success
With the disks clean, we can run pvcreate to initialise each one as a physical volume. This writes a small LVM header to the start of each disk and marks it as available to the manager.
root@server ~ # pvcreate /dev/sda Physical volume "/dev/sda" successfully created. root@server ~ # pvcreate /dev/sdb Physical volume "/dev/sdb" successfully created. root@server ~ # pvcreate /dev/sdc Physical volume "/dev/sdc" successfully created.
Run pvs to confirm the physical volumes exist. You should see all three disks listed, each showing its size and, at this stage, no volume group assignment yet.
root@server ~ # pvs PV VG Fmt Attr PSize PFree /dev/sda lvm2 --- <7.28t <7.28t /dev/sdb lvm2 --- <7.28t <7.28t /dev/sdc lvm2 --- 14.55t 14.55t
Building the volume group
Now create a volume group. This is the step that pools the three physical volumes into one addressable space. From here on you allocate storage from the group rather than thinking about individual disks, and the group can span all three at once.
root@server ~ # vgcreate vg00 /dev/sda /dev/sdb /dev/sdc Volume group "vg00" successfully created root@server ~ # vgdisplay vg00 --- Volume group --- VG Name vg00 System ID Format lvm2 Metadata Areas 3 Metadata Sequence No 1 VG Access read/write VG Status resizable MAX LV 0 Cur LV 0 Open LV 0 Max PV 0 Cur PV 3 Act PV 3 VG Size <29.11 TiB PE Size 4.00 MiB Total PE 7630353 Alloc PE / Size 0 / 0 Free PE / Size 7630353 / <29.11 TiB VG UUID CTRQ1a-MlEv-bFZy-7Ph9-eo0Q-mEQU-BBCewT
It is time to create one or more logical volumes on top of the volume group. I will create a 500GB volume for system backups, and the remaining space will become a second volume for media files. The -n option names the LV, -L sets a fixed size, and -l (lowercase L) sets a percentage of the remaining space in the container VG. Using a percentage for the second volume means you do not have to calculate the leftover capacity by hand: 100%FREE simply consumes whatever the backup volume left behind.
Splitting the pool this way is a deliberate choice rather than a technical requirement. Separate volumes let you apply different filesystems, mount options, or quota rules to backups and media, and they keep a runaway media library from filling the space your backups depend on. If you later find the ratio wrong, you can extend the backup volume into free space or shrink one volume to grow another, which is the whole reason to run LVM instead of plain partitions.
root@server ~ # lvcreate -n vol_backups -L 500G vg00 Logical volume "vol_backups" created. root@server ~ # lvcreate -n vol_media -l 100%FREE vg00 Logical volume "vol_media" created.
Run lvdisplay to check the result. It reports each logical volume, its size, and the device path you will use in the next steps.
root@server ~ # lvdisplay --- Logical volume --- LV Path /dev/vg00/vol_backups LV Name vol_backups VG Name vg00 LV UUID 4ULTFr-JTum-tOXD-byLF-FvCz-UzwJ-UsGnfq LV Write Access read/write LV Creation host, time server.darkq.net, 2023-05-10 17:15:43 +0200 LV Status available # open 0 LV Size 500.00 GiB Current LE 128000 Segments 1 Allocation inherit Read ahead sectors auto - currently set to 256 Block device 253:0 --- Logical volume --- LV Path /dev/vg00/vol_media LV Name vol_media VG Name vg00 LV UUID FubLXZ-3fPe-A9fP-HYdl-eauq-vSsi-Ls3JJA LV Write Access read/write LV Creation host, time server.darkq.net, 2023-05-10 17:17:23 +0200 LV Status available # open 0 LV Size <28.62 TiB Current LE 7502353 Segments 3 Allocation inherit Read ahead sectors auto - currently set to 256 Block device 253:1
Formatting and mounting
Now create the ext4 filesystems. ext4 is a sensible default for general storage: mature, well supported across distributions, and fast enough for both backup archives and large media files. If you had a specific need, say heavy snapshotting or built-in checksums, you might reach for something else, but for this setup ext4 keeps things simple.
root@server ~ # mkfs.ext4 /dev/vg00/vol_backups mke2fs 1.45.5 (07-Jan-2020) Creating filesystem with 131072000 4k blocks and 32768000 inodes Filesystem UUID: 9decc28e-dae7-469f-b1de-7d6da1fd5fb0 Superblock backups stored on blocks: 32768, 98304, 163840, 229376, 294912, 819200, 884736, 1605632, 2654208, 4096000, 7962624, 11239424, 20480000, 23887872, 71663616, 78675968, 102400000 Allocating group tables: done Writing inode tables: done Creating journal (262144 blocks): done Writing superblocks and filesystem accounting information: done root@server ~ # mkfs.ext4 /dev/vg00/vol_media mke2fs 1.45.5 (07-Jan-2020) Creating filesystem with 7682409472 4k blocks and 480151552 inodes Filesystem UUID: 5b262682-ba8e-4e03-98c2-c742ccebdff8 Superblock backups stored on blocks: 32768, 98304, 163840, 229376, 294912, 819200, 884736, 1605632, 2654208, 4096000, 7962624, 11239424, 20480000, 23887872, 71663616, 78675968, 102400000, 214990848, 512000000, 550731776, 644972544, 1934917632, 2560000000, 3855122432, 5804752896 Allocating group tables: done Writing inode tables: done Creating journal (262144 blocks): done Writing superblocks and filesystem accounting information: done
To mount the new volumes, we first create some identifiers. Referencing volumes by a stable identifier rather than a device name matters because /dev/sda and its siblings can be reassigned across reboots, especially once you add or remove disks. LVM device-mapper paths and filesystem UUIDs stay put, so entries in /etc/fstab keep pointing at the right storage no matter how the kernel enumerates the hardware on the next boot.
root@server ~ # blkid /dev/vg00/vol_backups /dev/vg00/vol_backups: UUID="9decc28e-dae7-469f-b1de-7d6da1fd5fb0" TYPE="ext4" root@server ~ # blkid /dev/vg00/vol_media /dev/vg00/vol_media: UUID="5b262682-ba8e-4e03-98c2-c742ccebdff8" TYPE="ext4"
With the identifiers in place, we can mount the volumes. Add matching lines to /etc/fstab if you want them to come back automatically after a reboot, then run a mount test before you trust it. A single mount -a followed by df -h tells you at a glance whether both volumes are mounted at the expected sizes.
Why this setup earns its keep
The reason to bother with all of this is operational headroom. When the media volume fills up, you extend it into free space or add a disk to the group, and the change is invisible to anything reading from the mount point. When a backup policy changes, you resize the backup volume rather than rebuilding partitions. That kind of quiet flexibility is what separates a storage layout you can live with from one you fight every few months.
It is worth noting that flexibility is not redundancy. A linear volume group across three disks gives you capacity, not fault tolerance. If any one of the three disks dies, the volume that spanned it is compromised. If the data matters, layer this on top of RAID, or make sure the backup volume is genuinely copying to storage that lives elsewhere. LVM does have mirroring and RAID modes of its own if you want to keep everything inside one tool, at the cost of usable capacity.
For anyone running this on a machine that other people depend on, treat the storage layout as part of the service you offer, not just plumbing. The same instinct that makes a business list itself in a curated place so customers can find and trust it applies to infrastructure: documented, predictable systems are easier for the next person to evaluate and maintain. Rachel Botsman, in Who Can You Trust? (2017), describes a shift toward distributed trust, where reputation systems and transparent records let people extend confidence to things they cannot inspect directly. A storage stack you can explain, with stable identifiers and clear volume names, is the same idea at a smaller scale: someone who inherits it can see what you built and why.
The concrete takeaway: pool your disks with LVM when you expect capacity needs to change, name and size your logical volumes for the jobs they do, mount by stable identifier, and pair the whole arrangement with real backups or RAID before you call it done. Do that, and resizing storage six months from now is a one-line command rather than a weekend rebuild.

