diff --git a/meta-opencentauri/images/files/overlayfs-etc-preinit.sh.in b/meta-opencentauri/images/files/overlayfs-etc-preinit.sh.in index d3a48249..a3f1e737 100644 --- a/meta-opencentauri/images/files/overlayfs-etc-preinit.sh.in +++ b/meta-opencentauri/images/files/overlayfs-etc-preinit.sh.in @@ -58,6 +58,34 @@ then mkdir -p $UPPER_DIR mkdir -p $WORK_DIR + # Remove local overlay edits to Cosmos-provided init scripts so upgrades + # use the new image versions. User-provided init scripts are preserved, + # matching previous Cosmos behavior; if an update breaks one, it is the + # user's responsibility to fix or remove it. + if [ -d "$UPPER_DIR/init.d" ]; then + for upper_script in "$UPPER_DIR"/init.d/*; do + [ -f "$upper_script" ] || continue + script_name=${{upper_script##*/}} + [ -f "/etc/init.d/$script_name" ] || continue + rm -f "$upper_script" + done + + # Remove whiteouts only when they hide an image-owned init script. + for whiteout in "$UPPER_DIR"/init.d/.wh.*; do + [ -e "$whiteout" ] || continue + whiteout_name=${{whiteout##*/}} + case "$whiteout_name" in + .wh..wh..opq) + rm -f "$whiteout" + ;; + .wh.*) + script_name=${{whiteout_name#.wh.}} + [ -f "/etc/init.d/$script_name" ] && rm -f "$whiteout" + ;; + esac + done + fi + if {OVERLAYFS_ETC_EXPOSE_LOWER}; then mkdir -p $LOWER_DIR diff --git a/meta-opencentauri/recipes-core/zram/files/init b/meta-opencentauri/recipes-core/zram/files/init old mode 100644 new mode 100755 index e9bdbf8e..4e69669b --- a/meta-opencentauri/recipes-core/zram/files/init +++ b/meta-opencentauri/recipes-core/zram/files/init @@ -1,72 +1,84 @@ #!/bin/sh ### BEGIN INIT INFO -# Provides: zram +# Provides: zram # Required-Start: # Required-Stop: # Default-Start: 2 3 4 5 # Default-Stop: 0 1 6 -# Short-Description: Increased Performance In Linux With zRam (Virtual Swap Compressed in RAM) -# Description: Adapted from zram init script in meta-openembedded +# Short-Description: zram swap with retries and logging ### END INIT INFO -set -e + +NAME=zram +ZRAM_DEV=${ZRAM_DEV:-/dev/zram0} +SYSFS=${ZRAM_SYSFS:-/sys/block/zram0} +PROC_SWAPS=${PROC_SWAPS:-/proc/swaps} +MEMINFO=${MEMINFO:-/proc/meminfo} +SYSCTL_DIR=${SYSCTL_DIR:-/proc/sys} +ATTEMPTS=5 + +log() { + logger -t "$NAME" "$*" 2>/dev/null || true + echo "$NAME: $*" +} + +is_active() { + grep -q "^${ZRAM_DEV}[[:space:]]" $PROC_SWAPS 2>/dev/null +} start() { #default Factor % = 200 change this value here or create /etc/default/zram FACTOR=200 - #& put the above single line in /etc/default/zram with the value you want [ -f /etc/default/zram ] && . /etc/default/zram || true - factor=$FACTOR # percentage - # get the amount of memory in the machine - memtotal=$(grep MemTotal /proc/meminfo | awk ' { print $2 } ') - disksize=$(($memtotal*$factor/100*1024)) + if is_active; then + log "already active" + return 0 + fi + + memtotal=$(awk '/^MemTotal:/ { print $2; exit }' $MEMINFO) + disksize=$((memtotal * FACTOR / 100 * 1024)) + log "memtotal=${memtotal}kB disksize=${disksize}B factor=${FACTOR}%" - # load dependency modules - modprobe zram num_devices=1 - echo "zram devices probed successfully" + attempt=1 + while [ "$attempt" -le "$ATTEMPTS" ]; do + log "attempt $attempt/$ATTEMPTS" - echo 1 > /sys/block/zram0/reset - echo lz4 > /sys/block/zram0/comp_algorithm - echo $disksize > /sys/block/zram0/disksize + modprobe zram num_devices=1 && \ + echo 1 > "$SYSFS/reset" && \ + echo lz4 > "$SYSFS/comp_algorithm" && \ + echo "$disksize" > "$SYSFS/disksize" && \ + mkswap "$ZRAM_DEV" && \ + swapon -p 100 "$ZRAM_DEV" - # Creating swap filesystems - mkswap /dev/zram0 + if is_active; then + echo 150 > $SYSCTL_DIR/vm/swappiness + echo 0 > $SYSCTL_DIR/vm/watermark_boost_factor + echo 125 > $SYSCTL_DIR/vm/watermark_scale_factor + echo 0 > $SYSCTL_DIR/vm/page-cluster + echo 500 > $SYSCTL_DIR/vm/vfs_cache_pressure + log "active: $(grep "^${ZRAM_DEV}[[:space:]]" $PROC_SWAPS)" + return 0 + fi - # zram tuning - echo 150 > /proc/sys/vm/swappiness - echo 0 > /proc/sys/vm/watermark_boost_factor - echo 125 > /proc/sys/vm/watermark_scale_factor - echo 0 > /proc/sys/vm/page-cluster - echo 500 > /proc/sys/vm/vfs_cache_pressure + log "attempt $attempt failed" + swapoff "$ZRAM_DEV" 2>/dev/null || true + attempt=$((attempt + 1)) + sleep 1 + done - # Switch the swaps on - swapon -p 100 /dev/zram0 + log "ERROR: no swap after $ATTEMPTS attempts" + return 1 } stop() { - # Switching off swap - if [ "$(grep /dev/zram0 /proc/swaps)" != "" ]; then - swapoff /dev/zram0 - sleep 1 - fi - sleep 1 - rmmod zram + is_active && swapoff "$ZRAM_DEV" + echo 1 > "$SYSFS/reset" 2>/dev/null || true + rmmod zram 2>/dev/null || true } case "$1" in - start) - start - ;; - stop) - stop - ;; - restart) - stop - sleep 3 - start - ;; - *) - echo "Usage: $0 {start|stop|restart}" - RETVAL=1 + start) start ;; + stop) stop ;; + restart) stop; sleep 1; start ;; + *) echo "Usage: $0 {start|stop|restart}"; exit 1 ;; esac -exit $RETVAL diff --git a/meta-opencentauri/recipes-core/zram/tests/init-test.sh b/meta-opencentauri/recipes-core/zram/tests/init-test.sh new file mode 100755 index 00000000..d15c0fc0 --- /dev/null +++ b/meta-opencentauri/recipes-core/zram/tests/init-test.sh @@ -0,0 +1,102 @@ +#!/bin/sh +# Host smoke test for the zram init script. Fakes modprobe/mkswap/swapon etc. +set -u +SCRIPT=$(cd "$(dirname "$0")/../files" && pwd)/init +ROOT=$(mktemp -d "${TMPDIR:-/tmp}/zram-test.XXXXXX") +FAILED=0 +trap 'rm -rf "$ROOT"' EXIT + +setup() { + CASE="$ROOT/case" + rm -rf "$CASE" + mkdir -p "$CASE/bin" "$CASE/sys/block/zram0" "$CASE/proc/sys/vm" + printf 'Filename\t\t\tType\t\tSize\tUsed\tPriority\n' > "$CASE/proc/swaps" + printf 'MemTotal: 114656 kB\n' > "$CASE/proc/meminfo" + : > "$CASE/sys/block/zram0/reset" + : > "$CASE/sys/block/zram0/comp_algorithm" + : > "$CASE/sys/block/zram0/disksize" + : > "$CASE/log" + rm -f "$CASE"/fail-* "$CASE"/always-fail-* + + for key in swappiness watermark_boost_factor watermark_scale_factor page-cluster vfs_cache_pressure; do + : > "$CASE/proc/sys/vm/$key" + done + + cat > "$CASE/bin/logger" <<'EOF' +#!/bin/sh +printf '%s\n' "$*" >> "$CASE/log" +EOF + cat > "$CASE/bin/modprobe" <<'EOF' +#!/bin/sh +[ -f "$CASE/fail-modprobe-once" ] && { rm -f "$CASE/fail-modprobe-once"; exit 1; } +[ -f "$CASE/always-fail-modprobe" ] && exit 1 +exit 0 +EOF + cat > "$CASE/bin/mkswap" <<'EOF' +#!/bin/sh +exit 0 +EOF + cat > "$CASE/bin/swapon" <<'EOF' +#!/bin/sh +[ -f "$CASE/fail-swapon-once" ] && { rm -f "$CASE/fail-swapon-once"; exit 1; } +grep -q "^${ZRAM_DEV}[[:space:]]" "$PROC_SWAPS" 2>/dev/null || \ + printf '%s\tpartition\t235520\t0\t100\n' "$ZRAM_DEV" >> "$PROC_SWAPS" +exit 0 +EOF + cat > "$CASE/bin/swapoff" <<'EOF' +#!/bin/sh +tmp="$PROC_SWAPS.tmp" +awk -v dev="$ZRAM_DEV" 'NR == 1 || $1 != dev { print }' "$PROC_SWAPS" > "$tmp" +mv "$tmp" "$PROC_SWAPS" +exit 0 +EOF + cat > "$CASE/bin/rmmod" <<'EOF' +#!/bin/sh +exit 0 +EOF + cat > "$CASE/bin/sleep" <<'EOF' +#!/bin/sh +exit 0 +EOF + chmod 0755 "$CASE"/bin/* +} + +run_init() { + env PATH="$CASE/bin:/bin:/usr/bin" \ + CASE="$CASE" \ + ZRAM_DEV="$CASE/zram0" \ + ZRAM_SYSFS="$CASE/sys/block/zram0" \ + PROC_SWAPS="$CASE/proc/swaps" \ + MEMINFO="$CASE/proc/meminfo" \ + SYSCTL_DIR="$CASE/proc/sys" \ + "$SCRIPT" "$@" +} + +check() { + desc="$1"; shift + if "$@"; then echo "ok: $desc"; else echo "FAIL: $desc"; FAILED=1; fi +} + +# success + idempotence +setup +run_init start >/dev/null +check "start succeeds" grep -q "$CASE/zram0" "$CASE/proc/swaps" +check "logs success" grep -q "active:" "$CASE/log" +run_init start >/dev/null +check "second start is no-op" grep -q "already active" "$CASE/log" + +# retry after one modprobe failure +setup +: > "$CASE/fail-modprobe-once" +run_init start >/dev/null +check "recovers from one modprobe failure" grep -q "$CASE/zram0" "$CASE/proc/swaps" +check "logged attempt 2" grep -q "attempt 2/5" "$CASE/log" + +# bounded failure +setup +: > "$CASE/always-fail-modprobe" +run_init start >/dev/null && { echo "FAIL: permanent modprobe failure should not succeed"; FAILED=1; } +check "gives up after 5 attempts" grep -q "after 5 attempts" "$CASE/log" +check "no swap left active" sh -c "! grep -q \"$CASE/zram0\" \"$CASE/proc/swaps\"" + +[ "$FAILED" -eq 0 ] && echo "PASS" || exit 1