Gentoo Websites Logo
Go to: Gentoo Home Documentation Forums Lists Bugs Planet Store Wiki Get Gentoo!
View | Details | Raw Unified | Return to bug 45593
Collapse All | Expand All

(-)linux-2.6.3/Documentation/laptop-mode.txt (+480 lines)
Line 0 Link Here
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
7
Introduction
8
------------
9
10
Laptopmode is used to minimize the time that the hard disk needs to be spun up,
11
to conserve battery power on laptops. It has been reported to cause significant
12
power savings.
13
14
Contents
15
--------
16
17
* Introduction
18
* The short story
19
* Caveats
20
* The details
21
* Tips & Tricks
22
* Control script
23
* ACPI integration
24
* Monitoring tool
25
26
27
The short story
28
---------------
29
30
If you just want to use it, run the laptop_mode control script (which is included
31
at the end of this document) as follows:
32
33
# laptop_mode start
34
35
Then set your harddisk spindown time to a relatively low value with hdparm:
36
37
hdparm -S 4 /dev/hda
38
39
The value -S 4 means 20 seconds idle time before spindown. Your harddisk will
40
now only spin up when a disk cache miss occurs, or at least once every 10
41
minutes to write back any pending changes.
42
43
To stop laptop_mode, remount your filesystems with regular commit intervals
44
(e.g., 5 seconds), and run "laptop_mode stop".
45
46
47
Caveats
48
-------
49
50
* The downside of laptop mode is that you have a chance of losing up
51
  to 10 minutes of work. If you cannot afford this, don't use it!
52
53
* Most desktop hard drives have a very limited lifetime measured in spindown
54
  cycles, typically about 50.000 times (it's usually listed on the spec sheet).
55
  Check your drive's rating, and don't wear down your drive's lifetime if you
56
  don't need to.
57
58
* If you mount some of your ext3/reiserfs filesystems with the -n option, then
59
  the control script will not be able to remount them correctly. You must set
60
  DO_REMOUNTS=0 in the control script, otherwise it will remount them with the
61
  wrong options -- or it will fail because it cannot write to /etc/mtab.
62
63
* If you have your filesystems listed as type "auto" in fstab, like I did, then
64
  the control script will not recognize them as filesystems that need remounting.
65
66
The details
67
-----------
68
69
Laptop-mode is controlled by the flag /proc/sys/vm/laptop_mode. When this
70
flag is set, any physical disk read operation (that might have caused the
71
hard disk to spin up) causes Linux to flush all dirty blocks. The result
72
of this is that after a disk has spun down, it will not be spun up anymore
73
to write dirty blocks, because those blocks had already been written
74
immediately after the most recent read operation
75
76
To increase the effectiveness of the laptop_mode strategy, the laptop_mode
77
control script increases dirty_expire_centisecs and dirty_writeback_centisecs in
78
/proc/sys/vm to about 10 minutes (by default), which means that pages that are
79
dirtied are not forced to be written to disk as often. The control script also
80
changes the dirty background ratio, so that background writeback of dirty pages
81
is not done anymore. Combined with a higher commit value (also 10 minutes) for
82
ext3 or ReiserFS filesystems (also done automatically by the control script),
83
this results in concentration of disk activity in a small time interval which
84
occurs only once every 10 minutes, or whenever the disk is forced to spin up by
85
a cache miss. The disk can then be spun down in the periods of inactivity.
86
87
If you want to find out which process caused the disk to spin up, you can
88
gather information by setting the flag /proc/sys/vm/block_dump. When this flag
89
is set, Linux reports all disk read and write operations that take place, and
90
all block dirtyings done to files. This makes it possible to debug why a disk
91
needs to spin up, and to increase battery life even more.
92
93
If 10 minutes is too much or too little downtime for you, you can configure
94
this downtime as follows. In the control script, set the MAX_AGE value to the
95
maximum number of seconds of disk downtime that you would like. You should
96
then set your filesystem's commit interval to the same value. The dirty ratio
97
is also configurable from the control script.
98
99
If you don't like the idea of the control script remounting your filesystems
100
for you, you can change DO_REMOUNTS to 0 in the script.
101
102
Thanks to Kiko Piris, the control script can be used to enable laptop mode on
103
both the Linux 2.4 and 2.6 series.
104
105
106
Tips & Tricks
107
-------------
108
109
* Bartek Kania reports getting up to 50 minutes of extra battery life (on top
110
  of his regular 3 to 3.5 hours) using very aggressive power management (hdparm
111
  -B1) and a spindown time of 5 seconds (hdparm -S1).
112
113
* You can spin down the disk while playing MP3, by setting the disk readahead
114
  to 8MB (hdparm -a 16384). Effectively, the disk will read a complete MP3 at
115
  once, and will then spin down while the MP3 is playing. (Thanks to Bartek
116
  Kania.)
117
118
* Drew Scott Daniels observed: "I don't know why, but when I decrease the number
119
  of colours that my display uses it consumes less battery power. I've seen
120
  this on powerbooks too. I hope that this is a piece of information that
121
  might be useful to the Laptop Mode patch or it's users."
122
123
124
Control script
125
--------------
126
127
Please note that this control script works for the Linux 2.4 and 2.6 series.
128
129
--------------------CONTROL SCRIPT BEGIN------------------------------------------
130
#!/bin/sh
131
132
# start or stop laptop_mode, best run by a power management daemon when
133
# ac gets connected/disconnected from a laptop
134
#
135
# install as /sbin/laptop_mode
136
#
137
# Contributors to this script:   Kiko Piris
138
#				 Bart Samwel
139
#				 Dax Kelson
140
# Original Linux 2.4 version by: Jens Axboe
141
142
parse_mount_opts () {
143
	echo "$*"			| \
144
	sed 's/commit=[0-9]*//g'	| \
145
	sed 's/,,*/,/g'			| \
146
	sed 's/^,//'			| \
147
	sed 's/,$//'			| \
148
	cat -
149
}
150
151
KLEVEL="$(uname -r | cut -c1-3)"
152
case "$KLEVEL" in
153
	"2.4")
154
		true
155
		;;
156
	"2.6")
157
		true
158
		;;
159
	*)
160
		echo "Unhandled kernel level: $KLEVEL ('uname -r' = '$(uname -r)')"
161
		exit 1
162
		;;
163
esac
164
165
# Shall we remount journaled fs. with appropiate commit interval? (1=yes)
166
DO_REMOUNTS=1
167
168
# age time, in seconds. should be put into a sysconfig file
169
MAX_AGE=600
170
171
# Allowed dirty ratio, in pct. should be put into a sysconfig file as well.
172
DIRTY_RATIO=40
173
174
# kernel default dirty buffer age
175
DEF_AGE=30
176
DEF_UPDATE=5
177
DEF_DIRTY_BACKGROUND_RATIO=10
178
DEF_DIRTY_RATIO=40
179
180
181
if [ ! -e /proc/sys/vm/laptop_mode ]; then
182
	echo "Kernel is not patched with laptop_mode patch."
183
	exit 1
184
fi
185
186
if [ ! -w /proc/sys/vm/laptop_mode ]; then
187
	echo "You do not have enough privileges to enable laptop_mode."
188
	exit 1
189
fi
190
191
case "$1" in
192
	start)
193
		AGE=$((100*$MAX_AGE))
194
		echo -n "Starting laptop_mode"
195
		case "$KLEVEL" in
196
			"2.4")
197
				echo "1"				> /proc/sys/vm/laptop_mode
198
				echo "30 500 0 0 $AGE $AGE 60 20 0"	> /proc/sys/vm/bdflush
199
				;;
200
			"2.6")
201
				echo "1"				> /proc/sys/vm/laptop_mode
202
				echo "$AGE"				> /proc/sys/vm/dirty_writeback_centisecs
203
				echo "$AGE"				> /proc/sys/vm/dirty_expire_centisecs
204
				echo "$DIRTY_RATIO"			> /proc/sys/vm/dirty_ratio
205
				echo "$DIRTY_RATIO"			> /proc/sys/vm/dirty_background_ratio
206
				;;
207
		esac
208
		if [ $DO_REMOUNTS -eq 1 ]; then
209
			cat /etc/mtab | while read DEV MP FST OPTS DUMP PASS ; do
210
				PARSEDOPTS="$(parse_mount_opts "$OPTS")"
211
				case "$FST" in
212
					"ext3")		mount $DEV -t $FST $MP -o remount,$PARSEDOPTS,commit=$MAX_AGE ;;
213
					"reiserfs")	mount $DEV -t $FST $MP -o remount,$PARSEDOPTS,commit=$MAX_AGE ;;
214
					"xfs")		mount $DEV -t $FST $MP -o remount,$PARSEDOPTS,commit=$MAX_AGE ;;
215
				esac
216
			done
217
		fi
218
		echo "."
219
		;;
220
	stop)
221
		U_AGE=$((100*$DEF_UPDATE))
222
		B_AGE=$((100*$DEF_AGE))
223
		echo -n "Stopping laptop_mode"
224
		case "$KLEVEL" in
225
			"2.4")
226
				echo "0"				> /proc/sys/vm/laptop_mode
227
				echo "30 500 0 0 $U_AGE $B_AGE 60 20 0"	> /proc/sys/vm/bdflush
228
				;;
229
			"2.6")
230
				echo "0"				> /proc/sys/vm/laptop_mode
231
				echo "$U_AGE"				> /proc/sys/vm/dirty_writeback_centisecs
232
				echo "$B_AGE"				> /proc/sys/vm/dirty_expire_centisecs
233
				echo "$DEF_DIRTY_RATIO"			> /proc/sys/vm/dirty_ratio
234
				echo "$DEF_DIRTY_BACKGROUND_RATIO"	> /proc/sys/vm/dirty_background_ratio
235
				;;
236
		esac
237
		if [ $DO_REMOUNTS -eq 1 ]; then
238
			cat /etc/mtab | while read DEV MP FST OPTS DUMP PASS ; do
239
				PARSEDOPTS="$(parse_mount_opts "$OPTS")"
240
				case "$FST" in
241
					"ext3")		mount $DEV -t $FST $MP -o remount,$PARSEDOPTS ;;
242
					"reiserfs")	mount $DEV -t $FST $MP -o remount,$PARSEDOPTS ;;
243
					"xfs")		mount $DEV -t $FST $MP -o remount,$PARSEDOPTS ;;
244
				esac
245
			done
246
		fi
247
		echo "."
248
		;;
249
	*)
250
		echo "$0 {start|stop}"
251
		;;
252
253
esac
254
255
exit 0
256
257
--------------------CONTROL SCRIPT END--------------------------------------------
258
259
260
ACPI integration
261
----------------
262
263
Dax Kelson submitted this so that the ACPI acpid daemon will
264
kick off the laptop_mode script and run hdparm.
265
266
---------------------------/etc/acpi/events/ac_adapter BEGIN-------------------------------------------
267
event=ac_adapter
268
action=/etc/acpi/actions/battery.sh
269
---------------------------/etc/acpi/events/ac_adapter END-------------------------------------------
270
271
---------------------------/etc/acpi/actions/battery.sh BEGIN-------------------------------------------
272
#!/bin/sh
273
274
# cpu throttling
275
# cat /proc/acpi/processor/CPU0/throttling for more info
276
ACAD_THR=0
277
BATT_THR=2
278
279
# spindown time for HD (man hdparm for valid values)
280
# I prefer 2 hours for acad and 20 seconds for batt
281
ACAD_HD=244
282
BATT_HD=4
283
284
# ac/battery event handler
285
286
status=`awk '/^state: / { print $2 }' /proc/acpi/ac_adapter/AC/state`
287
288
case $status in
289
        "on-line")
290
                echo "Setting HD spindown to 2 hours"
291
                /sbin/laptop-mode stop
292
                /sbin/hdparm -S $ACAD_HD /dev/hda > /dev/null 2>&1
293
                /sbin/hdparm -B 255 /dev/hda > /dev/null 2>&1
294
                #echo -n $ACAD_CPU:$ACAD_THR > /proc/acpi/processor/CPU0/limit
295
                exit 0
296
        ;;
297
        "off-line")
298
                echo "Setting HD spindown to 20 seconds"
299
                /sbin/laptop-mode start
300
                /sbin/hdparm -S $BATT_HD /dev/hda > /dev/null 2>&1
301
                /sbin/hdparm -B 1 /dev/hda > /dev/null 2>&1
302
                #echo -n $BATT_CPU:$BATT_THR > /proc/acpi/processor/CPU0/limit
303
                exit 0
304
        ;;
305
esac
306
---------------------------/etc/acpi/actions/battery.sh END-------------------------------------------
307
308
Monitoring tool
309
---------------
310
311
Bartek Kania submitted this, it can be used to measure how much time your disk
312
spends spun up/down.
313
314
---------------------------dslm.c BEGIN-------------------------------------------
315
/*
316
 * Simple Disk SLeep Monitor
317
 *  by Bartek Kania
318
 * Licenced under the GPL
319
 */
320
#include <unistd.h>
321
#include <stdlib.h>
322
#include <stdio.h>
323
#include <fcntl.h>
324
#include <errno.h>
325
#include <time.h>
326
#include <string.h>
327
#include <signal.h>
328
#include <sys/ioctl.h>
329
#include <linux/hdreg.h>
330
331
#ifdef DEBUG
332
#define D(x) x
333
#else
334
#define D(x)
335
#endif
336
337
int endit = 0;
338
339
/* Check if the disk is in powersave-mode
340
 * Most of the code is stolen from hdparm.
341
 * 1 = active, 0 = standby/sleep, -1 = unknown */
342
int check_powermode(int fd)
343
{
344
    unsigned char args[4] = {WIN_CHECKPOWERMODE1,0,0,0};
345
    int state;
346
347
    if (ioctl(fd, HDIO_DRIVE_CMD, &args)
348
	&& (args[0] = WIN_CHECKPOWERMODE2) /* try again with 0x98 */
349
	&& ioctl(fd, HDIO_DRIVE_CMD, &args)) {
350
	if (errno != EIO || args[0] != 0 || args[1] != 0) {
351
	    state = -1; /* "unknown"; */
352
	} else
353
	    state = 0; /* "sleeping"; */
354
    } else {
355
	state = (args[2] == 255) ? 1 : 0;
356
    }
357
    D(printf(" drive state is:  %s\n", state));
358
359
    return state;
360
}
361
362
char *state_name(int i)
363
{
364
    if (i == -1) return "unknown";
365
    if (i == 0) return "sleeping";
366
    if (i == 1) return "active";
367
368
    return "internal error";
369
}
370
371
char *myctime(time_t time)
372
{
373
    char *ts = ctime(&time);
374
    ts[strlen(ts) - 1] = 0;
375
376
    return ts;
377
}
378
379
void measure(int fd)
380
{
381
    time_t start_time;
382
    int last_state;
383
    time_t last_time;
384
    int curr_state;
385
    time_t curr_time = 0;
386
    time_t time_diff;
387
    time_t active_time = 0;
388
    time_t sleep_time = 0;
389
    time_t unknown_time = 0;
390
    time_t total_time = 0;
391
    int changes = 0;
392
    float tmp;
393
394
    printf("Starting measurements\n");
395
396
    last_state = check_powermode(fd);
397
    start_time = last_time = time(0);
398
    printf("  System is in state %s\n\n", state_name(last_state));
399
400
    while(!endit) {
401
	sleep(1);
402
	curr_state = check_powermode(fd);
403
404
	if (curr_state != last_state || endit) {
405
	    changes++;
406
	    curr_time = time(0);
407
	    time_diff = curr_time - last_time;
408
409
	    if (last_state == 1) active_time += time_diff;
410
	    else if (last_state == 0) sleep_time += time_diff;
411
	    else unknown_time += time_diff;
412
413
	    last_state = curr_state;
414
	    last_time = curr_time;
415
416
	    printf("%s: State-change to %s\n", myctime(curr_time),
417
		   state_name(curr_state));
418
	}
419
    }
420
    changes--; /* Compensate for SIGINT */
421
422
    total_time = time(0) - start_time;
423
    printf("\nTotal running time:  %lus\n", curr_time - start_time);
424
    printf(" State changed %d times\n", changes);
425
426
    tmp = (float)sleep_time / (float)total_time * 100;
427
    printf(" Time in sleep state:   %lus (%.2f%%)\n", sleep_time, tmp);
428
    tmp = (float)active_time / (float)total_time * 100;
429
    printf(" Time in active state:  %lus (%.2f%%)\n", active_time, tmp);
430
    tmp = (float)unknown_time / (float)total_time * 100;
431
    printf(" Time in unknown state: %lus (%.2f%%)\n", unknown_time, tmp);
432
}
433
434
void ender(int s)
435
{
436
    endit = 1;
437
}
438
439
void usage()
440
{
441
    puts("usage: dslm [-w <time>] <disk>");
442
    exit(0);
443
}
444
445
int main(int ac, char **av)
446
{
447
    int fd;
448
    char *disk = 0;
449
    int settle_time = 60;
450
451
    /* Parse the simple command-line */
452
    if (ac == 2)
453
	disk = av[1];
454
    else if (ac == 4) {
455
	settle_time = atoi(av[2]);
456
	disk = av[3];
457
    } else
458
	usage();
459
460
    if (!(fd = open(disk, O_RDONLY|O_NONBLOCK))) {
461
	printf("Can't open %s, because: %s\n", disk, strerror(errno));
462
	exit(-1);
463
    }
464
465
    if (settle_time) {
466
	printf("Waiting %d seconds for the system to settle down to "
467
	       "'normal'\n", settle_time);
468
	sleep(settle_time);
469
    } else
470
	puts("Not waiting for system to settle down");
471
472
    signal(SIGINT, ender);
473
474
    measure(fd);
475
476
    close(fd);
477
478
    return 0;
479
}
480
---------------------------dslm.c END---------------------------------------------
(-)linux-2.6.3/drivers/block/ll_rw_blk.c (+22 lines)
Lines 27-32 Link Here
27
#include <linux/completion.h>
27
#include <linux/completion.h>
28
#include <linux/slab.h>
28
#include <linux/slab.h>
29
#include <linux/swap.h>
29
#include <linux/swap.h>
30
#include <linux/writeback.h>
30
31
31
static void blk_unplug_work(void *data);
32
static void blk_unplug_work(void *data);
32
static void blk_unplug_timeout(unsigned long data);
33
static void blk_unplug_timeout(unsigned long data);
Lines 2305-2310 Link Here
2305
		mod_page_state(pgpgout, count);
2306
		mod_page_state(pgpgout, count);
2306
	else
2307
	else
2307
		mod_page_state(pgpgin, count);
2308
		mod_page_state(pgpgin, count);
2309
2310
	if (unlikely(block_dump)) {
2311
		char b[BDEVNAME_SIZE];
2312
		printk("%s(%d): %s block %Lu on %s\n",
2313
			current->comm, current->pid,
2314
			(rw & WRITE) ? "WRITE" : "READ",
2315
			(unsigned long long)bio->bi_sector, bdevname(bio->bi_bdev,b));
2316
	}
2317
2308
	generic_make_request(bio);
2318
	generic_make_request(bio);
2309
	return 1;
2319
	return 1;
2310
}
2320
}
Lines 2592-2601 Link Here
2592
		unsigned long duration = jiffies - req->start_time;
2602
		unsigned long duration = jiffies - req->start_time;
2593
		switch (rq_data_dir(req)) {
2603
		switch (rq_data_dir(req)) {
2594
		    case WRITE:
2604
		    case WRITE:
2605
			/*
2606
			 * schedule the writeout of pending dirty data when the disk is idle.
2607
			 * (Writeback is not postponed by writes, only by reads.)
2608
			 */
2609
			if (unlikely(laptop_mode))
2610
				disk_is_spun_up(0);
2595
			disk_stat_inc(disk, writes);
2611
			disk_stat_inc(disk, writes);
2596
			disk_stat_add(disk, write_ticks, duration);
2612
			disk_stat_add(disk, write_ticks, duration);
2597
			break;
2613
			break;
2598
		    case READ:
2614
		    case READ:
2615
			/*
2616
			 * schedule the writeout of pending dirty data when the disk is idle.
2617
			 * (postpone writeback until system is quiescent again.)
2618
			 */
2619
			if (unlikely(laptop_mode))
2620
				disk_is_spun_up(1);
2599
			disk_stat_inc(disk, reads);
2621
			disk_stat_inc(disk, reads);
2600
			disk_stat_add(disk, read_ticks, duration);
2622
			disk_stat_add(disk, read_ticks, duration);
2601
			break;
2623
			break;
(-)linux-2.6.3/fs/buffer.c (-2 / +5 lines)
Lines 857-866 Link Here
857
		struct buffer_head *bh = head;
857
		struct buffer_head *bh = head;
858
858
859
		do {
859
		do {
860
			if (buffer_uptodate(bh))
860
			if (buffer_uptodate(bh)) {
861
				set_buffer_dirty(bh);
861
				set_buffer_dirty(bh);
862
			else
862
				if (unlikely(block_dump))
863
					printk("%s(%d): dirtied buffer\n", current->comm, current->pid);
864
			} else {
863
				buffer_error();
865
				buffer_error();
866
			}
864
			bh = bh->b_this_page;
867
			bh = bh->b_this_page;
865
		} while (bh != head);
868
		} while (bh != head);
866
	}
869
	}
(-)linux-2.6.3/include/linux/sysctl.h (+2 lines)
Lines 156-161 Link Here
156
	VM_SWAPPINESS=19,	/* Tendency to steal mapped memory */
156
	VM_SWAPPINESS=19,	/* Tendency to steal mapped memory */
157
	VM_LOWER_ZONE_PROTECTION=20,/* Amount of protection of lower zones */
157
	VM_LOWER_ZONE_PROTECTION=20,/* Amount of protection of lower zones */
158
	VM_MIN_FREE_KBYTES=21,	/* Minimum free kilobytes to maintain */
158
	VM_MIN_FREE_KBYTES=21,	/* Minimum free kilobytes to maintain */
159
	VM_LAPTOP_MODE=22,      /* vm laptop mode */
160
	VM_BLOCK_DUMP=23,       /* block dump mode */
159
};
161
};
160
162
161
163
(-)linux-2.6.3/include/linux/writeback.h (-1 / +4 lines)
Lines 71-82 Link Here
71
 * mm/page-writeback.c
71
 * mm/page-writeback.c
72
 */
72
 */
73
int wakeup_bdflush(long nr_pages);
73
int wakeup_bdflush(long nr_pages);
74
void disk_is_spun_up(int postpone_writeback);
74
75
75
/* These 5 are exported to sysctl. */
76
/* These are exported to sysctl. */
76
extern int dirty_background_ratio;
77
extern int dirty_background_ratio;
77
extern int vm_dirty_ratio;
78
extern int vm_dirty_ratio;
78
extern int dirty_writeback_centisecs;
79
extern int dirty_writeback_centisecs;
79
extern int dirty_expire_centisecs;
80
extern int dirty_expire_centisecs;
81
extern int block_dump;
82
extern int laptop_mode;
80
83
81
struct ctl_table;
84
struct ctl_table;
82
struct file;
85
struct file;
(-)linux-2.6.3/kernel/sysctl.c (+20 lines)
Lines 714-719 Link Here
714
		.strategy	= &sysctl_intvec,
714
		.strategy	= &sysctl_intvec,
715
		.extra1		= &zero,
715
		.extra1		= &zero,
716
	},
716
	},
717
	{
718
		.ctl_name	= VM_LAPTOP_MODE,
719
		.procname	= "laptop_mode",
720
		.data		= &laptop_mode,
721
		.maxlen		= sizeof(laptop_mode),
722
		.mode		= 0644,
723
		.proc_handler	= &proc_dointvec,
724
		.strategy	= &sysctl_intvec,
725
		.extra1		= &zero,
726
	},
727
	{
728
		.ctl_name	= VM_BLOCK_DUMP,
729
		.procname	= "block_dump",
730
		.data		= &block_dump,
731
		.maxlen		= sizeof(block_dump),
732
		.mode		= 0644,
733
		.proc_handler	= &proc_dointvec,
734
		.strategy	= &sysctl_intvec,
735
		.extra1		= &zero,
736
	},
717
	{ .ctl_name = 0 }
737
	{ .ctl_name = 0 }
718
};
738
};
719
739
(-)linux-2.6.3/mm/page-writeback.c (-6 / +60 lines)
Lines 28-33 Link Here
28
#include <linux/smp.h>
28
#include <linux/smp.h>
29
#include <linux/sysctl.h>
29
#include <linux/sysctl.h>
30
#include <linux/cpu.h>
30
#include <linux/cpu.h>
31
#include <linux/quotaops.h>
31
32
32
/*
33
/*
33
 * The maximum number of pages to writeout in a single bdflush/kupdate
34
 * The maximum number of pages to writeout in a single bdflush/kupdate
Lines 81-86 Link Here
81
 */
82
 */
82
int dirty_expire_centisecs = 30 * 100;
83
int dirty_expire_centisecs = 30 * 100;
83
84
85
/*
86
 * Flag that makes the machine dump writes/reads and block dirtyings.
87
 */
88
int block_dump;
89
90
/*
91
 * Flag that puts the machine in "laptop mode".
92
 */
93
int laptop_mode;
94
84
/* End of sysctl-exported parameters */
95
/* End of sysctl-exported parameters */
85
96
86
97
Lines 195-201 Link Here
195
	if (nr_reclaimable + ps.nr_writeback <= dirty_thresh)
206
	if (nr_reclaimable + ps.nr_writeback <= dirty_thresh)
196
		dirty_exceeded = 0;
207
		dirty_exceeded = 0;
197
208
198
	if (!writeback_in_progress(bdi) && nr_reclaimable > background_thresh)
209
	if (!unlikely(laptop_mode) && !writeback_in_progress(bdi) && nr_reclaimable > background_thresh)
199
		pdflush_operation(background_writeout, 0);
210
		pdflush_operation(background_writeout, 0);
200
}
211
}
201
212
Lines 289-295 Link Here
289
	return pdflush_operation(background_writeout, nr_pages);
300
	return pdflush_operation(background_writeout, nr_pages);
290
}
301
}
291
302
292
static struct timer_list wb_timer;
303
304
static void wb_timer_fn(unsigned long unused);
305
306
/*
307
 * Both timers share the same handler
308
 */
309
static struct timer_list wb_timer =
310
			TIMER_INITIALIZER(wb_timer_fn, 0, 0);
311
static struct timer_list laptop_mode_wb_timer =
312
			TIMER_INITIALIZER(wb_timer_fn, 0, 0);
313
293
314
294
/*
315
/*
295
 * Periodic writeback of "old" data.
316
 * Periodic writeback of "old" data.
Lines 328-333 Link Here
328
	oldest_jif = jiffies - (dirty_expire_centisecs * HZ) / 100;
349
	oldest_jif = jiffies - (dirty_expire_centisecs * HZ) / 100;
329
	start_jif = jiffies;
350
	start_jif = jiffies;
330
	next_jif = start_jif + (dirty_writeback_centisecs * HZ) / 100;
351
	next_jif = start_jif + (dirty_writeback_centisecs * HZ) / 100;
352
	if (laptop_mode)
353
		wbc.older_than_this = NULL;
331
	nr_to_write = ps.nr_dirty + ps.nr_unstable +
354
	nr_to_write = ps.nr_dirty + ps.nr_unstable +
332
			(inodes_stat.nr_inodes - inodes_stat.nr_unused);
355
			(inodes_stat.nr_inodes - inodes_stat.nr_unused);
333
	while (nr_to_write > 0) {
356
	while (nr_to_write > 0) {
Lines 346-353 Link Here
346
		next_jif = jiffies + HZ;
369
		next_jif = jiffies + HZ;
347
	if (dirty_writeback_centisecs)
370
	if (dirty_writeback_centisecs)
348
		mod_timer(&wb_timer, next_jif);
371
		mod_timer(&wb_timer, next_jif);
372
	del_timer(&laptop_mode_wb_timer); /* May have been set as a result of our writes. */
349
}
373
}
350
374
375
351
/*
376
/*
352
 * sysctl handler for /proc/sys/vm/dirty_writeback_centisecs
377
 * sysctl handler for /proc/sys/vm/dirty_writeback_centisecs
353
 */
378
 */
Lines 364-376 Link Here
364
	return 0;
389
	return 0;
365
}
390
}
366
391
392
static struct timer_list laptop_mode_wb_timer;
393
394
static void laptop_mode_wb_timer_fn(unsigned long unused)
395
{
396
	mod_timer(&wb_timer, jiffies);
397
}
398
399
/*
400
 * We've spun up the disk and we're in laptop mode: schedule writeback
401
 * of all dirty data in 5 seconds.
402
 *
403
 * Laptop mode writeback will be delayed if it has previously been
404
 * scheduled to occur within 5 seconds. That way, the writeback will
405
 * only be triggered if the system is truly quiet again.
406
 */
407
void disk_is_spun_up(int postpone_writeback)
408
{
409
	if (postpone_writeback || !timer_pending(&laptop_mode_wb_timer))
410
		mod_timer(&laptop_mode_wb_timer, jiffies + 5 * HZ);
411
}
412
413
414
/*
415
 * Handler for wb_timer and laptop_mode_wb_timer.
416
 */
367
static void wb_timer_fn(unsigned long unused)
417
static void wb_timer_fn(unsigned long unused)
368
{
418
{
369
	if (pdflush_operation(wb_kupdate, 0) < 0)
419
	if (pdflush_operation(wb_kupdate, 0) < 0)
370
		mod_timer(&wb_timer, jiffies + HZ); /* delay 1 second */
420
		mod_timer(&wb_timer, jiffies + HZ); /* delay 1 second */
371
372
}
421
}
373
422
423
374
/*
424
/*
375
 * If ratelimit_pages is too high then we can get into dirty-data overload
425
 * If ratelimit_pages is too high then we can get into dirty-data overload
376
 * if a large number of processes all perform writes at the same time.
426
 * if a large number of processes all perform writes at the same time.
Lines 430-440 Link Here
430
		vm_dirty_ratio /= 100;
480
		vm_dirty_ratio /= 100;
431
	}
481
	}
432
482
433
	init_timer(&wb_timer);
434
	wb_timer.expires = jiffies + (dirty_writeback_centisecs * HZ) / 100;
483
	wb_timer.expires = jiffies + (dirty_writeback_centisecs * HZ) / 100;
435
	wb_timer.data = 0;
436
	wb_timer.function = wb_timer_fn;
437
	add_timer(&wb_timer);
484
	add_timer(&wb_timer);
485
486
	init_timer(&laptop_mode_wb_timer);
487
	laptop_mode_wb_timer.data = 0;
488
	laptop_mode_wb_timer.function = laptop_mode_wb_timer_fn;
489
438
	set_ratelimit();
490
	set_ratelimit();
439
	register_cpu_notifier(&ratelimit_nb);
491
	register_cpu_notifier(&ratelimit_nb);
440
}
492
}
Lines 526-531 Link Here
526
				__mark_inode_dirty(mapping->host,
578
				__mark_inode_dirty(mapping->host,
527
							I_DIRTY_PAGES);
579
							I_DIRTY_PAGES);
528
		}
580
		}
581
		if (unlikely(block_dump))
582
			printk("%s(%d): dirtied page\n", current->comm, current->pid);
529
	}
583
	}
530
	return ret;
584
	return ret;
531
}
585
}

Return to bug 45593