Proxmox ZFS Pool Health Audit Before PBS 4.2 Backup Jobs
ZFS pool health audit before PBS 4.2 backups checks scrub state, fragmentation, dataset drift, and snapshots so you can catch restore risks before backup jobs.

On this page
A ZFS pool health audit before PBS 4.2 backups is not just a disk check; it is a restore-readiness check. The audit should prove that the pool is clean, the scan state is current, fragmentation is not hiding under a healthy pool, and dataset properties have not drifted away from the backup target. I have seen backup jobs finish successfully while the storage underneath had a stale scan, a fragmented vdev, or a dataset that no longer matched the restore profile.
Key Takeaways
- Scrub state: The audit must separate pool health from scan state, because a pool can look healthy while the last scan is incomplete or stale.
- Fragmentation: High fragmentation can make backup writes uneven, even when the pool reports no checksum errors.
- Dataset drift: Snapshot counts, mount points, quotas, and recordsize values can drift enough to make a restore target misleading.
- Repeatable evidence: A good audit writes one dated file per run so you can compare today’s pool against yesterday’s pool.
- Restore proof: The audit should feed directly into a PBS restore test, not just prove that backup storage exists.
Why the Audit Belongs Before PBS 4.2 Backups
The first question is not whether the pool is online. It is whether the pool can be trusted as the source of a restore. A PBS backup can complete even when the ZFS pool is unhealthy, because the backup client may only see files, datasets, and available space. It does not automatically know whether the pool has a stale scan, a fragmented vdev, or a dataset that has drifted away from the restore assumptions.
That is where the audit matters. A PBS 4.2 backup job can write successfully to a pool that is not ready for a clean restore. The backup may be fine, but the source storage may have changed in ways that break later recovery. This is especially true when the backup target is remote, such as S3, because the restore path can fail for reasons unrelated to the backup itself. Pair this audit with a PBS 4.2 S3 restore test guide so the storage check and restore check are not treated as separate chores.
The same idea from the pre-install audit applies here. A ZFS pool can pass a simple health check while still failing as a backup source. If you have already done a storage verification checklist, turn it into a repeatable audit. The difference is simple: a checklist tells you what to look at once, while an audit gives you evidence you can compare over time.
How to Audit ZFS Pool Health Before a PBS Backup
Start with the status view. It should show the pool health, scan state, device state, and any recent errors. The status view is the first thing I read before any PBS backup audit.
zpool status -v tank
Then capture the property dump. This is noisier than a compact list, but it gives you the values you need for drift analysis.
zpool get all tank
For automation, use the parseable list. It is smaller and easier to diff between runs.
zpool list -p tank
The key properties are not just health and size. I look for fragmentation, allocation, free space, ashift, and readonly state.
zpool get health tank
zpool get fragmentation tank
zpool get allocated tank
zpool get free tank
zpool get size tank
zpool get ashift tank
zpool get readonly tank
Then inspect the datasets. The list view shows the dataset layout, but it does not show every property. For backup audits, I care about compression, recordsize, checksum, quotas, reservations, and mount points.
zfs list -r tank
zfs get -r compression,recordsize,checksum tank
zfs get -r used,available,quota,reservation tank
zfs get -r mountpoint tank
Finally, capture snapshot drift and recent pool history. The snapshot list can reveal whether a backup schedule is creating snapshots in unexpected places. The history tail can reveal recent property changes or dataset changes that happened after the last audit.
zfs list -t snapshot -r tank
zpool history tank | tail -n 20
What Each Audit Check Tells You
The audit becomes useful when each check has a clear pass signal. A pool can be healthy, fragmented, and still unsuitable for a predictable restore. A dataset can be present, have snapshots, and still have drifted away from the backup target.
| Audit area | What to look for | Why it matters |
|---|---|---|
| Pool health | Clean status, no errors, no failed devices | A healthy pool is the minimum condition for a trusted backup source |
| Scan state | Current scan, completed scrub, no stale scan | A stale scan can hide silent damage until restore time |
| Fragmentation | Fragmentation percentage and allocated/free balance | High fragmentation can make backup writes uneven and slow |
| Dataset layout | Expected datasets, mount points, quotas, reservations | Dataset drift can make a restore target look wrong |
| Snapshot pattern | Snapshot count, names, and age | Unexpected snapshots can indicate backup or lifecycle drift |
| PBS readiness | Datastore state, garbage collection, restore test | A backup job is not proof that the restore path is clean |
How to Check Scrub Status Without Starting a Scrub
Do not start a scrub every time you run the audit. A scrub is useful, but it is not the audit itself. The audit should read the scan state from the existing pool status. If the pool is healthy but the scan is stale, the next backup may still look successful while the restore path is weak.
Read the scan state directly.
zpool status -v tank
If you want a focused audit file, capture the scan-related lines separately.
zpool status -v tank | grep -E 'scrub|Scan|state'
On a 4 TiB pool, a full scrub can take 12 to 18 hours on spinning disks. On mirrored NVMe, the same scan can finish in 2 to 4 hours. That timing matters because a scrub that starts during a backup window can change the performance profile. I prefer to run scrubs outside the backup window, then audit the result the next day.
I once had a pool report as healthy after a failed disk, but the scan had not finished. The PBS backup completed, and the next restore failed because the mirror had not resilvered. The pool looked acceptable in a quick status check, but the scan state showed the real problem. That experience changed how I read the audit: health alone is not enough.
How to Spot Fragmentation and Dataset Drift
Fragmentation is often the quiet part of the audit. A pool can be healthy and still be fragmented enough to make backup writes unpredictable. The fragmentation value is useful, but it is not a simple pass or fail. A pool with 10 percent fragmentation and stable allocation can be fine. A pool with 40 percent fragmentation, sparse allocation, and many small writes can be a warning.
Use the property values together.
zpool get fragmentation tank
zpool get allocated tank
zpool get free tank
A high fragmentation value does not always mean the pool is broken. It can mean the pool is fragmented because of small writes, snapshot churn, or backup behavior. The honest tradeoff is that the compact parseable list is easier for automation, but it does not show scan state. The full property dump is noisier, but it captures more context. I keep both in the audit file.
Dataset drift is the second quiet problem. A dataset can still exist, still have snapshots, and still be wrong for a restore. The mount point may have changed. The recordsize may have changed. The quota may have been removed. The snapshot pattern may have drifted because a backup job or lifecycle rule changed.
Check the dataset layout.
zfs list -r tank
Check the properties that affect restore behavior.
zfs get -r compression,recordsize,checksum tank
Check the capacity properties that can make a restore target misleading.
zfs get -r used,available,quota,reservation tank
Check the mount points.
zfs get -r mountpoint tank
Then look at the snapshot pattern. A backup audit should not only show that snapshots exist. It should show whether the snapshot pattern matches the backup schedule. If the snapshot names, ages, or counts change unexpectedly, the restore path may have drifted.
zfs list -t snapshot -r tank
Finally, look at recent history. The history tail is often more useful than the full history because it shows recent changes without flooding the audit file.
zpool history tank | tail -n 20
How to Make the Audit Repeatable
A one-off audit is useful, but a repeatable audit is better. The audit should write one dated file per run. That makes it easy to compare today’s pool against yesterday’s pool. It also makes the audit useful before a PBS 4.2 backup, because the backup target can be healthy while the source storage has changed.
Put the audit in a shell script. The script below writes one audit file per run.
#!/bin/bash
set -euo pipefail
POOL=${1:-tank}
OUT="/var/log/pbs-zfs-audit-$(date +%Y%m%d-%H%M).txt"
mkdir -p /var/log
printf 'ZFS audit for %s\n' "$POOL" > "$OUT"
printf 'Run time: %s\n\n' "$(date)" >> "$OUT"
zpool status -v "$POOL" > "$OUT"
grep -E 'scrub|Scan|state' "$OUT" || true
zpool get all "$POOL" >> "$OUT"
zpool list -p "$POOL" >> "$OUT"
zpool get health "$POOL" >> "$OUT"
zpool get fragmentation "$POOL" >> "$OUT"
zpool get allocated "$POOL" >> "$OUT"
zpool get free "$POOL" >> "$OUT"
zpool get size "$POOL" >> "$OUT"
zpool get ashift "$POOL" >> "$OUT"
zpool get readonly "$POOL" >> "$OUT"
zfs list -r "$POOL" >> "$OUT"
zfs get -r compression,recordsize,checksum "$POOL" >> "$OUT"
zfs get -r used,available,quota,reservation "$POOL" >> "$OUT"
zfs get -r mountpoint "$POOL" >> "$OUT"
zfs list -t snapshot -r "$POOL" >> "$OUT"
zpool history "$POOL" | tail -n 20 >> "$OUT"
printf '\nAudit file: %s\n' "$OUT"
Install the script, make it executable, and schedule it weekly.
chmod +x /usr/local/bin/pbs-zfs-audit.sh
A weekly crontab entry is usually enough for a homelab. If the backup window is daily, run the audit the day before the backup window.
0 3 * * 1 /usr/local/bin/pbs-zfs-audit.sh tank
For PBS 4.2, the audit should also show whether the datastore is reachable and whether garbage collection has run recently. The PBS command line is useful here because it separates storage health from backup lifecycle state.
proxmox-backup-manager datastore list
proxmox-backup-manager garbage-collection status
If PBS is on a different node, run the ZFS audit on the Proxmox host, then compare the PBS datastore view. The PBS side can look healthy while the ZFS source storage has drifted. That is the gap the audit should close.
How to Turn the Audit Into a Restore Test
The audit should not stop at storage health. It should feed into a restore test. A PBS backup can look successful while the restore path is weak. The restore path can fail for reasons unrelated to the backup job itself. The dataset may have drifted. The snapshot pattern may have changed. The mount point may have moved. The PBS datastore may be reachable, but the restore assumptions may no longer match the source storage.
The practical outcome is simple: compare the audit file with the restore test. If the pool health, scan state, fragmentation, dataset layout, and snapshot pattern all match the expected backup source, the restore path is much easier to trust. If any of those values change unexpectedly, investigate before the next backup window.
Conclusion
A repeatable ZFS pool health audit before PBS 4.2 backups gives you restore-readiness evidence, not just a storage health check. It catches scrub failures, fragmentation, and dataset drift before they become restore problems. The next step is to run the audit before the next backup window, then compare the output with a PBS restore test so the backup path and restore path are checked as one system.


