nix-git/modules/btrfsScrub.nix

80 lines
3.5 KiB
Nix
Raw Normal View History

2023-10-08 22:02:21 +02:00
# BTRFS scrub.
#
# Scrubbing is the process of checking file consistency.
# Scrubbing may be done "online", meaning you don't need to unmount a subvolume to scrub it.
# https://nixos.wiki/wiki/Btrfs#Scrubbing
# Btrfs scrub is "[a]n online filesystem checking tool. Reads all the data and metadata on the filesystem and uses checksums and the duplicate copies from RAID storage to identify and repair any corrupt data."
# https://wiki.archlinux.org/title/btrfs#Scrub
# The scrub command operates on a whole filesystem, not just individual subvolumes.
# https://unix.stackexchange.com/a/724412
#
# As this command reads all data, it wears down the disk. One should not run it too often. For large, slow disks once per month should be fine.
#
# To run it manually:
# sudo btrfs scrub start /
# sudo btrfs scrub status /
2025-02-01 21:40:51 +01:00
# Print generated systemd unit file
# cat "$(systemctl show -P FragmentPath btrfs-scrub-mnt-backup.timer)"
# cat "$(systemctl show -P FragmentPath btrfs-scrub--.timer)"
{ lib, config, options, pkgs, modulesPath, utils, ... }:
2023-10-08 22:02:21 +02:00
with lib;
let
2025-01-31 12:52:59 +01:00
cfg = config.yoda.btrfsScrub;
2023-10-08 22:02:21 +02:00
in
{
options = {
2025-01-31 12:52:59 +01:00
yoda.btrfsScrub = mkOption {
2023-10-08 22:02:21 +02:00
type = types.listOf types.path;
2025-01-31 12:52:59 +01:00
default = config.yoda.btrfsFileSystems;
2023-10-08 22:02:21 +02:00
example = ["/" "/mnt/data"];
description = ''
List containing each mounted BTRFS filesystem once.
2025-01-31 12:52:59 +01:00
This should usually be left at its default value to regularly scrub all BTRFS file systems.
2023-10-08 22:02:21 +02:00
'';
};
};
config = mkIf (length cfg > 0) {
2025-02-01 21:40:51 +01:00
# Note:
# The systemd timers generated by `config.btrfs.autoScrub` do not wake the system and have accuracy of `1d`.
# As our system wakes up daily at ~12:05, we want the timers to start at the same time and also wake up the system.
# If they do not wake up the system, the will fail and not be executed for the current time period.
2023-10-08 22:02:21 +02:00
services.btrfs.autoScrub = {
enable = true;
2025-02-01 21:40:51 +01:00
# Important: Wake up at ~ same time as daily-backup-and-suspend.service to avoid system being powered on longer than necessary.
# Value: Each month on the 1st day at 12:00 - 5 minutes before daily-backup-and-suspend
# TODO: Let's see next month if this works. Maybe it doesn't if "resume from suspend" is still not finished when the scrub service is already being started. The latter conflicts with suspend. The idea is that it stops scrubbing when suspend is started. But maybe this prohibits us from "waking up to start scrub service"? We'll find out!
# https://www.freedesktop.org/software/systemd/man/latest/systemd.time.html#Calendar%20Events
interval = "*-*-01 12:00:00";
2023-10-08 22:02:21 +02:00
fileSystems = cfg;
};
2025-02-01 21:40:51 +01:00
# Copied from the definition of the scrub systemd timer. If the source changes, we have to adapt here as well!
# https://github.com/NixOS/nixpkgs/blob/7ad7702fa8b0d409aaf83eba8be1479b97823cdc/nixos/modules/tasks/filesystems/btrfs.nix#L140-L158
# TODO: Watch and get notified on changes
systemd.timers =
let
scrubTimer =
fs:
let
fs' = utils.escapeSystemdPath fs;
in
nameValuePair "btrfs-scrub-${fs'}" {
timerConfig = {
# Important:
# Overwrite `1d` with default value `1min`.
AccuracySec = lib.mkForce "1min";
# Important:
# host-specific.nix -> daily-backup-and-suspend.service
# -> System might be suspended. Without setting this to `true`, the timer would fail.
WakeSystem = true;
};
};
in
listToAttrs (map scrubTimer cfg);
2023-10-08 22:02:21 +02:00
};
}