Search:  
Gentoo Wiki

HOWTO_HDD_spindown_small_server

Contents

Why?

For most servers like file-, mail- or newsserver this is correct. Spinning up the disks would put unneccesary latency to the requests. Other services may very well have disks spun down like network gateways , firewalls or telephone servers. They don't have to store information for a longer time, so there is no need to store it on disks.

I would, if they could stand some million write cycles. But todays (Aug '06) flash memory won't exceed more than 100.000 write accesses, which wears them down quite early. Just think of the server log written every 10 minutes. And each e2fs block makes one write access.

It did to mine back then, too. Until I switched from ext2 fs to ext3 fs. The journal data is written without use of the pdflush daemon, making noflushd obsolete.

I did, and it didn't match my demands. For example, the spin down time of the hard disk was limited to 10 minutes. Spinning up/down a normal desktop hard disk every 10 minutes wears it down within 6-8 months.

How ?

The goal is to spin down the disk for some hours until the cache misses on some read access or the writeback buffer is full. Then the disk is spun up and the read or write request is fulfilled. After that all pending write requests are written to disk by use of the laptop_mode setting >0. Some seconds later a last "sync" is called and the disk gets another spin down command.

Install

Requirements

Installation

smart_spindown

smart_spindown is located at Bart Samwels page You can download it here

Copy the script to your favorite place for system scripts, e.g. /usr/sbin/ and set the appropriate access rights e.g.

-rwx------ root root /usr/sbin/smart_spindown

(chmod 0700 /usr/sbin/smart_spindown; chown root:root /usr/sbin/smart_spindown).


To extend with logging functionality use this:
The script below is extended with calls to the "logger" command, which logs all messages to syslog (i.e. /var/log/messages). This setting seemed more suitable for a server process.

File: /usr/sbin/smart_spindown
#! /bin/bash
#
# smart_spindown rev. 1
#
# Copyright (C) 2003 by Bart Samwel
#
# You may do with this file (and parts thereof) whatever you want, as long
# as my copyright notice is retained.
#
# Extended by joerk at www.gentoo-wiki.info
#
#
# How it works: This program monitors the read activity on a disk. If there
# is no read activity for a while, the disk is spun down. The time without
# read activity that is required is dynamic, using a backoff factor. When
# the recent spun-down periods are relatively short, this means that the
# machine might be busy with something, so the script tries to wait for
# longer periods without activity before spinning down again. When spun-down
# periods are long, the backoff factor is decreased, and the disk is spun
# down after shorter periods without read activity.
#
# This script REQUIRES that laptop_mode is enabled on your kernel. This is
# because it assumes that after a couple of seconds without read activity,
# all dirty blocks will be flushed. If this is not done, the disc will
# spin up at random times
#
# Configuration
#

# Output levels. Level 2 is verbose, level 1 is normal output.
# Enable all levels you would like to see.
OUTLEVEL1=true
OUTLEVEL2=false

# Decide which output to use. Useful if run in daemon mode
# echo or logger
# output1 is logged to normal, output2 to debug syslog
# Is PID of this shell logged?
#OUTPUT1=echo
#OUTPUT2=echo
OUTPUTTAG="$(basename -- $0)[$$]"
OUTPUT1="logger -t $OUTPUTTAG -p user.notice --"
OUTPUT2="logger -t $OUTPUTTAG -p user.debug  --"

# Disk to monitor.
DISK=hda

# Device name for the disk.
DEVNAME=/dev/$DISK

# Stats file: the file used to monitor the disk's read activity.
# The first entry in this stats file must represent the read activity.
STATSFILE=/sys/block/$DISK/stat

# Multiplication factor for the backoff after a spinup, in percentages.
# Default is 300 = factor 3.
BACKOFF_INCREASE_PCT=300

# Multiplication factor for the backoff at every poll that shows that
# the disk is spun down. This determines how fast the backoff value
# decreases.
BACKOFF_DECREASE_PCT=96

# The base "no reads" wait time (in seconds). This is multiplied by
# the backoff factor to determine the real "no reads" wait time.
WAITTIME=20

# The maximum "no reads" wait time (in seconds).
# This also limits the backoff factor: the backoff factor cannot increase
# above a value that makes the "no reads" wait time larger than MAXWAIT.
# Default is 120 seconds.
MAXWAIT=120

# Time (in seconds) between polls to see if the disk is active again.
# Default is 10 seconds.
POLLTIME=10

# Enable this if you don't use laptop_mode. This will make the script
# sync before spinning down the disc. To make this work, you must
# ensure that:
# 1. /proc/sys/vm/dirty_expire_centisecs is set to a high value. You can
#    use 60000 for 10 minutes.
# 2. /proc/sys/vm/dirty_writeback_centisecs is set to the same value.
# 3. Your ext3 filesystems are mounted with "commit=n", where n is the
#    number of seconds between commit. Use 600 for 10 minutes.
NO_LAPTOP_MODE=true	#false



#
# Let's go!
#

# Number of poll times that the disc was found to be spun down.
POLLSSPUNDOWN=0

# Number of spindowns performed
SPINDOWNS=0

# Number of times (*100) the WAITTIME of no-reads required before spindown
BACKOFF_FACTOR=100

# Stats: Total time the disk has been up.
UPTIME=0

# Total duration of last spun-down period.
LASTDOWNTIME=0

# Total duration of the last spun-up period.
LASTUPTIME=0

# Duration of the last poll. Always equal to POLLTIME except the first
# time around.
LASTPOLLTIME=0

# Make sure the stuff we use is in the cache. I've seen it happen
# that the script spun the disk down, and then "sleep" wasn't in
# the cache and the disk spun right up again. :)
true
false
sleep 1

# Log the end of script execution
trap "$OUTPUT1 'exiting.'" EXIT


$OUTLEVEL1 && ${OUTPUT1} "Monitoring spindown opportunities for disk $DISK."
if ($OUTLEVEL1) ; then
	hdparm -C $DEVNAME |grep active >/dev/null
	if [ "$?" == "0" ] ; then
		${OUTPUT1} "Drive is currently spun up." ;
	else
		${OUTPUT1} "Drive is currently spun down." ;
	fi ;
fi
while [[ /sbin/true ]]; do
	hdparm -C $DEVNAME |grep active >/dev/null
	if [ "$?" == "0" ] ; then
		THISWAIT=$(($WAITTIME*$BACKOFF_FACTOR/100)) ;
		if [[ $THISWAIT -gt $MAXWAIT ]] ; then
			THISWAIT=$MAXWAIT ;
		fi ;
		# Increase the backoff irrespective of whether we failed
		# or not. The backoff should drop again by the lack of
		# spinups afterwards.
		BACKOFF_FACTOR=$(($BACKOFF_FACTOR*$BACKOFF_INCREASE_PCT/100)) ;
		if [[ $(($BACKOFF_FACTOR*$WAITTIME/100)) -gt $MAXWAIT ]] ; then
			BACKOFF_FACTOR=$(($MAXWAIT*100/$WAITTIME)) ;
		fi ;
		UPTIME=$(($UPTIME+$LASTPOLLTIME)) ;
		LASTUPTIME=$(($LASTUPTIME+$LASTPOLLTIME)) ;
		if [ "$LASTDOWNTIME" != "0" ] ; then
			$OUTLEVEL1 && ${OUTPUT1} "Drive spun up after $LASTDOWNTIME seconds." ;
		fi
		PREVIOUS_READS=-1 ;
		NUM_EQUALS=0 ;
		$OUTLEVEL2 && ${OUTPUT2} "Waiting for $THISWAIT seconds of read inactivity..." ;
		PREVIOUS_READS=`cat $STATSFILE |awk '{ print $1; }'` ;
		while [[ $(($NUM_EQUALS*5)) -lt $THISWAIT ]]; do
			sleep 5 ;
			UPTIME=$(($UPTIME+5)) ;
			LASTUPTIME=$(($LASTUPTIME+5)) ;
			NEXT_READS=`cat $STATSFILE |awk '{ print $1; }'` ;
			if [[ $PREVIOUS_READS -ne $NEXT_READS ]] ; then
				NUM_EQUALS=0 ;
				PREVIOUS_READS=$NEXT_READS
				$OUTLEVEL2 && ${OUTPUT2} "Restarting..." ;
			else
				NUM_EQUALS=$(($NUM_EQUALS+1)) ;
				$OUTLEVEL2 && ${OUTPUT2} "Seconds of quiet: $(($NUM_EQUALS*5))" ;
			fi
		done
		# We've just had $THISWAIT seconds of read inactivity. Writes can be
		# cached, reads always spin up the disk; the inactivity indicates
		# that we're ready to go to sleep. Laptop mode will have synced all
		# writes for us after the last read, so we don't have to explicitly
		# sync.
		if ( $NO_LAPTOP_MODE ) ; then
			sync ;
		fi ;
		hdparm -q -y $DEVNAME ;
		SPINDOWNS=$(($SPINDOWNS+1)) ;
		$OUTLEVEL1 && ${OUTPUT1} "Drive spun down after $LASTUPTIME seconds \(with $THISWAIT seconds of inactivity\)." ;
		LASTUPTIME=0 ;
		LASTDOWNTIME=0 ;
	else
		POLLSSPUNDOWN=$(($POLLSSPUNDOWN+1)) ;
		if [[ $SPINDOWNS -eq 0 ]] ; then
			SPINDOWNS=1 ;
		fi
		LASTDOWNTIME=$(($LASTDOWNTIME+$LASTPOLLTIME)) ;
		BACKOFF_FACTOR=$(($BACKOFF_FACTOR*$BACKOFF_DECREASE_PCT/100)) ;
		if [ $BACKOFF_FACTOR -lt 100 ] ; then
			BACKOFF_FACTOR=100 ;
		fi
	fi ;
	if ( $OUTLEVEL2 ) ; then
		${OUTPUT2} "spindowns: $SPINDOWNS, time up/down: $UPTIME/$(($POLLSSPUNDOWN*$POLLTIME)), backoff $BACKOFF_FACTOR, down for $LASTDOWNTIME \(avg $(($POLLSSPUNDOWN*$POLLTIME/$SPINDOWNS))\)." ;
	fi ;
	sleep $POLLTIME ;
	LASTPOLLTIME=$POLLTIME ;
done

service start + stop script

Reuse an init script from the hddtemp guide.

Note: I believe there is an error in the file, but I'm a n00b, plz check sombody and remove me. see comment in code
File: /etc/init.d/smart_spindown
#!/sbin/runscript
# Copyright 1999-2006 joerk at www.gentoo-wiki.info
# Distributed under the terms of the GNU General Public License v2


# currently depend on nothing
# (maybe logger later on)
depend() {
        :
}

SMART_SPINDOWN_SCRIPT=/usr/sbin/smart_spindown
SMART_SPINDOWN_PID=/var/run/$(basename ${SMART_SPINDOWN_SCRIPT}).pid

checkconfig() {
        if [ ! -r $SMART_SPINDOWN_SCRIPT ] ; then
                eerror "Spindown script not found at $SMART_SPINDOWN_SCRIPT"
                return 1
        fi

        for A in dirty_expire_centisecs dirty_writeback_centisecs dirty_ratio dirty_background_ratio laptop_mode swappiness ; do
                if [ ! -w /proc/sys/vm/$A ] ; then
                        eerror "VM config /proc/sys/vm/$A not writable"
                        return 1
                fi
        done
}


start() {
        checkconfig || return 1
        ebegin "Starting ${SVCNAME}"

        echo 0 > /proc/sys/vm/dirty_expire_centisecs
        echo 0 > /proc/sys/vm/dirty_writeback_centisecs
        #echo 4320000 > /proc/sys/vm/dirty_expire_centisecs
        #echo 4320000 > /proc/sys/vm/dirty_writeback_centisecs
        echo 95 > /proc/sys/vm/dirty_ratio
        #echo 60 > /proc/sys/vm/dirty_background_ratio
        echo 10 > /proc/sys/vm/dirty_background_ratio
        echo 5 > /proc/sys/vm/laptop_mode
        echo 10 > /proc/sys/vm/swappiness
        start-stop-daemon --start --quiet --background \
                --pidfile ${SMART_SPINDOWN_PID} --make-pidfile \
                --exec ${SMART_SPINDOWN_SCRIPT}

        eend $?
}

stop() {
        ebegin "Stopping ${SVCNAME}"

        # "echo" before start-stop-deamon,
        # so we get the error code of s-s-d as exit code
        echo 3000 > /proc/sys/vm/dirty_expire_centisecs
        echo 500  > /proc/sys/vm/dirty_writeback_centisecs
        echo 40 > /proc/sys/vm/dirty_ratio
        echo 10 > /proc/sys/vm/dirty_background_ratio
        echo 0 > /proc/sys/vm/laptop_mode
        echo 60 > /proc/sys/vm/swappiness
        start-stop-daemon --stop --quiet --pidfile ${SMART_SPINDOWN_PID}

        eend $?
}

mount options

With the "commit=" option, one can configure the ext3 fs how long to wait before committing the journal to disk. The parameter is given in seconds

/dev/hda3      /       ext3        noatime,commit=43200     0 1

This setting syncs the journal at least twice a day.
The "noatime" option keeps the kernel from logging every (read and write) access to the file. Which would have filled the write buffer with unneccessary write commands and spun up the disk earlier.

Tweak settings

Script parameters

These settings can be adjusted in the spindown script

How much do you want to read about your spin down attempts?
OUTLEVEL1 gives informations about the seconds between the disk being spin up and spin down.
OUTLEVEL2 gives debugging info during the 2 events.

The disk to monitor. Only one disk can be specified. To monitor more disks, start all scripts in parallel.

Despite my kernel setting of /proc/sys/vm/laptop_mode = 5, I switched off the laptop setting in the script. Now the kernel flushes the disk 5 seconds after the disk has spun up. But the script does not rely on this behavior, and gives a last "sync" command before spinning down again.

Kernel parameters

These settings can be adjusted in the init script

Centi seconds to wait before flushing the write pages to disk. A higher value will increase the possibility of losing information, in case of a system crash/power failure after the disk spin down. Set to 0 to disable the feature.

A higher value will increase the possibility of losing information, in case of a system crash/power failure after the disk spin down. Set to 0 to disable the feature.

Percentage of write pages to keep in memory before flushing the queue. Percentage relative to whole memory. May be clipped to 95% or even lower to prevent OOM conditions.

Depending on laptop_mode: Percentage of write pages to keep after flushing the write queue (?)

Set to a value > 0 enables laptop mode. The value describes the flush of the write queue after a disk spinup [in seconds]. Set this to 0 to disable laptop mode.

A high value favours swapping to disk, a low value favours keeping in memory. Setting this to a low value keeps the kernel from using the swap partition.

Links

Retrieved from "http://www.gentoo-wiki.info/HOWTO_HDD_spindown_small_server"

Last modified: Mon, 15 Sep 2008 03:57:00 +0000 Hits: 20,419