The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/Documentation/laptop-mode.txt

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 How to conserve battery power using laptop-mode
    2 -----------------------------------------------
    3 
    4 Document Author: Bart Samwel (bart@samwel.tk)
    5 Date created: January 2, 2004
    6 Last modified: December 06, 2004
    7 
    8 Introduction
    9 ------------
   10 
   11 Laptop mode is used to minimize the time that the hard disk needs to be spun up,
   12 to conserve battery power on laptops. It has been reported to cause significant
   13 power savings.
   14 
   15 Contents
   16 --------
   17 
   18 * Introduction
   19 * Installation
   20 * Caveats
   21 * The Details
   22 * Tips & Tricks
   23 * Control script
   24 * ACPI integration
   25 * Monitoring tool
   26 
   27 
   28 Installation
   29 ------------
   30 
   31 To use laptop mode, you don't need to set any kernel configuration options
   32 or anything. Simply install all the files included in this document, and
   33 laptop mode will automatically be started when you're on battery. For
   34 your convenience, a tarball containing an installer can be downloaded at:
   35 
   36 http://www.samwel.tk/laptop_mode/laptop_mode/
   37 
   38 To configure laptop mode, you need to edit the configuration file, which is
   39 located in /etc/default/laptop-mode on Debian-based systems, or in
   40 /etc/sysconfig/laptop-mode on other systems.
   41 
   42 Unfortunately, automatic enabling of laptop mode does not work for
   43 laptops that don't have ACPI. On those laptops, you need to start laptop
   44 mode manually. To start laptop mode, run "laptop_mode start", and to
   45 stop it, run "laptop_mode stop". (Note: The laptop mode tools package now
   46 has experimental support for APM, you might want to try that first.)
   47 
   48 
   49 Caveats
   50 -------
   51 
   52 * The downside of laptop mode is that you have a chance of losing up to 10
   53   minutes of work. If you cannot afford this, don't use it! The supplied ACPI
   54   scripts automatically turn off laptop mode when the battery almost runs out,
   55   so that you won't lose any data at the end of your battery life.
   56 
   57 * Most desktop hard drives have a very limited lifetime measured in spindown
   58   cycles, typically about 50.000 times (it's usually listed on the spec sheet).
   59   Check your drive's rating, and don't wear down your drive's lifetime if you
   60   don't need to.
   61 
   62 * If you mount some of your ext3/reiserfs filesystems with the -n option, then
   63   the control script will not be able to remount them correctly. You must set
   64   DO_REMOUNTS=0 in the control script, otherwise it will remount them with the
   65   wrong options -- or it will fail because it cannot write to /etc/mtab.
   66 
   67 * If you have your filesystems listed as type "auto" in fstab, like I did, then
   68   the control script will not recognize them as filesystems that need remounting.
   69   You must list the filesystems with their true type instead.
   70 
   71 * It has been reported that some versions of the mutt mail client use file access
   72   times to determine whether a folder contains new mail. If you use mutt and
   73   experience this, you must disable the noatime remounting by setting the option
   74   DO_REMOUNT_NOATIME to 0 in the configuration file.
   75 
   76 
   77 The Details
   78 -----------
   79 
   80 Laptop mode is controlled by the knob /proc/sys/vm/laptop_mode. This knob is
   81 present for all kernels that have the laptop mode patch, regardless of any
   82 configuration options. When the knob is set, any physical disk I/O (that might
   83 have caused the hard disk to spin up) causes Linux to flush all dirty blocks. The
   84 result of this is that after a disk has spun down, it will not be spun up
   85 anymore to write dirty blocks, because those blocks had already been written
   86 immediately after the most recent read operation. The value of the laptop_mode
   87 knob determines the time between the occurrence of disk I/O and when the flush
   88 is triggered. A sensible value for the knob is 5 seconds. Setting the knob to
   89 0 disables laptop mode.
   90 
   91 To increase the effectiveness of the laptop_mode strategy, the laptop_mode
   92 control script increases dirty_expire_centisecs and dirty_writeback_centisecs in
   93 /proc/sys/vm to about 10 minutes (by default), which means that pages that are
   94 dirtied are not forced to be written to disk as often. The control script also
   95 changes the dirty background ratio, so that background writeback of dirty pages
   96 is not done anymore. Combined with a higher commit value (also 10 minutes) for
   97 ext3 or ReiserFS filesystems (also done automatically by the control script),
   98 this results in concentration of disk activity in a small time interval which
   99 occurs only once every 10 minutes, or whenever the disk is forced to spin up by
  100 a cache miss. The disk can then be spun down in the periods of inactivity.
  101 
  102 If you want to find out which process caused the disk to spin up, you can
  103 gather information by setting the flag /proc/sys/vm/block_dump. When this flag
  104 is set, Linux reports all disk read and write operations that take place, and
  105 all block dirtyings done to files. This makes it possible to debug why a disk
  106 needs to spin up, and to increase battery life even more. The output of
  107 block_dump is written to the kernel output, and it can be retrieved using
  108 "dmesg". When you use block_dump and your kernel logging level also includes
  109 kernel debugging messages, you probably want to turn off klogd, otherwise
  110 the output of block_dump will be logged, causing disk activity that is not
  111 normally there.
  112 
  113 
  114 Configuration
  115 -------------
  116 
  117 The laptop mode configuration file is located in /etc/default/laptop-mode on
  118 Debian-based systems, or in /etc/sysconfig/laptop-mode on other systems. It
  119 contains the following options:
  120 
  121 MAX_AGE:
  122 
  123 Maximum time, in seconds, of hard drive spindown time that you are
  124 comfortable with. Worst case, it's possible that you could lose this
  125 amount of work if your battery fails while you're in laptop mode.
  126 
  127 MINIMUM_BATTERY_MINUTES:
  128 
  129 Automatically disable laptop mode if the remaining number of minutes of
  130 battery power is less than this value. Default is 10 minutes.
  131 
  132 AC_HD/BATT_HD:
  133 
  134 The idle timeout that should be set on your hard drive when laptop mode
  135 is active (BATT_HD) and when it is not active (AC_HD). The defaults are
  136 20 seconds (value 4) for BATT_HD  and 2 hours (value 244) for AC_HD. The
  137 possible values are those listed in the manual page for "hdparm" for the
  138 "-S" option.
  139 
  140 HD:
  141 
  142 The devices for which the spindown timeout should be adjusted by laptop mode.
  143 Default is /dev/hda. If you specify multiple devices, separate them by a space.
  144 
  145 READAHEAD:
  146 
  147 Disk readahead, in 512-byte sectors, while laptop mode is active. A large
  148 readahead can prevent disk accesses for things like executable pages (which are
  149 loaded on demand while the application executes) and sequentially accessed data
  150 (MP3s).
  151 
  152 DO_REMOUNTS:
  153 
  154 The control script automatically remounts any mounted journaled filesystems
  155 with appropriate commit interval options. When this option is set to 0, this
  156 feature is disabled.
  157 
  158 DO_REMOUNT_NOATIME:
  159 
  160 When remounting, should the filesystems be remounted with the noatime option?
  161 Normally, this is set to "1" (enabled), but there may be programs that require
  162 access time recording.
  163 
  164 DIRTY_RATIO:
  165 
  166 The percentage of memory that is allowed to contain "dirty" or unsaved data
  167 before a writeback is forced, while laptop mode is active. Corresponds to
  168 the /proc/sys/vm/dirty_ratio sysctl.
  169 
  170 DIRTY_BACKGROUND_RATIO:
  171 
  172 The percentage of memory that is allowed to contain "dirty" or unsaved data
  173 after a forced writeback is done due to an exceeding of DIRTY_RATIO. Set
  174 this nice and low. This corresponds to the /proc/sys/vm/dirty_background_ratio
  175 sysctl.
  176 
  177 Note that the behaviour of dirty_background_ratio is quite different
  178 when laptop mode is active and when it isn't. When laptop mode is inactive,
  179 dirty_background_ratio is the threshold percentage at which background writeouts
  180 start taking place. When laptop mode is active, however, background writeouts
  181 are disabled, and the dirty_background_ratio only determines how much writeback
  182 is done when dirty_ratio is reached.
  183 
  184 DO_CPU:
  185 
  186 Enable CPU frequency scaling when in laptop mode. (Requires CPUFreq to be setup.
  187 See Documentation/cpu-freq/user-guide.txt for more info. Disabled by default.)
  188 
  189 CPU_MAXFREQ:
  190 
  191 When on battery, what is the maximum CPU speed that the system should use? Legal
  192 values are "slowest" for the slowest speed that your CPU is able to operate at,
  193 or a value listed in /sys/devices/system/cpu/cpu0/cpufreq/scaling_available_frequencies.
  194 
  195 
  196 Tips & Tricks
  197 -------------
  198 
  199 * Bartek Kania reports getting up to 50 minutes of extra battery life (on top
  200   of his regular 3 to 3.5 hours) using a spindown time of 5 seconds (BATT_HD=1).
  201 
  202 * You can spin down the disk while playing MP3, by setting disk readahead
  203   to 8MB (READAHEAD=16384). Effectively, the disk will read a complete MP3 at
  204   once, and will then spin down while the MP3 is playing. (Thanks to Bartek
  205   Kania.)
  206 
  207 * Drew Scott Daniels observed: "I don't know why, but when I decrease the number
  208   of colours that my display uses it consumes less battery power. I've seen
  209   this on powerbooks too. I hope that this is a piece of information that
  210   might be useful to the Laptop Mode patch or it's users."
  211 
  212 * In syslog.conf, you can prefix entries with a dash ``-'' to omit syncing the
  213   file after every logging. When you're using laptop-mode and your disk doesn't
  214   spin down, this is a likely culprit.
  215 
  216 * Richard Atterer observed that laptop mode does not work well with noflushd
  217   (http://noflushd.sourceforge.net/), it seems that noflushd prevents laptop-mode
  218   from doing its thing.
  219 
  220 * If you're worried about your data, you might want to consider using a USB
  221   memory stick or something like that as a "working area". (Be aware though
  222   that flash memory can only handle a limited number of writes, and overuse
  223   may wear out your memory stick pretty quickly. Do _not_ use journalling
  224   filesystems on flash memory sticks.)
  225 
  226 
  227 Configuration file for control and ACPI battery scripts
  228 -------------------------------------------------------
  229 
  230 This allows the tunables to be changed for the scripts via an external
  231 configuration file
  232 
  233 It should be installed as /etc/default/laptop-mode on Debian, and as
  234 /etc/sysconfig/laptop-mode on Red Hat, SUSE, Mandrake, and other work-alikes.
  235 
  236 --------------------CONFIG FILE BEGIN-------------------------------------------
  237 # Maximum time, in seconds, of hard drive spindown time that you are
  238 # comfortable with. Worst case, it's possible that you could lose this
  239 # amount of work if your battery fails you while in laptop mode.
  240 #MAX_AGE=600
  241 
  242 # Automatically disable laptop mode when the number of minutes of battery
  243 # that you have left goes below this threshold.
  244 MINIMUM_BATTERY_MINUTES=10
  245 
  246 # Read-ahead, in 512-byte sectors. You can spin down the disk while playing MP3/OGG
  247 # by setting the disk readahead to 8MB (READAHEAD=16384). Effectively, the disk
  248 # will read a complete MP3 at once, and will then spin down while the MP3/OGG is
  249 # playing.
  250 #READAHEAD=4096
  251 
  252 # Shall we remount journaled fs. with appropriate commit interval? (1=yes)
  253 #DO_REMOUNTS=1
  254 
  255 # And shall we add the "noatime" option to that as well? (1=yes)
  256 #DO_REMOUNT_NOATIME=1
  257 
  258 # Dirty synchronous ratio.  At this percentage of dirty pages the process
  259 # which
  260 # calls write() does its own writeback
  261 #DIRTY_RATIO=40
  262 
  263 #
  264 # Allowed dirty background ratio, in percent.  Once DIRTY_RATIO has been
  265 # exceeded, the kernel will wake pdflush which will then reduce the amount
  266 # of dirty memory to dirty_background_ratio.  Set this nice and low, so once
  267 # some writeout has commenced, we do a lot of it.
  268 #
  269 #DIRTY_BACKGROUND_RATIO=5
  270 
  271 # kernel default dirty buffer age
  272 #DEF_AGE=30
  273 #DEF_UPDATE=5
  274 #DEF_DIRTY_BACKGROUND_RATIO=10
  275 #DEF_DIRTY_RATIO=40
  276 #DEF_XFS_AGE_BUFFER=15
  277 #DEF_XFS_SYNC_INTERVAL=30
  278 #DEF_XFS_BUFD_INTERVAL=1
  279 
  280 # This must be adjusted manually to the value of HZ in the running kernel
  281 # on 2.4, until the XFS people change their 2.4 external interfaces to work in
  282 # centisecs. This can be automated, but it's a work in progress that still
  283 # needs# some fixes. On 2.6 kernels, XFS uses USER_HZ instead of HZ for
  284 # external interfaces, and that is currently always set to 100. So you don't
  285 # need to change this on 2.6.
  286 #XFS_HZ=100
  287 
  288 # Should the maximum CPU frequency be adjusted down while on battery?
  289 # Requires CPUFreq to be setup.
  290 # See Documentation/cpu-freq/user-guide.txt for more info
  291 #DO_CPU=0
  292 
  293 # When on battery what is the maximum CPU speed that the system should
  294 # use? Legal values are "slowest" for the slowest speed that your
  295 # CPU is able to operate at, or a value listed in:
  296 # /sys/devices/system/cpu/cpu0/cpufreq/scaling_available_frequencies
  297 # Only applicable if DO_CPU=1.
  298 #CPU_MAXFREQ=slowest
  299 
  300 # Idle timeout for your hard drive (man hdparm for valid values, -S option)
  301 # Default is 2 hours on AC (AC_HD=244) and 20 seconds for battery (BATT_HD=4).
  302 #AC_HD=244
  303 #BATT_HD=4
  304 
  305 # The drives for which to adjust the idle timeout. Separate them by a space,
  306 # e.g. HD="/dev/hda /dev/hdb".
  307 #HD="/dev/hda"
  308 
  309 # Set the spindown timeout on a hard drive?
  310 #DO_HD=1
  311 
  312 --------------------CONFIG FILE END---------------------------------------------
  313 
  314 
  315 Control script
  316 --------------
  317 
  318 Please note that this control script works for the Linux 2.4 and 2.6 series (thanks
  319 to Kiko Piris).
  320 
  321 --------------------CONTROL SCRIPT BEGIN----------------------------------------
  322 #!/bin/bash
  323 
  324 # start or stop laptop_mode, best run by a power management daemon when
  325 # ac gets connected/disconnected from a laptop
  326 #
  327 # install as /sbin/laptop_mode
  328 #
  329 # Contributors to this script:   Kiko Piris
  330 #                                Bart Samwel
  331 #                                Micha Feigin
  332 #                                Andrew Morton
  333 #                                Herve Eychenne
  334 #                                Dax Kelson
  335 #
  336 # Original Linux 2.4 version by: Jens Axboe
  337 
  338 #############################################################################
  339 
  340 # Source config
  341 if [ -f /etc/default/laptop-mode ] ; then
  342         # Debian
  343         . /etc/default/laptop-mode
  344 elif [ -f /etc/sysconfig/laptop-mode ] ; then
  345         # Others
  346         . /etc/sysconfig/laptop-mode
  347 fi
  348 
  349 # Don't raise an error if the config file is incomplete
  350 # set defaults instead:
  351 
  352 # Maximum time, in seconds, of hard drive spindown time that you are
  353 # comfortable with. Worst case, it's possible that you could lose this
  354 # amount of work if your battery fails you while in laptop mode.
  355 MAX_AGE=${MAX_AGE:-'600'}
  356 
  357 # Read-ahead, in kilobytes
  358 READAHEAD=${READAHEAD:-'4096'}
  359 
  360 # Shall we remount journaled fs. with appropriate commit interval? (1=yes)
  361 DO_REMOUNTS=${DO_REMOUNTS:-'1'}
  362 
  363 # And shall we add the "noatime" option to that as well? (1=yes)
  364 DO_REMOUNT_NOATIME=${DO_REMOUNT_NOATIME:-'1'}
  365 
  366 # Shall we adjust the idle timeout on a hard drive?
  367 DO_HD=${DO_HD:-'1'}
  368 
  369 # Adjust idle timeout on which hard drive?
  370 HD="${HD:-'/dev/hda'}"
  371 
  372 # spindown time for HD (hdparm -S values)
  373 AC_HD=${AC_HD:-'244'}
  374 BATT_HD=${BATT_HD:-'4'}
  375 
  376 # Dirty synchronous ratio.  At this percentage of dirty pages the process which
  377 # calls write() does its own writeback
  378 DIRTY_RATIO=${DIRTY_RATIO:-'40'}
  379 
  380 # cpu frequency scaling
  381 # See Documentation/cpu-freq/user-guide.txt for more info
  382 DO_CPU=${CPU_MANAGE:-'0'}
  383 CPU_MAXFREQ=${CPU_MAXFREQ:-'slowest'}
  384 
  385 #
  386 # Allowed dirty background ratio, in percent.  Once DIRTY_RATIO has been
  387 # exceeded, the kernel will wake pdflush which will then reduce the amount
  388 # of dirty memory to dirty_background_ratio.  Set this nice and low, so once
  389 # some writeout has commenced, we do a lot of it.
  390 #
  391 DIRTY_BACKGROUND_RATIO=${DIRTY_BACKGROUND_RATIO:-'5'}
  392 
  393 # kernel default dirty buffer age
  394 DEF_AGE=${DEF_AGE:-'30'}
  395 DEF_UPDATE=${DEF_UPDATE:-'5'}
  396 DEF_DIRTY_BACKGROUND_RATIO=${DEF_DIRTY_BACKGROUND_RATIO:-'10'}
  397 DEF_DIRTY_RATIO=${DEF_DIRTY_RATIO:-'40'}
  398 DEF_XFS_AGE_BUFFER=${DEF_XFS_AGE_BUFFER:-'15'}
  399 DEF_XFS_SYNC_INTERVAL=${DEF_XFS_SYNC_INTERVAL:-'30'}
  400 DEF_XFS_BUFD_INTERVAL=${DEF_XFS_BUFD_INTERVAL:-'1'}
  401 
  402 # This must be adjusted manually to the value of HZ in the running kernel
  403 # on 2.4, until the XFS people change their 2.4 external interfaces to work in
  404 # centisecs. This can be automated, but it's a work in progress that still needs
  405 # some fixes. On 2.6 kernels, XFS uses USER_HZ instead of HZ for external
  406 # interfaces, and that is currently always set to 100. So you don't need to
  407 # change this on 2.6.
  408 XFS_HZ=${XFS_HZ:-'100'}
  409 
  410 #############################################################################
  411 
  412 KLEVEL="$(uname -r |
  413              {
  414                IFS='.' read a b c
  415                echo $a.$b
  416              }
  417 )"
  418 case "$KLEVEL" in
  419         "2.4"|"2.6")
  420                 ;;
  421         *)
  422                 echo "Unhandled kernel version: $KLEVEL ('uname -r' = '$(uname -r)')" >&2
  423                 exit 1
  424                 ;;
  425 esac
  426 
  427 if [ ! -e /proc/sys/vm/laptop_mode ] ; then
  428         echo "Kernel is not patched with laptop_mode patch." >&2
  429         exit 1
  430 fi
  431 
  432 if [ ! -w /proc/sys/vm/laptop_mode ] ; then
  433         echo "You do not have enough privileges to enable laptop_mode." >&2
  434         exit 1
  435 fi
  436 
  437 # Remove an option (the first parameter) of the form option=<number> from
  438 # a mount options string (the rest of the parameters).
  439 parse_mount_opts () {
  440         OPT="$1"
  441         shift
  442         echo ",$*," | sed               \
  443          -e 's/,'"$OPT"'=[0-9]*,/,/g'   \
  444          -e 's/,,*/,/g'                 \
  445          -e 's/^,//'                    \
  446          -e 's/,$//'
  447 }
  448 
  449 # Remove an option (the first parameter) without any arguments from
  450 # a mount option string (the rest of the parameters).
  451 parse_nonumber_mount_opts () {
  452         OPT="$1"
  453         shift
  454         echo ",$*," | sed               \
  455          -e 's/,'"$OPT"',/,/g'          \
  456          -e 's/,,*/,/g'                 \
  457          -e 's/^,//'                    \
  458          -e 's/,$//'
  459 }
  460 
  461 # Find out the state of a yes/no option (e.g. "atime"/"noatime") in
  462 # fstab for a given filesystem, and use this state to replace the
  463 # value of the option in another mount options string. The device
  464 # is the first argument, the option name the second, and the default
  465 # value the third. The remainder is the mount options string.
  466 #
  467 # Example:
  468 # parse_yesno_opts_wfstab /dev/hda1 atime atime defaults,noatime
  469 #
  470 # If fstab contains, say, "rw" for this filesystem, then the result
  471 # will be "defaults,atime".
  472 parse_yesno_opts_wfstab () {
  473         L_DEV="$1"
  474         OPT="$2"
  475         DEF_OPT="$3"
  476         shift 3
  477         L_OPTS="$*"
  478         PARSEDOPTS1="$(parse_nonumber_mount_opts $OPT $L_OPTS)"
  479         PARSEDOPTS1="$(parse_nonumber_mount_opts no$OPT $PARSEDOPTS1)"
  480         # Watch for a default atime in fstab
  481         FSTAB_OPTS="$(awk '$1 == "'$L_DEV'" { print $4 }' /etc/fstab)"
  482         if echo "$FSTAB_OPTS" | grep "$OPT" > /dev/null ; then
  483                 # option specified in fstab: extract the value and use it
  484                 if echo "$FSTAB_OPTS" | grep "no$OPT" > /dev/null ; then
  485                         echo "$PARSEDOPTS1,no$OPT"
  486                 else
  487                         # no$OPT not found -- so we must have $OPT.
  488                         echo "$PARSEDOPTS1,$OPT"
  489                 fi
  490         else
  491                 # option not specified in fstab -- choose the default.
  492                 echo "$PARSEDOPTS1,$DEF_OPT"
  493         fi
  494 }
  495 
  496 # Find out the state of a numbered option (e.g. "commit=NNN") in
  497 # fstab for a given filesystem, and use this state to replace the
  498 # value of the option in another mount options string. The device
  499 # is the first argument, and the option name the second. The
  500 # remainder is the mount options string in which the replacement
  501 # must be done.
  502 #
  503 # Example:
  504 # parse_mount_opts_wfstab /dev/hda1 commit defaults,commit=7
  505 #
  506 # If fstab contains, say, "commit=3,rw" for this filesystem, then the
  507 # result will be "rw,commit=3".
  508 parse_mount_opts_wfstab () {
  509         L_DEV="$1"
  510         OPT="$2"
  511         shift 2
  512         L_OPTS="$*"
  513         PARSEDOPTS1="$(parse_mount_opts $OPT $L_OPTS)"
  514         # Watch for a default commit in fstab
  515         FSTAB_OPTS="$(awk '$1 == "'$L_DEV'" { print $4 }' /etc/fstab)"
  516         if echo "$FSTAB_OPTS" | grep "$OPT=" > /dev/null ; then
  517                 # option specified in fstab: extract the value, and use it
  518                 echo -n "$PARSEDOPTS1,$OPT="
  519                 echo ",$FSTAB_OPTS," | sed \
  520                  -e 's/.*,'"$OPT"'=//'  \
  521                  -e 's/,.*//'
  522         else
  523                 # option not specified in fstab: set it to 0
  524                 echo "$PARSEDOPTS1,$OPT=0"
  525         fi
  526 }
  527 
  528 deduce_fstype () {
  529         MP="$1"
  530         # My root filesystem unfortunately has
  531         # type "unknown" in /etc/mtab. If we encounter
  532         # "unknown", we try to get the type from fstab.
  533         cat /etc/fstab |
  534         grep -v '^#' |
  535         while read FSTAB_DEV FSTAB_MP FSTAB_FST FSTAB_OPTS FSTAB_DUMP FSTAB_DUMP ; do
  536                 if [ "$FSTAB_MP" = "$MP" ]; then
  537                         echo $FSTAB_FST
  538                         exit 0
  539                 fi
  540         done
  541 }
  542 
  543 if [ $DO_REMOUNT_NOATIME -eq 1 ] ; then
  544         NOATIME_OPT=",noatime"
  545 fi
  546 
  547 case "$1" in
  548         start)
  549                 AGE=$((100*$MAX_AGE))
  550                 XFS_AGE=$(($XFS_HZ*$MAX_AGE))
  551                 echo -n "Starting laptop_mode"
  552 
  553                 if [ -d /proc/sys/vm/pagebuf ] ; then
  554                         # (For 2.4 and early 2.6.)
  555                         # This only needs to be set, not reset -- it is only used when
  556                         # laptop mode is enabled.
  557                         echo $XFS_AGE > /proc/sys/vm/pagebuf/lm_flush_age
  558                         echo $XFS_AGE > /proc/sys/fs/xfs/lm_sync_interval
  559                 elif [ -f /proc/sys/fs/xfs/lm_age_buffer ] ; then
  560                         # (A couple of early 2.6 laptop mode patches had these.)
  561                         # The same goes for these.
  562                         echo $XFS_AGE > /proc/sys/fs/xfs/lm_age_buffer
  563                         echo $XFS_AGE > /proc/sys/fs/xfs/lm_sync_interval
  564                 elif [ -f /proc/sys/fs/xfs/age_buffer ] ; then
  565                         # (2.6.6)
  566                         # But not for these -- they are also used in normal
  567                         # operation.
  568                         echo $XFS_AGE > /proc/sys/fs/xfs/age_buffer
  569                         echo $XFS_AGE > /proc/sys/fs/xfs/sync_interval
  570                 elif [ -f /proc/sys/fs/xfs/age_buffer_centisecs ] ; then
  571                         # (2.6.7 upwards)
  572                         # And not for these either. These are in centisecs,
  573                         # not USER_HZ, so we have to use $AGE, not $XFS_AGE.
  574                         echo $AGE > /proc/sys/fs/xfs/age_buffer_centisecs
  575                         echo $AGE > /proc/sys/fs/xfs/xfssyncd_centisecs
  576                         echo 3000 > /proc/sys/fs/xfs/xfsbufd_centisecs
  577                 fi
  578 
  579                 case "$KLEVEL" in
  580                         "2.4")
  581                                 echo 1                                  > /proc/sys/vm/laptop_mode
  582                                 echo "30 500 0 0 $AGE $AGE 60 20 0"     > /proc/sys/vm/bdflush
  583                                 ;;
  584                         "2.6")
  585                                 echo 5                                  > /proc/sys/vm/laptop_mode
  586                                 echo "$AGE"                             > /proc/sys/vm/dirty_writeback_centisecs
  587                                 echo "$AGE"                             > /proc/sys/vm/dirty_expire_centisecs
  588                                 echo "$DIRTY_RATIO"                     > /proc/sys/vm/dirty_ratio
  589                                 echo "$DIRTY_BACKGROUND_RATIO"          > /proc/sys/vm/dirty_background_ratio
  590                                 ;;
  591                 esac
  592                 if [ $DO_REMOUNTS -eq 1 ]; then
  593                         cat /etc/mtab | while read DEV MP FST OPTS DUMP PASS ; do
  594                                 PARSEDOPTS="$(parse_mount_opts "$OPTS")"
  595                                 if [ "$FST" = 'unknown' ]; then
  596                                         FST=$(deduce_fstype $MP)
  597                                 fi
  598                                 case "$FST" in
  599                                         "ext3"|"reiserfs")
  600                                                 PARSEDOPTS="$(parse_mount_opts commit "$OPTS")"
  601                                                 mount $DEV -t $FST $MP -o remount,$PARSEDOPTS,commit=$MAX_AGE$NOATIME_OPT
  602                                                 ;;
  603                                         "xfs")
  604                                                 mount $DEV -t $FST $MP -o remount,$OPTS$NOATIME_OPT
  605                                                 ;;
  606                                 esac
  607                                 if [ -b $DEV ] ; then
  608                                         blockdev --setra $(($READAHEAD * 2)) $DEV
  609                                 fi
  610                         done
  611                 fi
  612                 if [ $DO_HD -eq 1 ] ; then
  613                         for THISHD in $HD ; do
  614                                 /sbin/hdparm -S $BATT_HD $THISHD > /dev/null 2>&1
  615                                 /sbin/hdparm -B 1 $THISHD > /dev/null 2>&1
  616                         done
  617                 fi
  618                 if [ $DO_CPU -eq 1 -a -e /sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_min_freq ]; then
  619                         if [ $CPU_MAXFREQ = 'slowest' ]; then
  620                                 CPU_MAXFREQ=`cat /sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_min_freq`
  621                         fi
  622                         echo $CPU_MAXFREQ > /sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq
  623                 fi
  624                 echo "."
  625                 ;;
  626         stop)
  627                 U_AGE=$((100*$DEF_UPDATE))
  628                 B_AGE=$((100*$DEF_AGE))
  629                 echo -n "Stopping laptop_mode"
  630                 echo 0 > /proc/sys/vm/laptop_mode
  631                 if [ -f /proc/sys/fs/xfs/age_buffer -a ! -f /proc/sys/fs/xfs/lm_age_buffer ] ; then
  632                         # These need to be restored, if there are no lm_*.
  633                         echo $(($XFS_HZ*$DEF_XFS_AGE_BUFFER))           > /proc/sys/fs/xfs/age_buffer
  634                         echo $(($XFS_HZ*$DEF_XFS_SYNC_INTERVAL))        > /proc/sys/fs/xfs/sync_interval
  635                 elif [ -f /proc/sys/fs/xfs/age_buffer_centisecs ] ; then
  636                         # These need to be restored as well.
  637                         echo $((100*$DEF_XFS_AGE_BUFFER))       > /proc/sys/fs/xfs/age_buffer_centisecs
  638                         echo $((100*$DEF_XFS_SYNC_INTERVAL))    > /proc/sys/fs/xfs/xfssyncd_centisecs
  639                         echo $((100*$DEF_XFS_BUFD_INTERVAL))    > /proc/sys/fs/xfs/xfsbufd_centisecs
  640                 fi
  641                 case "$KLEVEL" in
  642                         "2.4")
  643                                 echo "30 500 0 0 $U_AGE $B_AGE 60 20 0" > /proc/sys/vm/bdflush
  644                                 ;;
  645                         "2.6")
  646                                 echo "$U_AGE"                           > /proc/sys/vm/dirty_writeback_centisecs
  647                                 echo "$B_AGE"                           > /proc/sys/vm/dirty_expire_centisecs
  648                                 echo "$DEF_DIRTY_RATIO"                 > /proc/sys/vm/dirty_ratio
  649                                 echo "$DEF_DIRTY_BACKGROUND_RATIO"      > /proc/sys/vm/dirty_background_ratio
  650                                 ;;
  651                 esac
  652                 if [ $DO_REMOUNTS -eq 1 ] ; then
  653                         cat /etc/mtab | while read DEV MP FST OPTS DUMP PASS ; do
  654                                 # Reset commit and atime options to defaults.
  655                                 if [ "$FST" = 'unknown' ]; then
  656                                         FST=$(deduce_fstype $MP)
  657                                 fi
  658                                 case "$FST" in
  659                                         "ext3"|"reiserfs")
  660                                                 PARSEDOPTS="$(parse_mount_opts_wfstab $DEV commit $OPTS)"
  661                                                 PARSEDOPTS="$(parse_yesno_opts_wfstab $DEV atime atime $PARSEDOPTS)"
  662                                                 mount $DEV -t $FST $MP -o remount,$PARSEDOPTS
  663                                                 ;;
  664                                         "xfs")
  665                                                 PARSEDOPTS="$(parse_yesno_opts_wfstab $DEV atime atime $OPTS)"
  666                                                 mount $DEV -t $FST $MP -o remount,$PARSEDOPTS
  667                                                 ;;
  668                                 esac
  669                                 if [ -b $DEV ] ; then
  670                                         blockdev --setra 256 $DEV
  671                                 fi
  672                         done
  673                 fi
  674                 if [ $DO_HD -eq 1 ] ; then
  675                         for THISHD in $HD ; do
  676                                 /sbin/hdparm -S $AC_HD $THISHD > /dev/null 2>&1
  677                                 /sbin/hdparm -B 255 $THISHD > /dev/null 2>&1
  678                         done
  679                 fi
  680                 if [ $DO_CPU -eq 1 -a -e /sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_min_freq ]; then
  681                         echo `cat /sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq` > /sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq
  682                 fi
  683                 echo "."
  684                 ;;
  685         *)
  686                 echo "Usage: $0 {start|stop}" 2>&1
  687                 exit 1
  688                 ;;
  689 
  690 esac
  691 
  692 exit 0
  693 --------------------CONTROL SCRIPT END------------------------------------------
  694 
  695 
  696 ACPI integration
  697 ----------------
  698 
  699 Dax Kelson submitted this so that the ACPI acpid daemon will
  700 kick off the laptop_mode script and run hdparm. The part that
  701 automatically disables laptop mode when the battery is low was
  702 written by Jan Topinski.
  703 
  704 -----------------/etc/acpi/events/ac_adapter BEGIN------------------------------
  705 event=ac_adapter
  706 action=/etc/acpi/actions/ac.sh %e
  707 ----------------/etc/acpi/events/ac_adapter END---------------------------------
  708 
  709 
  710 -----------------/etc/acpi/events/battery BEGIN---------------------------------
  711 event=battery.*
  712 action=/etc/acpi/actions/battery.sh %e
  713 ----------------/etc/acpi/events/battery END------------------------------------
  714 
  715 
  716 ----------------/etc/acpi/actions/ac.sh BEGIN-----------------------------------
  717 #!/bin/bash
  718 
  719 # ac on/offline event handler
  720 
  721 status=`awk '/^state: / { print $2 }' /proc/acpi/ac_adapter/$2/state`
  722 
  723 case $status in
  724         "on-line")
  725                 /sbin/laptop_mode stop
  726                 exit 0
  727         ;;
  728         "off-line")
  729                 /sbin/laptop_mode start
  730                 exit 0
  731         ;;
  732 esac
  733 ---------------------------/etc/acpi/actions/ac.sh END--------------------------
  734 
  735 
  736 ---------------------------/etc/acpi/actions/battery.sh BEGIN-------------------
  737 #! /bin/bash
  738 
  739 # Automatically disable laptop mode when the battery almost runs out.
  740 
  741 BATT_INFO=/proc/acpi/battery/$2/state
  742 
  743 if [[ -f /proc/sys/vm/laptop_mode ]]
  744 then
  745    LM=`cat /proc/sys/vm/laptop_mode`
  746    if [[ $LM -gt 0 ]]
  747    then
  748      if [[ -f $BATT_INFO ]]
  749      then
  750         # Source the config file only now that we know we need
  751         if [ -f /etc/default/laptop-mode ] ; then
  752                 # Debian
  753                 . /etc/default/laptop-mode
  754         elif [ -f /etc/sysconfig/laptop-mode ] ; then
  755                 # Others
  756                 . /etc/sysconfig/laptop-mode
  757         fi
  758         MINIMUM_BATTERY_MINUTES=${MINIMUM_BATTERY_MINUTES:-'10'}
  759 
  760         ACTION="`cat $BATT_INFO | grep charging | cut -c 26-`"
  761         if [[ ACTION -eq "discharging" ]]
  762         then
  763            PRESENT_RATE=`cat $BATT_INFO | grep "present rate:" | sed  "s/.* \([0-9][0-9]* \).*/\1/" `
  764            REMAINING=`cat $BATT_INFO | grep "remaining capacity:" | sed  "s/.* \([0-9][0-9]* \).*/\1/" `
  765         fi
  766         if (($REMAINING * 60 / $PRESENT_RATE < $MINIMUM_BATTERY_MINUTES))
  767         then
  768            /sbin/laptop_mode stop
  769         fi
  770      else
  771        logger -p daemon.warning "You are using laptop mode and your battery interface $BATT_INFO is missing. This may lead to loss of data when the battery runs out. Check kernel ACPI support and /proc/acpi/battery folder, and edit /etc/acpi/battery.sh to set BATT_INFO to the correct path."
  772      fi
  773    fi
  774 fi
  775 ---------------------------/etc/acpi/actions/battery.sh END--------------------
  776 
  777 
  778 Monitoring tool
  779 ---------------
  780 
  781 Bartek Kania submitted this, it can be used to measure how much time your disk
  782 spends spun up/down.
  783 
  784 ---------------------------dslm.c BEGIN-----------------------------------------
  785 /*
  786  * Simple Disk Sleep Monitor
  787  *  by Bartek Kania
  788  * Licenced under the GPL
  789  */
  790 #include <unistd.h>
  791 #include <stdlib.h>
  792 #include <stdio.h>
  793 #include <fcntl.h>
  794 #include <errno.h>
  795 #include <time.h>
  796 #include <string.h>
  797 #include <signal.h>
  798 #include <sys/ioctl.h>
  799 #include <linux/hdreg.h>
  800 
  801 #ifdef DEBUG
  802 #define D(x) x
  803 #else
  804 #define D(x)
  805 #endif
  806 
  807 int endit = 0;
  808 
  809 /* Check if the disk is in powersave-mode
  810  * Most of the code is stolen from hdparm.
  811  * 1 = active, 0 = standby/sleep, -1 = unknown */
  812 int check_powermode(int fd)
  813 {
  814     unsigned char args[4] = {WIN_CHECKPOWERMODE1,0,0,0};
  815     int state;
  816 
  817     if (ioctl(fd, HDIO_DRIVE_CMD, &args)
  818         && (args[0] = WIN_CHECKPOWERMODE2) /* try again with 0x98 */
  819         && ioctl(fd, HDIO_DRIVE_CMD, &args)) {
  820         if (errno != EIO || args[0] != 0 || args[1] != 0) {
  821             state = -1; /* "unknown"; */
  822         } else
  823             state = 0; /* "sleeping"; */
  824     } else {
  825         state = (args[2] == 255) ? 1 : 0;
  826     }
  827     D(printf(" drive state is:  %d\n", state));
  828 
  829     return state;
  830 }
  831 
  832 char *state_name(int i)
  833 {
  834     if (i == -1) return "unknown";
  835     if (i == 0) return "sleeping";
  836     if (i == 1) return "active";
  837 
  838     return "internal error";
  839 }
  840 
  841 char *myctime(time_t time)
  842 {
  843     char *ts = ctime(&time);
  844     ts[strlen(ts) - 1] = 0;
  845 
  846     return ts;
  847 }
  848 
  849 void measure(int fd)
  850 {
  851     time_t start_time;
  852     int last_state;
  853     time_t last_time;
  854     int curr_state;
  855     time_t curr_time = 0;
  856     time_t time_diff;
  857     time_t active_time = 0;
  858     time_t sleep_time = 0;
  859     time_t unknown_time = 0;
  860     time_t total_time = 0;
  861     int changes = 0;
  862     float tmp;
  863 
  864     printf("Starting measurements\n");
  865 
  866     last_state = check_powermode(fd);
  867     start_time = last_time = time(0);
  868     printf("  System is in state %s\n\n", state_name(last_state));
  869 
  870     while(!endit) {
  871         sleep(1);
  872         curr_state = check_powermode(fd);
  873 
  874         if (curr_state != last_state || endit) {
  875             changes++;
  876             curr_time = time(0);
  877             time_diff = curr_time - last_time;
  878 
  879             if (last_state == 1) active_time += time_diff;
  880             else if (last_state == 0) sleep_time += time_diff;
  881             else unknown_time += time_diff;
  882 
  883             last_state = curr_state;
  884             last_time = curr_time;
  885 
  886             printf("%s: State-change to %s\n", myctime(curr_time),
  887                    state_name(curr_state));
  888         }
  889     }
  890     changes--; /* Compensate for SIGINT */
  891 
  892     total_time = time(0) - start_time;
  893     printf("\nTotal running time:  %lus\n", curr_time - start_time);
  894     printf(" State changed %d times\n", changes);
  895 
  896     tmp = (float)sleep_time / (float)total_time * 100;
  897     printf(" Time in sleep state:   %lus (%.2f%%)\n", sleep_time, tmp);
  898     tmp = (float)active_time / (float)total_time * 100;
  899     printf(" Time in active state:  %lus (%.2f%%)\n", active_time, tmp);
  900     tmp = (float)unknown_time / (float)total_time * 100;
  901     printf(" Time in unknown state: %lus (%.2f%%)\n", unknown_time, tmp);
  902 }
  903 
  904 void ender(int s)
  905 {
  906     endit = 1;
  907 }
  908 
  909 void usage()
  910 {
  911     puts("usage: dslm [-w <time>] <disk>");
  912     exit(0);
  913 }
  914 
  915 int main(int argc, char **argv)
  916 {
  917     int fd;
  918     char *disk = 0;
  919     int settle_time = 60;
  920 
  921     /* Parse the simple command-line */
  922     if (argc == 2)
  923         disk = argv[1];
  924     else if (argc == 4) {
  925         settle_time = atoi(argv[2]);
  926         disk = argv[3];
  927     } else
  928         usage();
  929 
  930     if (!(fd = open(disk, O_RDONLY|O_NONBLOCK))) {
  931         printf("Can't open %s, because: %s\n", disk, strerror(errno));
  932         exit(-1);
  933     }
  934 
  935     if (settle_time) {
  936         printf("Waiting %d seconds for the system to settle down to "
  937                "'normal'\n", settle_time);
  938         sleep(settle_time);
  939     } else
  940         puts("Not waiting for system to settle down");
  941 
  942     signal(SIGINT, ender);
  943 
  944     measure(fd);
  945 
  946     close(fd);
  947 
  948     return 0;
  949 }
  950 ---------------------------dslm.c END-------------------------------------------

Cache object: 71cbb8694151958fa015c8baff28685d


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.