[RFC] zswap for Precise, with script

John Moser john.r.moser at gmail.com
Thu May 17 13:55:52 UTC 2012


Any thoughts on this?  I wrote it on a whim after installing an SSD and 
completely disabling all swap.  Haven't checked to see if Ubuntu 
supports hibernate to file yet (creating a hibernation file on demand 
would be optimal for me...)

This works with kernel 3.2.0 ... 3.0 used num_devices as the parameter 
for zram, while 2.6.32 used num (I think).  They keep changing the 
parameter name!

This init script (sorry, I have no clue how to write an upstart job) 
will load zram, set one of its devices to a given size, create swap on 
it, and turn that swap on.  It'll also deactivate the swap and free the 
associated RAM.

Accepted sizes are "half" and "quarter" of installed RAM as gotten by 
MemTotal in /proc/meminfo; any size in bytes; or suffixed K, M, G sizes.


/etc/default/zswap can contain the following variables:

# Set to 1 to disable
ZSWAP_DISABLED=0

# Number of /dev/zramX devices
ZRAM_NUM_DEVICES=4

# Swap device is /dev/$ZSWAP_DEVICE
ZSWAP_DEVICE="zram0"

# Size
ZSWAP_SIZE="quarter"
-------------- next part --------------
#! /bin/sh
### BEGIN INIT INFO
# Provides:          zswap
# Required-Start:    $syslog
# Required-Stop:     $syslog
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description:       Activate compressed swap
### END INIT INFO
#
#
# Version:	1.0 john.r.moser at gmail.com
#

#
# It's also possible to resize the zswap by device hopping, i.e.
# making a new one on /dev/zram1, swapon /dev/zram1, and then
# swapoff /dev/zram0.  This would be CPU intensive...
#

PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
DESC="Sets up compressed swap"
NAME=zswap
SCRIPTNAME=/etc/init.d/$NAME

# Default value
ZRAM_NUM_DEVICES=4
ZSWAP_DEVICE="zram0"
ZSWAP_SIZE="quarter"

# Read config file if it is present.
if [ -r /etc/default/$NAME ]; then
	. /etc/default/$NAME
fi

# Gracefully exit if disabled
[ "$ZSWAP_DISABLED" = "1" ] && exit 0

is_numeric() {
	echo "$@" | grep -q -v "[^0-9]"
}

#Takes:
# zswap_to_bytes 524288
# zswap_to_bytes 512K
# zswap_to_bytes 128M
# zswap_to_bytes 2G
# otherwise formed parameters are errors.
zswap_to_bytes() {
	MODIFIER="${1#${1%?}}"
	ZR_SIZE="${1: -1}"

	# Numeric:  just pass as-is
	if ( is_numeric ${1} ) ; then
		echo ${1}
		return 0
	fi

	# If size isn't a number,
	if ! ( is_numeric ${ZR_SIZE} ) ; then
		echo "0"
		return 1
	fi

	if [ "${MODIFIER}" = "K" ]; then
		ZR_SIZE=$(( ZR_SIZE * 1024 ))
	elif [ "${MODIFIER}" = "M" ]; then
		ZR_SIZE=$(( ZR_SIZE * 1024 * 1024 ))
	elif [ "${MODIFIER}" = "G" ]; then
		ZR_SIZE=$(( ZR_SIZE * 1024 * 1024 * 1024 ))
	elif [ ! is_numeric "${MODIFIER}" ]; then
		echo "0"
		return 1
	fi
	echo $ZR_SIZE
}

#
#	Function that starts the daemon/service.
#
d_start() {
	ZSWAP_LOADED=0
	swapon -s | cut -f 1 | grep "/dev/${ZSWAP_DEVICE}" && ZSWAP_LOADED=1
	if [ "${ZSWAP_LOADED}" -eq "1" ]; then
		echo "zswap already in use"
		return 1
	fi
	# this parameter name keeps changing with new kernel versions
	modprobe zram zram_num_devices=${ZRAM_NUM_DEVICES}

	# Does it now exist?
	if [ ! -b /dev/${ZSWAP_DEVICE} ]; then
		echo "/dev/${ZSWAP_DEVICE} does not exist!"
		return 1
	fi

	# half or quarter size
	if [ "${ZSWAP_SIZE}" = "half" -o "${ZSWAP_SIZE}" = "quarter" ]; then
		MEM_SZ=$(cat /proc/meminfo | grep MemTotal | awk '{print $2}')
		if [ "${ZSWAP_SIZE}" = "half" ]; then
			ZSWAP_SIZE=$(( MEM_SZ * 512 ))
		else
			ZSWAP_SIZE=$(( MEM_SZ * 256 ))
		fi
	else
		ZSWAP_SIZE=$( zswap_to_bytes $ZSWAP_SIZE )
		if [ "${ZSWAP_SIZE}" = "0" ]; then
			echo "Invalid ZSWAP_SIZE"
			return 1
		fi
	fi
	echo $ZSWAP_SIZE > /sys/block/${ZSWAP_DEVICE}/disksize
	mkswap /dev/${ZSWAP_DEVICE}
	swapon /dev/${ZSWAP_DEVICE}
}

#
#	Function that stops the daemon/service.
#
d_stop() {
	ZSWAP_LOADED=0
	swapon -s | cut -f 1 | grep "/dev/${ZSWAP_DEVICE}" && ZSWAP_LOADED=1
	if [ "${ZSWAP_LOADED}" != "1" ]; then
		echo "zswap not in use"
		return 1
	fi
	if ! ( swapoff /dev/${ZSWAP_DEVICE} ); then
		echo "Cannot de-activate compressed swap /dev/${ZSWAP_DEVICE}!"
		return 1
	fi

	# Double check this
	ZSWAP_LOADED=0
	swapon -s | cut -f 1 | grep "/dev/${ZSWAP_DEVICE}" && ZSWAP_LOADED=1
	if [ "${ZSWAP_LOADED}" = "1" ]; then
		echo "zswap /dev/${ZSWAP_DEVICE} did not de-activate!"
		return 1
	fi

	# free the block device's memory
	echo 1 > /sys/block/${ZSWAP_DEVICE}/reset
	modprobe -r zram
}


case "$1" in
  start)

	echo -n "Starting $DESC: $NAME"
	d_start
	echo "."
	;;
  stop)
	echo -n "Stopping $DESC: $NAME"
	d_stop
	echo "."
	;;
  #reload)
	#
	#	No reload target
	#
  #;;
  restart|force-reload)
	echo -n "Restarting $DESC: $NAME"
	d_stop
	#sleep 1
	d_start
	echo "."
	;;
  *)
	echo "Usage: $SCRIPTNAME {start|stop|restart|force-reload}" >&2
	exit 1
	;;
esac

exit 0


More information about the Ubuntu-devel-discuss mailing list