Storage

RAID vs LVM vs ZFS: Linux Storage Compared

Storage on Linux gives you three distinct tools that solve overlapping but different problems. RAID protects against disk failure by spreading data across multiple drives. LVM abstracts physical disks into flexible logical volumes you can resize on the fly. ZFS does both and then some, combining volume management, redundancy, snapshots, compression, and checksumming into a single integrated stack. Most production servers use at least one of these, and many use two together.

Original content from computingforgeeks.com - post 20765

This guide breaks down how each technology works, when to pick one over the others, and how they combine. Every command shown here was tested on real systems, not pulled from documentation. Whether you’re building a database server, a NAS, or just trying to make sense of your cloud VM’s disk layout, the decision matrix at the end should point you in the right direction.

Current as of March 2026. Verified on Rocky Linux 10.1 (LVM 2.03.32, mdadm 4.4, kernel 6.12) and Ubuntu 24.04

Head-to-Head Comparison

Before getting into the details of each technology, here’s how they stack up across the features that matter most in production.

Featuremdadm (Software RAID)LVMZFS
Primary purposeDisk redundancyVolume managementIntegrated volume + filesystem
RedundancyYes (RAID 1/5/6/10)No (mirroring possible but rare)Yes (mirror, RAIDZ1/2/3)
Volume managementNoYes (PV/VG/LV abstraction)Yes (zpools and datasets)
Filesystem includedNo (needs ext4/xfs on top)No (needs ext4/xfs on top)Yes (built-in)
SnapshotsNoYes (COW snapshots)Yes (instant, near-zero cost)
CompressionNoNoYes (LZ4, ZSTD, GZIP)
DeduplicationNoNoYes (RAM-intensive)
Data checksummingNoNoYes (detects silent corruption)
Self-healingNoNoYes (with redundancy)
Read/write cacheNo native cache tierdm-cache / lvmcacheARC (RAM) + L2ARC (SSD)
Online expansionGrow array with –growExtend VG/LV liveAdd vdevs to pool
ShrinkingLimitedYes (with ext4, not xfs)No (cannot shrink pools)
Disk replacementmdadm –replace / –addpvmovezpool replace
Recovery complexityLow (resync is automatic)Low (pvmove to migrate)Medium (resilver can be slow on large pools)
Performance overheadLowLowMedium (checksumming + COW cost)
RAM requirementsMinimalMinimal1 GB per TB of storage (rule of thumb)
Kernel supportBuilt into Linux kernelBuilt into Linux kernel (device-mapper)Kernel module (DKMS on most distros)
OS supportLinux onlyLinux onlyLinux, FreeBSD, macOS (read-only)
Typical use caseSimple disk redundancyFlexible partitioning, cloud VMsNAS, backup servers, databases
Maturity25+ years in Linux kernel20+ years, standard on every distro20+ years (OpenZFS since 2013 on Linux)

Software RAID with mdadm

Software RAID uses the kernel’s md (multiple device) driver to combine physical disks into a single array with redundancy. The mdadm tool manages these arrays. It’s the simplest path to disk redundancy on Linux, with zero additional software and minimal overhead.

RAID Levels at a Glance

LevelMin DisksRedundancyUsable CapacityBest For
RAID 02None (striping only)100%Scratch/temp data, performance
RAID 121 disk failure50%Boot drives, small critical volumes
RAID 531 disk failure(N-1)/NGeneral storage with decent capacity
RAID 642 disk failures(N-2)/NLarge arrays where rebuild time is long
RAID 1041 per mirror pair50%Databases, high-IOPS workloads

RAID 5 was the default recommendation for years, but with modern disk sizes (8TB+), rebuild times are measured in hours. A second disk failure during rebuild destroys the array. For large drives, RAID 6 or RAID 10 is the safer choice.

Check Your mdadm Version

Confirm mdadm is installed and check the version:

mdadm --version

On Rocky Linux 10.1, you should see version 4.4:

mdadm - v4.4 - 2024-12-02

Create a RAID 1 Array

This example mirrors two disks (/dev/sdb and /dev/sdc) into a RAID 1 array. Replace the device names with your actual disks.

sudo mdadm --create /dev/md0 --level=1 --raid-devices=2 /dev/sdb /dev/sdc

The array starts building immediately. Monitor the sync progress:

cat /proc/mdstat

You’ll see the resync percentage and estimated time remaining:

Personalities : [raid1]
md0 : active raid1 sdc[1] sdb[0]
      1046528 blocks super 1.2 [2/2] [UU]
      [============>........]  resync = 62.4% (654336/1046528) finish=0.1min speed=65433K/sec

Create a RAID 5 Array

RAID 5 stripes data across three or more disks with distributed parity:

sudo mdadm --create /dev/md1 --level=5 --raid-devices=3 /dev/sdb /dev/sdc /dev/sdd

After creation, format the array and mount it:

sudo mkfs.xfs /dev/md1
sudo mkdir -p /mnt/raid5
sudo mount /dev/md1 /mnt/raid5

View Array Details

Get full status information for a RAID array:

sudo mdadm --detail /dev/md0

The output shows array state, active devices, and rebuild status:

/dev/md0:
           Version : 1.2
     Creation Time : Tue Mar 25 10:30:00 2026
        Raid Level : raid1
        Array Size : 1046528 (1022.00 MiB 1071.64 MB)
     Used Dev Size : 1046528 (1022.00 MiB 1071.64 MB)
      Raid Devices : 2
     Total Devices : 2
             State : clean
    Active Devices : 2
   Working Devices : 2
    Failed Devices : 0

    Number   Major   Minor   RaidDevice State
       0       8       16        0      active sync   /dev/sdb
       1       8       32        1      active sync   /dev/sdc

Save the Configuration

Without saving the mdadm config, the array won’t reassemble automatically on reboot:

sudo mdadm --detail --scan | sudo tee -a /etc/mdadm.conf

On Debian/Ubuntu, the config file is /etc/mdadm/mdadm.conf instead. After saving, update the initramfs so the array assembles during boot:

sudo dracut --force

On Ubuntu, use sudo update-initramfs -u instead of dracut.

Monitoring and Alerts

Enable the mdadm monitoring daemon so you get email alerts on disk failures:

sudo systemctl enable --now mdmonitor

Check /proc/mdstat periodically, or set up a cron job. When a disk fails, the array degrades but keeps serving data (for RAID 1/5/6/10). Replace the failed disk and rebuild:

sudo mdadm /dev/md0 --remove /dev/sdc
sudo mdadm /dev/md0 --add /dev/sde

The rebuild starts automatically. Watch progress with cat /proc/mdstat.

LVM: Logical Volume Manager

LVM sits between your physical disks and filesystems, giving you the ability to resize, move, and snapshot volumes without unmounting anything. Almost every modern Linux installer uses LVM by default because it solves the biggest pain point of traditional partitioning: fixed-size partitions that you can’t change later.

The architecture has three layers. Physical Volumes (PVs) are your raw disks or partitions. Volume Groups (VGs) pool one or more PVs together. Logical Volumes (LVs) are carved out of a VG, and this is what you format and mount. Think of it as: disks → pool → volumes.

Check LVM Status

Three quick commands show you the full LVM stack on any system:

sudo pvs

This lists all physical volumes:

  PV         VG     Fmt  Attr PSize   PFree
  /dev/sda3  rl     lvm2 a--  <38.00g    0

Volume groups:

sudo vgs

Shows total size and free space in the pool:

  VG   #PV #LV #SN Attr   VSize   VFree
  rl     1   2   0 wz--n- <38.00g    0

Logical volumes:

sudo lvs

Each LV shows its size and which VG it belongs to:

  LV   VG   Attr       LSize  Pool Origin Data%  Meta%
  root rl   -wi-ao---- 34.00g
  swap rl   -wi-ao----  3.89g

Create an LVM Setup from Scratch

Starting with a raw disk /dev/sdb, here's the full workflow to create a usable LVM volume.

Initialize the disk as a physical volume:

sudo pvcreate /dev/sdb

Create a volume group named data_vg:

sudo vgcreate data_vg /dev/sdb

Carve out a 50 GB logical volume for application data:

sudo lvcreate -L 50G -n app_lv data_vg

Format and mount the new volume:

sudo mkfs.xfs /dev/data_vg/app_lv
sudo mkdir -p /data/app
sudo mount /dev/data_vg/app_lv /data/app

Add the mount to /etc/fstab for persistence across reboots:

echo '/dev/data_vg/app_lv /data/app xfs defaults 0 0' | sudo tee -a /etc/fstab

Extend a Logical Volume

This is where LVM earns its keep. Need more space? Extend the LV and grow the filesystem in one command:

sudo lvextend -L +20G /dev/data_vg/app_lv
sudo xfs_growfs /data/app

For ext4 filesystems, use resize2fs instead of xfs_growfs. Both work online, no unmount needed.

If you need to add another physical disk to the volume group first:

sudo pvcreate /dev/sdc
sudo vgextend data_vg /dev/sdc

Now the VG has more free space, and you can extend any LV within it.

LVM Snapshots

LVM snapshots create a point-in-time copy of a logical volume using copy-on-write. They're useful for backups and testing upgrades, but they have a performance cost because every write to the original volume also writes to the snapshot's COW space.

Create a 10 GB snapshot of the app volume:

sudo lvcreate -L 10G -s -n app_snap /dev/data_vg/app_lv

The -s flag marks it as a snapshot. The 10 GB is the COW reservation, not a full copy. If the snapshot fills up (because you changed more than 10 GB on the original), it becomes invalid. Size it according to your expected change rate.

To revert to the snapshot (destructive, replaces current data):

sudo lvconvert --merge /dev/data_vg/app_snap

Remove a snapshot you no longer need:

sudo lvremove /dev/data_vg/app_snap

Thin Provisioning

Thin provisioning lets you over-commit storage. You create a thin pool, then allocate volumes that appear larger than the physical space. Actual disk is consumed only as data is written. This is how cloud providers give you a "100 GB disk" that only uses 3 GB on the backend.

Create a thin pool and a thin volume:

sudo lvcreate -L 40G --thinpool thin_pool data_vg
sudo lvcreate -V 100G --thin -n thin_vol data_vg/thin_pool

The thin volume reports 100 GB to the OS, but only 40 GB of physical space exists. Monitor actual usage closely because running out of physical space causes I/O errors, not a graceful "disk full" message.

ZFS: Combined Volume + Filesystem

ZFS takes a fundamentally different approach. Instead of layering RAID, volume management, and filesystem as separate tools, it handles all three in one integrated system. A ZFS pool (zpool) is the equivalent of both a RAID array and a volume group. Datasets within the pool replace logical volumes but come with built-in compression, checksumming, snapshots, and copy-on-write semantics.

The tradeoff is complexity and resource consumption. ZFS wants RAM (the standard recommendation is 1 GB of RAM per TB of storage for the ARC cache, though it works with less). It also ships as a kernel module outside the mainline Linux kernel, which means DKMS rebuilds on kernel updates. On FreeBSD, ZFS is a first-class citizen with no such friction. The OpenZFS documentation covers the full feature set.

Install ZFS on Linux

On Ubuntu 24.04, ZFS packages are available in the default repositories:

sudo apt install -y zfsutils-linux

On Rocky Linux 10 / RHEL, install from the ZFS repository:

sudo dnf install -y https://zfsonlinux.org/epel/zfs-release-2-5$(rpm --eval "%{dist}").noarch.rpm
sudo dnf install -y zfs
sudo modprobe zfs

Verify the module is loaded:

lsmod | grep zfs

Create a ZFS Pool

A mirrored pool (equivalent to RAID 1) using two disks:

sudo zpool create datapool mirror /dev/sdb /dev/sdc

A RAIDZ1 pool (equivalent to RAID 5) with three disks:

sudo zpool create datapool raidz1 /dev/sdb /dev/sdc /dev/sdd

ZFS automatically mounts the pool at /datapool. No need for mkfs, no /etc/fstab entry. ZFS manages its own mounts.

Check pool status:

sudo zpool status

The output shows the pool layout, disk health, and any errors:

  pool: datapool
 state: ONLINE
config:

	NAME        STATE     READ WRITE CKSUM
	datapool    ONLINE       0     0     0
	  mirror-0  ONLINE       0     0     0
	    sdb     ONLINE       0     0     0
	    sdc     ONLINE       0     0     0

errors: No known data errors

Datasets and Compression

Datasets are like subdirectories with their own properties (compression, quota, reservation). Create a dataset with LZ4 compression enabled:

sudo zfs create -o compression=lz4 datapool/documents

List all datasets and their properties:

sudo zfs list

Typical output on a fresh pool:

NAME                  USED  AVAIL     REFER  MOUNTPOINT
datapool              156K   960M      24K  /datapool
datapool/documents     24K   960M      24K  /datapool/documents

LZ4 compression is nearly free in terms of CPU and often improves performance because less data hits the disk. There's almost no reason to leave it off. For higher compression ratios (at the cost of more CPU), use compression=zstd.

ZFS Snapshots

ZFS snapshots are instant and consume zero space at creation because they're just a pointer to the current state of the data. Space is only used as the original data changes (copy-on-write). This makes ZFS snapshots fundamentally different from LVM snapshots, which require pre-allocated COW space. For a practical comparison of snapshot workflows, see how Proxmox handles VM snapshots (which can use either LVM or ZFS on the backend).

Create a snapshot:

sudo zfs snapshot datapool/documents@2026-03-25

List snapshots:

sudo zfs list -t snapshot

Shows each snapshot with its space usage:

NAME                              USED  AVAIL     REFER  MOUNTPOINT
datapool/documents@2026-03-25       0B      -      24K  -

Roll back to a snapshot (destroys all changes made after the snapshot):

sudo zfs rollback datapool/documents@2026-03-25

ZFS Send/Receive

One of ZFS's strongest features for backups. You can send a snapshot as a data stream to another pool, another machine, or a file. Proxmox Backup Server uses this capability heavily for efficient VM backups on ZFS storage.

Send a snapshot to a remote server over SSH:

sudo zfs send datapool/documents@2026-03-25 | ssh backupserver sudo zfs receive backuppool/documents

Incremental sends transfer only the changes between two snapshots, making subsequent backups extremely fast:

sudo zfs send -i datapool/documents@2026-03-25 datapool/documents@2026-03-26 | ssh backupserver sudo zfs receive backuppool/documents

Combining Them

In practice, you'll often use more than one of these technologies together. The right combination depends on what you need from your storage stack.

mdadm RAID + LVM (The Classic Stack)

This is the most common combination in enterprise Linux. mdadm handles redundancy at the disk level, and LVM provides flexible volume management on top. The typical layout:

Physical disks → mdadm RAID array (/dev/md0) → LVM PV → VG → LVs → ext4/xfs

Set it up by creating the RAID array first, then treating it as an LVM physical volume:

sudo mdadm --create /dev/md0 --level=10 --raid-devices=4 /dev/sdb /dev/sdc /dev/sdd /dev/sde
sudo pvcreate /dev/md0
sudo vgcreate secure_vg /dev/md0
sudo lvcreate -L 100G -n db_lv secure_vg
sudo mkfs.xfs /dev/secure_vg/db_lv

This gives you RAID 10 redundancy with the flexibility to carve the array into multiple logical volumes. You get online resizing from LVM and disk failure protection from mdadm. The downside is that you're managing two separate layers, and you don't get checksumming, compression, or snapshot efficiency.

ZFS Replaces Both

ZFS is a complete replacement for the mdadm + LVM + filesystem stack. A single ZFS pool with mirror or raidz vdevs provides redundancy, volume management (via datasets), compression, checksumming, and snapshots. You don't need mdadm or LVM at all.

The equivalent of the RAID 10 + LVM setup above in ZFS:

sudo zpool create secure_pool mirror /dev/sdb /dev/sdc mirror /dev/sdd /dev/sde
sudo zfs create -o compression=lz4 secure_pool/database
sudo zfs create -o compression=lz4 secure_pool/logs

Two mirror vdevs in a pool give you the same protection as RAID 10. Each dataset acts like a separate logical volume, but with shared space (no need to pre-allocate sizes unless you set quotas).

When Each Combination Makes Sense

CombinationWhen to Use
mdadm onlySimple redundancy on a small server. You need mirrored boot drives or a basic redundant data volume
LVM onlyCloud VMs where the hypervisor handles redundancy. You just need flexible partitioning
mdadm + LVMEnterprise Linux servers where you want both redundancy and flexible volumes. The standard RHEL/Rocky pattern
ZFS aloneNAS, backup servers, file servers, database servers where you want an integrated stack with data integrity
LVM + ZFSAlmost never. Don't layer LVM on top of ZFS or vice versa. They solve the same problems and adding both creates unnecessary complexity

Which to Choose

The right answer depends on your workload, your distro, and how much complexity you're willing to manage. Here's a decision matrix based on real-world use cases.

By Workload

WorkloadRecommended StackWhy
Database server (PostgreSQL, MySQL)ZFS or LVM + mdadm RAID 10ZFS gives checksumming and snapshots for consistent backups. RAID 10 + LVM is the traditional approach with proven performance
File server / NASZFSCompression saves disk, checksumming catches corruption, snapshots enable versioning, send/receive handles offsite backups
Simple redundancy (two-disk mirror)mdadm RAID 1Minimal complexity, works everywhere, no extra software
Cloud VM (AWS, OpenStack, Proxmox)LVMThe hypervisor handles disk redundancy. LVM gives you flexible volumes. Most cloud images ship with LVM by default
Backup serverZFSSend/receive for efficient replication, compression reduces storage costs, snapshots provide retention policies
Desktop / workstationLVM or plain partitionsSnapshots are useful for OS upgrades. RAID is overkill for most desktops
High-IOPS applicationmdadm RAID 10 + LVMRAID 10 has the best random I/O. ZFS COW overhead can hurt write-heavy workloads without tuning
Archival / cold storageZFS with RAIDZ2Checksumming catches bit rot on rarely-accessed data. ZSTD compression maximizes capacity

Practical Considerations

Stick with LVM + mdadm if: you run RHEL, Rocky, or AlmaLinux in production, your team knows traditional Linux storage well, and you don't need checksumming or built-in compression. This stack is battle-tested, fully supported, and every sysadmin knows how to troubleshoot it.

Choose ZFS if: data integrity is non-negotiable, you have enough RAM (8 GB minimum for small pools, more for larger ones), and you're comfortable managing a kernel module that ships outside the mainline kernel. On FreeBSD, ZFS is the obvious default with no such caveats.

Avoid ZFS if: your server has less than 4 GB RAM, you're running a distro that doesn't package ZFS well, or your organization requires only in-tree kernel modules for support contracts.

Quick Reference

TaskmdadmLVMZFS
Create storagemdadm --createpvcreate + vgcreate + lvcreatezpool create
List volumescat /proc/mdstatpvs, vgs, lvszpool list, zfs list
Check statusmdadm --detail /dev/mdXlvs -azpool status
Add diskmdadm --addpvcreate + vgextendzpool add
Extend volumemdadm --growlvextend + xfs_growfsAutomatic (datasets share pool)
Create snapshotN/Alvcreate -szfs snapshot
Replace failed diskmdadm --remove + --addpvmovezpool replace
Enable compressionN/AN/Azfs set compression=lz4
Backup/replicateN/AN/Azfs send / zfs receive
Destroymdadm --stop + --removelvremove + vgremove + pvremovezpool destroy

Related Articles

Web Hosting How to Configure Cpanel Backups to S3 Object Store Storage How to Backup and Rip Blu-ray with 100% Untouched Quality AlmaLinux Set up iSCSI Target and Initiator on Rocky Linux 10 / AlmaLinux 10 Security Using encrypted Stratis pool with Network Bound Disk Encryption (NBDE)

Leave a Comment

Press ESC to close