#!/bin/sh

DEFAULT_FILE="/etc/default/$(basename $0)"

# Defaults - don't touch, edit /etc/default/swapset
DEBUG=false
ENABLE_COMPCACHE=false
DEFAULT_COMPCACHE_TUNING=true
COMPCACHE_SIZE=65536
PRIORITY_COMPCACHE=15
PRIORITY_EXTERNAL=10
PRIORITY_INTERNAL=0
COMPCACHE_TIMEOUT=10
VM_DIRTY_RATIO=3
VM_DIRTY_BACKGROUND_RATIO=3
VM_DIRTY_WRITEBACK_CENTISECS=100
VM_DIRTY_EXPIRE_CENTISECS=100
VM_MIN_FREE_KBYTES=32
VM_SWAPPINESS=95
VM_VFS_CACHE_PRESSURE=200
VM_PAGE_CLUSTER=0
INT_NR_REQUESTS=4000
EXT_NR_REQUESTS=4000
COMPCACHE_MODULE="/lib/modules/current/ramzswap.ko"
COMPCACHE_SUCCEEDED=-1
DEVICE_INTERNAL="mmcblk0"
DEVICE_EXTERNAL="mmcblk1"
DEVICE_COMPCACHE="ramzswap0"
LOGFILE="/tmp/$(basename $0)"
BOOTCHECK="/etc/$(basename $0).loaded"
BOOTEDFILE="/var/run/$(basename $0)"

test -f $DEFAULT_FILE && . $DEFAULT_FILE

# Debugging
debug_start() {
	if [ -e $LOGFILE ]
	then
		rm $LOGFILE
	fi
}

debug() {
	if $DEBUG
	then
		exec >> $LOGFILE 2>&1
	else
		exec > /dev/null 2>&1
	fi
}

# Calculated
SWAPDRIVELIST_INTERNAL=$(sfdisk -lnd | grep Id=82 | awk "/$DEVICE_INTERNAL/ {print \$1}")
SWAPDRIVELIST_EXTERNAL=$(sfdisk -lnd | grep Id=82 | awk "/$DEVICE_EXTERNAL/ {print \$1}")
if [ -n "$(swapon 2>&1 | grep "\-p")" ]
then
	PRIORITY_AVAILABLE=true
fi

# If priority support is available, use it
if $PRIORITY_AVAILABLE
then
	PRIORITY_COMPCACHE="-p $PRIORITY_COMPCACHE "
	PRIORITY_EXTERNAL="-p $PRIORITY_EXTERNAL "
	PRIORITY_INTERNAL="-p $PRIORITY_INTERNAL "
fi

disable_compcache() {
	echo Disabling compcache...
	if [ -b /dev/$DEVICE_COMPCACHE ]
	then
		swapoff /dev/$DEVICE_COMPCACHE
		rmmod $COMPCACHE_MODULE
		echo ...Removed.
	else
		echo ...Module not loaded...
	fi
}

enable_compcache() {
	# Compcache first - we want stuff to get bumped here.
	echo Enabling compcache \($(expr $COMPCACHE_SIZE / 1024)mb\)...
	if [ -e "$COMPCACHE_MODULE" ] && $ENABLE_COMPCACHE
	then
		if $PRIORITY_AVAILABLE
		then
			PRIORITY=$PRIORITY_COMPCACHE
		fi

		echo ...Inserting module...
		insmod $COMPCACHE_MODULE disksize_kb=$COMPCACHE_SIZE
		COMPCACHE_SUCCEEDED=$?
		if [ $COMPCACHE_SUCCEEDED -eq 0 ]
		then
			START_WAIT=$(date +%s)
			while [  -b /dev/$DEVICE_COMPCACHE -a $(($(date +%s) - $START_WAIT)) -lt $COMPCACHE_TIMEOUT ]
			do
				printf "...Waiting %ds for compcache to be ready... \r" $(($COMPCACHE_TIMEOUT - ($(date +%s) - $START_WAIT)))
				echo -n .
			done
			echo ...Active.
			swapon $PRIORITY/dev/$DEVICE_COMPCACHE
		else
			echo ...Unable to insert module.
		fi
	else
		echo ...skipping. Compcache disabled.
	fi
}

disable_external() {
	# If we have at least one other type of swap, disable the external swap
	echo Disabling SD swap...
	if [ $COMPCACHE_SUCCEEDED -eq 0 -o -n "$SWAPDRIVELIST_INTERNAL" ]
	then
		# Turn off the external swap
		for swapdrive in $SWAPDRIVELIST_EXTERNAL
		do
			echo ...Disabling $SWAPDRIVE
			swapoff $SWAPDRIVE
		done
	else
		echo ...Unable to disable external swap - No other swap active
	fi
}

enable_external() {
	# Turn on SD swap first
	echo Enabling SD swap...
	for SWAPDRIVE in $SWAPDRIVELIST_EXTERNAL
	do
		if $PRIORITY_AVAILABLE
		then
			PRIORITY=$PRIORITY_EXTERNAL
		fi
		if [ -z "$(cat /proc/swaps | grep $SWAPDRIVE)" ]
		then
			echo ...Enabling $SWAPDRIVE @ $PRIORITY
 			swapon $PRIORITY$SWAPDRIVE
		fi
	done
}

disable_internal() {
	# If we have at least one other type of swap, disable the internal swap
	echo Disabling internal swap...
	if [ $COMPCACHE_SUCCEEDED -eq 0 -o -n "$SWAPDRIVELIST_EXTERNAL" ]
	then
		# Turn off the internal swap
		for SWAPDRIVE in $SWAPDRIVELIST_INTERNAL
		do
			echo ...Disabling $SWAPDRIVE
			swapoff $SWAPDRIVE
		done
	else
		echo ...Unable to disable internal swap - No other swap active
	fi
}

enable_internal() {
	echo Enabling internal swap...
	if [ -n "$SWAPDRIVELIST_INTERNAL" ]
	then
		# Turn on internal swap
		for SWAPDRIVE in $SWAPDRIVELIST_INTERNAL
		do
			if $PRIORITY_AVAILABLE
			then
				PRIORITY=$PRIORITY_INTERNAL
			fi
			if [ -z "$(cat /proc/swaps | grep $SWAPDRIVE)" ]
			then
				echo ...Enabling $SWAPDRIVE
				swapon $PRIORITY$SWAPDRIVE
			fi
		done
	fi
}

tune() {
	echo Tuning system...
	if $ENABLE_COMPCACHE && ! $DEFAULT_COMPCACHE_TUNING
	then
		echo $VM_DIRTY_RATIO > /proc/sys/vm/dirty_ratio
		echo $VM_DIRTY_BACKGROUND_RATIO > /proc/sys/vm/dirty_background_ratio
		echo $VM_DIRTY_WRITEBACK_CENTISECS > /proc/sys/vm/dirty_writeback_centisecs
		echo $VM_DIRTY_EXPIRE_CENTISECS > /proc/sys/vm/dirty_expire_centisecs
		echo $VM_MIN_FREE_KBYTES > /proc/sys/vm/min_free_kbytes
		echo $VM_SWAPPINESS > /proc/sys/vm/swappiness
		echo $VM_VFS_CACHE_PRESSURE > /proc/sys/vm/vfs_cache_pressure
		echo $VM_PAGE_CLUSTER > /proc/sys/vm/page-cluster
		echo $INT_NR_REQUESTS > /sys/block/mmcblk0/queue/nr_requests
		if [ -e /sys/block/mmcblk1 ]
		then
			 echo $EXT_NR_REQUESTS > /sys/block/mmcblk1/queue/nr_requests
		fi
		echo ...tuned.
	else
		echo ...Skipping. Compcache not enabled or default tuning active
	fi
}


if [ "$1" = "startup" ]
then
	debug_start
fi
debug

case "$1" in
	startup)
		if [ ! -e BOOTCHECK ]
		then
			touch BOOTCHECK

			echo Starting up...
			enable_compcache
			enable_external
			# Disable the internal swap to bump things into the preferred swap
			disable_internal
			enable_internal
		else
			echo Skipping SwapSet setup - previous boot failed
		fi
		rm BOOTCHECK
		touch BOOTEDFILE
	;;

	tune)
		if [ -e BOOTEDFILE ]
		then
			tune
		else
			echo SwapSet not initalised - tuning skipped
		fi
	;;

	unmount)
		enable_internal
		disable_external
	;;

	mount)
		enable_external
		# Disable the internal swap to bump things into the preferred swap
		disable_internal
		enable_internal
	;;

	defrag)
		echo Defragging swap...
		disable_compcache
		enable_compcache
		disable_external
		enable_external
		disable_internal
		enable_internal
	;;

	*)
		echo "Usage: /usr/sbin/swapset {startup|unmount|mount|defrag}"
		exit 1
esac

exit 0
