FreeBSD: Home NAS, part 5 – ZFS pool, datasets, snapshots та моніторинг

Автор |  22/12/2025
 

Продовжую for fun and profit сетапити собі домашній сервер з FreeBSD на Lenovo ThinkCentre M720s SFF.

І сьогодні, нарешті, зробимо основне – налаштуємо ZFS pool на реальних дисках, подивимось на роботу з datasets, шифруванням, снапшотами, моніторингом.

Попередні пости цієї серії:

Підготовка дисків

Дивимось, які диски фізично присутні в системі:

root@setevoy-nas:~ # geom disk list
Geom name: nda0
Providers:
1. Name: nda0
   Mediasize: 500107862016 (466G)
   ...

Geom name: ada0
Providers:
1. Name: ada0
   Mediasize: 4000787030016 (3.6T)
   ...

Geom name: ada1
Providers:
1. Name: ada1
   Mediasize: 4000787030016 (3.6T)
   ...

Або з camcontrol:

root@setevoy-nas:~ # camcontrol devlist
<Samsung SSD 870 EVO 4TB SVT03B6Q>  at scbus0 target 0 lun 0 (pass0,ada0)
<Samsung SSD 870 EVO 4TB SVT03B6Q>  at scbus1 target 0 lun 0 (pass1,ada1)
<CT500P310SSD8 VACR001>            at scbus7 target 0 lun 1 (pass3,nda0)

Тут в мене ada1 та ada2 – це SATA-диски для самого NAS storage, а nda0 – NVMe, на якому встановлена система (там зараз UFS, але потім, скоріш за все, перевстановлю із ZFS теж).

Імена пристроїв на кшталт /dev/ada0, /dev/ada1 або /dev/nda0 можуть змінюватися залежно від порядку підключення дисків, а тому напряму використовувати їх у ZFS не рекомендується – далі створимо власні GPT labels.

Створення GPT tables

Про всяк випадок – видаляємо існуючі таблиці розділів.

ВАЖЛИВО: таблиця розділів буде знищена. Дані залишаються на носії, але стануть недоступними.

В моєму випадку – диски нові, тому бачимо помилку “Invalid argument“:

root@setevoy-nas:~ # gpart destroy -F ada0
gpart: arg0 'ada0': Invalid argument
root@setevoy-nas:~ # gpart destroy -F ada1
gpart: arg0 'ada1': Invalid argument

Створюємо таблиці GPT (GUID Partition Table):

root@setevoy-nas:~ # gpart create -s gpt ada0
ada0 created
root@setevoy-nas:~ # gpart create -s gpt ada1
ada1 created

Перевіряємо з gpart:

root@setevoy-nas:~ # gpart show ada0
=>        40  7814037088  ada0  GPT  (3.6T)
          40  7814037088        - free -  (3.6T)

root@setevoy-nas:~ # gpart show ada1
=>        40  7814037088  ada1  GPT  (3.6T)
          40  7814037088        - free -  (3.6T)

Створення GPT labels

Для подальшої роботи з дисками створимо постійні GPT lables – іменовані ідентифікатори розділів, які зберігаються в GPT-таблиці розділів і читаються при старті системи.

Вони не змінюються після reboot, не залежать від порядку SATA портів, не залежать від того, як ядро виявило диск.

Додаємо для обох дисків:

root@setevoy-nas:~ # gpart add -t freebsd-zfs -l zfs_disk1 ada0
ada0p1 added
root@setevoy-nas:~ # gpart add -t freebsd-zfs -l zfs_disk2 ada1
ada1p1 added

Перевіряємо в /dev/gpt/:

root@setevoy-nas:~ # ls -l /dev/gpt/
total 0
crw-r-----  1 root operator 0x9b Dec 19 13:32 zfs_disk1
crw-r-----  1 root operator 0xa9 Dec 19 13:32 zfs_disk2

Або з gpart:

root@setevoy-nas:/home/setevoy # gpart show -l ada0
=>        40  7814037088  ada0  GPT  (3.6T)
          40  7814037088     1  zfs_disk1  (3.6T)

root@setevoy-nas:/home/setevoy # gpart show -l ada1
=>        40  7814037088  ada1  GPT  (3.6T)
          40  7814037088     1  zfs_disk2  (3.6T)

Або з glabel:

root@setevoy-nas:~ # glabel status
                                      Name  Status  Components
                             gpt/zfs_disk1     N/A  ada0p1
gptid/67ebfac9-dcce-11f0-98bf-00d861f3bff0     N/A  ada0p1
               diskid/DISK-S758NX0Y701757D     N/A  ada0
                             gpt/zfs_disk2     N/A  ada1p1
gptid/6a9c3ee5-dcce-11f0-98bf-00d861f3bff0     N/A  ada1p1
               diskid/DISK-S758NX0Y701756A     N/A  ada1

Диски готові – переходимо до ZFS, нам треба:

  • налаштувати ZFS pool з mirror
  • створити datasets
  • подивитись на шифрування даних
  • перевірити, як працювати зі snapshots

І в кінці окремо поговоримо про моніторинг дисків та ZFS pool.

Створення ZFS mirror pool

Використовуємо такі параметри:

  • ashift=12: розмір фізичного сектора, який ZFS використовує для I/O
    • розмір сектора визначається як 2^ashift байт, тобто  2¹² = 4096 байт
    • замінити значення ashift після створення Pool не можна
  • atime=off: вимикаємо оновлення часу доступу до файлів, зменшує кількість зайвих записів на диск
  • compression=lz4: швидка компресія даних на диску з мінімальним CPU-оверхедом
  • xattr: налаштування зберігання атрибутів файлі:
    • xattr=on: старий і default варіант, extended attributes зберігаються як окремі приховані файли
    • xattr=sa: xattr зберігаються безпосередньо в dnode файлу (аналог inode в UFS/ext4), без створення окремих прихованих файлів – менше звернень до диска і краща продуктивність
  • mirror: використовуємо ZFS mirror (аналог RAID1) – дані синхронно записуються на обидва диски (див. також vdev)

Див. ZFS Tuning Recommendations.

Створюємо пул з дисків /dev/gpt/zfs_disk1 та /dev/gpt/zfs_disk2:

root@setevoy-nas:~ # zpool create -o ashift=12 -O atime=off -O compression=lz4 -O xattr=sa nas mirror /dev/gpt/zfs_disk1 /dev/gpt/zfs_disk2

Перевіряємо:

root@setevoy-nas:~ # zpool status
  pool: nas
 state: ONLINE
config:

        NAME               STATE     READ WRITE CKSUM
        nas                ONLINE       0     0     0
          mirror-0         ONLINE       0     0     0
            gpt/zfs_disk1  ONLINE       0     0     0
            gpt/zfs_disk2  ONLINE       0     0     0

errors: No known data errors

Додаємо підключення при ребутах:

root@setevoy-nas:/home/setevoy # sysrc zfs_enable=YES
zfs_enable: NO -> YES

Створення ZFS datasets

ZFS dataset – це окрема файлова система всередині ZFS pool, яка має власні властивості (compression, quota, mountpoint тощо) і керується незалежно від інших datasets.

Зараз у нас один, корневий dataset:

root@setevoy-nas:~ # zfs list
NAME   USED  AVAIL  REFER  MOUNTPOINT
nas    420K  3.51T    96K  /nas

Корінь pool – це технічний корінь, а не місце для даних, тому створимо кілька окремих.

Не факт, що в мене датасети залишаться такими і надалі, але просто як ідея того, як можна розділити простір на дисках:

  • nas/data: основний dataset для збереження всяких даних типу музики-фільмів
  • nas/backups: сюди можна буде копіювати якісь periodic бекапи з робочого і домашнього ноутбуків
  • nas/private: зашифрований розділ для приватних даних та/або баз даних типу KeePass або бекапів 1Password
  • nas/shared: загальнодоступний dataset для доступу з телефонів і ноутбуків через Samba share (про налаштування Samba – окремим постом, вже є в чернетках)

Створюємо новий датасет з іменем nas/data:

root@setevoy-nas:~ # zfs create nas/data

Перевіряємо список ще раз:

root@setevoy-nas:~ # zfs list
NAME       USED  AVAIL  REFER  MOUNTPOINT
nas        540K  3.51T    96K  /nas
nas/data    96K  3.51T    96K  /nas/data

І каталог цього датасету:

root@setevoy-nas:~ # ls -la /nas/data/
total 1
drwxr-xr-x  2 root wheel 2 Dec 19 13:41 .
drwxr-xr-x  3 root wheel 3 Dec 19 13:41 ..

Він жеж має власну точку підключення:

root@setevoy-nas:/home/setevoy # mount | grep data
nas/data on /nas/data (zfs, local, noatime, nfsv4acls)

Яка задана у властивостях датасету:

root@setevoy-nas:/home/setevoy # zfs get mountpoint nas/data
NAME      PROPERTY    VALUE       SOURCE
nas/data  mountpoint  /nas/data   default

Додамо ще один:

root@setevoy-nas:~ # zfs create nas/backups

Ще раз список:

root@setevoy-nas:~ # zfs list
NAME          USED  AVAIL  REFER  MOUNTPOINT
nas           696K  3.51T    96K  /nas
nas/backups    96K  3.51T    96K  /nas/backups
nas/data       96K  3.51T    96K  /nas/data

Шифрування dataset

Хочеться мати окремий dataset для чутливих даних, тому глянемо, як це зроблено у ZFS.

Документація – Encrypting ZFS File Systems.

Важливо:

  • включити шифрування можна тільки створенні dataset – але можна відключити після
  • якщо батьківський dataset не зашифрований – дочірній можна зашифрувати
  • якщо батьківський зашифрований – дочірні успадковують його шифрування

Створимо новий dataset, вказуємо, що шифрується з паролем:

root@setevoy-nas:~ # zfs create -o encryption=on -o keyformat=passphrase -o keylocation=prompt nas/private
Enter new passphrase:
Re-enter new passphrase:

Перевіряємо цей датасет:

root@setevoy-nas:~ # zfs get encryption,keyformat,keylocation nas/private
NAME         PROPERTY     VALUE        SOURCE
nas/private  encryption   aes-256-gcm  -
nas/private  keyformat    passphrase   -
nas/private  keylocation  prompt       local

Як це буде виглядати після reboot:

  • pool nas імпортується
  • nas/private буде заблокований, і mountpoint не зʼявиться, доки вручну не ввести пароль і не розблокувати його

Для розблокування потім використовуємо:

root@setevoy-nas:~ # zfs load-key nas/private
root@setevoy-nas:~ # zfs mount nas/private

На відміну від, наприклад, шифрування розділів з LUKS – ZFS дозволяє змінювати пароль для зашифрованого dataset без перешифрування даних. Фактично змінюється лише ключ, який захищає основний ключ шифрування.

Якщо хочемо змінити пароль – виконуємо zfs change-key:

root@setevoy-nas:~ # zfs change-key nas/private
Enter new passphrase for 'nas/private':

Замість використання паролю можемо створити файл-ключ, який буде використаний про ребутах для підключення датасету.

Генеруємо ключ:

root@setevoy-nas:/home/setevoy # dd if=/dev/random of=/root/nas-private-pass.key bs=32 count=1

Змінюємо пароль, який вказали при створені датасету:

root@setevoy-nas:/home/setevoy # zfs change-key -o keyformat=raw -o keylocation=file:///root/nas-private-pass.key nas/private

Перевіряємо атрибути:

root@setevoy-nas:/home/setevoy # zfs get encryption,keyformat,keylocation nas/private
NAME         PROPERTY     VALUE                              SOURCE
nas/private  encryption   aes-256-gcm                        -
nas/private  keyformat    raw                                -
nas/private  keylocation  file:///root/nas-private-pass.key  local

Ребутаємо машину:

root@setevoy-nas:/home/setevoy # shutdown -r now
Shutdown NOW!
shutdown: [pid 13519]

І потім перевіряємо розділи:

root@setevoy-nas:/home/setevoy # mount | grep nas
nas on /nas (zfs, local, noatime, nfsv4acls)
nas/backups on /nas/backups (zfs, local, noatime, nfsv4acls)
nas/data on /nas/data (zfs, local, noatime, nfsv4acls)

Та з zfs list:

root@setevoy-nas:/home/setevoy # zfs list
NAME                        USED  AVAIL  REFER  MOUNTPOINT
nas                         200G  3.32T   112K  /nas
nas/backups                 200K   500G   104K  /nas/backups
nas/data                     96K  3.51T    96K  /nas/data
nas/private                 200K  3.32T   200K  /nas/private

Налаштування dataset quotas

ZFS datasets підтримують задання квот на розмір датасетів – тобто, максимальний розмір, який він може займати.

Документація – Setting Quotas on ZFS File Systems.

Зручно, наприклад, аби якийсь backups/ випадково не забив весь диск.

Є ще dataset reservation, але про це трохи далі.

Задамо ліміт в 500 гігабайт на nas/backups:

root@setevoy-nas:~ # zfs set quota=500G nas/backups

Перевіряємо:

root@setevoy-nas:~ # zfs get quota,used,available nas/backups
NAME         PROPERTY   VALUE  SOURCE
nas/backups  quota      500G   local
nas/backups  used       96K    -
nas/backups  available  500G   -

Налаштування dataset reservation

ZFS дозволяє зарезервувати місце для датасету, гарантуючи доступний простір незалежно від заповненості пулу.

Документація – Setting Reservations on ZFS File Systems.

Важливо, що ZFS Reservation резервує місце незалежно від того, використовується воно чи ні.

Задамо мінімально доступний розмір основного датасету nas/data:

root@setevoy-nas:~ # zfs set reservation=200G nas/data

Перевіряємо:

root@setevoy-nas:~ # zfs get reservation,used,available nas/data
NAME      PROPERTY     VALUE   SOURCE
nas/data  reservation  200G    local
nas/data  used         96K     -
nas/data  available    3.51T   -

Аби змінити reservation чи видалити – просто раз виконуємо zfs set з новим значенням:

root@setevoy-nas:~ # zfs set reservation=100G nas/data
root@setevoy-nas:~ # zfs set reservation=none nas/data

Використання ZFS snapshots

ZFS Snapshots – це миттєві read-only знімки стану dataset, які дозволяють швидко відкотитись до попереднього стану.

Документація – Overview of ZFS Snapshots.

Як це працює, коротко:

  • ZFS працює за принципом COW (Copy On Write), тобто при зміні в блоках даних – зміни робляться в новому блоку, а старі блоки не перезаписуються, поки на них є активні посилання
  • при створенні снапшоту ZFS не копіює дані, а створює таке посилання на цей блок
  • далі, коли ми робимо зміни в даних датасета, для якого є снапшот – то зміни на диску робляться в нових блоках даних, а доступ до старих зберігається через снапшот

Створення snapshots

Перевіряємо на прикладі.

Створимо тестовий файл в /nas/data/:

root@setevoy-nas:/home/setevoy # echo test-snap >> /nas/data/test-snap.txt

Створюємо снапшот:

root@setevoy-nas:/home/setevoy # zfs snapshot nas/data@test-snap

Перевіряємо його:

root@setevoy-nas:/home/setevoy # zfs list -t snapshot nas/data@test-snap
NAME                 USED  AVAIL  REFER  MOUNTPOINT
nas/data@test-snap     0B      -   104K  -

Його атрибути:

root@setevoy-nas:/home/setevoy # zfs get creation,used,referenced nas/data@test-snap
NAME                PROPERTY    VALUE                  SOURCE
nas/data@test-snap  creation    Sat Dec 20 15:46 2025  -
nas/data@test-snap  used        0B                     -
nas/data@test-snap  referenced  104K                   -

Відновлення зі snapshot

Снапшоти зберігаються в каталозі .zfs датасета – /nas/data/.zfs/snapshot/:

root@setevoy-nas:/home/setevoy # ll /nas/data/.zfs/snapshot/test-snap/
total 1
-rw-r--r--  1 root wheel 10 Dec 20 15:45 test-snap.txt

І звідси ми можемо отримати доступ і до нашого тестового файлу:

root@setevoy-nas:/home/setevoy # cat /nas/data/.zfs/snapshot/test-snap/test-snap.txt  
test-snap

Тепер видаляємо оригінальний файл з датасета:

root@setevoy-nas:/home/setevoy # rm /nas/data/test-snap.txt 
root@setevoy-nas:/home/setevoy # file /nas/data/test-snap.txt 
/nas/data/test-snap.txt: cannot open `/nas/data/test-snap.txt' (No such file or directory)

Але в снапшоті він доступний:

root@setevoy-nas:/home/setevoy # cat /nas/data/.zfs/snapshot/test-snap/test-snap.txt 
test-snap

Аби відновити зі снапшоту – можна або просто скопіювати з каталога /nas/data/.zfs/snapshot/test-snap/ з cp, або, якщо треба відкотити весь датасет, то використати zfs rollback – але в такому разі всі зміни, які були зроблені після створення снапшоту будуть втрачені:

root@setevoy-nas:/home/setevoy # zfs rollback nas/data@test-snap

І тепер файл знов на місці:

root@setevoy-nas:/home/setevoy # file /nas/data/test-snap.txt 
/nas/data/test-snap.txt: ASCII text
root@setevoy-nas:/home/setevoy # cat /nas/data/test-snap.txt 
test-snap

Ну і ZFS Boot Environments працюють через ті самі снапшоти – під час виконання freebsd-update install автоматично створюється копія даних, на яку можна відкотитись в разі проблем.

Взагалі ZFS Boot Environments дуже цікава штука, може, окремо про неї напишу.

Замість повного rollback – аби не перезаписувати дані на поточному датасеті – можна зробити клонування снапшоту в новий датасет:

root@setevoy-nas:~ # zfs clone nas/data@test-snap nas/data-restored

Перевіряємо:

root@setevoy-nas:/home/setevoy # zfs list 
NAME                        USED  AVAIL  REFER  MOUNTPOINT
nas                         200G  3.32T   120K  /nas
...
nas/data                    168K  3.51T   104K  /nas/data
nas/data-restored             0B  3.32T   104K  /nas/data-restored
...

І тепер файл доступний тут:

root@setevoy-nas:/home/setevoy # cat /nas/data-restored/test-snap.txt 
test-snap

Видалення snapshot

Для видалення використовуємо zfs destroy:

root@setevoy-nas:/home/setevoy # zfs destroy nas/data@test-snap

Аналогічно видаляються і датасети:

root@setevoy-nas:/home/setevoy # zfs destroy nas/data-restore

Копіювання snapshot

Снапшоти можна передавати між хостами і з zfs receive створювати новий снапшот, можна просто створити tar.gz архів.

Документація і багато прикладів –  Sending and Receiving ZFS Data.

Для передачі використовуємо zfs send, а потім через пайп – отримувача, наприклад – zfs receive:

root@setevoy-nas:/home/setevoy # zfs send nas/data@test-snap | zfs receive nas/backups/data-$(date +%Y%m%d)

Тепер в датасеті nas/backups у нас є новий датасет nas/backups/data-20251221:

root@setevoy-nas:/home/setevoy # zfs list | grep data
nas/backups/data-20251221   104K   500G   104K  /nas/backups/data-20251221
nas/data                    104K  3.51T   104K  /nas/data

В якому міститься копія снапшоту:

root@setevoy-nas:/home/setevoy # ll /nas/backups/data-20251221/.zfs/snapshot/
total 1
drwxr-xr-x  2 root wheel 4 Dec 20 15:45 test-snap

Також можна створювати інкрементальні копії снапшотів з -i та копіювати зашифровані снапшоти.

Якщо в снапшоті конфіденційна інформація, то для zfs send задаємо ключ -w (raw send) – в такому випадку дані передаються в зашифрованому вигляді.

FreeBSD Periodic та автоматизація створення снапшотів

Є кілька утиліт, які допомогають автоматизувати створення снапшотів, з основних – це zfsnap, zfs-periodic (див. більше на ZFS Orchestration Tools – Part 1: Snapshots).

Спробуємо зі zfsnap – встановлюємо його:

root@setevoy-nas:~ # pkg install zfsnap

Важливий нюанс – сам файл називається zfSnap а не zfsnap:

root@setevoy-nas:~ # pkg info -l zfsnap
zfsnap-1.11.1_1:
...
        /usr/local/sbin/zfSnap
...

Разом зі zfsnap додається набір Periodic-файлів:

root@setevoy-nas:/home/setevoy # ll /usr/local/etc/periodic/daily/ | grep Snap
-r-xr-xr-x  1 root wheel 1512 Nov 30 01:57 402.zfSnap
-r-xr-xr-x  1 root wheel 1073 Nov 30 01:57 403.zfSnap_delete

Які по суті являють собою просто shell-скрипти:

root@setevoy-nas:/home/setevoy # cat /usr/local/etc/periodic/daily//402.zfSnap 
#!/bin/sh

# If there is a global system configuration file, suck it in.
#
if [ -r /etc/defaults/periodic.conf ]; then
        . /etc/defaults/periodic.conf
        source_periodic_confs
fi
...

Включити запуск скриптів можна в файлі /etc/periodic.conf (або, краще, /etc/periodic.conf.local):

daily_zfsnap_enable="YES"
daily_zfsnap_recursive_fs="nas/data"
daily_zfsnap_delete_enable="YES"

Запустити виконання всіх daily задач, для яких в /etc/defaults/periodic.conf задано “YES” – з командою periodic:

root@setevoy-nas:/home/setevoy # periodic daily

І тепер  нас є новий снапшот:

root@setevoy-nas:/home/setevoy # zfs list -t snapshot 
NAME                                     USED  AVAIL  REFER  MOUNTPOINT
...
nas/data@daily-2025-12-21_16.41.03--1w     0B      -   104K  -

Моніторинг ZFS

Для моніторингу у нас є цілий набір утиліт – як дефолтні від самої файлової системи, так і додаткові, які можна встановити окремо.

Є класний документ Monitoring ZFS, хоча і 2017 року, але все ще актуальний.

З основного, чим можемо користуватись і що бажано моніторити:

  • SMART: перевірка самих дисків
  • zpool status: перевірка, що нема проблем на самих ZFS pools
  • zfs scrub: не зовсім про моніторинг, але може показати проблеми
  • zpool events: події пулів
  • arcstats: корисно перевіряти ефективність роботи кешу ZFS

Перевірка S.M.A.R.T. для SSD

Диски зовсім нові, але just in case і на майбутнє – налаштуємо S.M.A.R.T. (Self-Monitoring, Analysis, and Reporting Technology).

Встановлюємо пакет:

root@setevoy-nas:~ # pkg install smartmontools

І перевіряємо стан дисків:

root@setevoy-nas:~ # smartctl -a /dev/ada0
root@setevoy-nas:~ # smartctl -a /dev/ada1

Нам цікаві в основному такі показники:

  • SMART overall-health self-assessment test result: PASSED: перевірку пройдено (але зазвичай FAILED тут з’являється, коли все зовсім погано)
  • помилки:
    • Reallocated_Sector_Ct:
      • кількість битих секторів, які диск знайшов і замінив резервними
      • 0 – ідеально, зростання цього значення – поганий сигнал
    • Runtime_Bad_Block:
      • кількість некоректних блоків, знайдених під час нормальної роботи або деградацію лінка (наприклад, падіння швидкості SATA)
      • 0 – ідеально, зростання цього значення – поганий сигнал
    • Uncorrectable_Error_Cnt:
      • кількість помилок читання/запису, які неможливо було виправити
      • 0 – обов’язково має залишатися, зростання – вже серйозна проблема
  • Wear/Used reserve:
    • Wear_Leveling_Count:
      • показує знос елементів памʼяті SSD
      • 0 означає, що диск практично новий або знос мінімальний
    • Used_Rsvd_Blk_Cnt_Tot:
      • скільки резервних блоків уже використано для заміни зношених
      • 0 – ідеальний стан
  • Power_On_Hours:
    • кількість годин, протягом яких диск був увімкнений
    • 83 години – диски тільки нещодавно купив і підключив
  • CRC_Error_Count:
    • кількість помилок передачі даних між диском і контролером (кабель, порт)
    • 0 – норма, зростання часто означає проблеми з кабелем, а не з самим диском
  • Total_LBAs_Written / Host_Writes / NAND_Writes:
    • скільки даних реально записано на диск
    • порівнюємо зі TBW (Total Bytes Written) від виробника
    • в моєму випадку Total_LBAs_Written = 77982, де LBA – це Logical Block Address, який зазвичай SMART рахує по 512 байт, тобто записано на диск ~40 мегабайт – при заявлених Samsung 2400 TB
  • Temperature / Temperature_Celsius / Airflow_Temperature_Cel
    • температура дисків, в мене зараз 28 градусів

SMART Periodic

Для запуска SMART є власні скрипти в /usr/local/etc/periodic.

Аби включити перевірку і репорти – додаємо запуск smartd в автостарт:

root@setevoy-nas:/home/setevoy # sysrc smartd_enable="YES"

І налаштовуємо periodic в /etc/periodic.conf.local.

Аби включити перевірку – треба явно задати диски, по яким цю перевірку робити:

daily_status_smart_devices="/dev/ada0 /dev/ada1"

Результат в репорті:

ZFS Pool Status

zpool status вже запускали вище, тепер додамо запуск по крону і відправку повідомлень.

Скрипти для ZFS /etc/periodic/daily/, наприклад /etc/periodic/daily/404.status-zfs.

Додаємо до /etc/periodic.conf.local:

daily_status_zfs_enable="YES"

Запускаємо скрипти:

root@setevoy-nas:/home/setevoy # periodic daily

Отримуємо листа:

root@setevoy-nas:/home/setevoy # mail -u root
Mail version 8.1 6/6/93.  Type ? for help.
"/var/mail/root": 12 messages 4 new 12 unread
...
 N 12 root@setevoy-nas      Sun Dec 21 17:20  82/3368  "setevoy-nas daily run output"
& 

Читаємо його (вказуємо номер листа – 12, Enter):

(про налаштування пересилки пошти напишу окремо)

ZFS Scrubbing

ZFS Scrubbing – перевірка цілісності даних.

Під час scrub ZFS порівнює checksum кожного блоку зі збереженим значенням і у разі виявлення помилки система фіксує її в логах та, за наявності mirror, автоматично відновлює дані з другої копії.

Оскільки для цього виконується багато I/O операцій, тому не варто запускати scrubbing часто – раз на місяць буде достатньо.

Запускаємо вручну:

root@setevoy-nas:/home/setevoy # zpool scrub nas

І перевіряємо в zpool status:

root@setevoy-nas:/home/setevoy # zpool status
  pool: nas
 state: ONLINE
  scan: scrub repaired 0B in 00:00:00 with 0 errors on Fri Dec 19 16:54:04 2025
config:

        NAME               STATE     READ WRITE CKSUM
        nas                ONLINE       0     0     0
          mirror-0         ONLINE       0     0     0
            gpt/zfs_disk1  ONLINE       0     0     0
            gpt/zfs_disk2  ONLINE       0     0     0

errors: No known data errors

Тепер в scan є “scrub repaired 0B” – все добре.

Скрипт – /etc/periodic/daily/800.scrub-zfs, в якому перевіряється значення daily_scrub_zfs_default_threshold, і, якщо пройшло більше днів, ніж задано в threshold – то запускається zpool scrub.

З daily_scrub_zfs_pools можна вказати, які саме пули перевіряти.

Додаємо до нашого /etc/periodic.conf.local:

...
# SCRUB
daily_scrub_zfs_enable="YES"
daily_scrub_zfs_default_threshold=35
daily_scrub_zfs_pools="nas"
...

ZFS Events та History

З zpool events можна перевірити всі останні події в пулі:

root@setevoy-nas:/home/setevoy # zpool events
TIME                           CLASS
Dec 20 2025 16:46:39.702350180 sysevent.fs.zfs.history_event
Dec 20 2025 16:46:39.711350328 ereport.fs.zfs.config_cache_write
Dec 20 2025 16:46:39.711350328 sysevent.fs.zfs.config_sync
Dec 20 2025 16:46:39.711350328 sysevent.fs.zfs.pool_import
Dec 20 2025 16:46:39.712349914 sysevent.fs.zfs.history_event
Dec 20 2025 16:46:39.720349727 sysevent.fs.zfs.config_sync
Dec 20 2025 14:46:44.749348450 sysevent.fs.zfs.config_sync
...
Dec 21 2025 17:26:30.905209986 sysevent.fs.zfs.history_event

Аби побачити деталі – додаємо -z:

root@setevoy-nas:/home/setevoy #  zpool events -v
TIME                           CLASS
Dec 20 2025 16:46:39.702350180 sysevent.fs.zfs.history_event
        version = 0x0
        class = "sysevent.fs.zfs.history_event"
        pool = "nas"
        pool_guid = 0x2f9ad6b17a5e8426
        pool_state = 0x0
        pool_context = 0x0
        history_hostname = ""
        history_internal_str = "pool version 5000; software version zfs-2.2.7-0-ge269af1b3; uts  14.3-RELEASE 1403000 amd64"
        history_internal_name = "open"
        history_txg = 0x2d65
        history_time = 0x6946b6cf
        time = 0x6946b6cf 0x29dd0364 
        eid = 0x1
...

А з zpool history можна подивитись всі команди, які запускались:

root@setevoy-nas:/home/setevoy # zpool history
History for 'nas':
2025-12-19.13:37:17 zpool create -o ashift=12 -O atime=off -O compression=lz4 -O xattr=sa nas mirror /dev/gpt/zfs_disk1 /dev/gpt/zfs_disk2
2025-12-19.13:41:00 zfs create nas/data
2025-12-19.13:44:19 zfs create nas/backups
2025-12-19.13:48:44 zfs create -o encryption=on -o keyformat=passphrase -o keylocation=prompt nas/private
...
2025-12-21.17:26:30 zfs snapshot -r nas/data@daily-2025-12-21_17.26.30--1w

ZFS I/O statistic

Інформація по I/O операціям з zpool iostat:

root@setevoy-nas:/home/setevoy # zpool iostat
              capacity     operations     bandwidth 
pool        alloc   free   read  write   read  write
----------  -----  -----  -----  -----  -----  -----
nas         1.68M  3.62T      0      0     28    584

ZFS ARC моніторинг

ARC (Adaptive Replacement Cache) – кешування в пам’яті даних, які часто використовуються.

Перевірити поточні значення можна з sysctl:

root@setevoy-nas:/home/setevoy # sysctl kstat.zfs.misc.arcstats.size
kstat.zfs.misc.arcstats.size: 9379192
root@setevoy-nas:/home/setevoy # sysctl kstat.zfs.misc.arcstats.hits
kstat.zfs.misc.arcstats.hits: 26181
root@setevoy-nas:/home/setevoy # sysctl kstat.zfs.misc.arcstats.misses
kstat.zfs.misc.arcstats.misses: 6

Або встановити утиліту zfs-stats:

root@setevoy-nas:/home/setevoy # pkg install zfs-stats

І запустити з -E:

root@setevoy-nas:/home/setevoy # zfs-stats -E

------------------------------------------------------------------------
ZFS Subsystem Report                            Sun Dec 21 18:07:59 2025
------------------------------------------------------------------------

ARC Efficiency:                                 104.72  k
        Cache Hit Ratio:                99.87%  104.58  k
        Cache Miss Ratio:               0.13%   137
        Actual Hit Ratio:               99.87%  104.58  k

        Data Demand Efficiency:         100.00% 0

        CACHE HITS BY CACHE LIST:
          Most Recently Used:           23.21%  24.28   k
          Most Frequently Used:         76.79%  80.30   k
          Most Recently Used Ghost:     0.00%   0
          Most Frequently Used Ghost:   0.00%   0

        CACHE HITS BY DATA TYPE:
          Demand Data:                  0.00%   0
          Prefetch Data:                0.00%   0
          Demand Metadata:              99.96%  104.54  k
          Prefetch Metadata:            0.04%   39

        CACHE MISSES BY DATA TYPE:
          Demand Data:                  0.00%   0
          Prefetch Data:                0.00%   0
          Demand Metadata:              91.24%  125
          Prefetch Metadata:            8.76%   12

Або використати zfs-mon:

Ну і по моніторингу ZFS цього, мабуть, вистачить.

Ще окремо будемо говорити вже про повноцінний моніторинг системи – планую з VictoriaMetrics, і тоді можна буде додати якийсь експортер для ZFS, наприклад zfs_exporter.

Корисні посилання