diff --git a/buildroot-external/rootfs-overlay/etc/default/.empty b/buildroot-external/rootfs-overlay/etc/default/.empty new file mode 100644 index 00000000000..e69de29bb2d diff --git a/buildroot-external/rootfs-overlay/usr/lib/systemd/system/etc-default.mount b/buildroot-external/rootfs-overlay/usr/lib/systemd/system/etc-default.mount new file mode 100644 index 00000000000..8130c7f4792 --- /dev/null +++ b/buildroot-external/rootfs-overlay/usr/lib/systemd/system/etc-default.mount @@ -0,0 +1,13 @@ +[Unit] +Description=Persistent /etc/default directory +Requires=mnt-overlay.mount +After=mnt-overlay.mount + +[Mount] +What=/mnt/overlay/etc/default +Where=/etc/default +Type=None +Options=bind + +[Install] +WantedBy=hassos-bind.target diff --git a/buildroot-external/rootfs-overlay/usr/lib/systemd/system/haos-swapfile.service b/buildroot-external/rootfs-overlay/usr/lib/systemd/system/haos-swapfile.service index 872438487ef..263286329aa 100644 --- a/buildroot-external/rootfs-overlay/usr/lib/systemd/system/haos-swapfile.service +++ b/buildroot-external/rootfs-overlay/usr/lib/systemd/system/haos-swapfile.service @@ -1,8 +1,8 @@ [Unit] Description=HAOS swap DefaultDependencies=no -Requires=mnt-data.mount -After=mnt-data.mount systemd-growfs@mnt-data.service +Requires=etc-default.mount mnt-data.mount +After=etc-default.mount mnt-data.mount systemd-growfs@mnt-data.service Before=mnt-data-swapfile.swap [Service] diff --git a/buildroot-external/rootfs-overlay/usr/lib/systemd/system/mnt-data-swapfile.swap b/buildroot-external/rootfs-overlay/usr/lib/systemd/system/mnt-data-swapfile.swap index e7eca95dbb3..c6fb697baff 100644 --- a/buildroot-external/rootfs-overlay/usr/lib/systemd/system/mnt-data-swapfile.swap +++ b/buildroot-external/rootfs-overlay/usr/lib/systemd/system/mnt-data-swapfile.swap @@ -1,5 +1,6 @@ [Unit] Description=HAOS swap file +ConditionFileNotEmpty=/mnt/data/swapfile [Swap] What=/mnt/data/swapfile diff --git a/buildroot-external/rootfs-overlay/usr/libexec/haos-swapfile b/buildroot-external/rootfs-overlay/usr/libexec/haos-swapfile index 46080ff7674..e450392a84f 100755 --- a/buildroot-external/rootfs-overlay/usr/libexec/haos-swapfile +++ b/buildroot-external/rootfs-overlay/usr/libexec/haos-swapfile @@ -1,24 +1,59 @@ #!/bin/sh set -e -swapfile="/mnt/data/swapfile" +size2kilobytes() { + bytes="$(echo "$1" | awk \ + 'BEGIN{IGNORECASE = 1} + function tobytes(n,b,p) {printf "%u\n", n*b^p/1024} + /[0-9]B?$/{tobytes($1, 1, 0); next}; + /K(i?B)?$/{tobytes($1, 2, 10); next}; + /M(i?B)?$/{tobytes($1, 2, 20); next}; + /G(i?B)?$/{tobytes($1, 2, 30); next}; + {print -1}')" + echo "$bytes" +} + +if [ -f /etc/default/haos-swapfile ]; then + # shellcheck disable=SC1091 + . /etc/default/haos-swapfile +fi +SWAPFILE="/mnt/data/swapfile" + +# Swap size in kilobytes (as it's also what meminfo shows) +SWAPSIZE="$(size2kilobytes "${SWAPSIZE}")" + +if [ -z "${SWAPSIZE}" ] || [ "${SWAPSIZE}" = "-1" ]; then + # Default to 33% of total memory + SWAPSIZE="$(awk '/MemTotal/{ print int($2 * 0.33) }' /proc/meminfo)" + echo "[INFO] Using default swapsize of 33% RAM (${SWAPSIZE} kB)" +fi + # Swap space in 4k blocks -swapsize="$(awk '/MemTotal/{ print int($2 * 0.33 / 4) }' /proc/meminfo)" +SWAPSIZE_BLOCKS=$((SWAPSIZE / 4)) +if [ "${SWAPSIZE_BLOCKS}" -lt 10 ]; then + echo "[INFO] Requested swap size smaller than 40kB, disabling swap" -if [ ! -s "${swapfile}" ] || [ "$(stat "${swapfile}" -c '%s')" -lt $((swapsize * 4096)) ]; then - # Check free space (in 4k blocks) - if [ "$(stat -f /mnt/data -c '%f')" -lt "${swapsize}" ]; then - echo "[WARNING] Not enough space to allocate swapfile" - exit 1 - fi + if [ -f "${SWAPFILE}" ]; then + echo "[INFO] Removing existing swapfile" + rm -f "${SWAPFILE}" + fi - echo "[INFO] Creating swapfile of size $((swapsize *4))k" - umask 0077 - dd if=/dev/zero of="${swapfile}" bs=4k count="${swapsize}" + exit 0 fi -if ! swaplabel "${swapfile}" > /dev/null 2>&1; then - /usr/lib/systemd/systemd-makefs swap "${swapfile}" +if [ ! -s "${SWAPFILE}" ] || [ "$(stat "${SWAPFILE}" -c '%s')" -ne $((SWAPSIZE_BLOCKS * 4096)) ]; then + # Check free space (in 4k blocks) + if [ "$(stat -f /mnt/data -c '%f')" -lt "${SWAPSIZE_BLOCKS}" ]; then + echo "[ERROR] Not enough space to allocate swapfile" + exit 1 + fi + + echo "[INFO] Creating swapfile of size ${SWAPSIZE} kB (rounded to ${SWAPSIZE_BLOCKS} blocks)" + umask 0077 + dd if=/dev/zero of="${SWAPFILE}" bs=4k count="${SWAPSIZE_BLOCKS}" fi +if ! swaplabel "${SWAPFILE}" > /dev/null 2>&1; then + /usr/lib/systemd/systemd-makefs swap "${SWAPFILE}" +fi diff --git a/tests/smoke_test/test_basic.py b/tests/smoke_test/test_basic.py index eb6d42b4566..9ae86b10499 100644 --- a/tests/smoke_test/test_basic.py +++ b/tests/smoke_test/test_basic.py @@ -78,6 +78,31 @@ def test_systemctl_check_no_failed(shell): assert "0 loaded units listed." in output, f"Some units failed:\n{"\n".join(output)}" +@pytest.mark.dependency(depends=["test_init"]) +def test_custom_swap_size(shell, target): + output = shell.run_check("stat -c '%s' /mnt/data/swapfile") + # set new swap size to half of the previous size - round to 4k blocks + new_swap_size = (int(output[0]) // 2 // 4096) * 4096 + shell.run_check(f"echo 'SWAPSIZE={new_swap_size/1024/1024}M' > /etc/default/haos-swapfile; reboot") + # reactivate ShellDriver to handle login again + target.deactivate(shell) + target.activate(shell) + output = shell.run_check("stat -c '%s' /mnt/data/swapfile") + assert int(output[0]) == new_swap_size, f"Incorrect swap size {new_swap_size}B: {output}" + + +@pytest.mark.dependency(depends=["test_custom_swap_size"]) +def test_no_swap(shell, target): + output = shell.run_check("echo 'SWAPSIZE=0' > /etc/default/haos-swapfile; reboot") + # reactivate ShellDriver to handle login again + target.deactivate(shell) + target.activate(shell) + output = shell.run_check("systemctl --no-pager -l list-units --state=failed") + assert "0 loaded units listed." in output, f"Some units failed:\n{"\n".join(output)}" + swapon = shell.run_check("swapon --show") + assert swapon == [], f"Swapfile still exists: {swapon}" + + @pytest.mark.dependency(depends=["test_init"]) def test_kernel_not_tainted(shell): """Check if the kernel is not tainted - do it at the end of the