zram-generator-0.3.2/.cargo_vcs_info.json0000644000000001120000000000000137640ustar { "git": { "sha1": "7e14ee973dd5d6ac00fcc4a392425e5d12d7c0ac" } } zram-generator-0.3.2/.github/workflows/ci.yml000064400000000000000000000032220000000000000172520ustar 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 Rust uses: actions-rs/toolchain@v1 with: toolchain: ${{ matrix.rust }} override: true profile: minimal - name: Build run: make build CARGOFLAGS="--verbose" - name: Insert zram module run: sudo modprobe -v zram - 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: Check formatting uses: actions-rs/clippy@master with: args: -- -D warnings zram-generator-0.3.2/.gitignore000064400000000000000000000000420000000000000145240ustar 00000000000000*~ /Cargo.lock /target **/*.rs.bk zram-generator-0.3.2/Cargo.lock0000644000000150110000000000000117430ustar # This file is automatically @generated by Cargo. # It is not intended for manual editing. [[package]] name = "ahash" version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e8fd72866655d1904d6b0997d0b07ba561047d070fbe29de039031c641b61217" [[package]] name = "anyhow" version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "afddf7f520a80dbf76e6f50a35bca42a2331ef227a28b3b6dc5c2e2338d114b1" [[package]] name = "autocfg" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d" [[package]] name = "bitflags" version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" [[package]] name = "cfg-if" version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" [[package]] name = "clap" version = "2.33.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bdfa80d47f954d53a35a64987ca1422f495b8d6483c0fe9f7117b36c2a792129" dependencies = [ "bitflags", "textwrap", "unicode-width", ] [[package]] name = "dlv-list" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b391911b9a786312a10cb9d2b3d0735adfd5a8113eb3648de26a75e91b0826c" dependencies = [ "rand", ] [[package]] name = "fs_extra" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5f2a4a2034423744d2cc7ca2068453168dcdb82c438419e639a26bd87839c674" [[package]] name = "getrandom" version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7abc8dd8451921606d809ba32e95b6111925cd2906060d2dcc29c070220503eb" dependencies = [ "cfg-if", "libc", "wasi", ] [[package]] name = "hashbrown" version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96282e96bfcd3da0d3aa9938bedf1e50df3269b6db08b4876d2da0bb1a0841cf" dependencies = [ "ahash", "autocfg", ] [[package]] name = "libc" version = "0.2.71" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9457b06509d27052635f90d6466700c65095fdf75409b3fbdd903e988b886f49" [[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.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7" dependencies = [ "cfg-if", ] [[package]] name = "ordered-multimap" version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e88f947c6799d5eff50e6cf8a2365c17ac4aa8f8f43aceeedc29b616d872a358" dependencies = [ "dlv-list", "hashbrown", ] [[package]] name = "ppv-lite86" version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "237a5ed80e274dbc66f86bd59c1e25edc039660be53194b5fe0a482e0f2612ea" [[package]] name = "rand" version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" dependencies = [ "getrandom", "libc", "rand_chacha", "rand_core", "rand_hc", ] [[package]] name = "rand_chacha" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" dependencies = [ "ppv-lite86", "rand_core", ] [[package]] name = "rand_core" version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" dependencies = [ "getrandom", ] [[package]] name = "rand_hc" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" dependencies = [ "rand_core", ] [[package]] name = "redox_syscall" version = "0.1.56" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84" [[package]] name = "remove_dir_all" version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4a83fa3702a688b9359eccba92d153ac33fd2e8462f9e0e3fdf155239ea7792e" dependencies = [ "winapi", ] [[package]] name = "rust-ini" version = "0.15.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a3679dd538c876a7b606f3bb951c8a20fc281a0ff7795f59f7cb490e3f979e1" dependencies = [ "cfg-if", "ordered-multimap", ] [[package]] name = "tempfile" version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9" 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.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "caaa9d531767d1ff2150b9332433f32a24622147e5ebb1f26409d5da67afd479" [[package]] name = "wasi" version = "0.9.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" [[package]] name = "winapi" version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6" 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 = "0.3.2" dependencies = [ "anyhow", "clap", "fs_extra", "liboverdrop", "log", "rust-ini", "tempfile", ] zram-generator-0.3.2/Cargo.toml0000644000000023320000000000000117700ustar # 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 believe there's an error in this file please file an # issue against the rust-lang/cargo repository. If you're # editing this file be aware that the upstream Cargo.toml # will likely look very different (and much more reasonable) [package] edition = "2018" name = "zram-generator" version = "0.3.2" authors = ["Zbigniew Jędrzejewski-Szmek ", "Igor Raits ", "наб "] description = "Systemd unit generator for zram swap devices." homepage = "https://github.com/systemd/zram-generator" license = "MIT" [profile.release] lto = true [dependencies.anyhow] version = "1.0.12" [dependencies.clap] version = "2.33" default-features = false [dependencies.liboverdrop] version = "0.0.2" [dependencies.log] version = "0.4" features = ["std"] [dependencies.rust-ini] version = ">=0.13, <0.17" [dev-dependencies.fs_extra] version = "1.1" [dev-dependencies.tempfile] version = "3" zram-generator-0.3.2/Cargo.toml.orig000064400000000000000000000012300000000000000154230ustar 00000000000000# SPDX-License-Identifier: MIT [package] name = "zram-generator" version = "0.3.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" [dependencies] anyhow = "1.0.12" clap = { version = "2.33", default-features = false } liboverdrop = "0.0.2" rust-ini = ">=0.13, <0.17" log = { version = "0.4", features = ["std"] } [dev-dependencies] tempfile = "3" fs_extra = "1.1" [profile.release] lto = true zram-generator-0.3.2/LICENSE000064400000000000000000000017770000000000000135610ustar 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-0.3.2/Makefile000064400000000000000000000025310000000000000142010ustar 00000000000000# SPDX-License-Identifier: MIT INSTALL = install CARGO = cargo CARGOFLAGS = RONN = ronn PKG_CONFIG = pkg-config PREFIX = /usr 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 .DEFAULT: build .PHONY: build man check clean install build: systemd_service @$(CARGO) build --release $(CARGOFLAGS) systemd_service: @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: build @$(CARGO) test --release $(CARGOFLAGS) clean: @$(CARGO) clean @rm -f units/systemd-zram-setup@.service install: $(INSTALL) -Dpm755 target/release/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/ $(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/ zram-generator-0.3.2/README.md000064400000000000000000000065550000000000000140320ustar 00000000000000# `systemd-zram-setup@.service` generator for zram devices 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-fraction = 0.5 ``` A zram device will be created for each section. No actual configuration is necessary (the default of `zram-fraction=0.5` 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/tmp ``` This will set up a /dev/zram1 with ext2 and generate a mount unit for /var/tmp. ### Rust The second purpose of this program is to serve as an example of a systemd generator in rust. Details are still being figured out. ### 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: AUR packages https://aur.archlinux.org/packages/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`: * `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. ### 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-0.3.2/man/.gitignore000064400000000000000000000000270000000000000153020ustar 00000000000000/*.[1-8] /*.[1-8].html zram-generator-0.3.2/man/index.txt000064400000000000000000000012760000000000000151710ustar 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-0.3.2/man/zram-generator.conf.md000064400000000000000000000143000000000000000175140ustar 00000000000000 [comment]: SPDX-License-Identifier: MIT 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*. For compatibility with earlier versions, `memory-limit` is allowed as an alias for this option. Its use is discouraged, and administrators should migrate to `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. Defaults to *0.5*. * `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. Defaults to *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. * `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). ## 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 [MB] ^ │ 4G>│ ooooooooooooo │ o │ o │ o 2G>│ o │ o │ o 512M>│ o 0───────────────────────> total usable RAM [MB] ^ ^ ^ 1G 4G 8G ## REPORTING BUGS <> ## SEE ALSO zram-generator(8), systemd.syntax(5), proc(5) <> Linux documentation of zram: <>
and the zram sysfs ABI: <> zram-generator-0.3.2/man/zram-generator.md000064400000000000000000000053200000000000000165720ustar 00000000000000 [comment]: SPDX-License-Identifier: MIT 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 mount point. 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-swap-create@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-swap-create@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). ## 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-0.3.2/src/config.rs000064400000000000000000000313610000000000000151460ustar 00000000000000/* SPDX-License-Identifier: MIT */ use anyhow::{anyhow, Context, Result}; use ini::Ini; use liboverdrop::FragmentScanner; use log::{info, warn}; use std::cmp; use std::collections::{BTreeMap, HashMap}; use std::fmt; use std::fs; use std::io::{prelude::*, BufReader}; use std::path::{Component, Path, PathBuf}; pub struct Device { pub name: String, pub host_memory_limit_mb: Option, pub zram_fraction: f64, pub max_zram_size_mb: Option, pub compression_algorithm: Option, pub disksize: u64, pub swap_priority: i32, pub mount_point: Option, // when set, a mount unit will be created pub fs_type: Option, // useful mostly for mounts, None is the same // as "swap" when mount_point is not set } impl Device { fn new(name: String) -> Device { Device { name, host_memory_limit_mb: None, zram_fraction: 0.5, max_zram_size_mb: Some(4 * 1024), compression_algorithm: None, disksize: 0, swap_priority: 100, mount_point: None, fs_type: None, } } fn write_optional_mb(f: &mut fmt::Formatter<'_>, val: Option) -> fmt::Result { match val { Some(val) => { write!(f, "{}", val)?; f.write_str("MB")?; } None => f.write_str("")?, } Ok(()) } pub fn is_swap(&self) -> bool { return 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 { Some(ref fs_type) => fs_type, None => match self.is_swap() { true => "swap", false => "ext2", }, } } fn set_disksize_if_enabled(&mut self, memtotal_mb: u64) { if !self.is_enabled(memtotal_mb) { return; } self.disksize = (self.zram_fraction * memtotal_mb as f64) as u64 * 1024 * 1024; if let Some(max_mb) = self.max_zram_size_mb { self.disksize = cmp::min(self.disksize, max_mb * 1024 * 1024); } } } impl fmt::Display for Device { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{}: host-memory-limit=", self.name)?; Device::write_optional_mb(f, self.host_memory_limit_mb)?; write!(f, " zram-fraction={} max-zram-size=", self.zram_fraction)?; Device::write_optional_mb(f, self.max_zram_size_mb)?; f.write_str(" compression-algorithm=")?; match self.compression_algorithm.as_ref() { Some(alg) => f.write_str(alg)?, None => f.write_str("")?, } Ok(()) } } pub fn read_device(root: &Path, kernel_override: bool, name: &str) -> Result> { let memtotal_mb = (get_total_memory_kb(&root)? as f64 / 1024.) as u64; Ok(read_devices(root, kernel_override, memtotal_mb)? .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)? / 1024; let devices: Vec = read_devices(root, kernel_override, memtotal_mb)? .into_iter() .filter(|(_, dev)| dev.disksize > 0) .map(|(_, dev)| dev) .collect(); Ok(devices) } 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(); for dir in base_dirs.iter().rev() { let path = PathBuf::from(dir).join("systemd/zram-generator.conf"); if path.exists() { fragments.insert("".to_string(), path); // The empty string shall sort earliest break; } } 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..=32767 => Ok(val), _ => Err(anyhow!("Swap priority {} out of range", val)), } } fn verify_mount_point(val: &str) -> Result { let path = PathBuf::from(val); if path.is_relative() { return Err(anyhow!("mount-point {} is not absolute", val)); } if path.components().any(|c| c == Component::ParentDir) { return Err(anyhow!("mount-point {:#?} is not normalized", path)); } Ok(path) } 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-fraction" => { dev.zram_fraction = 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", f)) } })?; } "max-zram-size" => { dev.max_zram_size_mb = parse_optional_size(value)?; } "compression-algorithm" => { dev.compression_algorithm = Some(value.to_string()); } "swap-priority" => { dev.swap_priority = parse_swap_priority(value)?; } "mount-point" => { dev.mount_point = Some(verify_mount_point(value)?); } "fs-type" => { dev.fs_type = Some(value.to_string()); } _ => { warn!("Unknown key {}, ignoring.", 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:") = fields.next() { if let Some(v) = fields.next() { return Ok(v.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)?; // The last argument wins, so check all words in turn. Ok(text.split_whitespace().fold(None, |acc, w| { if !w.starts_with(word) { acc } else { match &w[word.len()..] { "" | "=1" | "=yes" | "=true" | "=on" => Some(true), "=0" | "=no" | "=false" | "=off" => Some(false), _ => acc, } } })) } 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(Some(true)) => Some(true), Ok(Some(false)) => { info!("Disabled by systemd.zram option in /proc/cmdline."); Some(false) } Ok(None) => None, Err(e) => { warn!("Failed to parse /proc/cmdline ({}), ignoring.", e); None } } } #[cfg(test)] mod tests { use super::*; #[test] fn test_get_total_memory_kb() { let mut file = tempfile::NamedTempFile::new().unwrap(); file.write( b"\ MemTotal: 8013220 kB MemFree: 721288 kB MemAvailable: 1740336 kB Buffers: 292752 kB ", ) .unwrap(); file.flush().unwrap(); 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 mut file = tempfile::NamedTempFile::new().unwrap(); file.write( b"\ MemTotala: 8013220 kB aMemTotal: 8013220 kB MemTotal:: 8013220 kB ", ) .unwrap(); file.flush().unwrap(); _get_total_memory_kb(file.path()).unwrap(); } #[test] fn test_kernel_has_option() { let mut file = tempfile::NamedTempFile::new().unwrap(); file.write( b"\ foo=1 foo=0 foo=on foo=off foo ", ) .unwrap(); file.flush().unwrap(); let foo = _kernel_has_option(file.path(), "foo").unwrap(); assert_eq!(foo, Some(true)); } #[test] fn test_kernel_has_no_option() { let mut file = tempfile::NamedTempFile::new().unwrap(); file.write( b"\ foo=1 foo=0 ", ) .unwrap(); file.flush().unwrap(); let foo = _kernel_has_option(file.path(), "foo").unwrap(); assert_eq!(foo, Some(false)); } #[test] fn test_verify_mount_point() { let p = verify_mount_point("/foobar").unwrap(); assert_eq!(p, PathBuf::from("/foobar")); } #[test] fn test_verify_mount_point_absolute() { let p = verify_mount_point("foo/bar"); assert!(p.is_err()); } #[test] fn test_verify_mount_point_normalized() { let p = verify_mount_point("/foo/../bar"); assert!(p.is_err()); } #[test] fn test_verify_mount_point_normalized2() { let p = verify_mount_point("/foo/.."); assert!(p.is_err()); } #[test] fn test_verify_mount_point_self() { verify_mount_point("/foo/./bar/").unwrap(); } } zram-generator-0.3.2/src/generator.rs000064400000000000000000000217670000000000000157000ustar 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; 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) { let status = Command::new("modprobe").arg(modname).status(); match 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 = match fs::read_to_string("/proc/crypto") { Ok(string) => string, Err(e) => { warn!("Failed to read /proc/crypto, proceeding as if empty: {}", e); String::from("") } }; 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)) } 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_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 ); /* 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/bindsto-swap.conf", device.name ), "\ [Unit] BindsTo=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} ", zram_device = device.name, swap_priority = device.swap_priority ), )?; /* 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(()) } fn mount_unit_name(path: &Path) -> String { /* FIXME: handle full escaping */ assert!(path.is_absolute()); let path = path.strip_prefix("/").unwrap().to_str().unwrap(); format!("{}.mount", path.replace("/", "-")) } 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 = &mount_unit_name(device.mount_point.as_ref().unwrap()); debug!( "Creating unit file {} (/dev/{} with {}MB)", mount_name, device.name, device.disksize / 1024 / 1024 ); /* 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/bindsto-mount.conf", device.name ), &format!( "\ [Unit] BindsTo={} ", 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:?} ", zram_device = device.name, mount_point = device.mount_point.as_ref().unwrap(), ), )?; /* 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 = vec!["zstd", "ccm(aes)", "ctr(aes)"]; assert_eq!(parse_known_compressors(data), BTreeSet::from_iter(expected)); } } zram-generator-0.3.2/src/kernlog.rs000064400000000000000000000044100000000000000153350ustar 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-0.3.2/src/lib.rs000064400000000000000000000001260000000000000144420ustar 00000000000000/* SPDX-License-Identifier: MIT */ pub mod config; pub mod generator; pub mod setup; zram-generator-0.3.2/src/main.rs000064400000000000000000000057360000000000000146340ustar 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"]), ) .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("ZRAM_GENERATOR_ROOT") { Ok(val) => (val.into(), true, LevelFilter::Trace), Err(env::VarError::NotPresent) => (Cow::from("/"), false, LevelFilter::Info), Err(e) => return Err(e.into()), }; let root = Path::new(&root[..]); 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 kernel_override = kernel_override(); 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 kernel_override = kernel_override(); 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-0.3.2/src/setup.rs000064400000000000000000000056320000000000000150430ustar 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::process::ExitStatusExt; use std::path::Path; use std::process::Command; 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() ) })?, } } 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-0.3.2/tests/01-basic/proc/meminfo000064400000000000000000000001240000000000000175160ustar 00000000000000MemTotal: 801322 kB MemFree: 611992 kB MemAvailable: 139764 kB zram-generator-0.3.2/tests/01-basic/run.expected/units/dev-zram0.swap000064400000000000000000000004230000000000000234470ustar 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 zram-generator-0.3.2/tests/01-basic/run.expected/units/swap.target.wants/dev-zram0.swap000064400000000000000000000004230000000000000270410ustar 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 ././@LongLink00006440000000000000000000000154000000000000007773Lustar zram-generator-0.3.2/tests/01-basic/run.expected/units/systemd-zram-setup@zram0.service.d/bindsto-swap.confzram-generator-0.3.2/tests/01-basic/run.expected/units/systemd-zram-setup@zram0.service.d/bindsto-sw000064400000000000000000000001100000000000000315030ustar 00000000000000# Automatically generated by zram-generator [Unit] BindsTo=dev-%i.swap zram-generator-0.3.2/tests/01-basic/usr/lib/systemd/zram-generator.conf000064400000000000000000000000100000000000000240430ustar 00000000000000[zram0] zram-generator-0.3.2/tests/02-zstd/etc/systemd/zram-generator.conf000064400000000000000000000001230000000000000231500ustar 00000000000000[zram0] compression-algorithm = zstd host-memory-limit = 2050 zram-fraction = 0.75 zram-generator-0.3.2/tests/02-zstd/proc/meminfo000064400000000000000000000001240000000000000174220ustar 00000000000000MemTotal: 801322 kB MemFree: 611992 kB MemAvailable: 139764 kB zram-generator-0.3.2/tests/02-zstd/run.expected/units/dev-zram0.swap000064400000000000000000000004230000000000000233530ustar 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 zram-generator-0.3.2/tests/02-zstd/run.expected/units/swap.target.wants/dev-zram0.swap000064400000000000000000000004230000000000000267450ustar 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 ././@LongLink00006440000000000000000000000153000000000000007772Lustar zram-generator-0.3.2/tests/02-zstd/run.expected/units/systemd-zram-setup@zram0.service.d/bindsto-swap.confzram-generator-0.3.2/tests/02-zstd/run.expected/units/systemd-zram-setup@zram0.service.d/bindsto-swa000064400000000000000000000001100000000000000315500ustar 00000000000000# Automatically generated by zram-generator [Unit] BindsTo=dev-%i.swap zram-generator-0.3.2/tests/03-too-much-memory/etc/systemd/zram-generator.conf000064400000000000000000000000370000000000000252320ustar 00000000000000[zram0] host-memory-limit=7824 zram-generator-0.3.2/tests/03-too-much-memory/proc/meminfo000064400000000000000000000002140000000000000215000ustar 00000000000000MemTotal: 8013220 kB MemFree: 1856196 kB MemAvailable: 2254912 kB Buffers: 94188 kB Cached: 1532436 kB zram-generator-0.3.2/tests/03-too-much-memory/run.expected/units/.empty000064400000000000000000000000000000000000000240560ustar 00000000000000zram-generator-0.3.2/tests/04-dropins/etc/systemd/zram-generator.conf.d/03-drop3.conf000064400000000000000000000000000000000000000262530ustar 00000000000000zram-generator-0.3.2/tests/04-dropins/etc/systemd/zram-generator.conf.d/04-drop4.conf000064400000000000000000000000540000000000000262660ustar 00000000000000[zram2] zram-fraction=0.8 swap-priority=200 zram-generator-0.3.2/tests/04-dropins/etc/systemd/zram-generator.conf.d/zram-generator.conf000064400000000000000000000002270000000000000277540ustar 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-0.3.2/tests/04-dropins/proc/meminfo000064400000000000000000000001240000000000000201160ustar 00000000000000MemTotal: 801322 kB MemFree: 611992 kB MemAvailable: 139764 kB zram-generator-0.3.2/tests/04-dropins/run.expected/units/dev-zram0.swap000064400000000000000000000004230000000000000240470ustar 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 zram-generator-0.3.2/tests/04-dropins/run.expected/units/dev-zram2.swap000064400000000000000000000004230000000000000240510ustar 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 zram-generator-0.3.2/tests/04-dropins/run.expected/units/swap.target.wants/dev-zram0.swap000064400000000000000000000004230000000000000274410ustar 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 zram-generator-0.3.2/tests/04-dropins/run.expected/units/swap.target.wants/dev-zram2.swap000064400000000000000000000004230000000000000274430ustar 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 ././@LongLink00006440000000000000000000000156000000000000007775Lustar zram-generator-0.3.2/tests/04-dropins/run.expected/units/systemd-zram-setup@zram0.service.d/bindsto-swap.confzram-generator-0.3.2/tests/04-dropins/run.expected/units/systemd-zram-setup@zram0.service.d/bindsto-000064400000000000000000000001100000000000000315310ustar 00000000000000# Automatically generated by zram-generator [Unit] BindsTo=dev-%i.swap ././@LongLink00006440000000000000000000000156000000000000007775Lustar zram-generator-0.3.2/tests/04-dropins/run.expected/units/systemd-zram-setup@zram2.service.d/bindsto-swap.confzram-generator-0.3.2/tests/04-dropins/run.expected/units/systemd-zram-setup@zram2.service.d/bindsto-000064400000000000000000000001100000000000000315330ustar 00000000000000# Automatically generated by zram-generator [Unit] BindsTo=dev-%i.swap zram-generator-0.3.2/tests/04-dropins/usr/lib/systemd/zram-generator.conf000064400000000000000000000000100000000000000244430ustar 00000000000000[zram0] zram-generator-0.3.2/tests/04-dropins/usr/lib/systemd/zram-generator.conf.d/01-drop1.conf000064400000000000000000000000370000000000000270650ustar 00000000000000[zram0] host-memory-limit=1234 zram-generator-0.3.2/tests/04-dropins/usr/lib/systemd/zram-generator.conf.d/02-drop2.conf000064400000000000000000000000370000000000000270670ustar 00000000000000[zram0] host-memory-limit=1235 zram-generator-0.3.2/tests/04-dropins/usr/lib/systemd/zram-generator.conf.d/03-drop3.conf000064400000000000000000000000720000000000000270700ustar 00000000000000[zram0] host-memory-limit=1236 [zram1] zram-fraction=0.7 zram-generator-0.3.2/tests/05-kernel-disabled/proc/cmdline000064400000000000000000000000510000000000000214460ustar 00000000000000asfdasdf=foobar bar=foood systemd.zram=0 zram-generator-0.3.2/tests/05-kernel-disabled/proc/meminfo000064400000000000000000000002140000000000000214660ustar 00000000000000MemTotal: 8013220 kB MemFree: 1856196 kB MemAvailable: 2254912 kB Buffers: 94188 kB Cached: 1532436 kB ././@LongLink00006440000000000000000000000166000000000000007776Lustar zram-generator-0.3.2/tests/05-kernel-disabled/run.expected/units/systemd-zram-setup@zram0.service.d/bindsto-swap.confzram-generator-0.3.2/tests/05-kernel-disabled/run.expected/units/systemd-zram-setup@zram0.service.d/000064400000000000000000000001070000000000000314470ustar 00000000000000# Automatically generated by zram-generator [Unit] BindsTo=dev-%i.swap zram-generator-0.3.2/tests/05-kernel-disabled/usr/lib/systemd/zram-generator.conf000064400000000000000000000000100000000000000260130ustar 00000000000000[zram0] zram-generator-0.3.2/tests/06-kernel-enabled/proc/cmdline000064400000000000000000000000200000000000000212660ustar 00000000000000 systemd.zram zram-generator-0.3.2/tests/06-kernel-enabled/proc/meminfo000064400000000000000000000002140000000000000213120ustar 00000000000000MemTotal: 8013220 kB MemFree: 1856196 kB MemAvailable: 2254912 kB Buffers: 94188 kB Cached: 1532436 kB zram-generator-0.3.2/tests/06-kernel-enabled/run.expected/units/dev-zram0.swap000064400000000000000000000004230000000000000252430ustar 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 zram-generator-0.3.2/tests/06-kernel-enabled/run.expected/units/swap.target.wants/dev-zram0.swap000064400000000000000000000004230000000000000306350ustar 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 ././@LongLink00006440000000000000000000000165000000000000007775Lustar zram-generator-0.3.2/tests/06-kernel-enabled/run.expected/units/systemd-zram-setup@zram0.service.d/bindsto-swap.confzram-generator-0.3.2/tests/06-kernel-enabled/run.expected/units/systemd-zram-setup@zram0.service.d/b000064400000000000000000000001100000000000000314270ustar 00000000000000# Automatically generated by zram-generator [Unit] BindsTo=dev-%i.swap zram-generator-0.3.2/tests/07-mount-point/etc/systemd/zram-generator.conf000064400000000000000000000000660000000000000244700ustar 00000000000000[zram11] mount-point = /var/compressed fs-type = ext4 zram-generator-0.3.2/tests/07-mount-point/proc/meminfo000064400000000000000000000001240000000000000207340ustar 00000000000000MemTotal: 801322 kB MemFree: 611992 kB MemAvailable: 139764 kB ././@LongLink00006440000000000000000000000150000000000000007767Lustar zram-generator-0.3.2/tests/07-mount-point/run.expected/units/local-fs.target.wants/var-compressed.mountzram-generator-0.3.2/tests/07-mount-point/run.expected/units/local-fs.target.wants/var-compressed.mo000064400000000000000000000005260000000000000315770ustar 00000000000000# Automatically generated by "/home/zbyszek/src/zram-generator/target/debug/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" ././@LongLink00006440000000000000000000000164000000000000007774Lustar zram-generator-0.3.2/tests/07-mount-point/run.expected/units/systemd-zram-setup@zram11.service.d/bindsto-mount.confzram-generator-0.3.2/tests/07-mount-point/run.expected/units/systemd-zram-setup@zram11.service.d/bin000064400000000000000000000001230000000000000314660ustar 00000000000000# Automatically generated by "zram-generator" [Unit] BindsTo=var-compressed.mount zram-generator-0.3.2/tests/07-mount-point/run.expected/units/var-compressed.mount000064400000000000000000000005260000000000000262060ustar 00000000000000# Automatically generated by "/home/zbyszek/src/zram-generator/target/debug/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" zram-generator-0.3.2/tests/08-plain-device/etc/systemd/zram-generator.conf000064400000000000000000000000300000000000000245270ustar 00000000000000[zram11] fs-type = ext2 zram-generator-0.3.2/tests/08-plain-device/proc/meminfo000064400000000000000000000001240000000000000210040ustar 00000000000000MemTotal: 801322 kB MemFree: 611992 kB MemAvailable: 139764 kB zram-generator-0.3.2/tests/08-plain-device/proc/self/mountinfo000064400000000000000000000000700000000000000223210ustar 0000000000000015 1 253:1 / / rw,relatime shared:1 - ext4 /dev/root ro zram-generator-0.3.2/tests/08-plain-device/run.expected/units/.empty000064400000000000000000000000000000000000000233620ustar 00000000000000zram-generator-0.3.2/tests/test_cases.rs000064400000000000000000000123750000000000000164150ustar 00000000000000/* SPDX-License-Identifier: MIT */ use zram_generator::{config, generator}; use anyhow::Result; use fs_extra::dir::{copy, CopyOptions}; use std::fs; use std::path::Path; use std::process::Command; use tempfile::TempDir; fn prepare_directory(srcroot: &Path) -> Result { let rootdir = TempDir::new()?; let root = rootdir.path(); let opts = CopyOptions::new(); for p in vec!["etc", "usr", "proc"] { if srcroot.join(p).exists() { copy(srcroot.join(p), root, &opts)?; } } let output_directory = root.join("run/units"); fs::create_dir_all(output_directory)?; Ok(rootdir) } fn test_generation(name: &str) -> Result> { let srcroot = Path::new(file!()).parent().unwrap().join(name); 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)?; match name { "01-basic" => { assert_eq!(devices.len(), 1); let d = devices.iter().next().unwrap(); assert!(d.is_swap()); assert_eq!(d.host_memory_limit_mb, None); assert_eq!(d.zram_fraction, 0.5); } "02-zstd" => { assert_eq!(devices.len(), 1); let d = devices.iter().next().unwrap(); assert!(d.is_swap()); assert_eq!(d.host_memory_limit_mb.unwrap(), 2050); assert_eq!(d.zram_fraction, 0.75); assert_eq!(d.compression_algorithm.as_ref().unwrap(), "zstd"); } "03-too-much-memory" => { assert_eq!(devices.len(), 0); } "04-dropins" => { assert_eq!(devices.len(), 2); for d in &devices { assert!(d.is_swap()); match d.name.as_str() { "zram0" => { assert_eq!(d.host_memory_limit_mb.unwrap(), 1235); assert_eq!(d.zram_fraction, 0.5); } "zram2" => { assert!(d.host_memory_limit_mb.is_none()); assert_eq!(d.zram_fraction, 0.8); } _ => panic!("Unexpected device {}", d), } } } "05-kernel-disabled" => { assert_eq!(devices.len(), 0); } "06-kernel-enabled" => { assert_eq!(devices.len(), 1); let d = devices.iter().next().unwrap(); assert!(d.is_swap()); assert_eq!(d.host_memory_limit_mb, None); assert_eq!(d.zram_fraction, 0.5); } "07-mount-point" => { assert_eq!(devices.len(), 1); let d = devices.iter().next().unwrap(); assert!(!d.is_swap()); assert_eq!(d.host_memory_limit_mb, None); assert_eq!(d.zram_fraction, 0.5); assert_eq!( d.mount_point.as_ref().unwrap(), Path::new("/var/compressed") ); assert_eq!(d.fs_type.as_ref().unwrap(), "ext4"); assert_eq!(d.effective_fs_type(), "ext4"); } "08-plain-device" => { assert_eq!(devices.len(), 1); let d = devices.iter().next().unwrap(); assert!(!d.is_swap()); assert_eq!(d.host_memory_limit_mb, None); assert_eq!(d.zram_fraction, 0.5); assert!(d.mount_point.is_none()); assert_eq!(d.fs_type.as_ref().unwrap(), "ext2"); assert_eq!(d.effective_fs_type(), "ext2"); } _ => (), } // 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("--recursive") .arg("--exclude=.empty") .arg("--ignore-matching-lines=^# Automatically generated by .*") .arg("--ignore-matching-lines=^ExecStart=/.* --setup-device '%i'") .arg("--ignore-matching-lines=^ExecStop=/.* --reset-device '%i'") .arg(srcroot.join("run.expected")) .arg(root.join("run")) .output()?; println!("stdout:\n{}", String::from_utf8_lossy(&diff.stdout)); println!("stderr:\n{}", String::from_utf8_lossy(&diff.stderr)); assert!(diff.status.success()); Ok(devices) } #[test] fn test_01_basic() { test_generation("01-basic").unwrap(); } #[test] fn test_02_zstd() { test_generation("02-zstd").unwrap(); } #[test] fn test_03_too_much_memory() { test_generation("03-too-much-memory").unwrap(); } #[test] fn test_04_dropins() { test_generation("04-dropins").unwrap(); } #[test] fn test_05_kernel_disabled() { test_generation("05-kernel-disabled").unwrap(); } #[test] fn test_06_kernel_enabled() { test_generation("06-kernel-enabled").unwrap(); } #[test] fn test_07_mount_point() { test_generation("07-mount-point").unwrap(); } #[test] fn test_08_plain_device() { test_generation("08-plain-device").unwrap(); } zram-generator-0.3.2/units/.gitignore000064400000000000000000000000350000000000000156700ustar 00000000000000/systemd-zram-setup@.service zram-generator-0.3.2/units/systemd-zram-setup@.service.d/binary-location.conf000064400000000000000000000002750000000000000254250ustar 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-0.3.2/units/systemd-zram-setup@.service.in000064400000000000000000000007300000000000000215660ustar 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-0.3.2/zram-generator.conf.example000064400000000000000000000030640000000000000200010ustar 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 fraction of memory to use as ZRAM. For example, if the machine # has 1 GiB, and zram-fraction=0.25, then the zram device will have # 256 MiB. Values in the range 0.10–0.50 are recommended. # # The default is 0.5. zram-fraction = 0.10 # The maximum size of the zram device (in MiB). # # If host-memory times zram-fraction is greater than this, # the size will be capped to this amount; # for example, on a machine with 2 GiB of RAM and with zram-fraction=0.5, # the device would still be 512 MiB in size due to the limit below. # # The default is 4096. max-zram-size = 512 # The compression algorithm to use for the zram device, # or leave unspecified to keep the kernel default. compression-algorithm = lzo-rle [zram1] # This section describes the settings for /dev/zram1. # # host-memory-limit is not specifed, so this device will always be created. # Size the device to a tenth of RAM. zram-fraction = 0.1 # 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