Skip to content

Commit d42e34f

Browse files
authored
Make swap size configurable (#3882)
Allow configuration of the swap size via /etc/default/haos-swapfile file. By setting the SWAPSIZE variable in this file, swapfile get recreated on the next reboot to the defined size. Size can be either in bytes or with optional units (B/K/M/G, accepting some variations but always interpreted as power of 10). The size is then rounded to 4k block size. If no override is defined or the value can't be parsed, it falls back to previously used 33% of system RAM. Fixes #968
1 parent dc7b693 commit d42e34f

File tree

6 files changed

+89
-15
lines changed

6 files changed

+89
-15
lines changed

buildroot-external/rootfs-overlay/etc/default/.empty

Whitespace-only changes.
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
[Unit]
2+
Description=Persistent /etc/default directory
3+
Requires=mnt-overlay.mount
4+
After=mnt-overlay.mount
5+
6+
[Mount]
7+
What=/mnt/overlay/etc/default
8+
Where=/etc/default
9+
Type=None
10+
Options=bind
11+
12+
[Install]
13+
WantedBy=hassos-bind.target

buildroot-external/rootfs-overlay/usr/lib/systemd/system/haos-swapfile.service

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
[Unit]
22
Description=HAOS swap
33
DefaultDependencies=no
4-
Requires=mnt-data.mount
5-
After=mnt-data.mount [email protected]
4+
Requires=etc-default.mount mnt-data.mount
5+
After=etc-default.mount mnt-data.mount [email protected]
66
Before=mnt-data-swapfile.swap
77

88
[Service]

buildroot-external/rootfs-overlay/usr/lib/systemd/system/mnt-data-swapfile.swap

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
[Unit]
22
Description=HAOS swap file
3+
ConditionFileNotEmpty=/mnt/data/swapfile
34

45
[Swap]
56
What=/mnt/data/swapfile
Lines changed: 48 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,59 @@
11
#!/bin/sh
22
set -e
33

4-
swapfile="/mnt/data/swapfile"
4+
size2kilobytes() {
5+
bytes="$(echo "$1" | awk \
6+
'BEGIN{IGNORECASE = 1}
7+
function tobytes(n,b,p) {printf "%u\n", n*b^p/1024}
8+
/[0-9]B?$/{tobytes($1, 1, 0); next};
9+
/K(i?B)?$/{tobytes($1, 2, 10); next};
10+
/M(i?B)?$/{tobytes($1, 2, 20); next};
11+
/G(i?B)?$/{tobytes($1, 2, 30); next};
12+
{print -1}')"
13+
echo "$bytes"
14+
}
15+
16+
if [ -f /etc/default/haos-swapfile ]; then
17+
# shellcheck disable=SC1091
18+
. /etc/default/haos-swapfile
19+
fi
20+
SWAPFILE="/mnt/data/swapfile"
21+
22+
# Swap size in kilobytes (as it's also what meminfo shows)
23+
SWAPSIZE="$(size2kilobytes "${SWAPSIZE}")"
24+
25+
if [ -z "${SWAPSIZE}" ] || [ "${SWAPSIZE}" = "-1" ]; then
26+
# Default to 33% of total memory
27+
SWAPSIZE="$(awk '/MemTotal/{ print int($2 * 0.33) }' /proc/meminfo)"
28+
echo "[INFO] Using default swapsize of 33% RAM (${SWAPSIZE} kB)"
29+
fi
30+
531
# Swap space in 4k blocks
6-
swapsize="$(awk '/MemTotal/{ print int($2 * 0.33 / 4) }' /proc/meminfo)"
32+
SWAPSIZE_BLOCKS=$((SWAPSIZE / 4))
733

34+
if [ "${SWAPSIZE_BLOCKS}" -lt 10 ]; then
35+
echo "[INFO] Requested swap size smaller than 40kB, disabling swap"
836

9-
if [ ! -s "${swapfile}" ] || [ "$(stat "${swapfile}" -c '%s')" -lt $((swapsize * 4096)) ]; then
10-
# Check free space (in 4k blocks)
11-
if [ "$(stat -f /mnt/data -c '%f')" -lt "${swapsize}" ]; then
12-
echo "[WARNING] Not enough space to allocate swapfile"
13-
exit 1
14-
fi
37+
if [ -f "${SWAPFILE}" ]; then
38+
echo "[INFO] Removing existing swapfile"
39+
rm -f "${SWAPFILE}"
40+
fi
1541

16-
echo "[INFO] Creating swapfile of size $((swapsize *4))k"
17-
umask 0077
18-
dd if=/dev/zero of="${swapfile}" bs=4k count="${swapsize}"
42+
exit 0
1943
fi
2044

21-
if ! swaplabel "${swapfile}" > /dev/null 2>&1; then
22-
/usr/lib/systemd/systemd-makefs swap "${swapfile}"
45+
if [ ! -s "${SWAPFILE}" ] || [ "$(stat "${SWAPFILE}" -c '%s')" -ne $((SWAPSIZE_BLOCKS * 4096)) ]; then
46+
# Check free space (in 4k blocks)
47+
if [ "$(stat -f /mnt/data -c '%f')" -lt "${SWAPSIZE_BLOCKS}" ]; then
48+
echo "[ERROR] Not enough space to allocate swapfile"
49+
exit 1
50+
fi
51+
52+
echo "[INFO] Creating swapfile of size ${SWAPSIZE} kB (rounded to ${SWAPSIZE_BLOCKS} blocks)"
53+
umask 0077
54+
dd if=/dev/zero of="${SWAPFILE}" bs=4k count="${SWAPSIZE_BLOCKS}"
2355
fi
2456

57+
if ! swaplabel "${SWAPFILE}" > /dev/null 2>&1; then
58+
/usr/lib/systemd/systemd-makefs swap "${SWAPFILE}"
59+
fi

tests/smoke_test/test_basic.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,31 @@ def test_systemctl_check_no_failed(shell):
7878
assert "0 loaded units listed." in output, f"Some units failed:\n{"\n".join(output)}"
7979

8080

81+
@pytest.mark.dependency(depends=["test_init"])
82+
def test_custom_swap_size(shell, target):
83+
output = shell.run_check("stat -c '%s' /mnt/data/swapfile")
84+
# set new swap size to half of the previous size - round to 4k blocks
85+
new_swap_size = (int(output[0]) // 2 // 4096) * 4096
86+
shell.run_check(f"echo 'SWAPSIZE={new_swap_size/1024/1024}M' > /etc/default/haos-swapfile; reboot")
87+
# reactivate ShellDriver to handle login again
88+
target.deactivate(shell)
89+
target.activate(shell)
90+
output = shell.run_check("stat -c '%s' /mnt/data/swapfile")
91+
assert int(output[0]) == new_swap_size, f"Incorrect swap size {new_swap_size}B: {output}"
92+
93+
94+
@pytest.mark.dependency(depends=["test_custom_swap_size"])
95+
def test_no_swap(shell, target):
96+
output = shell.run_check("echo 'SWAPSIZE=0' > /etc/default/haos-swapfile; reboot")
97+
# reactivate ShellDriver to handle login again
98+
target.deactivate(shell)
99+
target.activate(shell)
100+
output = shell.run_check("systemctl --no-pager -l list-units --state=failed")
101+
assert "0 loaded units listed." in output, f"Some units failed:\n{"\n".join(output)}"
102+
swapon = shell.run_check("swapon --show")
103+
assert swapon == [], f"Swapfile still exists: {swapon}"
104+
105+
81106
@pytest.mark.dependency(depends=["test_init"])
82107
def test_kernel_not_tainted(shell):
83108
"""Check if the kernel is not tainted - do it at the end of the

0 commit comments

Comments
 (0)