| # Copyright (c) 2012 The Chromium OS Authors. All rights reserved. |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| |
| description "Setup compressed memory swap" |
| author "chromium-os-dev@chromium.org" |
| |
| # Set margin for low-memory notifier (for tab discarder) |
| # Configure and start swap if SWAP_ENABLE_FILE exists. |
| # SWAP_ENABLE_FILE may optionally contain the uncompressed swap size (in Mb). |
| # Otherwise it is set to 1.5 times total RAM. |
| # |
| # To start swap, create file /home/chronos/.swap_enabled and run "start swap" |
| # or reboot. To stop swap, remove the file and reboot. |
| |
| start on starting system-services |
| |
| script |
| SWAP_ENABLE_FILE=/home/chronos/.swap_enabled |
| DEFAULT_SWAP_SIZE_FILE=/etc/default/zram-size |
| HIST_MIN=100 |
| HIST_MAX=10000 |
| HIST_BUCKETS=50 |
| HIST_ARGS="$HIST_MIN $HIST_MAX $HIST_BUCKETS" |
| |
| # Extract second field of MemTotal entry in /proc/meminfo. |
| # NOTE: this could be done with "read", "case", and a function |
| # that sets ram=$2, for a savings of about 3ms on an Alex. |
| ram=$(awk '/MemTotal/ { print $2; }' < /proc/meminfo) |
| [ "$ram" = "" ] && logger -t "$UPSTART_JOB" "could not get MemTotal" |
| |
| # compute fraction of total RAM used for low-mem margin. The fraction is |
| # given in bips. A "bip" or "basis point" is 1/100 of 1%. This unit is |
| # typically used in finance and in low-memory margin calculations. |
| MARGIN_BIPS=520 |
| margin=$(($ram / 1000 * $MARGIN_BIPS / 10000)) # MB |
| # set the margin |
| echo $margin > /sys/kernel/mm/chromeos-low_mem/margin |
| logger -t "$UPSTART_JOB" "setting low-mem margin to $margin MB" |
| |
| # Allocate zram (compressed ram disk) for swap. |
| # SWAP_ENABLE_FILE contains the zram size in MB. |
| # Empty or missing SWAP_ENABLE_FILE means use default size. |
| # 0 size means do not enable zram. |
| # Calculations are in Kb to avoid 32 bit overflow. |
| |
| # For security, only read first few bytes of SWAP_ENABLE_FILE. |
| REQUESTED_SIZE_MB="$(head -c 4 $SWAP_ENABLE_FILE)" || : |
| if [ -z "$REQUESTED_SIZE_MB" ]; then |
| if [ -f $DEFAULT_SWAP_SIZE_FILE ]; then |
| . $DEFAULT_SWAP_SIZE_FILE |
| else |
| ZRAM_SIZE_KB=$(awk '/MemTotal/ { print $2 * 3 / 2 }' /proc/meminfo) |
| fi |
| elif [ "$REQUESTED_SIZE_MB" = 0 ]; then |
| metrics_client Platform.CompressedSwapSize 0 $HIST_ARGS |
| exit 0 |
| elif [ "$REQUESTED_SIZE_MB" != 500 -a \ |
| "$REQUESTED_SIZE_MB" != 1000 -a \ |
| "$REQUESTED_SIZE_MB" != 2000 -a \ |
| "$REQUESTED_SIZE_MB" != 3000 -a \ |
| "$REQUESTED_SIZE_MB" != 4000 -a \ |
| "$REQUESTED_SIZE_MB" != 4500 -a \ |
| "$REQUESTED_SIZE_MB" != 6000 ]; then |
| logger -t "$UPSTART_JOB" "invalid value $REQUESTED_SIZE_MB for swap" |
| metrics_client Platform.CompressedSwapSize 0 $HIST_ARGS |
| exit 1 |
| else |
| ZRAM_SIZE_KB=$(($REQUESTED_SIZE_MB * 1024)) |
| fi |
| |
| # Load zram module. Ignore failure (it could be compiled in the kernel). |
| modprobe zram || logger -t "$UPSTART_JOB" "modprobe zram failed (compiled?)" |
| |
| logger -t "$UPSTART_JOB" "setting zram size to $ZRAM_SIZE_KB Kb" |
| # Approximate the kilobyte to byte conversion to avoid issues |
| # with 32-bit signed integer overflow. |
| echo ${ZRAM_SIZE_KB}000 >/sys/block/zram0/disksize || |
| logger -t "$UPSTART_JOB" "failed to set zram size" |
| mkswap /dev/zram0 || logger -t "$UPSTART_JOB" "mkswap /dev/zram0 failed" |
| # Swapon may fail because of races with other programs that inspect all |
| # block devices, so try several times. |
| tries=0 |
| while [ $tries -le 10 ]; do |
| swapon /dev/zram0 && break |
| tries=$((tries + 1)) |
| logger -t "$UPSTART_JOB" "swapon /dev/zram0 failed, try $tries" |
| sleep 0.1 |
| done |
| |
| swaptotalkb=$(awk '/SwapTotal/ { print $2 }' /proc/meminfo) |
| metrics_client Platform.CompressedSwapSize \ |
| $((swaptotalkb / 1024)) $HIST_ARGS |
| end script |