zram-generator-1.1.2/.cargo_vcs_info.json0000644000000001360000000000100137720ustar { "git": { "sha1": "1bf6b08d8bd15624280482b1c125902f90c706aa" }, "path_in_vcs": "" }zram-generator-1.1.2/.github/workflows/ci.yml000064400000000000000000000034210072674642500173250ustar 00000000000000# SPDX-License-Identifier: MIT name: ci on: push: pull_request: schedule: - cron: "0 4 * * *" env: CARGO_TERM_COLOR: always jobs: test: name: Build and run tests (rust ${{ matrix.rust }}) runs-on: ubuntu-latest strategy: matrix: rust: - stable - beta - nightly steps: - name: Checkout repository uses: actions/checkout@v2 - name: Install linux-modules-extra-$(uname -r) run: | sudo apt update sudo apt install -y linux-modules-extra-$(uname -r) - name: Insert zram module run: sudo modprobe -v zram - name: Install Rust uses: actions-rs/toolchain@v1 with: toolchain: ${{ matrix.rust }} override: true profile: minimal - name: Build run: make program CARGOFLAGS="--verbose" - name: Run tests run: make check CARGOFLAGS="--verbose" rustfmt: name: rustfmt runs-on: ubuntu-latest steps: - name: Checkout repository uses: actions/checkout@v2 - name: Install Rust uses: actions-rs/toolchain@v1 with: toolchain: stable override: true profile: minimal components: rustfmt - name: Check formatting uses: actions-rs/cargo@v1 with: command: fmt args: -- --check clippy: name: clippy runs-on: ubuntu-latest steps: - name: Checkout repository uses: actions/checkout@v2 - name: Install Rust uses: actions-rs/toolchain@v1 with: toolchain: nightly override: true profile: minimal components: clippy - name: Validate clippy run: make clippy CARGOFLAGS="-- -D warnings" zram-generator-1.1.2/.gitignore000064400000000000000000000000420072674642500145760ustar 00000000000000*~ /Cargo.lock /target **/*.rs.bk zram-generator-1.1.2/Cargo.lock0000644000000210020000000000100117400ustar # This file is automatically @generated by Cargo. # It is not intended for manual editing. version = 3 [[package]] name = "ahash" version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "739f4a8db6605981345c5654f3a85b056ce52f37a39d34da03f25bf2151ea16e" [[package]] name = "anyhow" version = "1.0.45" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ee10e43ae4a853c0a3591d4e2ada1719e553be18199d9da9d4a83f5927c2f5c7" [[package]] name = "autocfg" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" [[package]] name = "bitflags" version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" [[package]] name = "cc" version = "1.0.72" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "22a9137b95ea06864e018375b72adfb7db6e6f68cfc8df5a04d00288050485ee" [[package]] name = "cfg-if" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "clap" version = "2.33.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002" dependencies = [ "bitflags", "textwrap", "unicode-width", ] [[package]] name = "ctor" version = "0.1.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ccc0a48a9b826acdf4028595adc9db92caea352f7af011a3034acd172a52a0aa" dependencies = [ "quote", "syn", ] [[package]] name = "dlv-list" version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68df3f2b690c1b86e65ef7830956aededf3cb0a16f898f79b9a6f421a7b6211b" dependencies = [ "rand", ] [[package]] name = "fasteval" version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4f4cdac9e4065d7c48e30770f8665b8cef9a3a73a63a4056a33a5f395bc7cf75" [[package]] name = "fs_extra" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2022715d62ab30faffd124d40b76f4134a550a87792276512b18d63272333394" [[package]] name = "getrandom" version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753" dependencies = [ "cfg-if", "libc", "wasi", ] [[package]] name = "hashbrown" version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d7afe4a420e3fe79967a00898cc1f4db7c8a49a9333a29f8a4bd76a253d5cd04" dependencies = [ "ahash", ] [[package]] name = "libc" version = "0.2.107" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fbe5e23404da5b4f555ef85ebed98fb4083e55a00c317800bc2a50ede9f3d219" [[package]] name = "liboverdrop" version = "0.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3a8bcc76c5aad4677420857a8744ec8aef80b1b21c5501e2f8c7ac3fda2e19ba" dependencies = [ "log", ] [[package]] name = "log" version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" dependencies = [ "cfg-if", ] [[package]] name = "memoffset" version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "59accc507f1338036a0477ef61afdae33cde60840f4dfe481319ce3ad116ddf9" dependencies = [ "autocfg", ] [[package]] name = "nix" version = "0.22.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3bb9a13fa32bc5aeb64150cd3f32d6cf4c748f8f8a417cce5d2eb976a8370ba" dependencies = [ "bitflags", "cc", "cfg-if", "libc", "memoffset", ] [[package]] name = "ordered-multimap" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1c672c7ad9ec066e428c00eb917124a06f08db19e2584de982cc34b1f4c12485" dependencies = [ "dlv-list", "hashbrown", ] [[package]] name = "ppv-lite86" version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed0cfbc8191465bed66e1718596ee0b0b35d5ee1f41c5df2189d0fe8bde535ba" [[package]] name = "proc-macro2" version = "1.0.32" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba508cc11742c0dc5c1659771673afbab7a0efab23aa17e854cbab0837ed0b43" dependencies = [ "unicode-xid", ] [[package]] name = "quote" version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "38bc8cc6a5f2e3655e0899c1b848643b2562f853f114bfec7be120678e3ace05" dependencies = [ "proc-macro2", ] [[package]] name = "rand" version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2e7573632e6454cf6b99d7aac4ccca54be06da05aca2ef7423d22d27d4d4bcd8" dependencies = [ "libc", "rand_chacha", "rand_core", "rand_hc", ] [[package]] name = "rand_chacha" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" dependencies = [ "ppv-lite86", "rand_core", ] [[package]] name = "rand_core" version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7" dependencies = [ "getrandom", ] [[package]] name = "rand_hc" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d51e9f596de227fda2ea6c84607f5558e196eeaf43c986b724ba4fb8fdf497e7" dependencies = [ "rand_core", ] [[package]] name = "redox_syscall" version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff" dependencies = [ "bitflags", ] [[package]] name = "remove_dir_all" version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" dependencies = [ "winapi", ] [[package]] name = "rust-ini" version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "63471c4aa97a1cf8332a5f97709a79a4234698de6a1f5087faf66f2dae810e22" dependencies = [ "cfg-if", "ordered-multimap", ] [[package]] name = "syn" version = "1.0.81" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f2afee18b8beb5a596ecb4a2dce128c719b4ba399d34126b9e4396e3f9860966" dependencies = [ "proc-macro2", "quote", "unicode-xid", ] [[package]] name = "tempfile" version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dac1c663cfc93810f88aed9b8941d48cabf856a1b111c29a40439018d870eb22" dependencies = [ "cfg-if", "libc", "rand", "redox_syscall", "remove_dir_all", "winapi", ] [[package]] name = "textwrap" version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" dependencies = [ "unicode-width", ] [[package]] name = "unicode-width" version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973" [[package]] name = "unicode-xid" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" [[package]] name = "wasi" version = "0.10.2+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" [[package]] name = "winapi" version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" dependencies = [ "winapi-i686-pc-windows-gnu", "winapi-x86_64-pc-windows-gnu", ] [[package]] name = "winapi-i686-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "zram-generator" version = "1.1.2" dependencies = [ "anyhow", "clap", "ctor", "fasteval", "fs_extra", "liboverdrop", "log", "nix", "rust-ini", "tempfile", ] zram-generator-1.1.2/Cargo.toml0000644000000026650000000000100120010ustar # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2018" name = "zram-generator" version = "1.1.2" authors = ["Zbigniew Jędrzejewski-Szmek ", "Igor Raits ", "наб "] exclude = ["tests/07a-mount-point-excl", "tests/10-example"] description = "Systemd unit generator for zram swap devices." homepage = "https://github.com/systemd/zram-generator" license = "MIT" [profile.release] opt-level = "z" lto = true codegen-units = 1 panic = "abort" [dependencies.anyhow] version = "1.0.12" [dependencies.clap] version = "2.33" default-features = false [dependencies.fasteval] version = "0.2" default-features = false [dependencies.liboverdrop] version = "0.0.2" [dependencies.log] version = "0.4" features = ["std"] [dependencies.rust-ini] version = ">=0.15, <0.18" [dev-dependencies.ctor] version = "0.1" [dev-dependencies.fs_extra] version = "1.1" [dev-dependencies.nix] version = ">=0.22, <0.24" [dev-dependencies.tempfile] version = "3" zram-generator-1.1.2/Cargo.toml.orig000064400000000000000000000015540072674642500155060ustar 00000000000000# SPDX-License-Identifier: MIT [package] name = "zram-generator" version = "1.1.2" authors = ["Zbigniew Jędrzejewski-Szmek ", "Igor Raits ", "наб "] license = "MIT" description = "Systemd unit generator for zram swap devices." homepage = "https://github.com/systemd/zram-generator" edition = "2018" exclude = ["tests/07a-mount-point-excl", "tests/10-example"] [dependencies] anyhow = "1.0.12" clap = { version = "2.33", default-features = false } liboverdrop = "0.0.2" rust-ini = ">=0.15, <0.18" log = { version = "0.4", features = ["std"] } fasteval = { version = "0.2", default-features = false } [dev-dependencies] tempfile = "3" fs_extra = "1.1" nix = ">=0.22, <0.24" ctor = "0.1" [profile.release] lto = true opt-level = "z" codegen-units = 1 panic = "abort" zram-generator-1.1.2/LICENSE000064400000000000000000000017770072674642500136330ustar 00000000000000Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. zram-generator-1.1.2/Makefile000064400000000000000000000036400072674642500142550ustar 00000000000000# SPDX-License-Identifier: MIT INSTALL ?= install CARGO ?= cargo CARGOFLAGS ?= RONN ?= ronn PKG_CONFIG ?= pkg-config PREFIX ?= /usr BUILDTYPE ?= release SYSTEMD_UTIL_DIR := $(shell $(PKG_CONFIG) --variable=systemdutildir systemd) SYSTEMD_SYSTEM_UNIT_DIR := $(shell $(PKG_CONFIG) --variable=systemdsystemunitdir systemd) SYSTEMD_SYSTEM_GENERATOR_DIR := $(shell $(PKG_CONFIG) --variable=systemdsystemgeneratordir systemd) export SYSTEMD_UTIL_DIR ifeq ($(BUILDTYPE),release) override CARGOFLAGS := --release $(CARGOFLAGS) endif require_env = @[ -n "$($(1))" ] || { echo "\$$$(1) empty!" >&2; exit 1; } .DEFAULT: build .PHONY: build systemd-service program man check clean install build: program systemd-service ifndef NOMAN build: man endif program: $(call require_env,SYSTEMD_UTIL_DIR) $(CARGO) build $(CARGOFLAGS) systemd-service: $(call require_env,SYSTEMD_SYSTEM_GENERATOR_DIR) sed -e 's,@SYSTEMD_SYSTEM_GENERATOR_DIR@,$(SYSTEMD_SYSTEM_GENERATOR_DIR),' \ < units/systemd-zram-setup@.service.in \ > units/systemd-zram-setup@.service man: $(RONN) --organization="zram-generator developers" man/*.md check: program $(CARGO) test $(CARGOFLAGS) clippy: $(call require_env,SYSTEMD_UTIL_DIR) $(CARGO) clippy $(CARGOFLAGS) clean: $(CARGO) clean rm -f units/systemd-zram-setup@.service ifndef NOBUILD install: build endif install: $(call require_env,SYSTEMD_SYSTEM_GENERATOR_DIR) $(call require_env,SYSTEMD_SYSTEM_UNIT_DIR) $(call require_env,PREFIX) $(INSTALL) -Dpm755 target/$(BUILDTYPE)/zram-generator -t $(DESTDIR)$(SYSTEMD_SYSTEM_GENERATOR_DIR)/ $(INSTALL) -Dpm644 units/systemd-zram-setup@.service -t $(DESTDIR)$(SYSTEMD_SYSTEM_UNIT_DIR)/ $(INSTALL) -Dpm644 zram-generator.conf.example -t $(DESTDIR)$(PREFIX)/share/doc/zram-generator/ ifndef NOMAN $(INSTALL) -Dpm644 man/zram-generator.8 -t $(DESTDIR)$(PREFIX)/share/man/man8/ $(INSTALL) -Dpm644 man/zram-generator.conf.5 -t $(DESTDIR)$(PREFIX)/share/man/man5/ endif zram-generator-1.1.2/README.md000064400000000000000000000110660072674642500140750ustar 00000000000000# `systemd-zram-setup@.service` generator for zram devices Packaging status This generator provides a simple and fast mechanism to configure swap on `/dev/zram*` devices. The main use case is create **swap** devices, but devices with a file system can be created too, see below. ### Configuration A default config file may be located in /usr. This generator checks the following locations: * `/run/systemd/zram-generator.conf` * `/etc/systemd/zram-generator.conf` * `/usr/local/lib/systemd/zram-generator.conf` * `/usr/lib/systemd/zram-generator.conf` … and the first file found in that list wins. In addition, "drop-ins" will be loaded from `.conf` files in `/etc/systemd/zram-generator.conf.d/`, `/usr/lib/systemd/zram-generator.conf.d/`, etc. The main configuration file is read before any of the drop-ins and has the lowest precedence; entries in the drop-in files override entries in the main configuration file. See systemd.unit(5) for a detailed description of this logic. See `zram-generator.conf.example` for a list of available settings. ### Swap devices Create `/etc/systemd/zram-generator.conf`: ```ini # /etc/systemd/zram-generator.conf [zram0] zram-size = ram / 2 ``` A zram device will be created for each section. No actual configuration is necessary (the default of `zram-size = min(ram / 2, 4096)` will be used unless overriden), but the configuration file with at least one section must exist. ### Mount points ```ini # /etc/systemd/zram-generator.conf [zram1] mount-point = /var/compressed ``` This will set up a /dev/zram1 with ext2 and generate a mount unit for /var/compressed. In case you want this path to be user-writable, you can use following "high-quality hack" until `systemd-makefs` provides a proper mechanism to set ownership of a generated filesystem. For the above example, create an override for `systemd-zram-setup@zram1.service`, for example with `systemctl edit`, containing the following (note the sticky bit as required for [/var]/tmp): ```ini [Service] ExecStartPost=/bin/sh -c 'd=$(mktemp -d); mount "$1" "$d"; chmod 1777 "$d"; umount "$d"; rmdir "$d"' _ /dev/%i ``` ### Rust The second purpose of this program is to serve as an example of a systemd generator in rust. ### Installation It is recommended to use an existing package: * Fedora: `sudo dnf install zram-generator-defaults` (or `sudo dnf install zram-generator` to install without the default configuration) * Debian: packages provided by nabijaczleweli, see https://debian.nabijaczleweli.xyz/README. * Arch: `sudo pacman -S zram-generator` (or https://aur.archlinux.org/packages/zram-generator-git/ for the latest git commit) To install directly from sources, execute `make build && sudo make install NOBUILD=true`: * `zram-generator` binary is installed in the systemd system generator directory (usually `/usr/lib/systemd/system-generators/`) * `zram-generator(8)` and `zram-generator.conf(5)` manpages are installed into `/usr/share/man/manN/`, this requires [`ronn`](https://github.com/apjanke/ronn-ng). * `units/systemd-zram-setup@.service` is copied into the systemd system unit directory (usually `/usr/lib/systemd/system/`) * `zram-generator.conf.example` is copied into `/usr/share/doc/zram-generator/` You need though create your own config file at one of the locations listed above. #### tl;dr - Install `zram-generator` using one of the methods listed above. - Create a `zram-generator.conf` config file. - Run `systemctl daemon-reload` to create new device units. - Run `systemctl start /dev/zram0` (adjust the name as appropriate to match the config). - Call `zramctl` or `swapon` to confirm that the device has been created and is in use. Once installed and configured, the generator will be invoked by systemd early at boot, there is no need to do anything else. ### Testing The tests require either the `zram` module to be loaded, or root to run `modprobe zram`. Set the `ZRAM_GENERATOR_ROOT` environment variable to use that instead of `/` as root. The "{generator}" template in `units/systemd-zram-setup@.service.d/binary-location.conf` can be substituted for a non-standard location of the binary for testing. ### Authors Written by Zbigniew Jędrzejewski-Szmek <>, Igor Raits <>, наб <>, and others. See https://github.com/systemd/zram-generator/graphs/contributors for the full list. zram-generator-1.1.2/man/.gitignore000064400000000000000000000000270072674642500153540ustar 00000000000000/*.[1-8] /*.[1-8].html zram-generator-1.1.2/man/index.txt000064400000000000000000000012760072674642500152430ustar 00000000000000zram-generator(8) zram-generator.8.ronn zram-generator.conf(5) zram-generator.conf.5.ronn modprobe(8) https://man7.org/linux/man-pages/man8/modprobe.8.html proc(5) https://man7.org/linux/man-pages/man5/proc.5.html systemd-detect-virt(1) https://freedesktop.org/software/systemd/man/systemd-detect-virt.html systemd.generator(7) https://freedesktop.org/software/systemd/man/systemd.generator.html systemd.swap(5) https://freedesktop.org/software/systemd/man/systemd.swap.html systemd-makefs(8) https://freedesktop.org/software/systemd/man/systemd-makefs.html systemd.syntax(5) https://freedesktop.org/software/systemd/man/systemd.syntax.html zram-generator-1.1.2/man/zram-generator.conf.md000064400000000000000000000201060072674642500175670ustar 00000000000000 zram-generator.conf(5) -- Systemd unit generator for zram swap devices (configuration) ====================================================================================== ## SYNOPSIS `/usr/lib/systemd/zram-generator.conf`
`/usr/local/lib/systemd/zram-generator.conf`
`/etc/systemd/zram-generator.conf`
`/run/systemd/zram-generator.conf` `/usr/lib/systemd/zram-generator.conf.d/*.conf`
`/usr/local/lib/systemd/zram-generator.conf.d/*.conf`
`/etc/systemd/zram-generator.conf.d/*.conf`
`/run/systemd/zram-generator.conf.d/*.conf` ## DESCRIPTION These files configure devices created by zram-generator(8). See systemd.syntax(5) for a general description of the syntax. ## CONFIGURATION DIRECTORIES AND PRECEDENCE The default configuration doesn't specify any devices. Consult */usr/share/zram-generator/zram-generator.conf.example* for an example configuration file. When packages need to customize the configuration, they can install configuration snippets in */usr/lib/systemd/zram-generator.conf.d/*. Files in */etc/* are reserved for the local administrator, who may use this logic to override the configuration files installed by vendor packages. The main configuration file is read before any of the configuration directories, and has the lowest precedence; entries in a file in any configuration directory override entries in the single configuration file. Files in the *\*.conf.d/* configuration subdirectories are sorted by their filename in lexicographic order, regardless of which of the subdirectories they reside in. When multiple files specify the same option, for options which accept just a single value, the entry in the file with the lexicographically latest name takes precedence. It is recommended to prefix all filenames in those subdirectories with a two-digit number and a dash, to simplify the ordering of the files. To disable a configuration file supplied by the vendor, the recommended way is to place a symlink to */dev/null* in the configuration directory in */etc/*, with the same filename as the vendor configuration file. The generator understands the following option on the kernel command-line: `systemd.zram[=0|1]`. When specified with a true argument (or no argument), the `zram0` device will be created. Default options apply, but may be overridden by configuration on disk if present. When specified with a false argument, no zram devices will be created by the generator. This option thus has higher priority than the configuration files. ## OPTIONS Each device is configured independently in its `[zramN]` section, where N is a nonnegative integer. Other sections are ignored. Devices with the final size of *0* will be discarded. * `host-memory-limit`= Sets the upper limit on the total usable RAM (as defined by *MemTotal* in `/proc/meminfo`, confer proc(5)) above which the device will *not* be created. This takes a nonnegative number, representing that limit in megabytes, or the literal string *none*, which can be used to override a limit set earlier. Defaults to *none*. * `zram-size`= Sets the size of the zram device as a function of *MemTotal*, available as the `ram` variable. Arithmetic operators (^%/\*-+), e, π, SI suffixes, log(), int(), ceil(), floor(), round(), abs(), min(), max(), and trigonometric functions are supported. Defaults to *min(ram / 2, 4096)*. * `compression-algorithm`= Specifies the algorithm used to compress the zram device. This takes a literal string, representing the algorithm to use.
Consult */sys/block/zram0/comp_algorithm* for a list of currently loaded compression algorithms, but note that additional ones may be loaded on demand. If unset, none will be configured and the kernel's default will be used. * `writeback-device`= Write incompressible pages, for which no gain was achieved, to the specified device under memory pressure. This corresponds to the */sys/block/zramX/backing_dev* parameter. Takes a path to a block device, like */dev/disk/by-partuuid/2d54ffa0-01* or */dev/zvol/tarta-zoot/swap-writeback*. If unset, none is used, and incompressible pages are kept in RAM. * `swap-priority`= Controls the relative swap priority, a value between -1 and 32767. Higher numbers indicate higher priority. If unset, 100 is used. * `mount-point`= Format the device with a file system (not as swap) and mount this file system over the specified directory. When neither this option nor `fs-type`= is specified, the device will be formatted as swap. Note that the device is temporary: contents will be destroyed automatically after the file system is unmounted (to release the backing memory). * `fs-type`= Specifies how the device shall be formatted. The default is *ext2* if `mount-point` is specified, and *swap* otherwise. (Effectively, the device will be formatted as swap, if neither `fs-type`= nor `mount-point`= are specified.) Note that the device is temporary: contents will be destroyed automatically after the file system is unmounted (to release the backing memory). Also see systemd-makefs(8). * `options`= Sets mount or swapon options. Availability depends on `fs-type`. Defaults to *discard*. ## ENVIRONMENT VARIABLES Setting `ZRAM_GENERATOR_ROOT` during parsing will cause */proc/meminfo* to be read from *$ZRAM_GENERATOR_ROOT/proc/meminfo* instead, and *{/usr/lib,/usr/local/lib,/etc,/run}/systemd/zram-generator.conf* to be read from *$ZRAM_GENERATOR_ROOT/{/usr/lib,/usr/local/lib,/etc,/run}/systemd/zram-generator.conf*. ## EXAMPLES The default configuration will yield the following: zram device size ^ │ 4G>│ ooooooooooooo │ o │ o │ o 2G>│ o │ o │ o 512M>│ o 0───────────────────────> total usable RAM ^ ^ ^ 1G 4G 8G A piecewise-linear size 1:1 for the first 4G, then 1:2 above, up to a max of 32G:
  `zram-size = min(min(ram, 4096) + max(ram - 4096, 0) / 2, 32 * 1024)` zram device size ^ 32G>| oooooooooooooo | o 30G>| o | /=/ | 8G>│ o │ o │ o │ o │ o 4G>│ o │ o │ o 1G>│ o 0───────────────────────────────────||──────────────────────> total usable RAM ^ ^ ^ ^ ^ ^ ^ 1G 4G 8G 12G 56G 60G 64G ## OBSOLETE OPTIONS * `memory-limit`= Compatibility alias for `host-memory-limit`. * `zram-fraction`= Defines the scaling factor of the zram device's size with relation to the total usable RAM. This takes a nonnegative floating-point number representing that factor. Defaulted to *0.5*. Setting this or `max-zram-size` overrides `zram-size`. * `max-zram-size`= Sets the limit on the zram device's size obtained by `zram-fraction`. This takes a nonnegative number, representing that limit in megabytes, or the literal string *none*, which can be used to override a limit set earlier. Defaulted to *4096*. Setting this or `zram-fraction` overrides `zram-size`. ## REPORTING BUGS ## SEE ALSO zram-generator(8), systemd.syntax(5), proc(5) Linux documentation of zram:
and the zram sysfs ABI: `fasteval` documentation for the entire `zram-size` arithmetic DSL: zram-generator-1.1.2/man/zram-generator.md000064400000000000000000000074510072674642500166530ustar 00000000000000 zram-generator(8) -- Systemd unit generator for zram swap devices ================================================================= ## SYNOPSIS `/usr/lib/systemd/system-generators/zram-generator` `TARGET_DIR` [*2RGET_DIR* *3RGET_DIR*]
`/usr/lib/systemd/system-generators/zram-generator` --setup-device `DEVICE`
`/usr/lib/systemd/system-generators/zram-generator` --reset-device `DEVICE` ## DESCRIPTION `zram-generator` is a generator that creates systemd units to format and use compressed RAM devices, either as swap or a file system. The generator will be invoked by systemd early at boot. The generator will then: 1. read configuration files from *{/etc,/lib}/systemd/zram-generator.conf[.d]* (see zram-generator.conf(5) for details); 2. generate systemd.swap(5) and/or systemd.mount(5) units into `TARGET_DIR` and connect them to `swap.target` or `local-fs.target` as appropriate; 3. ensure the `zram` module is loaded and create the requested devices. The generator does nothing if run inside a container (as determined by *systemd-detect-virt(8) --container*). The generator also understands the kernel command-line option `systemd.zram`. See zram-generator.conf(5) for details. Setting the `ZRAM_GENERATOR_ROOT` environment variable makes the generator run in test mode, in which case containerisation is ignored and step `3` is skipped.
For the ramifications of `ZRAM_GENERATOR_ROOT` on config handling, see zram-generator.conf(5). Generated *dev-zramN.swap* units depend on `systemd-zram-setup@zramN.service`, which will: 1. read configuration files from *{/etc,/lib}/systemd/zram-generator.conf[.d]* (see zram-generator.conf(5) for details); 2. set the desired compression algorithm, if any; if the current kernel doesn't understand the specified algorithm, a warning is issued, but execution continues; 3. set the desired blockdev size and format it as swap with *systemd-makefs(8)*. Generated *path-to-mount-point.mount* units depend on `systemd-zram-setup@zramN.service`. The effect is similar to what happens for swap units, but of course they are formatted with a file system. When the unit is stopped, the zram device is reset, freeing memory and allowing the device to be reused. `zram-generator` implements systemd.generator(7). ### Applying config changes This generator is invoked in early boot, and the devices it configures will be created very early too, so the easiest way to apply config changes is to simply reboot the machine. Nevertheless, sometimes it may be useful to add new devices or apply config changes at runtime. Applying new configuration means restarting the units, and that in turn means recreating the zram devices. This means that *file systems are temporarily unmounted and their contents lost*, and *pages are moved out of the compressed swap device* into other memory. If this is acceptable, `systemctl restart systemd-zram-setup@zramN` or `systemctl restart systemd-zram-setup@*` may be used to recreate a specific device or all configured devices. (If the device didn't exist, `restart` will create it.) If the way the device is used (e.g. the mount point or file system type) is changed, `systemctl daemon-reload` needs to be called first to recreate systemd units. If a device or mount point is removed from configuration, the unit should be stopped before calling `daemon-reload`. Otherwise, systemd will not know how to stop the unit properly. ## REPORTING BUGS ## SEE ALSO zram-generator.conf(5), systemd.generator(7), systemd.swap(5) Linux documentation of zram:
and the zram sysfs ABI: zram-generator-1.1.2/src/config.rs000064400000000000000000000417370072674642500152300ustar 00000000000000/* SPDX-License-Identifier: MIT */ use anyhow::{anyhow, Context, Result}; use fasteval::Evaler; use ini::Ini; use liboverdrop::FragmentScanner; use log::{info, warn}; use std::borrow::Cow; use std::collections::{BTreeMap, HashMap}; use std::fmt; use std::fs; use std::io::{prelude::*, BufReader}; use std::path::{Component, Path, PathBuf}; const DEFAULT_ZRAM_SIZE: &str = "min(ram / 2, 4096)"; pub struct Device { pub name: String, pub host_memory_limit_mb: Option, /// Default: `DEFAULT_ZRAM_SIZE` pub zram_size: Option<(String, fasteval::ExpressionI, fasteval::Slab)>, pub compression_algorithm: Option, pub writeback_dev: Option, pub disksize: u64, pub swap_priority: i32, /// when set, a mount unit will be created pub mount_point: Option, /// useful mostly for mounts, /// None is the same as "swap" when mount_point is not set pub fs_type: Option, pub options: Cow<'static, str>, /// deprecated, overrides zram_size pub zram_fraction: Option, /// deprecated, overrides zram_size pub max_zram_size_mb: Option>, } impl Device { fn new(name: String) -> Device { Device { name, host_memory_limit_mb: None, zram_size: None, compression_algorithm: None, writeback_dev: None, disksize: 0, swap_priority: 100, mount_point: None, fs_type: None, options: "discard".into(), zram_fraction: None, max_zram_size_mb: None, } } pub fn is_swap(&self) -> bool { self.mount_point.is_none() && (self.fs_type.is_none() || self.fs_type.as_ref().unwrap() == "swap") } fn is_enabled(&self, memtotal_mb: u64) -> bool { match self.host_memory_limit_mb { Some(limit_mb) if limit_mb < memtotal_mb => { info!( "{}: system has too much memory ({:.1}MB), limit is {}MB, ignoring.", self.name, memtotal_mb, self.host_memory_limit_mb.unwrap() ); false } _ => true, } } pub fn effective_fs_type(&self) -> &str { match (self.fs_type.as_ref(), self.is_swap()) { (Some(fs_type), _) => fs_type, (None, true) => "swap", (None, false) => "ext2", } } fn set_disksize_if_enabled(&mut self, memtotal_mb: u64) -> Result<()> { if !self.is_enabled(memtotal_mb) { return Ok(()); } if self.zram_fraction.is_some() || self.max_zram_size_mb.is_some() { // deprecated path let max_mb = self.max_zram_size_mb.unwrap_or(None).unwrap_or(u64::MAX); self.disksize = ((self.zram_fraction.unwrap_or(0.5) * memtotal_mb as f64) as u64) .min(max_mb) * (1024 * 1024); } else { self.disksize = (match self.zram_size.as_ref() { Some(zs) => { zs.1.from(&zs.2.ps) .eval(&zs.2, &mut RamNs(memtotal_mb as f64)) .with_context(|| format!("{} zram-size", self.name)) .and_then(|f| { if f >= 0. { Ok(f) } else { Err(anyhow!("{}: zram-size={} < 0", self.name, f)) } })? } None => (memtotal_mb as f64 / 2.).min(4096.), // DEFAULT_ZRAM_SIZE } * 1024. * 1024.) as u64; } Ok(()) } } impl fmt::Display for Device { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!( f, "{}: host-memory-limit={} zram-size={} compression-algorithm={} writeback-device={} options={}", self.name, OptMB(self.host_memory_limit_mb), self.zram_size .as_ref() .map(|zs| &zs.0[..]) .unwrap_or(DEFAULT_ZRAM_SIZE), self.compression_algorithm.as_deref().unwrap_or(""), self.writeback_dev.as_deref().unwrap_or_else(|| Path::new("")).display(), self.options )?; if self.zram_fraction.is_some() || self.max_zram_size_mb.is_some() { f.write_str(" (")?; if let Some(zf) = self.zram_fraction { write!(f, "zram-fraction={}", zf)?; } if self.max_zram_size_mb.is_some() { f.write_str(" ")?; } if let Some(mzs) = self.max_zram_size_mb { write!(f, "max-zram-size={}", OptMB(mzs))?; } f.write_str(")")?; } Ok(()) } } struct OptMB(Option); impl fmt::Display for OptMB { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self.0 { Some(val) => write!(f, "{}MB", val), None => f.write_str(""), } } } struct RamNs(f64); impl fasteval::EvalNamespace for RamNs { fn lookup(&mut self, name: &str, args: Vec, _: &mut String) -> Option { if name == "ram" && args.is_empty() { Some(self.0) } else { None } } } pub fn read_device(root: &Path, kernel_override: bool, name: &str) -> Result> { let memtotal_mb = get_total_memory_kb(root)? as f64 / 1024.; Ok(read_devices(root, kernel_override, memtotal_mb as u64)? .remove(name) .filter(|dev| dev.disksize > 0)) } pub fn read_all_devices(root: &Path, kernel_override: bool) -> Result> { let memtotal_mb = get_total_memory_kb(root)? as f64 / 1024.; Ok(read_devices(root, kernel_override, memtotal_mb as u64)? .into_iter() .filter(|(_, dev)| dev.disksize > 0) .map(|(_, dev)| dev) .collect()) } fn read_devices( root: &Path, kernel_override: bool, memtotal_mb: u64, ) -> Result> { let fragments = locate_fragments(root); if fragments.is_empty() && !kernel_override { info!("No configuration found."); } let mut devices: HashMap = HashMap::new(); for (_, path) in fragments { let ini = Ini::load_from_file(&path)?; for (sname, props) in ini.iter() { let sname = match sname { None => { warn!( "{}: ignoring settings outside of section: {:?}", path.display(), props ); continue; } Some(sname) if sname.starts_with("zram") && sname[4..].parse::().is_ok() => { sname.to_string() } Some(sname) => { warn!("{}: Ignoring section \"{}\"", path.display(), sname); continue; } }; let dev = devices .entry(sname.clone()) .or_insert_with(|| Device::new(sname)); for (k, v) in props.iter() { parse_line(dev, k, v)?; } } } if kernel_override { devices .entry("zram0".to_string()) .or_insert_with(|| Device::new("zram0".to_string())); } for dev in devices.values_mut() { dev.set_disksize_if_enabled(memtotal_mb)?; } Ok(devices) } fn locate_fragments(root: &Path) -> BTreeMap { let base_dirs = vec![ String::from(root.join("usr/lib").to_str().unwrap()), String::from(root.join("usr/local/lib").to_str().unwrap()), String::from(root.join("etc").to_str().unwrap()), String::from(root.join("run").to_str().unwrap()), // We look at /run to allow temporary overriding // of configuration. There is no expectation of // programatic creation of config there. ]; let cfg = FragmentScanner::new( base_dirs.clone(), "systemd/zram-generator.conf.d", true, vec![String::from("conf")], ); let mut fragments = cfg.scan(); if let Some(path) = base_dirs .into_iter() .rev() .map(PathBuf::from) .map(|mut p| { p.push("systemd/zram-generator.conf"); p }) .find(|p| p.exists()) { fragments.insert(String::new(), path); // The empty string shall sort earliest } fragments } fn parse_optional_size(val: &str) -> Result> { Ok(if val == "none" { None } else { Some( val.parse() .with_context(|| format!("Failed to parse optional size \"{}\"", val))?, ) }) } fn parse_swap_priority(val: &str) -> Result { let val = val .parse() .with_context(|| format!("Failed to parse priority \"{}\"", val))?; /* See --priority in swapon(8). */ match val { -1..=0x7FFF => Ok(val), _ => Err(anyhow!("Swap priority {} out of range", val)), } } fn verify_mount_point(key: &str, val: &str) -> Result { let path = Path::new(val); if path.is_relative() { return Err(anyhow!("{} {} is not absolute", key, val)); } if path.components().any(|c| c == Component::ParentDir) { return Err(anyhow!("{} {:#?} is not normalized", key, path)); } Ok(path.components().collect()) // normalise away /./ components } fn parse_line(dev: &mut Device, key: &str, value: &str) -> Result<()> { match key { "host-memory-limit" | "memory-limit" => { /* memory-limit is for backwards compat. host-memory-limit name is preferred. */ dev.host_memory_limit_mb = parse_optional_size(value)?; } "zram-size" => { let mut sl = fasteval::Slab::new(); dev.zram_size = Some(( value.to_string(), fasteval::Parser::new() .parse_noclear(value, &mut sl.ps) .with_context(|| format!("{} zram-size", dev.name))?, sl, )); } "compression-algorithm" => { dev.compression_algorithm = Some(value.to_string()); } "writeback-device" => { dev.writeback_dev = Some(verify_mount_point(key, value)?); } "swap-priority" => { dev.swap_priority = parse_swap_priority(value)?; } "mount-point" => { dev.mount_point = Some(verify_mount_point(key, value)?); } "fs-type" => { dev.fs_type = Some(value.to_string()); } "options" => { dev.options = value.to_string().into(); } "zram-fraction" => { /* zram-fraction is for backwards compat. zram-size = is preferred. */ dev.zram_fraction = Some( value .parse() .with_context(|| format!("Failed to parse zram-fraction \"{}\"", value)) .and_then(|f| { if f >= 0. { Ok(f) } else { Err(anyhow!("{}: zram-fraction={} < 0", dev.name, f)) } })?, ); } "max-zram-size" => { /* zram-fraction is for backwards compat. zram-size = is preferred. */ dev.max_zram_size_mb = Some(parse_optional_size(value)?); } _ => { warn!("{}: unknown key {}, ignoring.", dev.name, key); } } Ok(()) } fn _get_total_memory_kb(path: &Path) -> Result { for line in BufReader::new(fs::File::open(&path).with_context(|| { format!("Failed to read memory information from {}", path.display()) })?) .lines() { let line = line?; let mut fields = line.split_whitespace(); if let (Some("MemTotal:"), Some(val)) = (fields.next(), fields.next()) { return Ok(val.parse()?); } } Err(anyhow!("Couldn't find MemTotal in {}", path.display())) } fn get_total_memory_kb(root: &Path) -> Result { let path = root.join("proc/meminfo"); _get_total_memory_kb(&path) } fn _kernel_has_option(path: &Path, word: &str) -> Result> { let text = fs::read_to_string(path)?; // Last argument wins Ok(text .split_whitespace() .rev() .filter(|w| w.starts_with(word)) .flat_map(|w| match &w[word.len()..] { "" | "=1" | "=yes" | "=true" | "=on" => Some(true), "=0" | "=no" | "=false" | "=off" => Some(false), _ => None, }) .next()) } pub fn kernel_has_option(root: &Path, word: &str) -> Result> { let path = root.join("proc/cmdline"); _kernel_has_option(&path, word) } pub fn kernel_zram_option(root: &Path) -> Option { match kernel_has_option(root, "systemd.zram") { Ok(r @ Some(true)) | Ok(r @ None) => r, Ok(Some(false)) => { info!("Disabled by systemd.zram option in /proc/cmdline."); Some(false) } Err(e) => { warn!("Failed to parse /proc/cmdline ({}), ignoring.", e); None } } } #[cfg(test)] mod tests { use super::*; fn file_with(data: &[u8]) -> tempfile::NamedTempFile { let mut file = tempfile::NamedTempFile::new().unwrap(); file.write(data).unwrap(); file.flush().unwrap(); file } #[test] fn test_get_total_memory_kb() { let file = file_with( b"\ MemTotal: 8013220 kB MemFree: 721288 kB MemAvailable: 1740336 kB Buffers: 292752 kB ", ); let mem = _get_total_memory_kb(file.path()).unwrap(); assert_eq!(mem, 8013220); } #[test] #[should_panic(expected = "Couldn't find MemTotal")] fn test_get_total_memory_not_found() { let file = file_with( b"\ MemTotala: 8013220 kB aMemTotal: 8013220 kB MemTotal:: 8013220 kB ", ); _get_total_memory_kb(file.path()).unwrap(); } #[test] fn test_kernel_has_option() { let file = file_with(b"foo=1 foo=0 foo=on foo=off foo\n"); assert_eq!(_kernel_has_option(file.path(), "foo").unwrap(), Some(true)); } #[test] fn test_kernel_has_no_option() { let file = file_with( b"\ foo=1 foo=0 ", ); assert_eq!(_kernel_has_option(file.path(), "foo").unwrap(), Some(false)); } #[test] fn test_verify_mount_point() { for e in ["foo/bar", "/foo/../bar", "/foo/.."] { assert!(verify_mount_point("test", e).is_err(), "{}", e); } for (p, o) in [ ("/foobar", "/foobar"), ("/", "/"), ("//", "/"), ("///", "/"), ("/foo/./bar/", "/foo/bar"), ] { assert_eq!( verify_mount_point("test", p).unwrap(), Path::new(o), "{} vs {}", p, o ); } } fn dev_with_zram_size_size(val: Option<&str>, memtotal_mb: u64) -> u64 { let mut dev = Device::new("zram0".to_string()); if let Some(val) = val { parse_line(&mut dev, "zram-size", val).unwrap(); } assert!(dev.is_enabled(memtotal_mb)); dev.set_disksize_if_enabled(memtotal_mb).unwrap(); dev.disksize } #[test] fn test_eval_size_expression() { assert_eq!( dev_with_zram_size_size(Some("0.5 * ram"), 100), 50 * 1024 * 1024 ); } #[test] fn test_eval_size_expression_default() { assert_eq!(dev_with_zram_size_size(None, 100), 50 * 1024 * 1024); assert_eq!(dev_with_zram_size_size(None, 10000), 4096 * 1024 * 1024); } #[test] fn test_eval_size_expression_default_equivalent() { assert_eq!( dev_with_zram_size_size(Some(DEFAULT_ZRAM_SIZE), 100), 50 * 1024 * 1024 ); assert_eq!( dev_with_zram_size_size(Some(DEFAULT_ZRAM_SIZE), 10000), 4096 * 1024 * 1024 ); } #[test] #[should_panic(expected = "Undefined(\"array\")")] fn test_eval_size_expression_unknown_variable() { dev_with_zram_size_size(Some("array(1,2)"), 100); } #[test] #[should_panic(expected = "zram-size=NaN")] fn test_eval_size_expression_nan() { dev_with_zram_size_size(Some("(ram-100)/0"), 100); } #[test] fn test_eval_size_expression_inf() { assert_eq!(dev_with_zram_size_size(Some("(ram-99)/0"), 100), u64::MAX); // +∞ } #[test] fn test_eval_size_expression_min() { assert_eq!( dev_with_zram_size_size(Some("min(0.5 * ram, 4000)"), 3000), 1500 * 1024 * 1024 ); } } zram-generator-1.1.2/src/generator.rs000064400000000000000000000257440072674642500157510ustar 00000000000000/* SPDX-License-Identifier: MIT */ use crate::config::Device; use anyhow::{anyhow, Context, Result}; use log::{debug, log, warn, Level}; use std::cmp; use std::collections::BTreeSet; use std::fs; use std::io::{self, Write}; use std::os::unix::fs::symlink; use std::path::Path; use std::process::Command; fn make_parent(of: &Path) -> Result<()> { let parent = of .parent() .ok_or_else(|| anyhow!("Couldn't get parent of {}", of.display()))?; fs::create_dir_all(&parent)?; Ok(()) } fn make_symlink(dst: &str, src: &Path) -> Result<()> { make_parent(src)?; symlink(dst, src) .with_context(|| format!("Failed to create symlink {}→{}", src.display(), dst))?; Ok(()) } fn virtualization_container() -> Result { let mut child = match Command::new("systemd-detect-virt") .arg("--quiet") .arg("--container") .spawn() { Ok(child) => child, Err(e) => { warn!( "systemd-detect-virt call failed, assuming we're not in a container: {}", e ); return Ok(false); } }; match child.wait() { Ok(status) => Ok(status.success()), Err(e) => Err(anyhow!("systemd-detect-virt call failed: {}", e)), } } fn modprobe(modname: &str, required: bool) { match Command::new("modprobe").arg(modname).status() { Err(e) => { let level = match !required && e.kind() == io::ErrorKind::NotFound { true => Level::Debug, false => Level::Warn, }; log!( level, "modprobe \"{}\" cannot be spawned, ignoring: {}", modname, e ); } Ok(status) => { if !status.success() { warn!("modprobe \"{}\" failed, ignoring: code {}", modname, status); } } }; } pub fn run_generator(devices: &[Device], output_directory: &Path, fake_mode: bool) -> Result<()> { if devices.is_empty() { debug!("No devices configured, exiting."); return Ok(()); } if virtualization_container()? && !fake_mode { debug!("Running in a container, exiting."); return Ok(()); } for device in devices { handle_device(output_directory, device)?; } if !devices.is_empty() && !fake_mode { /* We created some units, let's make sure the module is loaded and the devices exist */ if !Path::new("/sys/class/zram-control").exists() { modprobe("zram", true); } let max_device = devices .iter() .map(|device| { device.name[4..] .parse() .expect("already verified in read_devices()") }) .fold(0, cmp::max); if !Path::new("/dev") .join(format!("zram{}", max_device)) .exists() { while fs::read_to_string("/sys/class/zram-control/hot_add") .context("Adding zram device")? .trim_end() .parse::() .context("Fresh zram device number")? < max_device {} } } let compressors: BTreeSet<_> = devices .iter() .flat_map(|device| device.compression_algorithm.as_deref()) .collect(); if !compressors.is_empty() { let proc_crypto = fs::read_to_string("/proc/crypto").unwrap_or_else(|e| { warn!("Failed to read /proc/crypto, proceeding as if empty: {}", e); String::new() }); let known = parse_known_compressors(&proc_crypto); for comp in compressors.difference(&known) { modprobe(&format!("crypto-{}", comp), false); } } Ok(()) } // Returns a list of names of loaded compressors fn parse_known_compressors(proc_crypto: &str) -> BTreeSet<&str> { // Extract algorithm names (this includes non-compression algorithms too) proc_crypto .lines() .into_iter() .filter(|line| line.starts_with("name")) .map(|m| m.rsplit(':').next().unwrap().trim()) .collect() } fn write_contents(output_directory: &Path, filename: &str, contents: &str) -> Result<()> { let path = output_directory.join(filename); make_parent(&path)?; let contents = format!( "\ # Automatically generated by {exe_name} {contents}", exe_name = std::env::current_exe().unwrap().display(), contents = contents ); fs::write(&path, contents).with_context(|| format!("Failed to write {}", path.display())) } fn handle_device(output_directory: &Path, device: &Device) -> Result<()> { if device.is_swap() { handle_zram_swap(output_directory, device) } else { handle_zram_mount_point(output_directory, device) } } fn handle_zram_bindings(output_directory: &Path, device: &Device, specific: &str) -> Result<()> { let wb_unit = device .writeback_dev .as_ref() .map(|wd| unit_name_from_path(wd, ".device")) .unwrap_or_default(); /* systemd-zram-setup@.service. * We use the packaged unit, and only need to provide a small drop-in. */ write_contents( output_directory, &format!("systemd-zram-setup@{}.service.d/bindings.conf", device.name), &format!( "\ [Unit] BindsTo={}{}{}{}{} ", specific, &" "[device.writeback_dev.is_none() as usize..], wb_unit, device .writeback_dev .as_ref() .map(|_| "\nAfter=") .unwrap_or_default(), wb_unit, ), ) } fn handle_zram_swap(output_directory: &Path, device: &Device) -> Result<()> { let swap_name = format!("dev-{}.swap", device.name); debug!( "Creating unit file {} (/dev/{} with {}MB)", swap_name, device.name, device.disksize / 1024 / 1024 ); handle_zram_bindings(output_directory, device, "dev-%i.swap")?; /* dev-zramX.swap */ write_contents( output_directory, &swap_name, &format!( "\ [Unit] Description=Compressed Swap on /dev/{zram_device} Documentation=man:zram-generator(8) man:zram-generator.conf(5) Requires=systemd-zram-setup@{zram_device}.service After=systemd-zram-setup@{zram_device}.service [Swap] What=/dev/{zram_device} Priority={swap_priority} Options={options} ", zram_device = device.name, swap_priority = device.swap_priority, options = device.options.replace('%', "%%"), ), )?; /* enablement symlink */ let symlink_path = output_directory.join("swap.target.wants").join(&swap_name); let target_path = format!("../{}", swap_name); make_symlink(&target_path, &symlink_path)?; Ok(()) } /// Path escaping as described in systemd.unit(5) /// /// `/./` components stripped away when parsing `mount-point =` fn unit_name_from_path(path: &Path, suffix: &str) -> String { assert!(path.is_absolute()); let trimmed = path.to_str().unwrap().trim_matches('/'); if trimmed.is_empty() { format!("-{}", suffix) } else { let mut obuf = Vec::with_capacity(path.as_os_str().len() + suffix.len()); let mut just_slash = false; for (i, &b) in trimmed.as_bytes().iter().enumerate() { if b == b'/' && just_slash { continue; } just_slash = b == b'/'; match b { b'/' => obuf.push(b'-'), b'.' if i == 0 => write!(obuf, "\\x{:02x}", b'.').unwrap(), b'0'..=b'9' | b'a'..=b'z' | b'A'..=b'Z' | b':' | b'_' | b'.' => obuf.push(b), _ => write!(obuf, "\\x{:02x}", b).unwrap(), } } obuf.extend_from_slice(suffix.as_bytes()); String::from_utf8(obuf).unwrap() } } fn handle_zram_mount_point(output_directory: &Path, device: &Device) -> Result<()> { if device.mount_point.is_none() { /* In this case we don't need to generate any units. */ return Ok(()); } let mount_name = &unit_name_from_path(device.mount_point.as_ref().unwrap(), ".mount"); debug!( "Creating unit file {} (/dev/{} with {}MB)", mount_name, device.name, device.disksize / 1024 / 1024 ); handle_zram_bindings(output_directory, device, mount_name)?; write_contents( output_directory, mount_name, &format!( "\ [Unit] Description=Compressed Storage on /dev/{zram_device} Documentation=man:zram-generator(8) man:zram-generator.conf(5) Requires=systemd-zram-setup@{zram_device}.service After=systemd-zram-setup@{zram_device}.service [Mount] What=/dev/{zram_device} Where={mount_point} Options={options} ", zram_device = device.name, mount_point = device.mount_point.as_ref().unwrap().to_str().unwrap(), options = device.options.replace('%', "%%"), ), )?; /* enablement symlink */ let symlink_path = output_directory .join("local-fs.target.wants") .join(&mount_name); let target_path = format!("../{}", mount_name); make_symlink(&target_path, &symlink_path)?; Ok(()) } #[cfg(test)] mod tests { use super::*; use std::iter::FromIterator; #[test] fn test_parse_known_compressors() { let data = "\ name : zstd driver : zstd-scomp module : zstd priority : 0 refcnt : 1 selftest : passed internal : no type : scomp name : zstd driver : zstd-generic module : zstd priority : 0 refcnt : 1 selftest : passed internal : no type : compression name : ccm(aes) driver : ccm_base(ctr(aes-aesni),cbcmac(aes-aesni)) module : ccm priority : 300 refcnt : 2 selftest : passed internal : no type : aead async : no geniv : name : ctr(aes) driver : ctr(aes-aesni) module : kernel priority : 300 refcnt : 2 selftest : passed internal : no type : skcipher "; let expected = ["zstd", "ccm(aes)", "ctr(aes)"]; assert_eq!(parse_known_compressors(data), BTreeSet::from_iter(expected)); } #[test] fn test_unit_name_from_path() { assert_eq!( unit_name_from_path(&Path::new("/waldo"), ".mount"), "waldo.mount" ); assert_eq!( unit_name_from_path(&Path::new("/waldo/quuix"), ".mount"), "waldo-quuix.mount" ); assert_eq!( unit_name_from_path(&Path::new("/waldo/quuix/"), ".mount"), "waldo-quuix.mount" ); assert_eq!( unit_name_from_path(&Path::new("/waldo/quuix//"), ".mount"), "waldo-quuix.mount" ); assert_eq!(unit_name_from_path(&Path::new("/"), ".mount"), "-.mount"); assert_eq!(unit_name_from_path(&Path::new("//"), ".mount"), "-.mount"); assert_eq!(unit_name_from_path(&Path::new("///"), ".mount"), "-.mount"); } } zram-generator-1.1.2/src/kernlog.rs000064400000000000000000000044100072674642500154070ustar 00000000000000/* SPDX-License-Identifier: MIT */ //! Logger implementation for low level kernel log (using `/dev/kmsg`) //! //! Borrowed and cut down from https://github.com/kstep/kernlog.rs/pull/2, //! consider merging changes back when fixing something here; //! this automatically falls back to stdout and ignores problems with opening "/dev/kmsg". use std::fs::{File, OpenOptions}; use std::io::{self, Write}; use std::process::id; use std::sync::Mutex; /// Kernel logger implementation pub struct KernelLog { kmsg: Mutex>, maxlevel: log::LevelFilter, } impl KernelLog { /// Create new kernel logger with error level filter pub fn with_level(level: log::LevelFilter) -> KernelLog { KernelLog { kmsg: Mutex::new(OpenOptions::new().write(true).open("/dev/kmsg").ok()), maxlevel: level, } } } fn _write_kmsg(kmsg: &mut File, record: &log::Record) { let level: u8 = match record.level() { log::Level::Error => 3, log::Level::Warn => 4, log::Level::Info => 5, log::Level::Debug => 6, log::Level::Trace => 7, }; let mut buf = Vec::new(); writeln!( buf, "<{}>{}[{}]: {}", level, record.target(), id(), record.args() ) .unwrap(); let _ = kmsg.write(&buf); let _ = kmsg.flush(); } fn _write_stdout(record: &log::Record) { let stdout = io::stdout(); let mut stdout = stdout.lock(); let _ = writeln!(stdout, "{}", record.args()); let _ = stdout.flush(); } impl log::Log for KernelLog { fn enabled(&self, meta: &log::Metadata) -> bool { meta.level() <= self.maxlevel } fn log(&self, record: &log::Record) { if record.level() > self.maxlevel { return; } if let Ok(mut kmsg) = self.kmsg.lock() { match kmsg.as_mut() { Some(kmsg) => _write_kmsg(kmsg, record), None => _write_stdout(record), } } } fn flush(&self) {} } /// Setup kernel logger with specified error level as the default logger pub fn init_with_level(level: log::LevelFilter) -> Result<(), log::SetLoggerError> { log::set_boxed_logger(Box::new(KernelLog::with_level(level)))?; log::set_max_level(level); Ok(()) } zram-generator-1.1.2/src/lib.rs000064400000000000000000000001260072674642500145140ustar 00000000000000/* SPDX-License-Identifier: MIT */ pub mod config; pub mod generator; pub mod setup; zram-generator-1.1.2/src/main.rs000064400000000000000000000055730072674642500147050ustar 00000000000000/* SPDX-License-Identifier: MIT */ mod config; mod generator; mod kernlog; mod setup; use anyhow::Result; use clap::{crate_description, crate_name, crate_version, App, Arg}; use log::{info, LevelFilter}; use std::borrow::Cow; use std::env; use std::path::{Path, PathBuf}; #[derive(Debug)] enum Opts { /// Generate units into the directory GenerateUnits(String), /// Set up a single device SetupDevice(String), /// Reset (destroy) a device ResetDevice(String), } fn get_opts() -> Opts { let opts = App::new(crate_name!()) .version(crate_version!()) .about(crate_description!()) .arg( Arg::from_usage("--setup-device 'Set up a single device'") .conflicts_with("reset-device"), ) .arg(Arg::from_usage("--reset-device 'Reset (destroy) a device'")) .arg(Arg::from_usage( " 'Target directory for generator or device to operate on'", )) .arg( Arg::from_usage( "[extra-dir] 'Unused target directories to satisfy systemd.generator(5)'", ) .number_of_values(2) .conflicts_with_all(&["setup-device", "reset-device"]), ) .after_help(&*format!("Uses {}.", setup::SYSTEMD_MAKEFS_COMMAND)) .get_matches(); let val = opts .value_of("directory|device") .expect("clap invariant") .to_string(); if opts.is_present("setup-device") { Opts::SetupDevice(val) } else if opts.is_present("reset-device") { Opts::ResetDevice(val) } else { Opts::GenerateUnits(val) } } fn main() -> Result<()> { let (root, have_env_var, log_level) = match env::var_os("ZRAM_GENERATOR_ROOT") { Some(val) => (PathBuf::from(val).into(), true, LevelFilter::Trace), None => (Cow::from(Path::new("/")), false, LevelFilter::Info), }; let _ = kernlog::init_with_level(log_level); let kernel_override = || match config::kernel_zram_option(&root) { Some(false) => { info!("Disabled by kernel cmdline option, exiting."); std::process::exit(0); } None => false, Some(true) => true, }; match get_opts() { Opts::GenerateUnits(target) => { let devices = config::read_all_devices(&root, kernel_override())?; let output_directory = PathBuf::from(target); generator::run_generator(&devices, &output_directory, have_env_var) } Opts::SetupDevice(dev) => { let device = config::read_device(&root, kernel_override(), &dev)?; setup::run_device_setup(device, &dev) } Opts::ResetDevice(dev) => { // We don't read the config here, so that it's possible to remove a device // even after the config has been removed. setup::run_device_reset(&dev) } } } zram-generator-1.1.2/src/setup.rs000064400000000000000000000070330072674642500151120ustar 00000000000000/* SPDX-License-Identifier: MIT */ use crate::config::Device; use anyhow::{anyhow, Context, Result}; use log::warn; use std::fs; use std::io::ErrorKind; use std::os::unix::ffi::OsStrExt; use std::os::unix::process::ExitStatusExt; use std::path::Path; use std::process::Command; pub const SYSTEMD_MAKEFS_COMMAND: &str = concat!( env!( "SYSTEMD_UTIL_DIR", "Define $SYSTEMD_UTIL_DIR to the result of \ $(pkg-config --variable=systemdutildir systemd) (e.g. /usr/lib/systemd/)" ), "/systemd-makefs" ); pub fn run_device_setup(device: Option, device_name: &str) -> Result<()> { let device = device.ok_or_else(|| anyhow!("Device {} not found", device_name))?; let device_sysfs_path = Path::new("/sys/block").join(device_name); if let Some(ref compression_algorithm) = device.compression_algorithm { let comp_algorithm_path = device_sysfs_path.join("comp_algorithm"); match fs::write(&comp_algorithm_path, &compression_algorithm) { Ok(_) => {} Err(err) if err.kind() == ErrorKind::InvalidInput => { warn!( "Warning: algorithm {:?} not recognised; consult {} for a list of available ones", compression_algorithm, comp_algorithm_path.display(), ); } err @ Err(_) => err.with_context(|| { format!( "Failed to configure compression algorithm into {}", comp_algorithm_path.display() ) })?, } } if let Some(ref wb_dev) = device.writeback_dev { let writeback_path = device_sysfs_path.join("backing_dev"); if writeback_path.exists() { fs::write(&writeback_path, wb_dev.as_os_str().as_bytes()).with_context(|| { format!( "Failed to configure write-back device into {}", writeback_path.display() ) })?; } else { warn!("Warning: writeback-device={} set for {}, but system doesn't support write-back. Ignoring.", writeback_path.display(), device_name) } } let disksize_path = device_sysfs_path.join("disksize"); fs::write(&disksize_path, format!("{}", device.disksize)).with_context(|| { format!( "Failed to configure disk size into {}", disksize_path.display() ) })?; let fs_type = device.effective_fs_type(); match Command::new(SYSTEMD_MAKEFS_COMMAND).arg(fs_type).arg(Path::new("/dev").join(device_name)).status() { Ok(status) => match status.code() { Some(0) => Ok(()), Some(code) => Err(anyhow!("{} failed with exit code {}", SYSTEMD_MAKEFS_COMMAND, code)), None => Err(anyhow!("{} terminated by signal {}", SYSTEMD_MAKEFS_COMMAND, status.signal().expect("on unix, status status.code() is None iff status.signal() isn't; \ this expect() will never panic, save for an stdlib bug"))), }, Err(e) => Err(e).with_context(|| { format!( "{} call failed for /dev/{}", SYSTEMD_MAKEFS_COMMAND, device_name ) }), } } pub fn run_device_reset(device_name: &str) -> Result<()> { let reset = Path::new("/sys/block").join(device_name).join("reset"); fs::write(reset, b"1")?; Ok(()) } zram-generator-1.1.2/tests/01-basic/proc/meminfo000064400000000000000000000001240072674642500175700ustar 00000000000000MemTotal: 801322 kB MemFree: 611992 kB MemAvailable: 139764 kB zram-generator-1.1.2/tests/01-basic/run.expected/units/dev-zram0.swap000064400000000000000000000004430072674642500235230ustar 00000000000000# Automatically generated by zram-generator [Unit] Description=Compressed Swap on /dev/zram0 Documentation=man:zram-generator(8) man:zram-generator.conf(5) Requires=systemd-zram-setup@zram0.service After=systemd-zram-setup@zram0.service [Swap] What=/dev/zram0 Priority=100 Options=discard zram-generator-1.1.2/tests/01-basic/run.expected/units/swap.target.wants/dev-zram0.swap000064400000000000000000000004430072674642500271150ustar 00000000000000# Automatically generated by zram-generator [Unit] Description=Compressed Swap on /dev/zram0 Documentation=man:zram-generator(8) man:zram-generator.conf(5) Requires=systemd-zram-setup@zram0.service After=systemd-zram-setup@zram0.service [Swap] What=/dev/zram0 Priority=100 Options=discard ././@LongLink00006440000000000000000000000150000000000000007767Lustar zram-generator-1.1.2/tests/01-basic/run.expected/units/systemd-zram-setup@zram0.service.d/bindings.confzram-generator-1.1.2/tests/01-basic/run.expected/units/systemd-zram-setup@zram0.service.d/bindings.c000064400000000000000000000001100072674642500315020ustar 00000000000000# Automatically generated by zram-generator [Unit] BindsTo=dev-%i.swap zram-generator-1.1.2/tests/01-basic/usr/lib/systemd/zram-generator.conf000064400000000000000000000000100072674642500241150ustar 00000000000000[zram0] zram-generator-1.1.2/tests/02-zstd/etc/systemd/zram-generator.conf000064400000000000000000000001250072674642500232240ustar 00000000000000[zram0] compression-algorithm = zstd host-memory-limit = 2050 zram-size = ram * 0.75 zram-generator-1.1.2/tests/02-zstd/proc/meminfo000064400000000000000000000001240072674642500174740ustar 00000000000000MemTotal: 801322 kB MemFree: 611992 kB MemAvailable: 139764 kB zram-generator-1.1.2/tests/02-zstd/run.expected/units/dev-zram0.swap000064400000000000000000000004430072674642500234270ustar 00000000000000# Automatically generated by zram-generator [Unit] Description=Compressed Swap on /dev/zram0 Documentation=man:zram-generator(8) man:zram-generator.conf(5) Requires=systemd-zram-setup@zram0.service After=systemd-zram-setup@zram0.service [Swap] What=/dev/zram0 Priority=100 Options=discard zram-generator-1.1.2/tests/02-zstd/run.expected/units/swap.target.wants/dev-zram0.swap000064400000000000000000000004430072674642500270210ustar 00000000000000# Automatically generated by zram-generator [Unit] Description=Compressed Swap on /dev/zram0 Documentation=man:zram-generator(8) man:zram-generator.conf(5) Requires=systemd-zram-setup@zram0.service After=systemd-zram-setup@zram0.service [Swap] What=/dev/zram0 Priority=100 Options=discard ././@LongLink00006440000000000000000000000147000000000000007775Lustar zram-generator-1.1.2/tests/02-zstd/run.expected/units/systemd-zram-setup@zram0.service.d/bindings.confzram-generator-1.1.2/tests/02-zstd/run.expected/units/systemd-zram-setup@zram0.service.d/bindings.co000064400000000000000000000001100072674642500315650ustar 00000000000000# Automatically generated by zram-generator [Unit] BindsTo=dev-%i.swap zram-generator-1.1.2/tests/03-too-much-memory/etc/systemd/zram-generator.conf000064400000000000000000000000370072674642500253040ustar 00000000000000[zram0] host-memory-limit=7824 zram-generator-1.1.2/tests/03-too-much-memory/proc/meminfo000064400000000000000000000002140072674642500215520ustar 00000000000000MemTotal: 8013220 kB MemFree: 1856196 kB MemAvailable: 2254912 kB Buffers: 94188 kB Cached: 1532436 kB zram-generator-1.1.2/tests/03-too-much-memory/run.expected/units/.empty000064400000000000000000000000000072674642500241300ustar 00000000000000zram-generator-1.1.2/tests/04-dropins/etc/systemd/zram-generator.conf.d/03-drop3.conf000064400000000000000000000000000072674642500263250ustar 00000000000000zram-generator-1.1.2/tests/04-dropins/etc/systemd/zram-generator.conf.d/04-drop4.conf000064400000000000000000000000650072674642500263420ustar 00000000000000[zram2] zram-size=ram*0.8 swap-priority=200 options= zram-generator-1.1.2/tests/04-dropins/etc/systemd/zram-generator.conf.d/zram-generator.conf000064400000000000000000000002270072674642500300260ustar 00000000000000# This one is empty on purpose. The goal is to make sure that a dropin # with the same name as the main config fragment is not confused with the # it. zram-generator-1.1.2/tests/04-dropins/proc/meminfo000064400000000000000000000001240072674642500201700ustar 00000000000000MemTotal: 801322 kB MemFree: 611992 kB MemAvailable: 139764 kB zram-generator-1.1.2/tests/04-dropins/run.expected/units/dev-zram0.swap000064400000000000000000000004430072674642500241230ustar 00000000000000# Automatically generated by zram-generator [Unit] Description=Compressed Swap on /dev/zram0 Documentation=man:zram-generator(8) man:zram-generator.conf(5) Requires=systemd-zram-setup@zram0.service After=systemd-zram-setup@zram0.service [Swap] What=/dev/zram0 Priority=100 Options=discard zram-generator-1.1.2/tests/04-dropins/run.expected/units/dev-zram2.swap000064400000000000000000000004340072674642500241250ustar 00000000000000# Automatically generated by zram-generator [Unit] Description=Compressed Swap on /dev/zram2 Documentation=man:zram-generator(8) man:zram-generator.conf(5) Requires=systemd-zram-setup@zram2.service After=systemd-zram-setup@zram2.service [Swap] What=/dev/zram2 Priority=200 Options= zram-generator-1.1.2/tests/04-dropins/run.expected/units/swap.target.wants/dev-zram0.swap000064400000000000000000000004430072674642500275150ustar 00000000000000# Automatically generated by zram-generator [Unit] Description=Compressed Swap on /dev/zram0 Documentation=man:zram-generator(8) man:zram-generator.conf(5) Requires=systemd-zram-setup@zram0.service After=systemd-zram-setup@zram0.service [Swap] What=/dev/zram0 Priority=100 Options=discard zram-generator-1.1.2/tests/04-dropins/run.expected/units/swap.target.wants/dev-zram2.swap000064400000000000000000000004340072674642500275170ustar 00000000000000# Automatically generated by zram-generator [Unit] Description=Compressed Swap on /dev/zram2 Documentation=man:zram-generator(8) man:zram-generator.conf(5) Requires=systemd-zram-setup@zram2.service After=systemd-zram-setup@zram2.service [Swap] What=/dev/zram2 Priority=200 Options= ././@LongLink00006440000000000000000000000152000000000000007771Lustar zram-generator-1.1.2/tests/04-dropins/run.expected/units/systemd-zram-setup@zram0.service.d/bindings.confzram-generator-1.1.2/tests/04-dropins/run.expected/units/systemd-zram-setup@zram0.service.d/bindings000064400000000000000000000001100072674642500316610ustar 00000000000000# Automatically generated by zram-generator [Unit] BindsTo=dev-%i.swap ././@LongLink00006440000000000000000000000152000000000000007771Lustar zram-generator-1.1.2/tests/04-dropins/run.expected/units/systemd-zram-setup@zram2.service.d/bindings.confzram-generator-1.1.2/tests/04-dropins/run.expected/units/systemd-zram-setup@zram2.service.d/bindings000064400000000000000000000001100072674642500316630ustar 00000000000000# Automatically generated by zram-generator [Unit] BindsTo=dev-%i.swap zram-generator-1.1.2/tests/04-dropins/usr/lib/systemd/zram-generator.conf000064400000000000000000000000100072674642500245150ustar 00000000000000[zram0] zram-generator-1.1.2/tests/04-dropins/usr/lib/systemd/zram-generator.conf.d/01-drop1.conf000064400000000000000000000000370072674642500271370ustar 00000000000000[zram0] host-memory-limit=1234 zram-generator-1.1.2/tests/04-dropins/usr/lib/systemd/zram-generator.conf.d/02-drop2.conf000064400000000000000000000000370072674642500271410ustar 00000000000000[zram0] host-memory-limit=1235 zram-generator-1.1.2/tests/04-dropins/usr/lib/systemd/zram-generator.conf.d/03-drop3.conf000064400000000000000000000000720072674642500271420ustar 00000000000000[zram0] host-memory-limit=1236 [zram1] zram-size=ram*0.7 zram-generator-1.1.2/tests/05-kernel-disabled/proc/cmdline000064400000000000000000000000510072674642500215200ustar 00000000000000asfdasdf=foobar bar=foood systemd.zram=0 zram-generator-1.1.2/tests/05-kernel-disabled/proc/meminfo000064400000000000000000000002140072674642500215400ustar 00000000000000MemTotal: 8013220 kB MemFree: 1856196 kB MemAvailable: 2254912 kB Buffers: 94188 kB Cached: 1532436 kB ././@LongLink00006440000000000000000000000162000000000000007772Lustar zram-generator-1.1.2/tests/05-kernel-disabled/run.expected/units/systemd-zram-setup@zram0.service.d/bindings.confzram-generator-1.1.2/tests/05-kernel-disabled/run.expected/units/systemd-zram-setup@zram0.service.d/000064400000000000000000000001070072674642500315210ustar 00000000000000# Automatically generated by zram-generator [Unit] BindsTo=dev-%i.swap zram-generator-1.1.2/tests/05-kernel-disabled/usr/lib/systemd/zram-generator.conf000064400000000000000000000000100072674642500260650ustar 00000000000000[zram0] zram-generator-1.1.2/tests/06-kernel-enabled/proc/cmdline000064400000000000000000000000200072674642500213400ustar 00000000000000 systemd.zram zram-generator-1.1.2/tests/06-kernel-enabled/proc/meminfo000064400000000000000000000002140072674642500213640ustar 00000000000000MemTotal: 8013220 kB MemFree: 1856196 kB MemAvailable: 2254912 kB Buffers: 94188 kB Cached: 1532436 kB zram-generator-1.1.2/tests/06-kernel-enabled/run.expected/units/dev-zram0.swap000064400000000000000000000004430072674642500253170ustar 00000000000000# Automatically generated by zram-generator [Unit] Description=Compressed Swap on /dev/zram0 Documentation=man:zram-generator(8) man:zram-generator.conf(5) Requires=systemd-zram-setup@zram0.service After=systemd-zram-setup@zram0.service [Swap] What=/dev/zram0 Priority=100 Options=discard zram-generator-1.1.2/tests/06-kernel-enabled/run.expected/units/swap.target.wants/dev-zram0.swap000064400000000000000000000004430072674642500307110ustar 00000000000000# Automatically generated by zram-generator [Unit] Description=Compressed Swap on /dev/zram0 Documentation=man:zram-generator(8) man:zram-generator.conf(5) Requires=systemd-zram-setup@zram0.service After=systemd-zram-setup@zram0.service [Swap] What=/dev/zram0 Priority=100 Options=discard ././@LongLink00006440000000000000000000000161000000000000007771Lustar zram-generator-1.1.2/tests/06-kernel-enabled/run.expected/units/systemd-zram-setup@zram0.service.d/bindings.confzram-generator-1.1.2/tests/06-kernel-enabled/run.expected/units/systemd-zram-setup@zram0.service.d/b000064400000000000000000000001100072674642500315010ustar 00000000000000# Automatically generated by zram-generator [Unit] BindsTo=dev-%i.swap zram-generator-1.1.2/tests/07-mount-point/etc/systemd/zram-generator.conf000064400000000000000000000003770072674642500245470ustar 00000000000000[zram11] mount-point = /var/compressed fs-type = ext4 [zram12] mount-point = /var/folded fs-type = ext4 options = discard,casefold # systemd.unit(5) example [zram13] mount-point = /foo//bar/baz/ fs-type = ext4 [zram15] mount-point = /// fs-type = ext4 zram-generator-1.1.2/tests/07-mount-point/proc/meminfo000064400000000000000000000001240072674642500210060ustar 00000000000000MemTotal: 801322 kB MemFree: 611992 kB MemAvailable: 139764 kB zram-generator-1.1.2/tests/07-mount-point/run.expected/units/-.mount000064400000000000000000000004460072674642500234630ustar 00000000000000# Automatically generated by zram-generator [Unit] Description=Compressed Storage on /dev/zram15 Documentation=man:zram-generator(8) man:zram-generator.conf(5) Requires=systemd-zram-setup@zram15.service After=systemd-zram-setup@zram15.service [Mount] What=/dev/zram15 Where=/ Options=discard zram-generator-1.1.2/tests/07-mount-point/run.expected/units/foo-bar-baz.mount000064400000000000000000000004610072674642500254230ustar 00000000000000# Automatically generated by zram-generator [Unit] Description=Compressed Storage on /dev/zram13 Documentation=man:zram-generator(8) man:zram-generator.conf(5) Requires=systemd-zram-setup@zram13.service After=systemd-zram-setup@zram13.service [Mount] What=/dev/zram13 Where=/foo/bar/baz Options=discard zram-generator-1.1.2/tests/07-mount-point/run.expected/units/local-fs.target.wants/-.mount000064400000000000000000000004460072674642500276030ustar 00000000000000# Automatically generated by zram-generator [Unit] Description=Compressed Storage on /dev/zram15 Documentation=man:zram-generator(8) man:zram-generator.conf(5) Requires=systemd-zram-setup@zram15.service After=systemd-zram-setup@zram15.service [Mount] What=/dev/zram15 Where=/ Options=discard zram-generator-1.1.2/tests/07-mount-point/run.expected/units/local-fs.target.wants/foo-bar-baz.mount000064400000000000000000000004610072674642500315430ustar 00000000000000# Automatically generated by zram-generator [Unit] Description=Compressed Storage on /dev/zram13 Documentation=man:zram-generator(8) man:zram-generator.conf(5) Requires=systemd-zram-setup@zram13.service After=systemd-zram-setup@zram13.service [Mount] What=/dev/zram13 Where=/foo/bar/baz Options=discard ././@LongLink00006440000000000000000000000150000000000000007767Lustar zram-generator-1.1.2/tests/07-mount-point/run.expected/units/local-fs.target.wants/var-compressed.mountzram-generator-1.1.2/tests/07-mount-point/run.expected/units/local-fs.target.wants/var-compressed.mo000064400000000000000000000004640072674642500316520ustar 00000000000000# Automatically generated by zram-generator [Unit] Description=Compressed Storage on /dev/zram11 Documentation=man:zram-generator(8) man:zram-generator.conf(5) Requires=systemd-zram-setup@zram11.service After=systemd-zram-setup@zram11.service [Mount] What=/dev/zram11 Where=/var/compressed Options=discard zram-generator-1.1.2/tests/07-mount-point/run.expected/units/local-fs.target.wants/var-folded.mount000064400000000000000000000004710072674642500314700ustar 00000000000000# Automatically generated by zram-generator [Unit] Description=Compressed Storage on /dev/zram12 Documentation=man:zram-generator(8) man:zram-generator.conf(5) Requires=systemd-zram-setup@zram12.service After=systemd-zram-setup@zram12.service [Mount] What=/dev/zram12 Where=/var/folded Options=discard,casefold ././@LongLink00006440000000000000000000000157000000000000007776Lustar zram-generator-1.1.2/tests/07-mount-point/run.expected/units/systemd-zram-setup@zram11.service.d/bindings.confzram-generator-1.1.2/tests/07-mount-point/run.expected/units/systemd-zram-setup@zram11.service.d/bin000064400000000000000000000001210072674642500315360ustar 00000000000000# Automatically generated by zram-generator [Unit] BindsTo=var-compressed.mount ././@LongLink00006440000000000000000000000157000000000000007776Lustar zram-generator-1.1.2/tests/07-mount-point/run.expected/units/systemd-zram-setup@zram12.service.d/bindings.confzram-generator-1.1.2/tests/07-mount-point/run.expected/units/systemd-zram-setup@zram12.service.d/bin000064400000000000000000000001150072674642500315420ustar 00000000000000# Automatically generated by zram-generator [Unit] BindsTo=var-folded.mount ././@LongLink00006440000000000000000000000157000000000000007776Lustar zram-generator-1.1.2/tests/07-mount-point/run.expected/units/systemd-zram-setup@zram13.service.d/bindings.confzram-generator-1.1.2/tests/07-mount-point/run.expected/units/systemd-zram-setup@zram13.service.d/bin000064400000000000000000000001160072674642500315440ustar 00000000000000# Automatically generated by zram-generator [Unit] BindsTo=foo-bar-baz.mount ././@LongLink00006440000000000000000000000157000000000000007776Lustar zram-generator-1.1.2/tests/07-mount-point/run.expected/units/systemd-zram-setup@zram15.service.d/bindings.confzram-generator-1.1.2/tests/07-mount-point/run.expected/units/systemd-zram-setup@zram15.service.d/bin000064400000000000000000000001040072674642500315430ustar 00000000000000# Automatically generated by zram-generator [Unit] BindsTo=-.mount zram-generator-1.1.2/tests/07-mount-point/run.expected/units/var-compressed.mount000064400000000000000000000004640072674642500262610ustar 00000000000000# Automatically generated by zram-generator [Unit] Description=Compressed Storage on /dev/zram11 Documentation=man:zram-generator(8) man:zram-generator.conf(5) Requires=systemd-zram-setup@zram11.service After=systemd-zram-setup@zram11.service [Mount] What=/dev/zram11 Where=/var/compressed Options=discard zram-generator-1.1.2/tests/07-mount-point/run.expected/units/var-folded.mount000064400000000000000000000004710072674642500253500ustar 00000000000000# Automatically generated by zram-generator [Unit] Description=Compressed Storage on /dev/zram12 Documentation=man:zram-generator(8) man:zram-generator.conf(5) Requires=systemd-zram-setup@zram12.service After=systemd-zram-setup@zram12.service [Mount] What=/dev/zram12 Where=/var/folded Options=discard,casefold zram-generator-1.1.2/tests/08-plain-device/etc/systemd/zram-generator.conf000064400000000000000000000000300072674642500246010ustar 00000000000000[zram11] fs-type = ext2 zram-generator-1.1.2/tests/08-plain-device/proc/meminfo000064400000000000000000000001240072674642500210560ustar 00000000000000MemTotal: 801322 kB MemFree: 611992 kB MemAvailable: 139764 kB zram-generator-1.1.2/tests/08-plain-device/proc/self/mountinfo000064400000000000000000000000700072674642500223730ustar 0000000000000015 1 253:1 / / rw,relatime shared:1 - ext4 /dev/root ro zram-generator-1.1.2/tests/08-plain-device/run.expected/units/.empty000064400000000000000000000000000072674642500234340ustar 00000000000000zram-generator-1.1.2/tests/09-zram-size/etc/systemd/zram-generator.conf000064400000000000000000000001400072674642500241650ustar 00000000000000[zram0] compression-algorithm = zstd host-memory-limit = 2050 zram-size = min(0.75 * ram, 6000) zram-generator-1.1.2/tests/09-zram-size/proc/meminfo000064400000000000000000000001240072674642500204400ustar 00000000000000MemTotal: 801322 kB MemFree: 611992 kB MemAvailable: 139764 kB zram-generator-1.1.2/tests/09-zram-size/run.expected/units/dev-zram0.swap000064400000000000000000000004430072674642500243730ustar 00000000000000# Automatically generated by zram-generator [Unit] Description=Compressed Swap on /dev/zram0 Documentation=man:zram-generator(8) man:zram-generator.conf(5) Requires=systemd-zram-setup@zram0.service After=systemd-zram-setup@zram0.service [Swap] What=/dev/zram0 Priority=100 Options=discard zram-generator-1.1.2/tests/09-zram-size/run.expected/units/swap.target.wants/dev-zram0.swap000064400000000000000000000004430072674642500277650ustar 00000000000000# Automatically generated by zram-generator [Unit] Description=Compressed Swap on /dev/zram0 Documentation=man:zram-generator(8) man:zram-generator.conf(5) Requires=systemd-zram-setup@zram0.service After=systemd-zram-setup@zram0.service [Swap] What=/dev/zram0 Priority=100 Options=discard ././@LongLink00006440000000000000000000000154000000000000007773Lustar zram-generator-1.1.2/tests/09-zram-size/run.expected/units/systemd-zram-setup@zram0.service.d/bindings.confzram-generator-1.1.2/tests/09-zram-size/run.expected/units/systemd-zram-setup@zram0.service.d/bindin000064400000000000000000000001100072674642500315770ustar 00000000000000# Automatically generated by zram-generator [Unit] BindsTo=dev-%i.swap zram-generator-1.1.2/tests/11-obsolete/etc/systemd/zram-generator.conf000064400000000000000000000003610072674642500240560ustar 00000000000000[zram0] zram-fraction = 0.10 max-zram-size = 2048 memory-limit = 100000 [zram1] host-memory-limit = 2 [zram1] zram-fraction = 0.10 max-zram-size = none memory-limit = none [zram2] zram-fraction = 0.10 max-zram-size = 2048 memory-limit = 1 zram-generator-1.1.2/tests/11-obsolete/proc/meminfo000064400000000000000000000001240072674642500203240ustar 00000000000000MemTotal: 801322 kB MemFree: 611992 kB MemAvailable: 139764 kB zram-generator-1.1.2/tests/11-obsolete/run.expected/units/dev-zram0.swap000064400000000000000000000004430072674642500242570ustar 00000000000000# Automatically generated by zram-generator [Unit] Description=Compressed Swap on /dev/zram0 Documentation=man:zram-generator(8) man:zram-generator.conf(5) Requires=systemd-zram-setup@zram0.service After=systemd-zram-setup@zram0.service [Swap] What=/dev/zram0 Priority=100 Options=discard zram-generator-1.1.2/tests/11-obsolete/run.expected/units/dev-zram1.swap000064400000000000000000000004430072674642500242600ustar 00000000000000# Automatically generated by zram-generator [Unit] Description=Compressed Swap on /dev/zram1 Documentation=man:zram-generator(8) man:zram-generator.conf(5) Requires=systemd-zram-setup@zram1.service After=systemd-zram-setup@zram1.service [Swap] What=/dev/zram1 Priority=100 Options=discard zram-generator-1.1.2/tests/11-obsolete/run.expected/units/swap.target.wants/dev-zram0.swap000064400000000000000000000004430072674642500276510ustar 00000000000000# Automatically generated by zram-generator [Unit] Description=Compressed Swap on /dev/zram0 Documentation=man:zram-generator(8) man:zram-generator.conf(5) Requires=systemd-zram-setup@zram0.service After=systemd-zram-setup@zram0.service [Swap] What=/dev/zram0 Priority=100 Options=discard zram-generator-1.1.2/tests/11-obsolete/run.expected/units/swap.target.wants/dev-zram1.swap000064400000000000000000000004430072674642500276520ustar 00000000000000# Automatically generated by zram-generator [Unit] Description=Compressed Swap on /dev/zram1 Documentation=man:zram-generator(8) man:zram-generator.conf(5) Requires=systemd-zram-setup@zram1.service After=systemd-zram-setup@zram1.service [Swap] What=/dev/zram1 Priority=100 Options=discard ././@LongLink00006440000000000000000000000153000000000000007772Lustar zram-generator-1.1.2/tests/11-obsolete/run.expected/units/systemd-zram-setup@zram0.service.d/bindings.confzram-generator-1.1.2/tests/11-obsolete/run.expected/units/systemd-zram-setup@zram0.service.d/binding000064400000000000000000000001100072674642500316320ustar 00000000000000# Automatically generated by zram-generator [Unit] BindsTo=dev-%i.swap ././@LongLink00006440000000000000000000000153000000000000007772Lustar zram-generator-1.1.2/tests/11-obsolete/run.expected/units/systemd-zram-setup@zram1.service.d/bindings.confzram-generator-1.1.2/tests/11-obsolete/run.expected/units/systemd-zram-setup@zram1.service.d/binding000064400000000000000000000001100072674642500316330ustar 00000000000000# Automatically generated by zram-generator [Unit] BindsTo=dev-%i.swap zram-generator-1.1.2/tests/test_cases.rs000064400000000000000000000236150072674642500164660ustar 00000000000000/* SPDX-License-Identifier: MIT */ use zram_generator::{config, generator}; use anyhow::Result; use fs_extra::dir::{copy, CopyOptions}; use std::fs; use std::io::{self, Write}; use std::path::Path; use std::process::{exit, Command}; use tempfile::TempDir; #[ctor::ctor] fn unshorn() { use nix::{errno, mount, sched, unistd}; use std::os::unix::fs::symlink; let (uid, gid) = (unistd::geteuid(), unistd::getegid()); if !uid.is_root() { match sched::unshare(sched::CloneFlags::CLONE_NEWUSER) { Err(errno::Errno::EPERM) => { eprintln!("unshare(NEWUSER) forbidden and not running as root: skipping tests"); exit(0); } r => r.expect("unshare(NEWUSER)"), } fs::write("/proc/self/setgroups", b"deny").unwrap(); fs::write("/proc/self/uid_map", format!("0 {} 1", uid)).unwrap(); fs::write("/proc/self/gid_map", format!("0 {} 1", gid)).unwrap(); } sched::unshare(sched::CloneFlags::CLONE_NEWNS).expect("unshare(NEWNS)"); mount::mount::<_, _, str, str>( Some("none"), "/", None, mount::MsFlags::MS_REC | mount::MsFlags::MS_PRIVATE, None, ) .unwrap(); mount::mount::(None, "/proc", Some("tmpfs"), mount::MsFlags::empty(), None) .unwrap(); fs::create_dir("/proc/self").unwrap(); symlink("zram-generator", "/proc/self/exe").unwrap(); } fn prepare_directory(srcroot: &Path) -> Result { let rootdir = TempDir::new()?; let root = rootdir.path(); let opts = CopyOptions::new(); for p in ["etc", "usr", "proc"] .iter() .map(|p| srcroot.join(p)) .filter(|p| p.exists()) { copy(p, root, &opts)?; } let output_directory = root.join("run/units"); fs::create_dir_all(output_directory)?; Ok(rootdir) } fn test_generation(path: &str) -> Result> { let srcroot = Path::new(path); let rootdir = prepare_directory(&srcroot)?; let root = rootdir.path(); let kernel_override = match config::kernel_zram_option(root) { Some(true) => true, Some(false) => { return Ok(vec![]); } _ => false, }; let devices = config::read_all_devices(root, kernel_override)?; let output_directory = root.join("run/units"); generator::run_generator(&devices, &output_directory, true)?; // Compare output directory to expected value. // ExecStart lines include the full path to the generating binary, // so exclude them from comparison. let diff = Command::new("diff") .arg("-u") .arg("--recursive") .arg("--exclude=.empty") .arg(srcroot.join("run.expected")) .arg(root.join("run")) .output()?; for (h, d) in [("stdout", &diff.stdout), ("stderr", &diff.stderr)] { if !d.is_empty() { println!("{}:{}", h, String::from_utf8_lossy(d)); } } assert!(diff.status.success()); Ok(devices) } fn z_s_name(zram_size: &(String, fasteval::ExpressionI, fasteval::Slab)) -> &str { &zram_size.0 } #[test] fn test_01_basic() { let devices = test_generation("tests/01-basic").unwrap(); assert_eq!(devices.len(), 1); let d = &devices[0]; assert!(d.is_swap()); assert_eq!(d.host_memory_limit_mb, None); assert_eq!(d.zram_size.as_ref().map(z_s_name), None); assert_eq!(d.options, "discard"); } #[test] fn test_02_zstd() { let devices = test_generation("tests/02-zstd").unwrap(); assert_eq!(devices.len(), 1); let d = &devices[0]; assert!(d.is_swap()); assert_eq!(d.host_memory_limit_mb, Some(2050)); assert_eq!(d.zram_size.as_ref().map(z_s_name), Some("ram * 0.75")); assert_eq!(d.compression_algorithm.as_ref().unwrap(), "zstd"); assert_eq!(d.options, "discard"); } #[test] fn test_03_too_much_memory() { let devices = test_generation("tests/03-too-much-memory").unwrap(); assert_eq!(devices.len(), 0); } #[test] fn test_04_dropins() { let devices = test_generation("tests/04-dropins").unwrap(); assert_eq!(devices.len(), 2); for d in &devices { assert!(d.is_swap()); match &d.name[..] { "zram0" => { assert_eq!(d.host_memory_limit_mb, Some(1235)); assert_eq!(d.zram_size.as_ref().map(z_s_name), None); assert_eq!(d.options, "discard"); } "zram2" => { assert_eq!(d.host_memory_limit_mb, None); assert_eq!(d.zram_size.as_ref().map(z_s_name), Some("ram*0.8")); assert_eq!(d.options, ""); } _ => panic!("Unexpected device {}", d), } } } #[test] fn test_05_kernel_disabled() { let devices = test_generation("tests/05-kernel-disabled").unwrap(); assert_eq!(devices.len(), 0); } #[test] fn test_06_kernel_enabled() { let devices = test_generation("tests/06-kernel-enabled").unwrap(); assert_eq!(devices.len(), 1); let d = &devices[0]; assert!(d.is_swap()); assert_eq!(d.host_memory_limit_mb, None); assert_eq!(d.zram_size.as_ref().map(z_s_name), None); assert_eq!(d.options, "discard"); } #[test] fn test_07_mount_point() { let devices = test_generation("tests/07-mount-point").unwrap(); assert_eq!(devices.len(), 4); test_07_devices(devices); } /// cargo-package refuses to pack files with `\`s in them, /// so we split them off to be able to push to crates.io #[test] fn test_07a_mount_point_excl() { if !Path::new("tests/07a-mount-point-excl").exists() { io::stdout() .write_all(b"07a-mount-point-excl doesn't exist: assuming package, skipping\n") .unwrap(); return; } let devices = test_generation("tests/07a-mount-point-excl").unwrap(); assert_eq!(devices.len(), 1); test_07_devices(devices); } fn test_07_devices(devices: Vec) { for d in &devices { assert!(!d.is_swap()); assert_eq!(d.host_memory_limit_mb, None); assert_eq!(d.zram_size.as_ref().map(z_s_name), None); assert_eq!(d.fs_type.as_ref().unwrap(), "ext4"); assert_eq!(d.effective_fs_type(), "ext4"); match &d.name[..] { "zram11" => { assert_eq!( d.mount_point.as_ref().unwrap(), Path::new("/var/compressed") ); assert_eq!(d.options, "discard"); } "zram12" => { assert_eq!(d.mount_point.as_ref().unwrap(), Path::new("/var/folded")); assert_eq!(d.options, "discard,casefold"); } "zram13" => { assert_eq!(d.mount_point.as_ref().unwrap(), Path::new("/foo//bar/baz/")); assert_eq!(d.options, "discard"); } "zram14" => { assert_eq!(d.mount_point.as_ref().unwrap(), Path::new("/.żupan-ci3pły")); assert_eq!(d.options, "discard"); } "zram15" => { assert_eq!(d.mount_point.as_ref().unwrap(), Path::new("///")); assert_eq!(d.options, "discard"); } _ => panic!("Unexpected device {}", d), } } } #[test] fn test_08_plain_device() { let devices = test_generation("tests/08-plain-device").unwrap(); assert_eq!(devices.len(), 1); let d = &devices[0]; assert!(!d.is_swap()); assert_eq!(d.host_memory_limit_mb, None); assert_eq!(d.zram_size.as_ref().map(z_s_name), None); assert!(d.mount_point.is_none()); assert_eq!(d.fs_type.as_ref().unwrap(), "ext2"); assert_eq!(d.effective_fs_type(), "ext2"); assert_eq!(d.options, "discard"); } #[test] fn test_09_zram_size() { let devices = test_generation("tests/09-zram-size").unwrap(); assert_eq!(devices.len(), 1); let d = &devices[0]; assert!(d.is_swap()); assert_eq!(d.host_memory_limit_mb, Some(2050)); assert_eq!( d.zram_size.as_ref().map(z_s_name), Some("min(0.75 * ram, 6000)") ); assert_eq!(d.compression_algorithm.as_ref().unwrap(), "zstd"); } #[test] fn test_10_example() { if !Path::new("tests/10-example").exists() { io::stdout() .write_all(b"10-example doesn't exist: assuming package, skipping\n") .unwrap(); return; } let devices = test_generation("tests/10-example").unwrap(); assert_eq!(devices.len(), 2); for d in &devices { match d.name.as_str() { "zram0" => { assert!(d.is_swap()); assert_eq!(d.host_memory_limit_mb, Some(9048)); assert_eq!( d.zram_size.as_ref().map(z_s_name), Some("min(ram / 10, 2048)") ); assert_eq!(d.compression_algorithm.as_deref(), Some("lzo-rle")); assert_eq!(d.options, ""); } "zram1" => { assert_eq!(d.fs_type.as_ref().unwrap(), "ext2"); assert_eq!(d.effective_fs_type(), "ext2"); assert_eq!(d.zram_size.as_ref().map(z_s_name), Some("ram / 10")); assert_eq!(d.options, "discard"); } _ => panic!("Unexpected device {}", d), } } } #[test] fn test_11_obsolete() { let devices = test_generation("tests/11-obsolete").unwrap(); assert_eq!(devices.len(), 2); for d in &devices { assert!(d.is_swap()); assert_eq!(d.options, "discard"); match d.name.as_str() { "zram0" => { assert_eq!(d.host_memory_limit_mb, Some(100000)); assert_eq!(d.zram_fraction, Some(0.1)); assert_eq!(d.max_zram_size_mb, Some(Some(2048))); } "zram1" => { assert_eq!(d.host_memory_limit_mb, None); assert_eq!(d.zram_fraction, Some(0.1)); assert_eq!(d.max_zram_size_mb, Some(None)); } _ => panic!("Unexpected device {}", d), } } } zram-generator-1.1.2/units/.gitignore000064400000000000000000000000350072674642500157420ustar 00000000000000/systemd-zram-setup@.service zram-generator-1.1.2/units/systemd-zram-setup@.service.d/binary-location.conf000064400000000000000000000002750072674642500254770ustar 00000000000000# SPDX-License-Identifier: MIT # This file is part of the zram-generator project # https://github.com/systemd/zram-generator [Service] ExecStart= ExecStart={generator} --setup-device '%i' zram-generator-1.1.2/units/systemd-zram-setup@.service.in000064400000000000000000000007300072674642500216400ustar 00000000000000# SPDX-License-Identifier: MIT # This file is part of the zram-generator project # https://github.com/systemd/zram-generator [Unit] Description=Create swap on /dev/%i Documentation=man:zram-generator(8) man:zram-generator.conf(5) After=dev-%i.device DefaultDependencies=false [Service] Type=oneshot RemainAfterExit=yes ExecStart=@SYSTEMD_SYSTEM_GENERATOR_DIR@/zram-generator --setup-device '%i' ExecStop=@SYSTEMD_SYSTEM_GENERATOR_DIR@/zram-generator --reset-device '%i' zram-generator-1.1.2/zram-generator.conf.example000064400000000000000000000033710072674642500200540ustar 00000000000000# This file is part of the zram-generator project # https://github.com/systemd/zram-generator [zram0] # This section describes the settings for /dev/zram0. # # The maximum amount of memory (in MiB). If the machine has more RAM # than this, zram device will not be created. # # "host-memory-limit = none" may be used to disable this limit. This # is also the default. host-memory-limit = 9048 # The size of the zram device, as a function of MemTotal, both in MB. # For example, if the machine has 1 GiB, and zram-size=ram/4, # then the zram device will have 256 MiB. # Fractions in the range 0.1–0.5 are recommended. # # The default is "min(ram / 2, 4096)". zram-size = min(ram / 10, 2048) # The compression algorithm to use for the zram device, # or leave unspecified to keep the kernel default. compression-algorithm = lzo-rle # By default, file systems and swap areas are trimmed on-the-go # by setting "discard". # Setting this to the empty string clears the option. options = # Write incompressible pages to this device, # as there's no gain from keeping them in RAM writeback-device = /dev/zvol/tarta-zoot/swap-writeback # The following options are deprecated, and override zram-size. # These values would be equivalent to the zram-size setting above. #zram-fraction = 0.10 #max-zram-size = 2048 [zram1] # This section describes the settings for /dev/zram1. # # host-memory-limit is not specified, so this device will always be created. # Size the device to a tenth of RAM. zram-size = ram / 10 # The file system to put on the device. If not specified, ext2 will be used. fs-type = ext2 # Where to mount the file system. If a mount point is not specified, # the device will be initialized, but will not be used for anything. mount-point = /run/compressed-mount-point