3
# Laptop mode tools module: core laptop mode functionality
9
# Remove an option (the first parameter) of the form option=<number> from
10
# a mount options string (the rest of the parameters).
11
remove_numeric_mount_option () {
15
-e 's|,'"$OPT"'=[0-9]*,|,|g' \
21
# Remove an option (the first parameter) without any arguments from
22
# a mount option string (the rest of the parameters).
23
remove_fixed_mount_option () {
27
-e 's|,'"$OPT"',|,|g' \
33
# Find out the state of an atime option ("atime"/"noatime"/"relatime"/"norelatime")
34
# in a set of mount options, and use this state to replace the value of the
35
# option in another mount options string.
38
# replace_atime_mount_option defaults,user=1000,atime defaults,noatime
40
# This yields "defaults,atime".
41
replace_atime_mount_option () {
44
PARSEDOPTS="$(remove_fixed_mount_option atime $OPTS)"
45
PARSEDOPTS="$(remove_fixed_mount_option noatime $PARSEDOPTS)"
46
PARSEDOPTS="$(remove_fixed_mount_option relatime $PARSEDOPTS)"
47
PARSEDOPTS="$(remove_fixed_mount_option norelatime $PARSEDOPTS)"
49
case ",$REPLACEMENT_OPTS," in
51
echo "$PARSEDOPTS,relatime"
54
echo "$PARSEDOPTS,noatime"
57
# Kind of strange: to go from relatime to atime, we have to
58
# explicitly specify norelatime.
59
echo "$PARSEDOPTS,atime,norelatime"
64
# Find out the state of a numbered option (e.g. "commit=NNN") in
65
# a set of options, and use this state to replace the
66
# value of the option in another mount options string.
69
# replace_numeric_mount_option commit defaults,user=1000,commit=3 defaults,commit=7
71
# This example yields "defaults,commit=3".
72
replace_numeric_mount_option () {
77
PARSEDOPTS="$(remove_numeric_mount_option $OPT $OPTS)"
79
if echo ",$REPLACEMENT_OPTS," | grep ",$OPT=[0123456789]+," > /dev/null ; then
80
echo -n "$PARSEDOPTS,$OPT="
81
echo ",$REPLACEMENT_OPTS," | sed \
82
-e 's/.*,'"$OPT"'=//' \
85
# Option not present in REPLACEMENT_OPTS: use the default.
86
echo "$PARSEDOPTS,$DEF_OPT"
92
# My root filesystem unfortunately has type "unknown" in
93
# /etc/mtab. If we encounter "unknown", we try to get the
94
# type from fstab. This still might be wrong, in which
95
# case the code further down will issue a big warning.
96
sed 's/[[:space:]]*#.*$//' /etc/fstab |
97
while read FSTAB_DEV FSTAB_MP FSTAB_FST FSTAB_OPTS FSTAB_DUMP FSTAB_DUMP ; do
98
if [ "$FSTAB_MP" = "$MP" ]; then
107
# Set kernel setting, showing an error if this fails.
109
# Parameter 1: sysctl/proc path
110
# Parameter 2: the value
113
$LM_VERBOSE && echo "Executing: echo $2 > $1" >> $OUTPUT
114
if ! echo "$2" > "$1" ; then
115
echo "SETTING OF KERNEL PARAMETER FAILED: echo $2 \> $1"
120
if [ "$CONTROL_READAHEAD" -ne 0 ] ; then
121
if /sbin/blockdev --help 2>&1 | grep -Fq -- '--setfra' ; then
122
READAHEAD_OPTION=--setfra
124
READAHEAD_OPTION=--setra
125
if [ "$KLEVEL" = "2.4" ] ; then
126
echo "Warning: Running a 2.4 kernel with blockdev that does not support --setfra."
127
echo "File system readahead will not function properly."
134
if [ $CONTROL_NOATIME -eq 1 ] ; then
135
if [ "$KLEVEL" = "2.4" ] ; then
136
$LM_VERBOSE && echo "Relatime is not supported on 2.4 kernels. Using noatime instead" >> $OUTPUT
138
elif [ "$KLEVEL" = "2.6" -a "$KMINOR" -lt 23 ] ; then
139
$LM_VERBOSE && echo "Relatime is not supported on kernels before 2.6.23. Using noatime instead." >> $OUTPUT
142
if [ "$USE_RELATIME" = 1 ] ; then
143
NOATIME_OPT=",relatime"
145
NOATIME_OPT=",noatime"
150
# Adjust kernel settings and mount options (but only if data loss
151
# sensitive features are active)
152
if [ "$ACTIVATE_WITH_POSSIBLE_DATA_LOSS" -eq 1 ] ; then
153
# Take MAX_LOST_WORK_SECONDS from LM_BATT_MAX_LOST_WORK_SECONDS or LM_AC_MAX_LOST_WORK_SECONDS_WITH_LM, depending on power state.
154
MAX_LOST_WORK_SECONDS=$LM_BATT_MAX_LOST_WORK_SECONDS
155
if [ $ON_AC -eq 1 ] ; then
156
MAX_LOST_WORK_SECONDS=$LM_AC_MAX_LOST_WORK_SECONDS
159
AGE=$((100*$MAX_LOST_WORK_SECONDS))
160
XFS_AGE=$(($XFS_HZ*$MAX_LOST_WORK_SECONDS))
162
if [ -d /proc/sys/vm/pagebuf ] ; then
163
# (For 2.4 and early 2.6.)
164
# This only needs to be set, not reset -- it is only used when
165
# laptop mode is enabled.
166
$LM_VERBOSE && echo "Adjusting XFS kernel parameters for 2.4 and early 2.6 kernels." >> $OUTPUT
167
set_sysctl /proc/sys/vm/pagebuf/lm_flush_age $XFS_AGE
168
set_sysctl /proc/sys/fs/xfs/lm_sync_interval $XFS_AGE
169
elif [ -f /proc/sys/fs/xfs/lm_age_buffer ] ; then
170
# (A couple of early 2.6 laptop mode patches had these.)
171
# This only needs to be set, not reset -- it is only used when
172
# laptop mode is enabled.
173
$LM_VERBOSE && echo "Adjusting XFS kernel parameters for early patched 2.6 kernels." >> $OUTPUT
174
set_sysctl /proc/sys/fs/xfs/lm_age_buffer $XFS_AGE
175
set_sysctl /proc/sys/fs/xfs/lm_sync_interval $XFS_AGE
176
elif [ -f /proc/sys/fs/xfs/age_buffer ] ; then
178
# But not for these -- they are also used in normal
180
$LM_VERBOSE && echo "Adjusting XFS kernel parameters for 2.6.6 kernel." >> $OUTPUT
181
set_sysctl /proc/sys/fs/xfs/age_buffer $XFS_AGE
182
set_sysctl /proc/sys/fs/xfs/sync_interval $XFS_AGE
183
elif [ -f /proc/sys/fs/xfs/age_buffer_centisecs ] ; then
185
# And not for these either. These are in centisecs,
186
# not USER_HZ, so we have to use $AGE, not $XFS_AGE.
187
$LM_VERBOSE && echo "Adjusting XFS kernel parameters for >2.6.7 kernel." >> $OUTPUT
188
set_sysctl /proc/sys/fs/xfs/age_buffer_centisecs $AGE
189
set_sysctl /proc/sys/fs/xfs/xfssyncd_centisecs $AGE
190
set_sysctl /proc/sys/fs/xfs/xfsbufd_centisecs 3000
195
$LM_VERBOSE && echo "Adjusting 2.4 kernel parameters to enable laptop mode." >> $OUTPUT
196
set_sysctl /proc/sys/vm/laptop_mode 1
197
set_sysctl /proc/sys/vm/bdflush "30 500 0 0 $AGE $AGE 60 20 0"
200
$LM_VERBOSE && echo "Adjusting 2.6 kernel parameters to enable laptop mode." >> $OUTPUT
201
set_sysctl /proc/sys/vm/laptop_mode "$LM_SECONDS_BEFORE_SYNC"
202
set_sysctl /proc/sys/vm/dirty_writeback_centisecs "$AGE"
203
set_sysctl /proc/sys/vm/dirty_expire_centisecs "$AGE"
204
set_sysctl /proc/sys/vm/dirty_ratio "$LM_DIRTY_RATIO"
205
set_sysctl /proc/sys/vm/dirty_background_ratio "$LM_DIRTY_BACKGROUND_RATIO"
208
if [ $CONTROL_MOUNT_OPTIONS -eq 1 ]; then
209
$LM_VERBOSE && echo "Remounting filesystems." >> $OUTPUT
210
cat /etc/mtab | while read DEV MP FST OPTS DUMP PASS ; do
212
rootfs|unionfs|tmpfs|squashfs|sysfs|usbfs|proc|devpts)
219
case " $PARTITIONS " in
222
$LM_VERBOSE && echo "$DEV found in PARTITIONS." >> $OUTPUT
225
$LM_VERBOSE && echo "$DEV not found in PARTITIONS." >> $OUTPUT
228
case " $PARTITIONS " in
231
$LM_VERBOSE && echo "$MP found in PARTITIONS." >> $OUTPUT
234
$LM_VERBOSE && echo "$MP not found in PARTITIONS." >> $OUTPUT
236
case " $PARTITIONS " in
238
$LM_VERBOSE && echo "Checking $DEV against HD because PARTITIONS contains \"auto\"." >> $OUTPUT
239
for THISHD in $HD ; do
240
$LM_VERBOSE && echo " Considering $THISHD." >> $OUTPUT
241
case " $DEV" in *"$THISHD"*)
243
$LM_VERBOSE && echo " $DEV contains $THISHD, which is in HD, so we will remount it." >> $OUTPUT
250
if [ "$DO" -ne 0 ] ; then
251
$LM_VERBOSE && echo "Original options: $OPTS" >> $OUTPUT
252
if [ "$WAS_ACTIVE" -eq 0 ] ; then
253
# Coming from inactive state: save last known mount options for the device.
254
$LM_VERBOSE && echo "Updating /var/run/laptop-mode-tools/nolm-mountopts." >> $OUTPUT
255
if [ -f /var/run/laptop-mode-tools/nolm-mountopts ] ; then
256
sed -i "s|^$DEV .*$||" /var/run/laptop-mode-tools/nolm-mountopts
258
echo $DEV $OPTS >> /var/run/laptop-mode-tools/nolm-mountopts
260
$LM_VERBOSE && echo "Not updating /var/run/laptop-mode-tools/nolm-mountopts because laptop mode was already active." >> $OUTPUT
262
if [ "$FST" = 'unknown' ]; then
263
$LM_VERBOSE && echo "Deducing fstype for $MP." >> $OUTPUT
264
FST=$(deduce_fstype $MP)
265
$LM_VERBOSE && echo "Deduced fstype for $MP as $FST." >> $OUTPUT
267
# Strip stuff like ext3,ext2 into just ext3.
268
$LM_VERBOSE && echo "Reducing file system type." >> $OUTPUT
272
$LM_VERBOSE && echo "Removing commit mount option from original options." >> $OUTPUT
273
PARSEDOPTS="$(remove_numeric_mount_option commit "$OPTS")"
274
$LM_VERBOSE && echo "Executing: mount $DEV $MP -t $FST -o remount,$PARSEDOPTS,commit=$MAX_LOST_WORK_SECONDS$NOATIME_OPT" >> $OUTPUT
275
if (! mount $DEV $MP -t $FST -o remount,$PARSEDOPTS,commit=$MAX_LOST_WORK_SECONDS$NOATIME_OPT) ; then
276
if [ "$FST" = "ext3" -a "$MP" = "/" ] ; then
277
echo "BIG FAT WARNING: Your root filesystem mounted as ext3 seems to lack support for"
278
echo "the commit mount option. This usually means that your root filesystem is"
279
echo "mounted as ext2 because there is no ext3 support in the kernel at boot time,"
280
echo "usually because you compiled ext3 as a module and don't load it in an initrd."
281
echo "Note that on recent 2.6 kernels, /proc/mounts shows the correct fs type for"
282
echo "the device /dev/root. You can check your actual root filesystem mount type"
283
echo "there. To fix the problem, either make ext3 available at boot time by compiling"
284
echo "it statically into the kernel, or configure the correct filesystem type in"
290
$LM_VERBOSE && echo "Executing: mount $DEV $MP -t $FST -o remount,$OPTS$NOATIME_OPT" >> $OUTPUT
291
mount $DEV $MP -t $FST -o remount,$OPTS$NOATIME_OPT
294
if [ -b $DEV -a "$CONTROL_READAHEAD" -ne 0 ] ; then
295
$LM_VERBOSE && echo "Executing: /sbin/blockdev $READAHEAD_OPTION $(($LM_READAHEAD * 2)) $DEV" >> $OUTPUT
296
/sbin/blockdev $READAHEAD_OPTION $(($LM_READAHEAD * 2)) $DEV >> $OUTPUT 2>&1
302
# DEACTIVATE w.r.t. kernel options and mount point settings
303
U_AGE=$((100*$DEF_UPDATE))
304
B_AGE=$((100*$DEF_MAX_AGE))
305
set_sysctl /proc/sys/vm/laptop_mode 0
306
if [ -f /proc/sys/fs/xfs/age_buffer -a ! -f /proc/sys/fs/xfs/lm_age_buffer ] ; then
307
# These need to be restored, if there are no lm_*.
308
$LM_VERBOSE && echo "Restoring default XFS settings (pre-centisecs version)." >> $OUTPUT
309
set_sysctl /proc/sys/fs/xfs/age_buffer $(($XFS_HZ*$DEF_XFS_AGE_BUFFER))
310
set_sysctl /proc/sys/fs/xfs/sync_interval $(($XFS_HZ*$DEF_XFS_SYNC_INTERVAL))
311
elif [ -f /proc/sys/fs/xfs/age_buffer_centisecs ] ; then
312
# These need to be restored as well.
313
$LM_VERBOSE && echo "Restoring default XFS settings." >> $OUTPUT
314
set_sysctl /proc/sys/fs/xfs/age_buffer_centisecs $((100*$DEF_XFS_AGE_BUFFER))
315
set_sysctl /proc/sys/fs/xfs/xfssyncd_centisecs $((100*$DEF_XFS_SYNC_INTERVAL))
316
set_sysctl /proc/sys/fs/xfs/xfsbufd_centisecs $((100*$DEF_XFS_BUFD_INTERVAL))
320
$LM_VERBOSE && echo "Adjusting 2.4 kernel parameters to disable laptop mode." >> $OUTPUT
321
set_sysctl /proc/sys/vm/bdflush "30 500 0 0 $U_AGE $B_AGE 60 20 0"
324
$LM_VERBOSE && echo "Adjusting 2.6 kernel parameters to disable laptop mode." >> $OUTPUT
325
set_sysctl /proc/sys/vm/dirty_writeback_centisecs "$U_AGE"
326
set_sysctl /proc/sys/vm/dirty_expire_centisecs "$B_AGE"
327
set_sysctl /proc/sys/vm/dirty_ratio "$NOLM_DIRTY_RATIO"
328
set_sysctl /proc/sys/vm/dirty_background_ratio "$NOLM_DIRTY_BACKGROUND_RATIO"
331
if [ $CONTROL_MOUNT_OPTIONS -eq 1 ] ; then
332
$LM_VERBOSE && echo "Remounting filesystems." >> $OUTPUT
333
cat /etc/mtab | while read DEV MP FST OPTS DUMP PASS ; do
335
case " $PARTITIONS " in
338
$LM_VERBOSE && echo "$DEV found in PARTITIONS." >> $OUTPUT
341
$LM_VERBOSE && echo "$DEV not found in PARTITIONS." >> $OUTPUT
344
case " $PARTITIONS " in
347
$LM_VERBOSE && echo "$MP found in PARTITIONS." >> $OUTPUT
350
$LM_VERBOSE && echo "$MP not found in PARTITIONS." >> $OUTPUT
353
case " $PARTITIONS " in
355
$LM_VERBOSE && echo "Checking $DEV against HD because PARTITIONS contains \"auto\"." >> $OUTPUT
356
for THISHD in $HD ; do
357
$LM_VERBOSE && echo " Considering $THISHD." >> $OUTPUT
358
case " $DEV" in *"$THISHD"*)
360
$LM_VERBOSE && echo " $DEV contains $THISHD, which is in HD, so we will remount it." >> $OUTPUT
367
if [ "$DO" -ne 0 ] ; then
368
# Reset commit and atime options to defaults.
369
$LM_VERBOSE && echo "Original options: $OPTS" >> $OUTPUT
370
if [ "$FST" = 'unknown' ]; then
371
$LM_VERBOSE && echo "Deducing fstype for $MP." >> $OUTPUT
372
FST=$(deduce_fstype $MP)
373
$LM_VERBOSE && echo "Deduced fstype for $MP as $FST." >> $OUTPUT
376
# Strip stuff like ext3,ext2 into just ext3.
377
$LM_VERBOSE && echo "Reducing file system type." >> $OUTPUT
380
# Retrieve original non-laptop mode mount options and restore them.
381
# If the file that stores them doesn't exist, then laptop mode
382
# has never been started.
383
if [ "$WAS_ACTIVE" -ne 0 -a -f /var/run/laptop-mode-tools/nolm-mountopts ] ; then
384
SAVED_OPTS=`grep "^$DEV " /var/run/laptop-mode-tools/nolm-mountopts`
385
SAVED_OPTS=${SAVED_OPTS#* } # trim device name
389
PARSEDOPTS="$(replace_numeric_mount_option commit commit=0 $SAVED_OPTS $OPTS)"
390
PARSEDOPTS="$(replace_atime_mount_option $SAVED_OPTS $PARSEDOPTS)"
391
$LM_VERBOSE && echo "Executing: mount $DEV $MP -t $FST -o remount,$PARSEDOPTS" >> $OUTPUT
392
mount $DEV $MP -t $FST -o remount,$PARSEDOPTS
395
PARSEDOPTS="$(replace_atime_mount_option $SAVED_OPTS $OPTS)"
396
$LM_VERBOSE && echo "Executing: mount $DEV $MP -t $FST -o remount,$PARSEDOPTS" >> $OUTPUT
397
mount $DEV $MP -t $FST -o remount,$PARSEDOPTS
401
$LM_VERBOSE && echo "No saved mount options, so apparently we never remounted this filesystem during this session." >> $OUTPUT
402
$LM_VERBOSE && echo "Not remounting." >> $OUTPUT
404
if [ -b $DEV -a "$CONTROL_READAHEAD" -ne 0 ] ; then
405
$LM_VERBOSE && echo "Executing: /sbin/blockdev $READAHEAD_OPTION $(($NOLM_READAHEAD * 2)) $DEV" >> $OUTPUT
406
/sbin/blockdev $READAHEAD_OPTION $(($NOLM_READAHEAD * 2)) $DEV >> $OUTPUT 2>&1