port the swap section, and size it against the disk
Four things the original got wrong, all of which only show up on a machine that is not this one: It detected swap with `swapon --show | grep -q '/'` — a test for a swap FILE. A machine using zram or a swap partition reports no swap at all, and the step would add a swapfile beside working swap. Reads SwapTotal from /proc/meminfo now, which covers every kind. It never looked at free disk. On a VPS with 4G free and 16G of RAM it would fallocate 8G, fail, and take the run down under `set -e`. The recommendation is now capped by what is actually there, keeping 5G back, and refuses rather than shrinking to something useless. fallocate was assumed to work. It produces a file that btrfs and zfs will not swap on, so dd is the fallback — slow, but it always works. swappiness was written by sed'ing /etc/sysctl.conf in place, tangling it with whatever else lives there. It is a drop-in at /etc/sysctl.d now, so what this script set is visible as its own file. Role-dependent, which is the first use of MACHINE_ROLE: swappiness 10 on a server, where swapping is the emergency valve and a page fault on a request path is latency somebody is waiting for; the kernel default of 60 on dev, where swapping out an application nobody has touched in an hour is exactly what you want. WSL is left alone entirely — WSL2 runs its own managed swap inside the VM, and a swapfile written here is wasted disk the kernel will not use. Sizes are reported rounded rather than floored. A 4 GiB swapfile is 4194300 kB, which floors to 3 and reads as though a gigabyte went missing. Free disk stays floored, deliberately: it decides how much to allocate, and rounding up invents space. Verified on this host — 4G RAM, 4G existing swap correctly detected and left alone — and with the disk check stubbed at 6G free (caps to 1G) and 3G free (refuses). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -261,13 +261,67 @@ if ! skip; then
|
||||
step_ok
|
||||
fi
|
||||
|
||||
# =============================================================================
|
||||
# 7. Swap
|
||||
# =============================================================================
|
||||
#
|
||||
# Disk the kernel can park cold pages on when RAM fills, so a spike costs
|
||||
# latency instead of a process. A `bun install` or a Docker build on a small
|
||||
# machine is exactly the spike this is for.
|
||||
|
||||
step "Swap"
|
||||
if ! skip; then
|
||||
ACTIVE_SWAP_GB="$(swap_active_gb)"
|
||||
WANT_SWAP_GB="$(swap_recommended_gb)"
|
||||
SWAPPINESS="$(swappiness_for_role)"
|
||||
CURRENT_SWAPPINESS="$(sysctl -n vm.swappiness 2>/dev/null || echo unknown)"
|
||||
|
||||
echo ""
|
||||
info "Swap — overflow space so a memory spike costs speed rather than a process"
|
||||
echo " RAM: $(ram_gb)G"
|
||||
echo " active swap: ${ACTIVE_SWAP_GB}G"
|
||||
echo " swappiness: ${CURRENT_SWAPPINESS} -> ${SWAPPINESS} (${MACHINE_ROLE})"
|
||||
|
||||
if [[ "$IS_WSL" == true ]]; then
|
||||
# WSL2 runs its own managed swap inside the VM; a swapfile here is wasted
|
||||
# disk and is not what the kernel would use anyway.
|
||||
echo " WSL manages its own swap — leaving it alone"
|
||||
SUMMARY+=("Swap: left to WSL")
|
||||
elif ((ACTIVE_SWAP_GB > 0)); then
|
||||
echo " already has ${ACTIVE_SWAP_GB}G of swap, leaving it alone"
|
||||
if [[ "$CURRENT_SWAPPINESS" != "$SWAPPINESS" ]] && confirm "Set swappiness to ${SWAPPINESS}?"; then
|
||||
swappiness_set "$SWAPPINESS"
|
||||
ok "swappiness set to ${SWAPPINESS}"
|
||||
SUMMARY+=("Swap: kept ${ACTIVE_SWAP_GB}G, swappiness ${SWAPPINESS}")
|
||||
else
|
||||
SUMMARY+=("Swap: kept ${ACTIVE_SWAP_GB}G")
|
||||
fi
|
||||
elif ((WANT_SWAP_GB == 0)); then
|
||||
# Capped to nothing by the disk check rather than by choice.
|
||||
warn "not enough free disk to add swap safely — $(disk_free_gb)G free"
|
||||
SUMMARY+=("Swap: none added, disk too full")
|
||||
else
|
||||
echo " to create: ${WANT_SWAP_GB}G at ${SWAPFILE} ($(disk_free_gb)G free now)"
|
||||
if confirm "Proceed?"; then
|
||||
swap_create "$WANT_SWAP_GB"
|
||||
swappiness_set "$SWAPPINESS"
|
||||
ok "${WANT_SWAP_GB}G swap active, swappiness ${SWAPPINESS}"
|
||||
SUMMARY+=("Swap: ${WANT_SWAP_GB}G created, swappiness ${SWAPPINESS}")
|
||||
else
|
||||
warn "skipped by request"
|
||||
SUMMARY+=("Swap: SKIPPED by request")
|
||||
fi
|
||||
fi
|
||||
step_ok
|
||||
fi
|
||||
|
||||
# =============================================================================
|
||||
# NOT PORTED YET
|
||||
# =============================================================================
|
||||
#
|
||||
# Sections still to move across from scripts/setup-old/setup-ubuntu.sh, in order:
|
||||
#
|
||||
# swap · auto-suspend · boot-hang fix · user creation ·
|
||||
# auto-suspend · boot-hang fix · user creation ·
|
||||
# ssh keys · ssh hardening · dns · static ip · fail2ban · unattended-upgrades ·
|
||||
# git config · docker · zsh + prompt · tailscale · neovim · js runtimes ·
|
||||
# dev tools · ufw · zshrc · disk ballast
|
||||
|
||||
Reference in New Issue
Block a user