Skip to content
FreeBSDDeep Dive July 11, 2026 5 min readViews unavailable

HAST and Ctl: FreeBSD's Built-In Storage Replication and iSCSI Target

How HAST mirrors block devices across two hosts over the network, how Ctl serves them out as an iSCSI target, and where each one actually fits versus ZFS's own replication tools.

FreeBSD ships two storage components that solve adjacent but distinct problems: HAST replicates a block device across two machines over a network link, and Ctl (the CAM Target Layer) serves block storage out to other machines as a SCSI/iSCSI target. Neither is ZFS, and understanding what each one actually does — and doesn’t — matters before reaching for either.

HAST: block-level replication, not a filesystem

HAST (Highly Available STorage) operates entirely below the filesystem layer. It takes a local block device (a disk, a partition, a gpart-carved slice) and mirrors every write to it across a network connection to a peer machine running the same block device locally. The result is a GEOM provider — /dev/hast/<resource> — that behaves like any other block device to whatever sits above it, whether that’s UFS, a swap partition, or (with caveats) a ZFS vdev.

The mechanism is synchronous by default: a write to the HAST device doesn’t complete until it’s been acknowledged by both the local disk and the remote peer over the network. This is what makes HAST meaningfully different from asynchronous replication schemes — a crash of the primary node, at any point, leaves the secondary with a fully consistent, up-to-date copy, because no write was ever considered “done” until both sides had it. The cost is exactly what you’d expect: every write now has network round-trip latency added to it, which makes HAST a poor fit for latency-sensitive, high-write-volume workloads and a reasonable fit for lower-throughput services where availability matters more than raw write performance.

HAST’s role: replication, not clustering

HAST by itself does not provide automatic failover — it replicates data, but something else has to decide when the primary has actually failed and promote the secondary to primary. In practice this means HAST is almost always deployed alongside a cluster resource manager (historically CARP for the failover-detection/IP-takeover piece, with something scripting the HAST role switch and mounting the now-primary device) rather than used standalone. HAST’s contract is narrower and more mechanical than a full HA solution: “keep this block device identical on two hosts, and let me switch which one is primary on command.” Building the actual failure-detection and automated promotion logic on top of that is a separate, deliberate piece of system design — HAST won’t do it for you, and treating it as a complete HA solution on its own is a common and costly misunderstanding.

Where HAST sits relative to ZFS

It’s worth being direct about the overlap: ZFS has its own, generally preferred, mechanisms for keeping data safe and replicated — zfs send/zfs receive for shipping snapshots to another host, and mirrored/raidz vdevs for local redundancy. For most modern FreeBSD storage designs, zfs send | ssh host zfs receive (whether scripted periodically or continuously via tools built around it) covers the “keep a remote copy in sync” use case with less operational complexity than layering HAST underneath a ZFS pool, and it does so at the filesystem/snapshot level, which is a more natural place to reason about consistency than raw block replication.

HAST still has a real niche: workloads where the layer above the block device isn’t ZFS at all — UFS-based services, applications with their own on-disk format expectations, or scenarios needing synchronous, sub-second-consistent replication that a periodic (even frequent) zfs send snapshot schedule can’t provide, since snapshot-based replication always has some window of divergence between snapshots. HAST’s synchronous nature closes that window to zero, at the cost of the latency penalty described above.

Ctl: FreeBSD’s SCSI/iSCSI target subsystem

Ctl (the CAM Target Layer) is a separate subsystem that turns FreeBSD into a storage target — something other machines connect to and see as SCSI/iSCSI LUNs — rather than a storage initiator connecting to someone else’s storage. It sits inside FreeBSD’s CAM (Common Access Method) SCSI framework, and it can back the LUNs it exposes with several kinds of local storage: raw disks, files, ZFS zvols, or md(4) memory disks.

The practical entry point is ctladm for direct LUN management and, more commonly, /etc/ctl.conf plus the ctld daemon for iSCSI target configuration specifically. A minimal ctl.conf target definition looks roughly like:

target iqn.2026-07.com.example:target0 {
    auth-group no-authentication
    portal-group pg0

    lun 0 {
        path /dev/zvol/tank/iscsi-lun0
        blocksize 512
    }
}

Backing an iSCSI LUN with a ZFS zvol is a common and effective pattern specifically because it lets the target inherit ZFS’s own data-integrity guarantees (checksumming, and if the underlying pool is redundant, self-healing) underneath a block-level protocol that itself has no concept of any of that — from the initiator’s perspective it’s just a SCSI disk, but the actual storage backing it benefits from everything ZFS already does.

Two tools, two layers

The useful way to hold both of these in mind is by which problem each one is actually solving: HAST answers “how do I keep this block device’s contents identical on a second machine in real time,” entirely independent of what filesystem or protocol sits above it. Ctl answers “how do I expose local storage as a network block device that other machines can mount as if it were locally attached,” entirely independent of how that storage is protected or replicated underneath. They can be combined — a Ctl-exposed LUN backed by a HAST-replicated device is a valid, if somewhat elaborate, stack — but each one is a single-purpose building block, not a complete storage architecture on its own, and FreeBSD deliberately keeps them decoupled rather than fusing them into one opinionated all-in-one solution.