summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristopher Baines <mail@cbaines.net>2026-08-07 20:34:24 +0100
committerChristopher Baines <mail@cbaines.net>2026-08-21 16:42:58 +0100
commitdd12ee28474c2e4b128e8ab37cc4113a2088b604 (patch)
treedccbb075f59028b545eb860c24be269bf4481b1a
parentc3832cd497a8fcd87e84878c6ee3bbc10f42d0ca (diff)
gnu: services: pm: Add hd-idle.
* gnu/services/pm.scm: (hd-idle-disk, hd-idle-disk?, hd-idle-configuration, hd-idle-configuration?): New prodedures. (hd-idle-service-type): New variable. * doc/guix.texi (Power Management Services): Document it. Change-Id: I205b9a8de9aa8a15314d03962582aa3ae245a31e
-rw-r--r--doc/guix.texi95
-rw-r--r--gnu/services/pm.scm143
2 files changed, 237 insertions, 1 deletions
diff --git a/doc/guix.texi b/doc/guix.texi
index f13c6ed970f..f19cb4f1ee6 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -41289,6 +41289,101 @@ packages linux)} module
41289@end table 41289@end table
41290@end deftp 41290@end deftp
41291 41291
41292@cindex hd-idle
41293@cindex spinning down hard disks
41294@subsubheading hd-idle
41295
41296The @code{(gnu services pm)} module also provides a service definition
41297for @uref{https://github.com/adelolmo/hd-idle, hd-idle}, a daemon that
41298spins down hard disks after a period of inactivity. It is primarily
41299useful for external @acronym{USB, Universal Serial Bus} disks, which
41300usually do not support setting an idle timer with @command{hdparm}.
41301
41302@defvar hd-idle-service-type
41303The service type for hd-idle. Its value is an
41304@code{hd-idle-configuration} record, as in this example, which spins
41305down all disks after ten minutes of inactivity, except for
41306@file{/dev/sda}, which is spun down after two minutes:
41307
41308@lisp
41309(service hd-idle-service-type
41310 (hd-idle-configuration
41311 (idle-time 600)
41312 (disks (list (hd-idle-disk
41313 (name "sda")
41314 (idle-time 120))))))
41315@end lisp
41316@end defvar
41317
41318@deftp {Data Type} hd-idle-configuration
41319Data type representing the configuration of @code{hd-idle-service-type}.
41320
41321@table @asis
41322@item @code{idle-time} (default: @code{600})
41323Number of seconds a disk must be idle before it is spun down. A value
41324of @code{0} disables spinning down.
41325
41326To have hd-idle only work with the explicitly configured disks, set this
41327to @code{0}.
41328
41329@item @code{command-type} (default: @code{'scsi})
41330The command used to spin disks down, either @code{'scsi} or @code{'ata}.
41331
41332@item @code{power-condition} (default: @code{0})
41333The power condition passed to the @acronym{SCSI, Small Computer System
41334Interface} @code{START STOP UNIT} command, an integer between @code{0}
41335and @code{15}. It is ignored when @code{command-type} is @code{'ata}.
41336
41337@item @code{symlink-policy} (default: @code{0})
41338How to resolve disk names that are symbolic links. @code{0} resolves
41339them once at startup, whereas with @code{1} symlinks are also resolved
41340on runtime until success.
41341
41342@item @code{log-file} (default: unset)
41343A file name to which hd-idle logs disk spin-up and spin-down events, for
41344instance @code{"/var/log/hd-idle.log"}. When left unset, no log file is
41345written.
41346
41347@item @code{ignore-spin-down-detection?} (default: @code{#f})
41348Whether to skip detection of disks that were spun down by some other
41349means.
41350
41351@item @code{debug?} (default: @code{#f})
41352Whether to log the disk statistics that hd-idle reads on each poll.
41353
41354@item @code{disks} (default: @code{'()})
41355A list of @code{hd-idle-disk} records (see below) describing per-disk
41356overrides. Disks that are not listed here are still managed, using the
41357values above.
41358
41359@item @code{hd-idle} (default: @code{hd-idle})
41360The hd-idle package to use.
41361@end table
41362@end deftp
41363
41364@deftp {Data Type} hd-idle-disk
41365Data type overriding the configuration above for a single disk. Fields
41366left unset default to the corresponding top-level
41367@code{hd-idle-configuration} value.
41368
41369@table @asis
41370@item @code{name}
41371The device to configure, either a name under @file{/dev} such as
41372@code{"sda"}, or an absolute file name such as
41373@code{"/dev/disk/by-uuid/1234-5678"}.
41374
41375@item @code{idle-time} (default: unset)
41376Number of seconds this disk must be idle before it is spun down.
41377
41378@item @code{command-type} (default: unset)
41379The command used to spin this disk down, either @code{'scsi} or
41380@code{'ata}.
41381
41382@item @code{power-condition} (default: unset)
41383The power condition to use for this disk.
41384@end table
41385@end deftp
41386
41292The @code{(gnu services power)} module provides a service definition for 41387The @code{(gnu services power)} module provides a service definition for
41293@uref{http://www.apcupsd.org/, apcupsd}, a utility to interact with 41388@uref{http://www.apcupsd.org/, apcupsd}, a utility to interact with
41294@acronym{APC, APC by Schneider Electric or formerly American Power 41389@acronym{APC, APC by Schneider Electric or formerly American Power
diff --git a/gnu/services/pm.scm b/gnu/services/pm.scm
index 12f05b4b335..ab867f7cad0 100644
--- a/gnu/services/pm.scm
+++ b/gnu/services/pm.scm
@@ -27,6 +27,7 @@
27 #:use-module (guix records) 27 #:use-module (guix records)
28 #:use-module (gnu packages admin) 28 #:use-module (gnu packages admin)
29 #:use-module (gnu packages freedesktop) 29 #:use-module (gnu packages freedesktop)
30 #:use-module (gnu packages hardware)
30 #:use-module (gnu packages linux) 31 #:use-module (gnu packages linux)
31 #:use-module (gnu services) 32 #:use-module (gnu services)
32 #:use-module (gnu services base) 33 #:use-module (gnu services base)
@@ -44,7 +45,13 @@
44 thermald-service-type 45 thermald-service-type
45 46
46 powertop-configuration 47 powertop-configuration
47 powertop-service-type)) 48 powertop-service-type
49
50 hd-idle-disk
51 hd-idle-disk?
52 hd-idle-configuration
53 hd-idle-configuration?
54 hd-idle-service-type))
48 55
49;;; 56;;;
50;;; power-profiles-daemon 57;;; power-profiles-daemon
@@ -579,3 +586,137 @@ prevent overheating.")))
579 (default-value (powertop-configuration)) 586 (default-value (powertop-configuration))
580 (description "Tune power-related kernel parameters to reduce energy 587 (description "Tune power-related kernel parameters to reduce energy
581 consumption."))) 588 consumption.")))
589
590
591
592;;;
593;;; hd-idle
594;;;
595;;; Spins down hard disks that have been idle for a while.
596
597(define (hd-idle-command-type? val)
598 (memq val '(scsi ata)))
599(define-maybe/no-serialization hd-idle-command-type)
600
601(define (hd-idle-power-condition? val)
602 (and (exact-integer? val) (<= 0 val 15)))
603(define-maybe/no-serialization hd-idle-power-condition)
604
605(define (hd-idle-symlink-policy? val)
606 (and (exact-integer? val) (<= 0 val 1)))
607
608(define-configuration/no-serialization hd-idle-disk
609 (name
610 string
611 "The device to configure, either a name under @file{/dev} such as
612@code{\"sda\"}, or an absolute file name such as
613@code{\"/dev/disk/by-uuid/1234-5678\"}.")
614
615 (idle-time
616 maybe-non-negative-integer
617 "Number of seconds this disk must be idle before it is spun down.")
618
619 (command-type
620 maybe-hd-idle-command-type
621 "The command used to spin this disk down, either @code{'scsi} or
622@code{'ata}.")
623
624 (power-condition
625 maybe-hd-idle-power-condition
626 "The power condition to use for this disk."))
627
628(define list-of-hd-idle-disks?
629 (list-of hd-idle-disk?))
630
631(define-configuration/no-serialization hd-idle-configuration
632 (idle-time
633 (non-negative-integer 600)
634 "Number of seconds a disk must be idle before it is spun down. A value
635of @code{0} disables spinning down.")
636
637 (command-type
638 (hd-idle-command-type 'scsi)
639 "The command used to spin disks down, either @code{'scsi} or @code{'ata}.")
640
641 (power-condition
642 (hd-idle-power-condition 0)
643 "The power condition passed to the @acronym{SCSI, Small Computer System
644Interface} @code{START STOP UNIT} command, an integer between @code{0} and
645@code{15}. It is ignored when @code{command-type} is @code{'ata}.")
646
647 (symlink-policy
648 (hd-idle-symlink-policy 0)
649 "How to resolve disk names that are symbolic links. @code{0} resolves
650them once at startup, whereas with @code{1} symlinks are also resolved on
651runtime until success.")
652
653 (log-file
654 maybe-string
655 "A file name to which hd-idle logs disk spin-up and spin-down events, for
656instance @code{\"/var/log/hd-idle.log\"}.")
657
658 (ignore-spin-down-detection?
659 (boolean #f)
660 "Whether to skip detection of disks that were spun down by some other
661means.")
662
663 (debug?
664 (boolean #f)
665 "Whether to log the disk statistics that hd-idle reads on each poll.")
666
667 (disks
668 (list-of-hd-idle-disks '())
669 "A list of @code{hd-idle-disk} records describing per-disk overrides.
670Disks that are not listed here are still managed, using the values above.")
671
672 (hd-idle
673 (file-like hd-idle)
674 "The hd-idle package to use."))
675
676(define (hd-idle-disk-arguments disk)
677 (match-record disk <hd-idle-disk>
678 (name idle-time command-type power-condition)
679 `("-a" ,name
680 ,@(if (maybe-value-set? idle-time)
681 (list "-i" (number->string idle-time))
682 '())
683 ,@(if (maybe-value-set? command-type)
684 (list "-c" (symbol->string command-type))
685 '())
686 ,@(if (maybe-value-set? power-condition)
687 (list "-p" (number->string power-condition))
688 '()))))
689
690(define (hd-idle-arguments config)
691 (match-record config <hd-idle-configuration>
692 (idle-time command-type power-condition symlink-policy
693 log-file ignore-spin-down-detection? debug? disks)
694 `("-i" ,(number->string idle-time)
695 "-c" ,(symbol->string command-type)
696 "-p" ,(number->string power-condition)
697 "-s" ,(number->string symlink-policy)
698 ,@(if (maybe-value-set? log-file) (list "-l" log-file) '())
699 ,@(if ignore-spin-down-detection? '("-I") '())
700 ,@(if debug? '("-d") '())
701 ,@(append-map hd-idle-disk-arguments disks))))
702
703(define (hd-idle-shepherd-service config)
704 (list
705 (shepherd-service
706 (provision '(hd-idle))
707 (requirement '(user-processes udev))
708 (documentation "Spin down idle hard disks.")
709 (start #~(make-forkexec-constructor
710 (list #$(file-append (hd-idle-configuration-hd-idle config)
711 "/bin/hd-idle")
712 #$@(hd-idle-arguments config))))
713 (stop #~(make-kill-destructor)))))
714
715(define hd-idle-service-type
716 (service-type
717 (name 'hd-idle)
718 (extensions (list (service-extension shepherd-root-service-type
719 hd-idle-shepherd-service)))
720 (default-value (hd-idle-configuration))
721 (description "Run @command{hd-idle}, which spins down hard disks that have
722not been accessed for a configurable period of time.")))