#!/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

can_disable() {
	echo Checking we can disable swap device $1
	
	SWAP_AVAILABLE=`grep -v $1 /proc/swaps | awk 'BEGIN{total=0} /dev/ {total += $3} END{print total}'`
	SWAP_REQUIRED=`cat /proc/swaps | awk 'BEGIN{total=0} /dev/ {total += $4} END{print total}'`
	echo Mem: `grep Mem /proc/meminfo`
	echo Swap: `grep Swap /proc/meminfo`
	echo Swap required is $SWAP_REQUIRED, available: $SWAP_AVAILABLE

	return `expr $SWAP_REQUIRED \>= $SWAP_AVAILABLE`
}

disable_compcache() {
	echo Disabling compcache...
	if [ -b /dev/$DEVICE_COMPCACHE ]
	then
		if can_disable $DEVICE_COMPCACHE
		then
			swapoff /dev/$DEVICE_COMPCACHE
			rmmod $COMPCACHE_MODULE
			echo ...Removed.
		else
			echo ...Unable to disable - insufficient swap available.
		fi
	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" -a ! -b $DEVICE_COMPCACHE ] && $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 -o $(($(date +%s) - $START_WAIT)) -gt $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 "" == "$SWAPDRIVELIST_INTERNAL" ]
	then
                if [ "" != "$SWAPDRIVELIST_EXTERNAL" ]
		then
			# Turn off the external swap
			for swapdrive in $SWAPDRIVELIST_EXTERNAL
			do
				echo ...Disabling $SWAPDRIVE
		                if can_disable $SWAPDRIVE
		                then
					swapoff $SWAPDRIVE
				else
					echo ...Unable to disable $SWAPDRIVE. Insufficient other swap.
				fi
			done
		else
			echo ...No SD swap devices found.
		fi
	else
		echo ...Unable to disable external swap - No other swap active
	fi
}

enable_external() {
	# Turn on SD swap first
	echo Enabling SD swap...
        if [ "" != "$SWAPDRIVELIST_EXTERNAL" ]
        then
		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
	else
		echo ...No SD swap devices found.
	fi
}

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
 			if can_disable $SWAPDRIVE
                        then
                              swapoff $SWAPDRIVE
                        else
                              echo ...Unable to disable $SWAPDRIVE. Insufficient other swap.
                        fi
		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}" > /dev/tty
		exit 1
	;;
esac

exit 0
