如何使用笔记本模式节约电量

文档作者:Bart Samwel (bart@samwel.tk)

创建日期:2004 年 1 月 2 日

上次修改日期:2004 年 12 月 6 日

简介

笔记本模式用于最大限度地减少硬盘需要启动的时间,以节省笔记本电脑的电池电量。据报道,它可以显著节省电力。

安装

要使用笔记本模式,您无需设置任何内核配置选项或任何其他内容。只需安装本文档中包含的所有文件,当您使用电池供电时,笔记本模式将自动启动。为了您的方便,可以在以下位置下载包含安装程序的 tarball:

要配置笔记本模式,您需要编辑配置文件,该文件位于基于 Debian 的系统上的 /etc/default/laptop-mode 中,或位于其他系统上的 /etc/sysconfig/laptop-mode 中。

不幸的是,对于没有 ACPI 的笔记本电脑,笔记本模式的自动启用不起作用。在这些笔记本电脑上,您需要手动启动笔记本模式。要启动笔记本模式,请运行 “laptop_mode start”,要停止它,请运行 “laptop_mode stop”。 (注意:笔记本模式工具包现在对 APM 具有实验性支持,您可能需要首先尝试一下。)

注意事项

  • 笔记本模式的缺点是您可能会丢失最多 10 分钟的工作。如果您无法承受此损失,请不要使用它!提供的 ACPI 脚本会在电池电量即将耗尽时自动关闭笔记本模式,以便您在电池寿命结束时不会丢失任何数据。

  • 大多数桌面硬盘的寿命以停转周期来衡量,通常约为 50,000 次(通常在规格表上列出)。检查您的硬盘额定值,如果您不需要,请不要缩短硬盘的寿命。

  • 如果您使用 -n 选项挂载某些 ext3/reiserfs 文件系统,则控制脚本将无法正确重新挂载它们。您必须在控制脚本中设置 DO_REMOUNTS=0,否则它将使用错误的选项重新挂载它们 - 或者它将失败,因为它无法写入 /etc/mtab。

  • 如果您像我一样在 fstab 中将文件系统列为“auto”类型,则控制脚本将无法识别它们为需要重新挂载的文件系统。您必须使用它们的真实类型列出文件系统。

  • 据报道,某些版本的 mutt 邮件客户端使用文件访问时间来确定文件夹是否包含新邮件。如果您使用 mutt 并遇到此问题,您必须通过在配置文件中将选项 DO_REMOUNT_NOATIME 设置为 0 来禁用 noatime 重新挂载。

细节

笔记本模式由旋钮 /proc/sys/vm/laptop_mode 控制。此旋钮对于所有具有笔记本模式补丁的内核都存在,无论是否有任何配置选项。设置旋钮后,任何可能导致硬盘启动的物理磁盘 I/O 都会导致 Linux 刷新所有脏块。这样做的结果是,在磁盘停转后,它不会再启动以写入脏块,因为这些块已经在最近的读取操作之后立即写入。laptop_mode 旋钮的值决定了磁盘 I/O 的发生时间和触发刷新的时间之间的时间。旋钮的合理值为 5 秒。将旋钮设置为 0 将禁用笔记本模式。

为了提高笔记本模式策略的有效性,笔记本模式控制脚本会将 /proc/sys/vm 中的 dirty_expire_centisecs 和 dirty_writeback_centisecs 增加到大约 10 分钟(默认),这意味着脏页不会经常被强制写入磁盘。控制脚本还会更改脏背景比率,以便不再进行脏页的后台回写。结合 ext3 或 ReiserFS 文件系统更高的提交值(也是由控制脚本自动完成的),这会导致磁盘活动集中在一个很小的时间间隔内,该间隔每 10 分钟发生一次,或者在磁盘被缓存未命中强制启动时发生。然后,磁盘可以在不活动的期间内停转。

配置

笔记本模式配置文件位于基于 Debian 的系统上的 /etc/default/laptop-mode 中,或位于其他系统上的 /etc/sysconfig/laptop-mode 中。它包含以下选项

MAX_AGE

您舒适的硬盘停转时间的最大时间(以秒为单位)。最坏的情况下,如果您的电池在您处于笔记本模式时发生故障,您可能会丢失这段时间的工作。

MINIMUM_BATTERY_MINUTES

如果剩余电池电量的分钟数小于此值,则自动禁用笔记本模式。默认值为 10 分钟。

AC_HD/BATT_HD

当笔记本模式处于活动状态 (BATT_HD) 和不活动状态 (AC_HD) 时,应在硬盘上设置的空闲超时。BATT_HD 的默认值为 20 秒(值 4),AC_HD 的默认值为 2 小时(值 244)。可能的值是“hdparm”手册页中 “-S” 选项列出的值。

HD

笔记本模式应调整停转超时的设备。默认为 /dev/hda。如果您指定多个设备,请用空格分隔它们。

READAHEAD

当笔记本模式处于活动状态时,磁盘预读(以 512 字节扇区为单位)。较大的预读可以防止对可执行页面(在应用程序执行时按需加载)和按顺序访问的数据(MP3)之类的东西进行磁盘访问。

DO_REMOUNTS

控制脚本会自动使用适当的提交间隔选项重新挂载任何已挂载的日志文件系统。当此选项设置为 0 时,此功能将被禁用。

DO_REMOUNT_NOATIME

重新挂载时,文件系统是否应该使用 noatime 选项重新挂载?通常,此设置为“1”(启用),但可能有一些程序需要访问时间记录。

DIRTY_RATIO

在强制回写之前,允许内存包含“脏”或未保存数据的百分比(当笔记本模式处于活动状态时)。对应于 /proc/sys/vm/dirty_ratio sysctl。

DIRTY_BACKGROUND_RATIO

在由于超出 DIRTY_RATIO 而完成强制回写后,允许内存包含“脏”或未保存数据的百分比。将其设置得足够低。这对应于 /proc/sys/vm/dirty_background_ratio sysctl。

请注意,当笔记本模式处于活动状态时和不处于活动状态时,dirty_background_ratio 的行为完全不同。当笔记本模式不活动时,dirty_background_ratio 是后台写出开始发生的阈值百分比。但是,当笔记本模式处于活动状态时,后台写出被禁用,并且 dirty_background_ratio 仅确定在达到 dirty_ratio 时完成多少回写。

DO_CPU

启用笔记本电脑模式下的 CPU 频率调节。(需要设置 CPUFreq。更多信息请参阅 CPU 性能调节。默认禁用。)

CPU_MAXFREQ

当使用电池时,系统应该使用的最大 CPU 速度是多少?合法的值为“slowest”,表示 CPU 能够运行的最低速度,或者 /sys/devices/system/cpu/cpu0/cpufreq/scaling_available_frequencies 中列出的值。

技巧和窍门

  • Bartek Kania 报告说,使用 5 秒的停止旋转时间(BATT_HD=1)可以额外获得长达 50 分钟的电池续航时间(在他通常的 3 到 3.5 小时的基础上)。

  • 您可以在播放 MP3 时停止硬盘旋转,只需将磁盘预读设置为 8MB (READAHEAD=16384)。实际上,硬盘会一次性读取完整的 MP3,然后在 MP3 播放时停止旋转。(感谢 Bartek Kania。)

  • Drew Scott Daniels 观察到:“我不知道为什么,但当我减少显示器使用的颜色数量时,它会消耗更少的电池电量。我在 Powerbook 上也看到了这一点。我希望这条信息对笔记本电脑模式补丁或其用户有用。”

  • 在 syslog.conf 中,您可以在条目前面加上一个破折号 - 以省略每次日志记录后同步文件的操作。当您使用笔记本电脑模式且您的硬盘没有停止旋转时,这很可能是一个罪魁祸首。

  • Richard Atterer 观察到,笔记本电脑模式与 noflushd ( http://noflushd.sourceforge.net/ ) 不能很好地配合使用,似乎 noflushd 阻止了笔记本电脑模式的正常工作。

  • 如果您担心您的数据,您可能需要考虑使用 USB 记忆棒或类似的东西作为“工作区”。(但请注意,闪存只能处理有限的写入次数,过度使用可能会很快磨损您的记忆棒。请_不要_在闪存记忆棒上使用日志文件系统。)

用于控制和 ACPI 电池脚本的配置文件

这允许通过外部配置文件更改脚本的调优参数

它应该以 /etc/default/laptop-mode 的形式安装在 Debian 上,并以 /etc/sysconfig/laptop-mode 的形式安装在 Red Hat、SUSE、Mandrake 和其他类似系统上。

配置文件

# Maximum time, in seconds, of hard drive spindown time that you are
# comfortable with. Worst case, it's possible that you could lose this
# amount of work if your battery fails you while in laptop mode.
#MAX_AGE=600

# Automatically disable laptop mode when the number of minutes of battery
# that you have left goes below this threshold.
MINIMUM_BATTERY_MINUTES=10

# Read-ahead, in 512-byte sectors. You can spin down the disk while playing MP3/OGG
# by setting the disk readahead to 8MB (READAHEAD=16384). Effectively, the disk
# will read a complete MP3 at once, and will then spin down while the MP3/OGG is
# playing.
#READAHEAD=4096

# Shall we remount journaled fs. with appropriate commit interval? (1=yes)
#DO_REMOUNTS=1

# And shall we add the "noatime" option to that as well? (1=yes)
#DO_REMOUNT_NOATIME=1

# Dirty synchronous ratio.  At this percentage of dirty pages the process
# which
# calls write() does its own writeback
#DIRTY_RATIO=40

#
# Allowed dirty background ratio, in percent.  Once DIRTY_RATIO has been
# exceeded, the kernel will wake flusher threads which will then reduce the
# amount of dirty memory to dirty_background_ratio.  Set this nice and low,
# so once some writeout has commenced, we do a lot of it.
#
#DIRTY_BACKGROUND_RATIO=5

# kernel default dirty buffer age
#DEF_AGE=30
#DEF_UPDATE=5
#DEF_DIRTY_BACKGROUND_RATIO=10
#DEF_DIRTY_RATIO=40
#DEF_XFS_AGE_BUFFER=15
#DEF_XFS_SYNC_INTERVAL=30
#DEF_XFS_BUFD_INTERVAL=1

# This must be adjusted manually to the value of HZ in the running kernel
# on 2.4, until the XFS people change their 2.4 external interfaces to work in
# centisecs. This can be automated, but it's a work in progress that still
# needs# some fixes. On 2.6 kernels, XFS uses USER_HZ instead of HZ for
# external interfaces, and that is currently always set to 100. So you don't
# need to change this on 2.6.
#XFS_HZ=100

# Should the maximum CPU frequency be adjusted down while on battery?
# Requires CPUFreq to be setup.
# See Documentation/admin-guide/pm/cpufreq.rst for more info
#DO_CPU=0

# When on battery what is the maximum CPU speed that the system should
# use? Legal values are "slowest" for the slowest speed that your
# CPU is able to operate at, or a value listed in:
# /sys/devices/system/cpu/cpu0/cpufreq/scaling_available_frequencies
# Only applicable if DO_CPU=1.
#CPU_MAXFREQ=slowest

# Idle timeout for your hard drive (man hdparm for valid values, -S option)
# Default is 2 hours on AC (AC_HD=244) and 20 seconds for battery (BATT_HD=4).
#AC_HD=244
#BATT_HD=4

# The drives for which to adjust the idle timeout. Separate them by a space,
# e.g. HD="/dev/hda /dev/hdb".
#HD="/dev/hda"

# Set the spindown timeout on a hard drive?
#DO_HD=1

控制脚本

请注意,此控制脚本适用于 Linux 2.4 和 2.6 系列(感谢 Kiko Piris)。

控制脚本

#!/bin/bash

# start or stop laptop_mode, best run by a power management daemon when
# ac gets connected/disconnected from a laptop
#
# install as /sbin/laptop_mode
#
# Contributors to this script:   Kiko Piris
#                              Bart Samwel
#                              Micha Feigin
#                              Andrew Morton
#                              Herve Eychenne
#                              Dax Kelson
#
# Original Linux 2.4 version by: Jens Axboe

#############################################################################

# Source config
if [ -f /etc/default/laptop-mode ] ; then
      # Debian
      . /etc/default/laptop-mode
elif [ -f /etc/sysconfig/laptop-mode ] ; then
      # Others
        . /etc/sysconfig/laptop-mode
fi

# Don't raise an error if the config file is incomplete
# set defaults instead:

# Maximum time, in seconds, of hard drive spindown time that you are
# comfortable with. Worst case, it's possible that you could lose this
# amount of work if your battery fails you while in laptop mode.
MAX_AGE=${MAX_AGE:-'600'}

# Read-ahead, in kilobytes
READAHEAD=${READAHEAD:-'4096'}

# Shall we remount journaled fs. with appropriate commit interval? (1=yes)
DO_REMOUNTS=${DO_REMOUNTS:-'1'}

# And shall we add the "noatime" option to that as well? (1=yes)
DO_REMOUNT_NOATIME=${DO_REMOUNT_NOATIME:-'1'}

# Shall we adjust the idle timeout on a hard drive?
DO_HD=${DO_HD:-'1'}

# Adjust idle timeout on which hard drive?
HD="${HD:-'/dev/hda'}"

# spindown time for HD (hdparm -S values)
AC_HD=${AC_HD:-'244'}
BATT_HD=${BATT_HD:-'4'}

# Dirty synchronous ratio.  At this percentage of dirty pages the process which
# calls write() does its own writeback
DIRTY_RATIO=${DIRTY_RATIO:-'40'}

# cpu frequency scaling
# See Documentation/admin-guide/pm/cpufreq.rst for more info
DO_CPU=${CPU_MANAGE:-'0'}
CPU_MAXFREQ=${CPU_MAXFREQ:-'slowest'}

#
# Allowed dirty background ratio, in percent.  Once DIRTY_RATIO has been
# exceeded, the kernel will wake flusher threads which will then reduce the
# amount of dirty memory to dirty_background_ratio.  Set this nice and low,
# so once some writeout has commenced, we do a lot of it.
#
DIRTY_BACKGROUND_RATIO=${DIRTY_BACKGROUND_RATIO:-'5'}

# kernel default dirty buffer age
DEF_AGE=${DEF_AGE:-'30'}
DEF_UPDATE=${DEF_UPDATE:-'5'}
DEF_DIRTY_BACKGROUND_RATIO=${DEF_DIRTY_BACKGROUND_RATIO:-'10'}
DEF_DIRTY_RATIO=${DEF_DIRTY_RATIO:-'40'}
DEF_XFS_AGE_BUFFER=${DEF_XFS_AGE_BUFFER:-'15'}
DEF_XFS_SYNC_INTERVAL=${DEF_XFS_SYNC_INTERVAL:-'30'}
DEF_XFS_BUFD_INTERVAL=${DEF_XFS_BUFD_INTERVAL:-'1'}

# This must be adjusted manually to the value of HZ in the running kernel
# on 2.4, until the XFS people change their 2.4 external interfaces to work in
# centisecs. This can be automated, but it's a work in progress that still needs
# some fixes. On 2.6 kernels, XFS uses USER_HZ instead of HZ for external
# interfaces, and that is currently always set to 100. So you don't need to
# change this on 2.6.
XFS_HZ=${XFS_HZ:-'100'}

#############################################################################

KLEVEL="$(uname -r |
             {
             IFS='.' read a b c
             echo $a.$b
           }
)"
case "$KLEVEL" in
      "2.4"|"2.6")
              ;;
      *)
              echo "Unhandled kernel version: $KLEVEL ('uname -r' = '$(uname -r)')" >&2
              exit 1
              ;;
esac

if [ ! -e /proc/sys/vm/laptop_mode ] ; then
      echo "Kernel is not patched with laptop_mode patch." >&2
      exit 1
fi

if [ ! -w /proc/sys/vm/laptop_mode ] ; then
      echo "You do not have enough privileges to enable laptop_mode." >&2
      exit 1
fi

# Remove an option (the first parameter) of the form option=<number> from
# a mount options string (the rest of the parameters).
parse_mount_opts () {
      OPT="$1"
      shift
      echo ",$*," | sed               \
       -e 's/,'"$OPT"'=[0-9]*,/,/g'   \
       -e 's/,,*/,/g'                 \
       -e 's/^,//'                    \
       -e 's/,$//'
}

# Remove an option (the first parameter) without any arguments from
# a mount option string (the rest of the parameters).
parse_nonumber_mount_opts () {
      OPT="$1"
      shift
      echo ",$*," | sed               \
       -e 's/,'"$OPT"',/,/g'          \
       -e 's/,,*/,/g'                 \
       -e 's/^,//'                    \
       -e 's/,$//'
}

# Find out the state of a yes/no option (e.g. "atime"/"noatime") in
# fstab for a given filesystem, and use this state to replace the
# value of the option in another mount options string. The device
# is the first argument, the option name the second, and the default
# value the third. The remainder is the mount options string.
#
# Example:
# parse_yesno_opts_wfstab /dev/hda1 atime atime defaults,noatime
#
# If fstab contains, say, "rw" for this filesystem, then the result
# will be "defaults,atime".
parse_yesno_opts_wfstab () {
      L_DEV="$1"
      OPT="$2"
      DEF_OPT="$3"
      shift 3
      L_OPTS="$*"
      PARSEDOPTS1="$(parse_nonumber_mount_opts $OPT $L_OPTS)"
      PARSEDOPTS1="$(parse_nonumber_mount_opts no$OPT $PARSEDOPTS1)"
      # Watch for a default atime in fstab
      FSTAB_OPTS="$(awk '$1 == "'$L_DEV'" { print $4 }' /etc/fstab)"
      if echo "$FSTAB_OPTS" | grep "$OPT" > /dev/null ; then
              # option specified in fstab: extract the value and use it
              if echo "$FSTAB_OPTS" | grep "no$OPT" > /dev/null ; then
                      echo "$PARSEDOPTS1,no$OPT"
              else
                      # no$OPT not found -- so we must have $OPT.
                      echo "$PARSEDOPTS1,$OPT"
              fi
      else
              # option not specified in fstab -- choose the default.
              echo "$PARSEDOPTS1,$DEF_OPT"
      fi
}

# Find out the state of a numbered option (e.g. "commit=NNN") in
# fstab for a given filesystem, and use this state to replace the
# value of the option in another mount options string. The device
# is the first argument, and the option name the second. The
# remainder is the mount options string in which the replacement
# must be done.
#
# Example:
# parse_mount_opts_wfstab /dev/hda1 commit defaults,commit=7
#
# If fstab contains, say, "commit=3,rw" for this filesystem, then the
# result will be "rw,commit=3".
parse_mount_opts_wfstab () {
      L_DEV="$1"
      OPT="$2"
      shift 2
      L_OPTS="$*"
      PARSEDOPTS1="$(parse_mount_opts $OPT $L_OPTS)"
      # Watch for a default commit in fstab
      FSTAB_OPTS="$(awk '$1 == "'$L_DEV'" { print $4 }' /etc/fstab)"
      if echo "$FSTAB_OPTS" | grep "$OPT=" > /dev/null ; then
              # option specified in fstab: extract the value, and use it
              echo -n "$PARSEDOPTS1,$OPT="
              echo ",$FSTAB_OPTS," | sed \
               -e 's/.*,'"$OPT"'=//'  \
               -e 's/,.*//'
      else
              # option not specified in fstab: set it to 0
              echo "$PARSEDOPTS1,$OPT=0"
      fi
}

deduce_fstype () {
      MP="$1"
      # My root filesystem unfortunately has
      # type "unknown" in /etc/mtab. If we encounter
      # "unknown", we try to get the type from fstab.
      cat /etc/fstab |
      grep -v '^#' |
      while read FSTAB_DEV FSTAB_MP FSTAB_FST FSTAB_OPTS FSTAB_DUMP FSTAB_DUMP ; do
              if [ "$FSTAB_MP" = "$MP" ]; then
                      echo $FSTAB_FST
                      exit 0
              fi
      done
}

if [ $DO_REMOUNT_NOATIME -eq 1 ] ; then
      NOATIME_OPT=",noatime"
fi

case "$1" in
      start)
              AGE=$((100*$MAX_AGE))
              XFS_AGE=$(($XFS_HZ*$MAX_AGE))
              echo -n "Starting laptop_mode"

              if [ -d /proc/sys/vm/pagebuf ] ; then
                      # (For 2.4 and early 2.6.)
                      # This only needs to be set, not reset -- it is only used when
                      # laptop mode is enabled.
                      echo $XFS_AGE > /proc/sys/vm/pagebuf/lm_flush_age
                      echo $XFS_AGE > /proc/sys/fs/xfs/lm_sync_interval
              elif [ -f /proc/sys/fs/xfs/lm_age_buffer ] ; then
                      # (A couple of early 2.6 laptop mode patches had these.)
                      # The same goes for these.
                      echo $XFS_AGE > /proc/sys/fs/xfs/lm_age_buffer
                      echo $XFS_AGE > /proc/sys/fs/xfs/lm_sync_interval
              elif [ -f /proc/sys/fs/xfs/age_buffer ] ; then
                      # (2.6.6)
                      # But not for these -- they are also used in normal
                      # operation.
                      echo $XFS_AGE > /proc/sys/fs/xfs/age_buffer
                      echo $XFS_AGE > /proc/sys/fs/xfs/sync_interval
              elif [ -f /proc/sys/fs/xfs/age_buffer_centisecs ] ; then
                      # (2.6.7 upwards)
                      # And not for these either. These are in centisecs,
                      # not USER_HZ, so we have to use $AGE, not $XFS_AGE.
                      echo $AGE > /proc/sys/fs/xfs/age_buffer_centisecs
                      echo $AGE > /proc/sys/fs/xfs/xfssyncd_centisecs
                      echo 3000 > /proc/sys/fs/xfs/xfsbufd_centisecs
              fi

              case "$KLEVEL" in
                      "2.4")
                              echo 1                                  > /proc/sys/vm/laptop_mode
                              echo "30 500 0 0 $AGE $AGE 60 20 0"     > /proc/sys/vm/bdflush
                              ;;
                      "2.6")
                              echo 5                                  > /proc/sys/vm/laptop_mode
                              echo "$AGE"                             > /proc/sys/vm/dirty_writeback_centisecs
                              echo "$AGE"                             > /proc/sys/vm/dirty_expire_centisecs
                              echo "$DIRTY_RATIO"                     > /proc/sys/vm/dirty_ratio
                              echo "$DIRTY_BACKGROUND_RATIO"          > /proc/sys/vm/dirty_background_ratio
                              ;;
              esac
              if [ $DO_REMOUNTS -eq 1 ]; then
                      cat /etc/mtab | while read DEV MP FST OPTS DUMP PASS ; do
                              PARSEDOPTS="$(parse_mount_opts "$OPTS")"
                              if [ "$FST" = 'unknown' ]; then
                                      FST=$(deduce_fstype $MP)
                              fi
                              case "$FST" in
                                      "ext3"|"reiserfs")
                                              PARSEDOPTS="$(parse_mount_opts commit "$OPTS")"
                                              mount $DEV -t $FST $MP -o remount,$PARSEDOPTS,commit=$MAX_AGE$NOATIME_OPT
                                              ;;
                                      "xfs")
                                              mount $DEV -t $FST $MP -o remount,$OPTS$NOATIME_OPT
                                              ;;
                              esac
                              if [ -b $DEV ] ; then
                                      blockdev --setra $(($READAHEAD * 2)) $DEV
                              fi
                      done
              fi
              if [ $DO_HD -eq 1 ] ; then
                      for THISHD in $HD ; do
                              /sbin/hdparm -S $BATT_HD $THISHD > /dev/null 2>&1
                              /sbin/hdparm -B 1 $THISHD > /dev/null 2>&1
                      done
              fi
              if [ $DO_CPU -eq 1 -a -e /sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_min_freq ]; then
                      if [ $CPU_MAXFREQ = 'slowest' ]; then
                              CPU_MAXFREQ=`cat /sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_min_freq`
                      fi
                      echo $CPU_MAXFREQ > /sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq
              fi
              echo "."
              ;;
      stop)
              U_AGE=$((100*$DEF_UPDATE))
              B_AGE=$((100*$DEF_AGE))
              echo -n "Stopping laptop_mode"
              echo 0 > /proc/sys/vm/laptop_mode
              if [ -f /proc/sys/fs/xfs/age_buffer -a ! -f /proc/sys/fs/xfs/lm_age_buffer ] ; then
                      # These need to be restored, if there are no lm_*.
                      echo $(($XFS_HZ*$DEF_XFS_AGE_BUFFER))           > /proc/sys/fs/xfs/age_buffer
                      echo $(($XFS_HZ*$DEF_XFS_SYNC_INTERVAL))        > /proc/sys/fs/xfs/sync_interval
              elif [ -f /proc/sys/fs/xfs/age_buffer_centisecs ] ; then
                      # These need to be restored as well.
                      echo $((100*$DEF_XFS_AGE_BUFFER))       > /proc/sys/fs/xfs/age_buffer_centisecs
                      echo $((100*$DEF_XFS_SYNC_INTERVAL))    > /proc/sys/fs/xfs/xfssyncd_centisecs
                      echo $((100*$DEF_XFS_BUFD_INTERVAL))    > /proc/sys/fs/xfs/xfsbufd_centisecs
              fi
              case "$KLEVEL" in
                      "2.4")
                              echo "30 500 0 0 $U_AGE $B_AGE 60 20 0" > /proc/sys/vm/bdflush
                              ;;
                      "2.6")
                              echo "$U_AGE"                           > /proc/sys/vm/dirty_writeback_centisecs
                              echo "$B_AGE"                           > /proc/sys/vm/dirty_expire_centisecs
                              echo "$DEF_DIRTY_RATIO"                 > /proc/sys/vm/dirty_ratio
                              echo "$DEF_DIRTY_BACKGROUND_RATIO"      > /proc/sys/vm/dirty_background_ratio
                              ;;
              esac
              if [ $DO_REMOUNTS -eq 1 ] ; then
                      cat /etc/mtab | while read DEV MP FST OPTS DUMP PASS ; do
                              # Reset commit and atime options to defaults.
                              if [ "$FST" = 'unknown' ]; then
                                      FST=$(deduce_fstype $MP)
                              fi
                              case "$FST" in
                                      "ext3"|"reiserfs")
                                              PARSEDOPTS="$(parse_mount_opts_wfstab $DEV commit $OPTS)"
                                              PARSEDOPTS="$(parse_yesno_opts_wfstab $DEV atime atime $PARSEDOPTS)"
                                              mount $DEV -t $FST $MP -o remount,$PARSEDOPTS
                                              ;;
                                      "xfs")
                                              PARSEDOPTS="$(parse_yesno_opts_wfstab $DEV atime atime $OPTS)"
                                              mount $DEV -t $FST $MP -o remount,$PARSEDOPTS
                                              ;;
                              esac
                              if [ -b $DEV ] ; then
                                      blockdev --setra 256 $DEV
                              fi
                      done
              fi
              if [ $DO_HD -eq 1 ] ; then
                      for THISHD in $HD ; do
                              /sbin/hdparm -S $AC_HD $THISHD > /dev/null 2>&1
                              /sbin/hdparm -B 255 $THISHD > /dev/null 2>&1
                      done
              fi
              if [ $DO_CPU -eq 1 -a -e /sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_min_freq ]; then
                      echo `cat /sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq` > /sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq
              fi
              echo "."
              ;;
      *)
              echo "Usage: $0 {start|stop}" 2>&1
              exit 1
              ;;

esac

exit 0

ACPI 集成

Dax Kelson 提交了此内容,以便 ACPI acpid 守护程序将启动 laptop_mode 脚本并运行 hdparm。当电池电量低时自动禁用笔记本电脑模式的部分由 Jan Topinski 编写。

/etc/acpi/events/ac_adapter

event=ac_adapter
action=/etc/acpi/actions/ac.sh %e

/etc/acpi/events/battery

event=battery.*
action=/etc/acpi/actions/battery.sh %e

/etc/acpi/actions/ac.sh

#!/bin/bash

# ac on/offline event handler

status=`awk '/^state: / { print $2 }' /proc/acpi/ac_adapter/$2/state`

case $status in
        "on-line")
                /sbin/laptop_mode stop
                exit 0
        ;;
        "off-line")
                /sbin/laptop_mode start
                exit 0
        ;;
esac

/etc/acpi/actions/battery.sh

#! /bin/bash

# Automatically disable laptop mode when the battery almost runs out.

BATT_INFO=/proc/acpi/battery/$2/state

if [[ -f /proc/sys/vm/laptop_mode ]]
then
   LM=`cat /proc/sys/vm/laptop_mode`
   if [[ $LM -gt 0 ]]
   then
     if [[ -f $BATT_INFO ]]
     then
        # Source the config file only now that we know we need
        if [ -f /etc/default/laptop-mode ] ; then
                # Debian
                . /etc/default/laptop-mode
        elif [ -f /etc/sysconfig/laptop-mode ] ; then
                # Others
                . /etc/sysconfig/laptop-mode
        fi
        MINIMUM_BATTERY_MINUTES=${MINIMUM_BATTERY_MINUTES:-'10'}

        ACTION="`cat $BATT_INFO | grep charging | cut -c 26-`"
        if [[ ACTION -eq "discharging" ]]
        then
           PRESENT_RATE=`cat $BATT_INFO | grep "present rate:" | sed  "s/.* \([0-9][0-9]* \).*/\1/" `
           REMAINING=`cat $BATT_INFO | grep "remaining capacity:" | sed  "s/.* \([0-9][0-9]* \).*/\1/" `
        fi
        if (($REMAINING * 60 / $PRESENT_RATE < $MINIMUM_BATTERY_MINUTES))
        then
           /sbin/laptop_mode stop
        fi
     else
       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."
     fi
   fi
fi

监控工具

Bartek Kania 提交了此工具,它可用于测量您的磁盘处于旋转状态/停止旋转状态的时间。请参阅 tools/laptop/dslm/dslm.c