Skip to main contentSkip to navigation

Technical Reference

How ZFS Differs from Hardware RAID

Louis Rossmann
Written by
Louis Rossmann
Founder & Chief Technician
Published March 8, 2026
Updated June 17, 2026

Summary: ZFS versus hardware RAID

ZFS vs RAID comes down to where the redundancy lives. ZFS keeps it inside the filesystem, which is also the volume manager, while a hardware RAID controller keeps it below the filesystem and shows the operating system one virtual volume. ZFS checksums every block and repairs a bad one from a redundant copy as part of a normal read. Copy-on-write keeps ZFS's on-disk tree consistent by design, while hardware RAID relies on a protected write cache to survive torn writes. ZFS needs direct disk access via HBA passthrough or JBOD, never behind a hardware RAID controller.

ZFS and hardware RAID both provide data redundancy across multiple drives, but they operate at different layers of the storage stack. Hardware RAID controllers (Dell PERC, HP SmartArray, LSI MegaRAID, Adaptec) manage redundancy below the filesystem, presenting a single virtual volume to the operating system.

ZFS manages redundancy within the filesystem itself, combining volume management and filesystem operations into a single integrated layer. This architectural difference affects data integrity, failure handling, and recovery.

How does copy-on-write differ from in-place update?

Traditional filesystems (NTFS, ext4, XFS) and hardware RAID controllers use in-place updates: when data is modified, the new version overwrites the old version at the same physical location. If power is lost during the write, the block may contain a mix of old and new data (a torn write). A hardware RAID controller guards against this with a write cache backed by a battery or a supercapacitor, so pending writes survive the power loss. Filesystems use journaling to record write intent before committing changes.

ZFS uses copy-on-write (COW): modified data is always written to a new location. The old data remains intact until the new write completes and the metadata tree is updated to point to the new location. The metadata tree itself is also written copy-on-write, all the way up to the root (the "uberblock"). Only after the entire tree of changes is written does ZFS atomically update the uberblock pointer.

The effect: ZFS never overwrites live data. A power loss at any point during a write leaves the filesystem tree in a consistent state, either reflecting the old data or the new data, never a torn mix.

On mount, ZFS opens the most recent valid uberblock. If acknowledged synchronous writes (fsync, O_SYNC, NFS COMMIT) were logged to the ZFS Intent Log (ZIL) but not yet committed in a transaction group, ZFS replays the ZIL to recover them. Async writes that never reached stable storage are lost, same as on any filesystem.

How do checksumming and self-healing reads work?

ZFS checksums every block of data and metadata using a 256-bit hash (fletcher4 by default, or SHA-256 for dedup). The checksum is stored in the block's parent pointer, not alongside the data. This separation means a single disk corruption event cannot simultaneously damage both the data and its checksum.

When ZFS reads a block, it verifies the checksum before returning the data. If the checksum does not match, ZFS knows the data is corrupt.

In a redundant configuration (mirror or RAIDZ), ZFS automatically reads the block from a different copy or reconstructs it from parity. If the alternate copy is valid, ZFS overwrites the corrupted copy with correct data. This is self-healing: corruption is detected and repaired transparently during normal reads.

FeatureHardware RAIDZFS
Write consistencyRelies on a protected write cacheCopy-on-write (inherent)
Disk visibilityController hides individual disksFilesystem manages individual disks
Cache safetyBattery- or supercapacitor-protected write cacheZIL on separate SLOG device (optional)

How does ZFS scrub differ from a hardware RAID rebuild?

Some hardware RAID controllers can check redundant data. On a Broadcom MegaRAID controller, a consistency check on a parity array recalculates the data on one drive and compares the result against what's on the parity drive.

ZFS scrub reads every allocated block on every drive and verifies its checksum. If a block fails verification, ZFS repairs it from redundant copies (mirror or parity). A scrub is non-destructive and can run on a live, mounted filesystem.

When a drive fails, ZFS resilvering (the equivalent of a RAID rebuild) only reads and writes the blocks that are actually allocated. A hardware RAID rebuild runs across the entire drive capacity, because the controller sits below the filesystem and doesn't know which blocks hold data.

What causes ZFS pools to fail, and what does recovery look like?

ZFS isn't immune to failure. Either of these will break a pool:

  • Too many drive failures. RAIDZ1 (single parity) tolerates one drive failure. RAIDZ2 (double parity) tolerates two. RAIDZ3 tolerates three. ZFS won't import a pool that's missing a top-level vdev, so losing more drives than any one top-level vdev tolerates leaves the whole pool unimportable.
  • Pool metadata corruption. The uberblock, MOS (Meta Object Set), and space maps are critical metadata structures. If these corrupt on all copies (possible with firmware bugs or controller errors during a multi-drive event), the pool cannot mount.

Recovery from a failed ZFS pool involves imaging all drives individually and using ZFS-aware recovery tools to parse the on-disk structures. Because ZFS stores metadata in a Merkle tree (every block pointer includes the checksum of the block it points to), recovery tools can validate data integrity during reconstruction.

ZFS keeps more than one copy of its metadata, so a damaged metadata block can sometimes be reconstructed from another copy. Uberblocks are stored redundantly across all drives, and ZFS writes an extra copy of metadata on top of the pool's own redundancy.

When pool metadata is corrupted on every copy and ZFS-aware tools cannot import the pool, our RAID data recovery service reads the vdev labels to identify pool membership, then uses ZFS-aware tools to walk the surviving metadata tree from the individual drive images and extract the readable datasets.

Metadata damage at that depth runs through our ZFS data recovery service, where every member is imaged first & the dataset extraction runs against those clones, so the vdev labels on the original drives are never written.

ZFS should never sit behind a hardware RAID controller.

ZFS needs direct access to individual disks to self-heal. A hardware RAID controller hides individual disks behind a virtual volume, preventing ZFS from detecting which disk returned bad data. The controller's write cache is one more thing that can fail. If its battery dies, or it has no flash and the power doesn't come back in time, the cached writes are gone. Use an HBA (Host Bus Adapter) in passthrough or JBOD mode instead.

Why can't standard de-striping tools reconstruct a RAID-Z pool?

Standard de-striping tools cannot reconstruct a RAID-Z pool because RAID-Z has no fixed, repeating stripe geometry for those tools to detect. RAID-Z uses a variable stripe width: each logical record gets its own parity and is spread across a data-dependent number of member sectors. There is no single fixed chunk that repeats uniformly down every column, and the per-disk chunk is not a globally configurable geometry the way it is on a hardware array.

A hardware RAID array works the opposite way. It uses one fixed stripe size, also called the chunk or block size, and lays it out the same way on every member drive. A geometry-detection tool such as Data Extractor Express RAID Edition, the ACE Lab RAID reconstruction software, detects that repeating stripe size and the parity rotation from the cloned member images and reassembles the virtual volume.

Stripe size and stripe width aren't the same thing. Stripe size is the chunk size, which is configurable and detectable, and stripe width is the number of member drives.

Because a RAID-Z pool has no repeating fixed stripe size to detect, the hardware-RAID geometry-detection approach does not apply to it. Reconstruction instead walks the ZFS block-pointer and uberblock tree at the transaction-group level from the individual member images, which is why a RAID-Z pool is rebuilt with ZFS-aware tools rather than hex-level de-striping.

When the block-pointer tree is too damaged to walk without lab tooling, our RAID data recovery service images each member and reconstructs the array at our Austin, TX lab, and TrueNAS ZFS pools are reassembled from those images with ZFS-aware tooling rather than de-striping software.

Our RAIDZ pool reconstruction work starts from those member images, reading the uberblock ring inside each cloned vdev label to rebuild the dataset tree without writing to the original drives.

Why is a deduplicated ZFS pool so slow after an import?

A deduplicated ZFS pool can crawl for a long time after import when its Deduplication Table (DDT) exceeds available physical RAM. The DDT lives in on-disk ZAP objects, and ZFS pages it into the Adaptive Replacement Cache (ARC) on demand rather than loading it at import, so the pool comes up either way; what changes is the random I/O every deduplicated write or deletion then costs.

The sizing guidance is roughly 1 to 5 GB of RAM per 1 TB of deduplicated data to keep the table in ARC. That ratio compounds quietly: an array that ran fine on its original host slows sharply the moment the unique deduplicated dataset outgrows the RAM that cached its DDT. Dedup is never free storage. Every block of dedup capacity carries a standing RAM cost that is paid in time when it is not met.

Under severe memory pressure from a large DDT, iXsystems documents that loading the table on demand can take days after an import or reboot. Because the DDT is not needed to read existing data, the recovery path on undersized hardware is a strictly read-only import rather than a higher-RAM rig.

Forensic recovery of an undersized dedup pool.

Image every member first, then import the pool read-only from those images. At our Austin, TX lab we image the member drives with the PC-3000 Portable III and DeepSpar Disk Imager, then run the read-only import against those images, never against the live members.

When the original host can't take the RAM that table demands, the job becomes ZFS pool recovery from member images, and we run the read-only import against those images instead of the original drives.

How does uberblock rollback recover a pool that a corrupted transaction group broke?

Uberblock rollback recovers the pool by importing it at an earlier transaction group (TXG) whose metadata is still consistent, bypassing the corrupted most-recent state. ZFS structures the pool as a Merkle tree rooted in uberblocks, and each vdev label carries a ring buffer of up to roughly 128 uberblocks that rotate per TXG.

ZFS batches writes into transaction groups, and the default zfs_txg_timeout is 5 seconds. Pool import normally walks back from the most recent valid uberblock. When that most recent TXG is corrupted, an engineer steps the import back to an earlier uberblock so the tree resolves against metadata that was committed before the corruption.

ZFS is copy-on-write, so this is not an in-place overwrite. Import replays the ZFS Intent Log (ZIL) and advances or rolls back the TXG pointer; it does not overwrite parity or live data in place. Rewinding the TXG permanently orphans the newer transaction groups, which is exactly why the rollback must run against bit-for-bit member images rather than the live members.

The forensic command sequence:

  • zdb -ul <device> reads the vdev labels on a member image and lists the uberblocks stored there with their TXG numbers.
  • zpool import -F automatically rolls back transaction groups to the last consistent state.
  • zpool import -T <txg> targets a specific earlier transaction group identified from the zdb output.

What is ashift, and why does a wrong sector-size choice surface only later?

ashift is the base-2 logarithm of the sector size ZFS commits to for a top-level vdev. ashift=9 means 512-byte sectors; ashift=12 means 4096-byte (4K) sectors. It is chosen once at vdev creation and is immutable for the life of that vdev. The value is stored in the vdev label nvlist, so the on-disk stride is self-describing whenever the pool is imported.

Some early Advanced Format hard drives misreported their sector size as 512 bytes. Any drive that misreports its sector size that way can leave a vdev at ashift=9 unless whoever builds the pool sets ashift=12 at vdev creation. On 4K physical media, every write smaller than 4K then forces the drive into an internal read-modify-write, because a sub-sector write can't land without first reading the surrounding 4K block.

ashift also sets the depth of the uberblock ring described above. Each vdev label reserves a roughly 128 KiB uberblock region, and each uberblock slot occupies max(2^ashift, 1 KiB). So the rotating uberblock ring holds 128 slots on a 512-byte / ashift=9 pool but only 32 slots on a 4K / ashift=12 pool. The "up to roughly 128 uberblocks" figure from the rollback section is an upper bound that holds only at ashift=9; on a 4K pool the ring is a quarter as deep, which shortens how far back a transaction-group rollback can reach.

The wrong choice surfaces long after creation, at drive replacement rather than at import. A native 4Kn replacement drive, one that refuses 512-byte writes, cannot be added to an ashift=9 vdev: zpool replace refuses the device because its minimum ashift exceeds the vdev's. A creation-time mistake therefore stays invisible until a member fails and its replacement will not join the vdev, mid-degraded-rebuild. The only correction for a wrong ashift is to destroy and recreate the pool and restore from backup; it cannot be changed in place. When a pool refuses to mount for a different reason, diagnosing an import-time I/O error is a separate path from this replacement-time failure.

What happens when a ZFS native encryption key is lost?

Lose a ZFS native encryption key with no saved key export and the drives give up only ciphertext, no matter what shape they're in. ZFS native encryption works per dataset and uses AES. A per-dataset master key encrypts the data and is itself wrapped by the user's wrapping key, passphrase, or key file.

If that wrapping key, passphrase, or key file is gone, imaging the drives yields only ciphertext. Modern AES cannot be brute-forced without the key. This is a different failure class from drive failure: a healthy pool with a lost key is unrecoverable, while a degraded pool with intact key material can be imaged and reconstructed at our Austin, TX lab.

What happens to in-flight writes when a SLOG device fails?

A failed SLOG device coincident with sudden power loss permanently destroys the in-flight synchronous writes that had been acknowledged to the application but not yet committed to a transaction group. The SLOG is a separate log device that holds the ZFS Intent Log (ZIL).

Synchronous writes (fsync, O_SYNC, NFS COMMIT) are acknowledged once they land in the ZIL, so when the ZIL is offloaded to a separate SLOG, losing that device at the moment of power loss takes the acknowledged-but-uncommitted writes with it.

The data-loss window is specific to the separate-SLOG configuration. When there is no separate SLOG, the ZIL lives on the main pool and survives power loss because those writes are already on stable storage.

This is a distinct failure class from the hardware-RAID counterpart. The SLOG vector is transaction loss: writes acknowledged to the application but never committed. The hardware-RAID counterpart during a degraded rebuild is different in kind. Reading every surviving member to recalculate parity raises the probability of hitting a latent unrecoverable sector, and a read error at that moment leaves a parity block that cannot be calculated. One is lost transactions; the other is a probabilistic media error during parity recalculation.

When a SLOG loss leaves a pool that will not import cleanly, our ZFS pool-import recovery path images the members and reconstructs the pool at our Austin, TX lab against those images.

How do ZFS snapshots and send/receive change recovery outcomes versus hardware RAID?

ZFS snapshots are instantaneous, copy-on-write, and read-only. Because they share unchanged blocks with the live dataset, they consume only the space of subsequently changed data. Roll a dataset back to a snapshot with zfs rollback, or browse a prior state through the hidden .zfs/snapshot directory without rolling back at all.

zfs send and zfs receive serialize a snapshot, full or incremental, to a separate pool or a remote host. That gives point-in-time replication and off-box recovery: a copy of the dataset state exists outside the source pool.

The RAID redundancy layer has no point-in-time equivalent. Mirror and parity protect against drive failure only. An accidental deletion or a ransomware write propagates to every member immediately, because mirror and parity reproduce the current block state and keep no history. This is the concrete sense in which RAID is availability, not a backup.

Snapshots are not a backup on their own. They live inside the same pool, so they don't protect against pool loss. If the pool won't import because it ran out of redundancy or has metadata problems, the snapshots go with it. Only zfs send to a separate target is true disaster recovery.

When a snapshot-bearing pool itself will not import, recovery still means imaging the members and reconstructing the pool with ZFS-aware recovery tooling at our Austin, TX lab, the same layered path used for any unimportable pool.

Frequently Asked Questions

Does ZFS make data recovery unnecessary?
No. ZFS provides stronger data integrity guarantees than hardware RAID through checksumming, copy-on-write, and self-healing reads. However, ZFS cannot protect against all failure modes. If enough drives in a vdev fail to exceed the redundancy level (e.g., two drives in a single-parity RAIDZ1), the pool becomes unimportable. If the pool metadata on all drives is corrupted (possible with firmware bugs, controller errors, or multiple simultaneous failures), the pool cannot mount. ZFS also can't protect against user error (deleting files without snapshots).
Why should I not put ZFS behind a hardware RAID controller?
ZFS needs direct access to individual disks to self-heal. A hardware RAID controller presents a single virtual volume to the operating system, hiding the individual disks. ZFS can't tell which disk returned bad data, so it can't use the controller's redundancy to repair it. The controller's write cache is one more thing that can fail. If its battery fails, or it has no flash and power isn't restored in time, the cached writes are lost, and that can badly damage the pool. ZFS should be connected to an HBA (Host Bus Adapter) in passthrough/JBOD mode, not a RAID controller.
What is ZFS ashift, and can it be changed after pool creation?
ashift is the log2 of the sector size a vdev commits to (9 = 512-byte, 12 = 4K). It is set once at vdev creation and cannot be changed afterward. A pool created with ashift=9 on 4K Advanced Format drives suffers read-modify-write on every sub-4K write, and a native 4Kn replacement drive cannot join that vdev because zpool replace refuses a device whose minimum ashift exceeds the vdev's. Correcting ashift requires destroying and recreating the pool from backup.
Can ZFS snapshots replace a backup?
No. Snapshots are point-in-time and space-efficient and recover user-error deletions or ransomware writes with zfs rollback, but they live inside the same pool. If the pool becomes unimportable from redundancy exhaustion or metadata corruption, the snapshots are lost with it. Only zfs send/receive to a separate pool or host is true disaster recovery. The RAID redundancy layer offers no point-in-time capability of its own.

If you are experiencing this issue, learn about our RAID recovery service.