Storage Layout
Independent data disks unioned by mergerfs, protected by a single SnapRAID parity
disk, with an NVMe cache for appdata and in-progress usenet downloads. SABnzbd
stages incomplete/ on the NVMe (/mnt/cache/data/usenet) so par2/unpack I/O stays
off the spinning disks; post-processing then writes the finished file straight to
the array, so there is no mover and none is needed. Completed downloads and all
torrents live on the array: SnapRAID has no realtime parity penalty, the data disks
stay spinning anyway, and torrents need to share a filesystem with the media for
hardlinks. Torrents seed indefinitely, so they can never stage on cache.
Sanitized: serial numbers and filesystem UUIDs are intentionally not committed. Disks are addressed by
/dev/disk/by-id/(model + serial) on the host; the real IDs live in the host's/etc/fstabandsnapraid.conf, not in this repo.
Disks
| Role | Capacity | Model | Filesystem | Mount |
|---|---|---|---|---|
| parity | 28 TB | Seagate Exos | XFS | holds the SnapRAID parity file |
| disk1 | 28 TB | Seagate Exos | XFS | /mnt/disk1 |
| disk2 | 28 TB | Seagate Exos | XFS | /mnt/disk2 |
| disk3 | 12 TB | Seagate Exos | XFS | /mnt/disk3 |
| disk4 | 12 TB | Seagate Exos | XFS | /mnt/disk4 |
| disk5 | 12 TB | Seagate Exos | XFS | /mnt/disk5 |
| cache | 2 TB | Samsung NVMe | btrfs | /mnt/cache |
- The five data disks (
/mnt/disk1../mnt/disk5) are unioned by mergerfs into/mnt/user. - The parity disk sits outside the mergerfs pool. Its capacity must be at least as
large as the largest data disk (so 28 TB here). It is touched only by writes and
snapraid sync/scrub, never by reads, which is why it is the one disk that spins down. - The cache is not part of the parity set; appdata is backed up separately.
- The cache NVMe is the reused Unraid cache pool (single-device btrfs): it is
mounted as-is on Debian, never reformatted, so appdata carries over on the device
itself. It also holds Kometa assets. The Docker data root is not here:
it stayed at the default
/var/lib/dockeron the OS SSD (seehost-facts.md§Docker; the Unraid-erasystem/dockershare is gone). The Debian OS lives on its own SSD, outside this layout.
Addressing convention
Always reference disks by /dev/disk/by-id/ rather than /dev/sdX, because sdX names
are not stable across reboots. Find them with ls -l /dev/disk/by-id/.
Operational notes
- SATA link power management is forced to
max_performanceby the host hardening config to avoid link resets on the SATA data disks. - Historical
disk3/disk5ATA read timeout/link reset events observed during the Debian cutover period were investigated and treated as resolved. Futurehard resetting linkor kernel I/O errors for those disks should be handled as a recurrence, not as an open known issue.
Templated /etc/fstab (data disks)
Replace each REPLACE-WITH-BY-ID with the real /dev/disk/by-id/ata-... entry on the host.
# data disks (XFS), by-id, nofail so a missing disk does not block boot
/dev/disk/by-id/REPLACE-WITH-BY-ID-1 /mnt/disk1 xfs defaults,nofail 0 0
/dev/disk/by-id/REPLACE-WITH-BY-ID-2 /mnt/disk2 xfs defaults,nofail 0 0
/dev/disk/by-id/REPLACE-WITH-BY-ID-3 /mnt/disk3 xfs defaults,nofail 0 0
/dev/disk/by-id/REPLACE-WITH-BY-ID-4 /mnt/disk4 xfs defaults,nofail 0 0
/dev/disk/by-id/REPLACE-WITH-BY-ID-5 /mnt/disk5 xfs defaults,nofail 0 0
# parity disk (XFS)
/dev/disk/by-id/REPLACE-WITH-BY-ID-P /mnt/parity xfs defaults,nofail 0 0
# cache (btrfs)
/dev/disk/by-id/REPLACE-WITH-BY-ID-C /mnt/cache btrfs defaults,nofail 0 0
# mergerfs pool over the data disks
# (no use_ino/nonempty: both are deprecated in modern mergerfs (>=2.40 on Debian 13).
# use_ino is superseded by inodecalc, nonempty does nothing; per upstream docs
# "they should not be used". These exact options are confirmed working on the live host.)
# x-systemd.requires-mounts-for: without it the pool can mount BEFORE the branch
# disks at boot (the glob happily matches the empty mountpoint dirs) and present
# an empty pool. nofail keeps a dead disk from blocking boot, so ordering must be
# stated explicitly.
/mnt/disk* /mnt/user fuse.mergerfs allow_other,category.create=mfs,minfreespace=200G,fsname=mergerfs,nofail,x-systemd.requires-mounts-for=/mnt/disk1,x-systemd.requires-mounts-for=/mnt/disk2,x-systemd.requires-mounts-for=/mnt/disk3,x-systemd.requires-mounts-for=/mnt/disk4,x-systemd.requires-mounts-for=/mnt/disk5 0 0
Templated snapraid.conf (skeleton)
A reference skeleton. Match content-file locations and exclusions to the live
host. See man snapraid.
# one parity disk protects the data disks
parity /mnt/parity/snapraid.parity
# content files: keep several copies on different disks
content /var/snapraid/snapraid.content
content /mnt/disk1/.snapraid.content
content /mnt/disk3/.snapraid.content
# data disks (the mergerfs branches)
data disk1 /mnt/disk1
data disk2 /mnt/disk2
data disk3 /mnt/disk3
data disk4 /mnt/disk4
data disk5 /mnt/disk5
# exclusions
exclude *.unrecoverable
exclude /tmp/
exclude lost+found/
exclude .Trash-*/
exclude incomplete/