From a445e01371b90253f202539433c937608d887bec Mon Sep 17 00:00:00 2001 From: Efraim Flashner Date: Wed, 22 Jul 2020 21:07:31 +0300 Subject: [PATCH v2] services: Add zram-device-service. * gnu/services/linux.scm (): New record. (zram-device-service-type): New variable. * doc/guix.texi (Linux Services): Document it. * tests/services/linux.scm (zram-swap-device-test): New tests. --- doc/guix.texi | 45 ++++++++++++++++++++++ gnu/services/linux.scm | 81 +++++++++++++++++++++++++++++++++++++++- tests/services/linux.scm | 37 ++++++++++++++++++ 3 files changed, 162 insertions(+), 1 deletion(-) diff --git a/doc/guix.texi b/doc/guix.texi index d4557b360a..37ececd72f 100644 --- a/doc/guix.texi +++ b/doc/guix.texi @@ -27259,6 +27259,51 @@ parameters, can be done as follow: @end lisp @end deffn +@cindex zram +@cindex compressed swap +@cindex Compressed RAM-based block devices +@subsubheading Zram Device Service + +The Zram device service provides a compressed swap device in system +memory. The Linux Kernel documentation has more information about +@uref{https://www.kernel.org/doc/html/latest/admin-guide/blockdev/zram.html,zram} +devices. + +@deffn {Scheme Variable} zram-device-service-type +This service creates the zram block device, formats it as swap and +enables it as a swap device. The service's value is a +@code{zram-device-configuration} record. + +@deftp {Data Type} zram-device-configuration +This is the data type representing the configuration for the zram-device +service. + +@table @asis +@item @code{size} (default @var{"1G"}) +This is the amount of space you wish to provide for the zram device. It +accepts a string and can be a number of bytes or use a suffix, eg.: +@var{"512M"} or @var{1024000}. +@item @code{compression-algorithm} (default @var{'lzo}) +This is the compression algorithm you wish to use. It is difficult to +list all the possible compression options, but common ones supported by +Guix's Linux Libre Kernel include @var{'lzo}, @var{'lz4} and @var{'zstd}. +@item @code{memory-limit} (default @var{0}) +This is the maximum amount of memory which the zram device can use. +Setting it to '0' disables the limit. While it is generally expected +that compression will be 2:1, it is possible that uncompressable data +can be written to swap and this is a method to limit how much memory can +be used. It accepts a string and can be a number of bytes or use a +suffix, eg.: @var{"2G"}. +@item @code{priority} (default @var{-1}) +This is the priority of the swap device created from the zram device. +@code{swapon} accepts values between -1 and 32767, with higher values +indicating higher priority. Higher priority swap will generally be used +first. +@end table + +@end deftp +@end deffn + @node Hurd Services @subsection Hurd Services diff --git a/gnu/services/linux.scm b/gnu/services/linux.scm index 12934c2084..ec42663a11 100644 --- a/gnu/services/linux.scm +++ b/gnu/services/linux.scm @@ -1,6 +1,7 @@ ;;; GNU Guix --- Functional package management for GNU ;;; Copyright © 2020 Maxim Cournoyer ;;; Copyright © 2020 Brice Waegeneire +;;; Copyright © 2020 Efraim Flashner ;;; ;;; This file is part of GNU Guix. ;;; @@ -22,6 +23,7 @@ #:use-module (guix records) #:use-module (guix modules) #:use-module (gnu services) + #:use-module (gnu services base) #:use-module (gnu services shepherd) #:use-module (gnu packages linux) #:use-module (srfi srfi-1) @@ -42,7 +44,15 @@ earlyoom-configuration-send-notification-command earlyoom-service-type - kernel-module-loader-service-type)) + kernel-module-loader-service-type + + zram-device-configuration + zram-device-configuration? + zram-device-configuration-size + zram-device-configuration-compression-algorithm + zram-device-configuration-memory-limit + zram-device-configuration-priority + zram-device-service-type)) ;;; @@ -177,3 +187,72 @@ representation." (compose concatenate) (extend append) (default-value '()))) + + +;;; +;;; Kernel module loader. +;;; + +(define-record-type* + zram-device-configuration make-zram-device-configuration + zram-device-configuration? + (size zram-device-configration-size + (default "1G")) ; string or integer + (compression-algorithm zram-device-configuration-compression-algorithm + (default 'lzo)) ; symbol + (memory-limit zram-device-configuration-memory-limit + (default 0)) ; string or integer + (priority zram-device-configuration-priority + (default -1))) ; integer + +(define (zram-device-configuration->udev-string config) + "Translate a into a string which can be +placed in a udev rules file." + (match config + (($ size compression-algorithm memory-limit priority) + (string-append + "KERNEL==\"zram0\", " + "ATTR{comp_algorithm}=\"" (symbol->string compression-algorithm) "\" " + (if (not (or (equal? "0" size) + (equal? 0 size))) + (string-append "ATTR{disksize}=\"" (if (number? size) + (number->string size) + size) + "\" ") + "") + (if (not (or (equal? "0" memory-limit) + (equal? 0 memory-limit))) + (string-append "ATTR{mem_limit}=\"" (if (number? memory-limit) + (number->string memory-limit) + memory-limit) + "\" ") + "") + "RUN+=\"/run/current-system/profile/sbin/mkswap /dev/zram0\" " + "RUN+=\"/run/current-system/profile/sbin/swapon " + (if (not (equal? -1 priority)) + (string-append "--priority " (number->string priority) " ") + "") + "/dev/zram0\"\n")))) + +(define %zram-device-config + `("modprobe.d/zram.conf" + ,(plain-file "zram.conf" + "options zram num_devices=1"))) + +(define (zram-device-udev-rule config) + (file->udev-rule "99-zram.rules" + (plain-file "99-zram.rules" + (zram-device-configuration->udev-string config)))) + +(define zram-device-service-type + (service-type + (name 'zram) + (default-value (zram-device-configuration)) + (extensions + (list (service-extension kernel-module-loader-service-type + (const (list "zram"))) + (service-extension etc-service-type + (const (list %zram-device-config))) + (service-extension udev-service-type + (compose list zram-device-udev-rule)))) + (description "Creates a zram swap device."))) diff --git a/tests/services/linux.scm b/tests/services/linux.scm index 8ad119c49f..e2cd191e48 100644 --- a/tests/services/linux.scm +++ b/tests/services/linux.scm @@ -1,5 +1,6 @@ ;;; GNU Guix --- Functional package management for GNU ;;; Copyright © 2020 Maxim Cournoyer +;;; Copyright © 2020 Efraim Flashner ;;; ;;; This file is part of GNU Guix. ;;; @@ -54,4 +55,40 @@ "-N" "python \"/some/path/notify-all-users.py\"") (earlyoom-configuration->command-line-args %earlyoom-configuration-sample)) + +;;; +;;; Zram swap device. +;;; + +(define zram-device-configuration->udev-string + (@@ (gnu services linux) zram-device-configuration->udev-string)) + +(define %zram-swap-device-test-1 + (zram-device-configuration + (size "2G") + (compression-algorithm 'zstd) + (memory-limit "1G") + (priority 42))) + +(test-equal "zram-swap-device-test-1" + "KERNEL==\"zram0\", ATTR{comp_algorithm}=\"zstd\" ATTR{disksize}=\"2G\" ATTR{mem_limit}=\"1G\" RUN+=\"/run/current-system/profile/sbin/mkswap /dev/zram0\" RUN+=\"/run/current-system/profile/sbin/swapon --priority 42 /dev/zram0\"\n" + (zram-device-configuration->udev-string %zram-swap-device-test-1)) + +(define %zram-swap-device-test-2 + (zram-device-configuration + (size 1048576) ; 1M + (compression-algorithm 'lz4))) + +(test-equal "zram-swap-device-test-2" + "KERNEL==\"zram0\", ATTR{comp_algorithm}=\"lz4\" ATTR{disksize}=\"1048576\" RUN+=\"/run/current-system/profile/sbin/mkswap /dev/zram0\" RUN+=\"/run/current-system/profile/sbin/swapon /dev/zram0\"\n" + (zram-device-configuration->udev-string %zram-swap-device-test-2)) + +(define %zram-swap-device-test-3 + (zram-device-configuration + (memory-limit (* 512 1000)))) + +(test-equal "zram-swap-device-test-3" + "KERNEL==\"zram0\", ATTR{comp_algorithm}=\"lzo\" ATTR{disksize}=\"1G\" ATTR{mem_limit}=\"512000\" RUN+=\"/run/current-system/profile/sbin/mkswap /dev/zram0\" RUN+=\"/run/current-system/profile/sbin/swapon /dev/zram0\"\n" + (zram-device-configuration->udev-string %zram-swap-device-test-3)) + (test-end "linux-services") -- 2.27.0