Initial code push

This commit is contained in:
Scott B 2019-12-22 23:33:58 -08:00
parent 461049a206
commit 4241a70d94
5 changed files with 207 additions and 1 deletions

View file

@ -1,2 +1,32 @@
# zram-swap
zram swap setup + teardown with systemd unit & /etd/default configuration
Simple zram swap setup + teardown script with systemd unit & /etc/default configuration
https://github.com/foundObjects/zram-swap
### Installation
```
git clone https://github.com/foundObjects/zram-swap.git
cd zram-swap && sudo bash install.sh
```
### Usage
zram-swap.service will be started automatically during boot.
The default allocation creates a zram device that should use around half of physical memory when completely full.
Edit `/etc/default/zram-swap-service` if you'd like to change compression algorithms or swap allocation and then restart zram-swap with `systemctl restart zram-swap.service`.
Run `zramctl` during use to monitor swap compression and real memory usage.
### Debugging
Either start zram-swap.sh with `bash -x zram-swap.sh` or `./zram-swap.sh -x (start|stop)` to see what's going wrong.
To dump the full execution trace during service start/stop edit /etc/systemd/systemd/zram-swap.service and add -x to the following two lines:
```
ExecStart=/usr/local/sbin/zram-swap.sh -x init
ExecStop=/usr/local/sbin/zram-swap.sh -x end
```

16
install.sh Executable file
View file

@ -0,0 +1,16 @@
#!/usr/bin/env bash
[[ "$EUID" == 0 ]] || { echo "This script requires root." && exit 1; }
set -ex
if systemctl -q is-active zram-swap.service; then
systemctl stop zram-swap.service
fi
install -o root zram-swap.sh /usr/local/sbin/zram-swap.sh
install -o root zram-swap-service /etc/default/zram-swap-service
install -o root zram-swap.service /etc/systemd/system/zram-swap.service
systemctl daemon-reload
systemctl enable zram-swap.service
systemctl start zram-swap.service

22
zram-swap-service Normal file
View file

@ -0,0 +1,22 @@
# portion of real ram to use as zram swap (expression: "1/2", "0.5", etc)
_zram_fraction="1/2"
# compression algorithm to employ (lzo, lz4, zstd, lzo-rle)
_zram_algorithm="lz4"
# set expected compression ratio based on algorithm; this is a rough estimate
# set this by hand if you use an algorithm other than lzo/lz4/zstd
#_comp_factor="2.5"
#
# defaults:
#case $_zram_algorithm in
# lzo*|zstd)
# _comp_factor="3"
# ;;
# lz4)
# _comp_factor="2.5"
# ;;
# *)
# _comp_factor="2"
# ;;
#esac

13
zram-swap.service Normal file
View file

@ -0,0 +1,13 @@
[Unit]
Description=zram swap service
Requires=systemd-modules-load.service local-fs.target
[Service]
Type=oneshot
ExecStart=/usr/local/sbin/zram-swap.sh init
ExecStop=/usr/local/sbin/zram-swap.sh end
RemainAfterExit=True
[Install]
WantedBy=sysinit.target
#RequiredBy=

125
zram-swap.sh Executable file
View file

@ -0,0 +1,125 @@
#!/bin/bash
# source: https://github.com/foundObjects/zram-swap
[[ "$EUID" == "0" ]] || { echo "This script requires root." && exit 1; }
set -eo pipefail
# parse debug flag early so we can trace everything
[[ "$1" == "-x" ]] && { shift && set -x; } >&/dev/null
# set sane defaults, see /etc/default/zram-swap-service for explanations
_zram_fraction="1/2"
_zram_algorithm="lz4"
_comp_factor=''
# load user config
[[ -f /etc/default/zram-swap-service ]] &&
source /etc/default/zram-swap-service
# set expected compression ratio based on algorithm; this is a rough estimate
# skip if already set in user config
if [[ -z "$_comp_factor" ]]; then
case $_zram_algorithm in
lzo* | zstd) _comp_factor="3" ;;
lz4) _comp_factor="2.5" ;;
*) _comp_factor="2" ;;
esac
fi
# main script:
_main() {
if ! modprobe zram; then
err "Failed to load zram module, exiting"
return 1
fi
case "$1" in
# a little magic to quietly set -u after testing our last expected empty variable
# matches every case, runs set -u without logging to the trace and then continues matching
*) { set -u; } 2>/dev/null ;;&
"init" | "start")
if grep -q zram /proc/swaps; then
err "zram swap already in use, exiting"
return 1
fi
_init
;;
"end" | "stop")
if ! grep -q zram /proc/swaps; then
err "no zram swaps to cleanup, exiting"
return 1
fi
_end
;;
*)
echo "Usage: $0 (init|end)"
return 1
;;
esac
}
# initialize swap
_init() {
# Calculate memory to use for zram
totalmem=$(LC_ALL=C free | grep -e "^Mem:" | sed -e 's/^Mem: *//' -e 's/ *.*//')
mem=$(calc "$totalmem * $_comp_factor * $_zram_fraction * 1024")
# NOTE: init is a little janky; zramctl sometimes fails if we don't wait after module
# load so retry a couple of times with slightly increasing delay before giving up
_device=''
for i in $(seq 3); do
sleep "$(calc "0.1 * $i")"
_device=$(zramctl -f -s "$mem" -a "$_zram_algorithm") || true
[[ -b "$_device" ]] && break
done
if [[ -b "$_device" ]]; then
# cleanup the device if swap setup fails
trap "_rem_zdev $_device" EXIT
mkswap "$_device"
swapon -p 5 "$_device"
trap - EXIT
return 0
else
err "Failed to initialize zram device"
return 1
fi
}
# end swapping and cleanup
_end() {
local ret="0"
DEVICES=$(grep zram /proc/swaps | awk '{print $1}')
for d in $DEVICES; do
swapoff "$d"
if ! _rem_zdev "$d"; then
err "Failed to remove zram device $d"
ret=1
fi
done
return "$ret"
}
# Remove zram device with retry
_rem_zdev() {
if [[ ! -b "$1" ]]; then
err "No zram device '$1' to remove"
return 1
fi
for i in $(seq 3); do
sleep "$(calc "0.1 * $i")"
zramctl -r "$1" || true
[[ -b "$1" ]] || break
done
if [[ -b "$1" ]]; then
err "Couldn't remove zram device '$1' after 3 attempts"
return 1
fi
return 0
}
calc() { awk "BEGIN{print $*}"; }
#crapout() { echo "$@" >&2 && exit 1; }
err() { echo "Err '${FUNCNAME[1]}': $*" >&2; }
_main "$@"