diff options
| author | Joan V. C. <codeberg-hn80@joanvc.cat> | 2026-03-20 09:42:50 +0100 |
|---|---|---|
| committer | Efraim Flashner <efraim@flashner.co.il> | 2026-05-20 11:37:30 +0300 |
| commit | 3b7fd1e76698559f8575ffeeed116673bd00ade1 (patch) | |
| tree | e49b166727766800ed1005bd4baf792f667c1ec5 | |
| parent | 5912f01e976480b50c18c65f8236a998fc7db7f9 (diff) | |
gnu: services: Add btrfs-scrub-service-type.
* gnu/services/linux.scm (btrfs-scrub-configuration): New configuration
record.
(btrfs-scrub-service-type): New service type with custom actions.
(fstrim-/shepherd-calendar-event?): Refactor to avoid name collisions.
* doc/guix.texi: Add service documentation.
Change-Id: I04747914591a80cd535d2f79d35e08f68081b2fc
Signed-off-by: Joan Vilardaga Castro <codeberg-hn80@joanvc.cat>
Signed-off-by: Efraim Flashner <efraim@flashner.co.il>
| -rw-r--r-- | doc/guix.texi | 76 | ||||
| -rw-r--r-- | gnu/services/linux.scm | 135 |
2 files changed, 208 insertions, 3 deletions
diff --git a/doc/guix.texi b/doc/guix.texi index 8d45ed1f43b..debe9b48a77 100644 --- a/doc/guix.texi +++ b/doc/guix.texi | |||
| @@ -151,6 +151,7 @@ Copyright @copyright{} 2025 Noé Lopez@* | |||
| 151 | Copyright @copyright{} 2026 David Elsing@* | 151 | Copyright @copyright{} 2026 David Elsing@* |
| 152 | Copyright @copyright{} 2026 Nguyễn Gia Phong@* | 152 | Copyright @copyright{} 2026 Nguyễn Gia Phong@* |
| 153 | Copyright @copyright{} 2026 Yarl Baudig@* | 153 | Copyright @copyright{} 2026 Yarl Baudig@* |
| 154 | Copyright @copyright{} 2026 Joan Vilardaga Castro@* | ||
| 154 | 155 | ||
| 155 | Permission is granted to copy, distribute and/or modify this document | 156 | Permission is granted to copy, distribute and/or modify this document |
| 156 | under the terms of the GNU Free Documentation License, Version 1.3 or | 157 | under the terms of the GNU Free Documentation License, Version 1.3 or |
| @@ -45888,6 +45889,81 @@ mount. | |||
| 45888 | @end table | 45889 | @end table |
| 45889 | @end deftp | 45890 | @end deftp |
| 45890 | 45891 | ||
| 45892 | @subsubheading btrfs-scrub Service | ||
| 45893 | @cindex btrfs-scrub service | ||
| 45894 | @cindex solid state drives, periodic trim | ||
| 45895 | @cindex solid state drives, trim | ||
| 45896 | |||
| 45897 | @c This was copied from the btrfs-scrub manpage, with some Texinfo touch-ups. | ||
| 45898 | @quotation Information | ||
| 45899 | Scrub is a validation pass over all filesystem data and metadata that | ||
| 45900 | detects data checksum errors, basic super block errors, basic metadata | ||
| 45901 | block header errors, and disk read errors. | ||
| 45902 | |||
| 45903 | Scrub is done on a per-device base, if a device is specified to | ||
| 45904 | @command{btrfs scrub start}, then only that device will be | ||
| 45905 | scrubbed. Although btrfs will also try to read other device to find a | ||
| 45906 | good copy, if the mirror on that specified device failed to be read or | ||
| 45907 | pass verification. | ||
| 45908 | |||
| 45909 | If a path of btrfs is specified to @command{btrfs scrub start}, btrfs | ||
| 45910 | will scrub all devices in parallel. | ||
| 45911 | |||
| 45912 | On filesystems that use replicated block group profiles (e.g. RAID1), | ||
| 45913 | read-write scrub will also automatically repair any damage by copying | ||
| 45914 | verified good data from one of the other replicas. | ||
| 45915 | |||
| 45916 | Such automatic repair is also carried out when reading metadata or data | ||
| 45917 | from a read-write mounted filesystem. | ||
| 45918 | @end quotation | ||
| 45919 | |||
| 45920 | @defvar btrfs-scrub-service-type | ||
| 45921 | Type for a service that periodically runs @command{btrfs-scrub} on a | ||
| 45922 | certain device, whose value must be an | ||
| 45923 | @code{<btrfs-scrub-configuration>} object. The service can be | ||
| 45924 | instantiated in its default configuration with: | ||
| 45925 | |||
| 45926 | @lisp | ||
| 45927 | ;; This will scrub the root (@file{/}) filesystem. | ||
| 45928 | (service btrfs-scrub-service-type) | ||
| 45929 | |||
| 45930 | ;; This will scrub the @file{/gnu/store} filesystem (assuming it's a | ||
| 45931 | ;; different filesystem from @file{/}). | ||
| 45932 | |||
| 45933 | (service btrfs-scrub-service-type | ||
| 45934 | (btrfs-scrub-configuration | ||
| 45935 | (to-scrub "/gnu/store"))) | ||
| 45936 | @end lisp | ||
| 45937 | @end defvar | ||
| 45938 | |||
| 45939 | @c %start of fragment | ||
| 45940 | |||
| 45941 | @deftp {Data Type} btrfs-scrub-configuration | ||
| 45942 | Available @code{btrfs-scrub-configuration} fields are: | ||
| 45943 | |||
| 45944 | @table @asis | ||
| 45945 | @item @code{package} (default: @code{btrfs-progs}) (type: file-like) | ||
| 45946 | The package providing the @command{btrfs} command. | ||
| 45947 | |||
| 45948 | @item @code{schedule} (default: @code{"0 0 1-7 * 0"}) (type: Shepherd calendar event) | ||
| 45949 | Schedule for launching @command{btrfs-scrub}, expressed as a string in | ||
| 45950 | traditional cron syntax or as a gexp evaluating to a Shepherd calendar | ||
| 45951 | event (@pxref{Timers,,, shepherd, The GNU Shepherd Manual}). By default | ||
| 45952 | this is set to run the 1st Sunday of the month, at 00:00. | ||
| 45953 | |||
| 45954 | @item @code{to-scrub} (default: @code{"/"}) (type: maybe-string) | ||
| 45955 | Device to scrub. It will scrub the root (@file{/}) if not given. | ||
| 45956 | |||
| 45957 | @item @code{extra-arguments} (type: maybe-list-of-strings) | ||
| 45958 | Extra options to append to @command{btrfs scrub start} (run @samp{man | ||
| 45959 | btrfs-scrub.8} for more information). Keep in mind that, by definition, | ||
| 45960 | this service uses the @option{-B} flag (do not background and print | ||
| 45961 | scrub statistics when finished). | ||
| 45962 | |||
| 45963 | @end table | ||
| 45964 | |||
| 45965 | @end deftp | ||
| 45966 | |||
| 45891 | @cindex oom | 45967 | @cindex oom |
| 45892 | @cindex out of memory killer | 45968 | @cindex out of memory killer |
| 45893 | @cindex earlyoom | 45969 | @cindex earlyoom |
diff --git a/gnu/services/linux.scm b/gnu/services/linux.scm index 2284741a659..f6e74b60ff5 100644 --- a/gnu/services/linux.scm +++ b/gnu/services/linux.scm | |||
| @@ -9,6 +9,7 @@ | |||
| 9 | ;;; Copyright © 2023 Felix Lechner <felix.lechner@lease-up.com> | 9 | ;;; Copyright © 2023 Felix Lechner <felix.lechner@lease-up.com> |
| 10 | ;;; Copyright © 2025 Edouard Klein <edk@beaver-labs.com> | 10 | ;;; Copyright © 2025 Edouard Klein <edk@beaver-labs.com> |
| 11 | ;;; Copyright © 2026 Giacomo Leidi <therewasa@fishinthecalculator.me> | 11 | ;;; Copyright © 2026 Giacomo Leidi <therewasa@fishinthecalculator.me> |
| 12 | ;;; Copyright © 2026 Joan Vilardaga Castro <codeberg-hn80@joanvc.cat> | ||
| 12 | ;;; | 13 | ;;; |
| 13 | ;;; This file is part of GNU Guix. | 14 | ;;; This file is part of GNU Guix. |
| 14 | ;;; | 15 | ;;; |
| @@ -52,7 +53,10 @@ | |||
| 52 | #:use-module (ice-9 format) | 53 | #:use-module (ice-9 format) |
| 53 | #:use-module (ice-9 match) | 54 | #:use-module (ice-9 match) |
| 54 | #:use-module (ice-9 string-fun) | 55 | #:use-module (ice-9 string-fun) |
| 55 | #:export (earlyoom-configuration | 56 | #:export (btrfs-scrub-configuration |
| 57 | btrfs-scrub-service-type | ||
| 58 | |||
| 59 | earlyoom-configuration | ||
| 56 | earlyoom-configuration? | 60 | earlyoom-configuration? |
| 57 | earlyoom-configuration-earlyoom | 61 | earlyoom-configuration-earlyoom |
| 58 | earlyoom-configuration-minimum-available-memory | 62 | earlyoom-configuration-minimum-available-memory |
| @@ -161,6 +165,131 @@ | |||
| 161 | 165 | ||
| 162 | 166 | ||
| 163 | ;;; | 167 | ;;; |
| 168 | ;;; BTRFS scrub. | ||
| 169 | ;;; | ||
| 170 | |||
| 171 | (define (btrfs-scrub-shepherd-calendar-event? x) | ||
| 172 | (or (string? x) (gexp? x))) | ||
| 173 | |||
| 174 | (define-maybe string (prefix btrfs-scrub-)) | ||
| 175 | |||
| 176 | (define-maybe list-of-strings (prefix btrfs-scrub-)) | ||
| 177 | |||
| 178 | (define (btrfs-scrub-serialize-string field-name value) | ||
| 179 | (if (maybe-value-set? value) | ||
| 180 | (list value) '())) | ||
| 181 | |||
| 182 | (define (btrfs-scrub-serialize-list-of-string field-name value) | ||
| 183 | (if (maybe-value-set? value) | ||
| 184 | value '())) | ||
| 185 | |||
| 186 | (define-configuration btrfs-scrub-configuration | ||
| 187 | (package | ||
| 188 | (file-like btrfs-progs) | ||
| 189 | "The package providing the @command{btrfs} command." empty-serializer) | ||
| 190 | (schedule (btrfs-scrub-shepherd-calendar-event "0 0 1-7 * 0") | ||
| 191 | "Schedule for launching @command{btrfs-scrub}, expressed as a string in | ||
| 192 | traditional cron syntax or as a gexp evaluating to a Shepherd calendar | ||
| 193 | event (@pxref{Timers,,, shepherd, The GNU Shepherd Manual}). By default this | ||
| 194 | is set to run the 1st Sunday of the month, at 00:00." | ||
| 195 | empty-serializer) | ||
| 196 | ;; The following are btrfs-scrub-related options. | ||
| 197 | (to-scrub (maybe-string "/") | ||
| 198 | "Device to scrub. It will scrub the root (\"/\") if not given.") | ||
| 199 | (extra-arguments maybe-list-of-strings | ||
| 200 | "Extra options to append to @command{btrfs scrub start} | ||
| 201 | (run @samp{man btrfs-scrub} for more information). Keep in mind that, | ||
| 202 | by default, this service uses the @option{-B} flag (do not background and | ||
| 203 | print scrub statistics when finished).") | ||
| 204 | (prefix btrfs-scrub-)) | ||
| 205 | |||
| 206 | (define (serialize-btrfs-scrub-configuration config) | ||
| 207 | (list-transduce (compose (base-transducer config) tconcatenate) | ||
| 208 | rcons | ||
| 209 | btrfs-scrub-configuration-fields)) | ||
| 210 | |||
| 211 | |||
| 212 | (define (btrfs-scrub-template-action-procedure btrfs-bin cmd-args to-scrub) | ||
| 213 | "Template procedure to call the btrfs command, print it's outputs and return | ||
| 214 | it's exit code. Taken from | ||
| 215 | https://www.gnu.org/software/guile/manual/html_node/Processes.html#index-spawn" | ||
| 216 | #~(lambda (_ . args) | ||
| 217 | (let* ((stdout-in-out (pipe)) (stderr-in-out (pipe)) | ||
| 218 | (argv (append (list #$btrfs-bin) '#$cmd-args '(#$to-scrub))) | ||
| 219 | (pid (spawn #$btrfs-bin argv | ||
| 220 | #:output (cdr stdout-in-out) | ||
| 221 | #:error (cdr stderr-in-out)))) | ||
| 222 | (close-port (cdr stdout-in-out)) | ||
| 223 | (close-port (cdr stderr-in-out)) | ||
| 224 | (display (get-string-all (car stdout-in-out))) | ||
| 225 | ;; Redirect stderr to stdout to make it printable for "herd" | ||
| 226 | (display (get-string-all (car stderr-in-out))) | ||
| 227 | (close-port (car stdout-in-out)) | ||
| 228 | (close-port (car stderr-in-out)) | ||
| 229 | (let* ((status (waitpid pid)) (exit-val (status:exit-val (cdr status)))) | ||
| 230 | (= EXIT_SUCCESS exit-val))))) | ||
| 231 | |||
| 232 | |||
| 233 | (define (btrfs-scrub-status-action-procedure btrfs-bin to-scrub) | ||
| 234 | "Return a procedure to check the status of the current BTRFS scrub." | ||
| 235 | (btrfs-scrub-template-action-procedure btrfs-bin '("scrub" "status") to-scrub)) | ||
| 236 | |||
| 237 | (define (btrfs-scrub-cancel-action-procedure btrfs-bin to-scrub) | ||
| 238 | "Return a procedure to always cancel the current BTRFS scrub." | ||
| 239 | (btrfs-scrub-template-action-procedure btrfs-bin '("scrub" "cancel") to-scrub)) | ||
| 240 | |||
| 241 | (define (btrfs-scrub-extra-actions btrfs-bin to-scrub) | ||
| 242 | (list shepherd-trigger-action | ||
| 243 | (shepherd-action (name 'scrub-status) | ||
| 244 | (documentation | ||
| 245 | "Print the status of the scrubing process.") | ||
| 246 | (procedure (btrfs-scrub-status-action-procedure | ||
| 247 | btrfs-bin | ||
| 248 | to-scrub))) | ||
| 249 | (shepherd-action (name 'cancel) | ||
| 250 | (documentation | ||
| 251 | "Cancel the current scrub (it's an alias for stop).") | ||
| 252 | (procedure (btrfs-scrub-cancel-action-procedure | ||
| 253 | btrfs-bin | ||
| 254 | to-scrub))))) | ||
| 255 | |||
| 256 | |||
| 257 | (define (btrfs-scrub-shepherd-services config) | ||
| 258 | (match-record config <btrfs-scrub-configuration> | ||
| 259 | (package schedule to-scrub) | ||
| 260 | (let ((btrfs-bin (file-append package "/bin/btrfs"))) | ||
| 261 | (list (shepherd-service | ||
| 262 | (provision (list (string->symbol (string-append "btrfs-scrub-" to-scrub)))) | ||
| 263 | (requirement '(user-processes)) | ||
| 264 | (modules '((shepherd service timer) | ||
| 265 | (ice-9 popen) | ||
| 266 | (ice-9 textual-ports))) | ||
| 267 | (start #~(make-timer-constructor | ||
| 268 | #$(if (string? schedule) | ||
| 269 | #~(cron-string->calendar-event #$schedule) | ||
| 270 | schedule) | ||
| 271 | (command (list #$btrfs-bin | ||
| 272 | "scrub" | ||
| 273 | "start" | ||
| 274 | "-B" | ||
| 275 | #$@(serialize-btrfs-scrub-configuration config))) | ||
| 276 | #:wait-for-termination? #t)) | ||
| 277 | (stop (btrfs-scrub-cancel-action-procedure btrfs-bin to-scrub)) | ||
| 278 | (documentation "Periodically run the 'btrfs-scrub' command.") | ||
| 279 | (actions (btrfs-scrub-extra-actions btrfs-bin to-scrub))))))) | ||
| 280 | |||
| 281 | |||
| 282 | (define btrfs-scrub-service-type | ||
| 283 | (service-type (name 'btrfs-scrub) | ||
| 284 | (extensions (list (service-extension | ||
| 285 | shepherd-root-service-type | ||
| 286 | btrfs-scrub-shepherd-services))) | ||
| 287 | (description | ||
| 288 | "Verify the block checksums of a BTRFS filesystem.") | ||
| 289 | (default-value (btrfs-scrub-configuration)))) | ||
| 290 | |||
| 291 | |||
| 292 | ;;; | ||
| 164 | ;;; Early OOM daemon. | 293 | ;;; Early OOM daemon. |
| 165 | ;;; | 294 | ;;; |
| 166 | 295 | ||
| @@ -251,7 +380,7 @@ representation." | |||
| 251 | ;;; fstrim | 380 | ;;; fstrim |
| 252 | ;;; | 381 | ;;; |
| 253 | 382 | ||
| 254 | (define (shepherd-calendar-event? x) | 383 | (define (fstrim-shepherd-calendar-event? x) |
| 255 | (or (string? x) (gexp? x))) | 384 | (or (string? x) (gexp? x))) |
| 256 | 385 | ||
| 257 | (define-maybe list-of-strings (prefix fstrim-)) | 386 | (define-maybe list-of-strings (prefix fstrim-)) |
| @@ -271,7 +400,7 @@ representation." | |||
| 271 | "The package providing the @command{fstrim} command." | 400 | "The package providing the @command{fstrim} command." |
| 272 | empty-serializer) | 401 | empty-serializer) |
| 273 | (schedule | 402 | (schedule |
| 274 | (shepherd-calendar-event "0 0 * * 0") | 403 | (fstrim-shepherd-calendar-event "0 0 * * 0") |
| 275 | "Schedule for launching @command{fstrim}, expressed as a string in | 404 | "Schedule for launching @command{fstrim}, expressed as a string in |
| 276 | traditional cron syntax or as a gexp evaluating to a Shepherd calendar | 405 | traditional cron syntax or as a gexp evaluating to a Shepherd calendar |
| 277 | event (@pxref{Timers,,, shepherd, The GNU Shepherd Manual}). By default this | 406 | event (@pxref{Timers,,, shepherd, The GNU Shepherd Manual}). By default this |
