]> git.pld-linux.org Git - packages/kernel.git/blob - laptop-mode-2.6.1-7.patch
- _rel 1.19,
[packages/kernel.git] / laptop-mode-2.6.1-7.patch
1 diff -Nbaur linux-2.6.1/Documentation/laptop-mode.txt linux-2.6.1-withlaptopmode/Documentation/laptop-mode.txt
2 --- linux-2.6.1/Documentation/laptop-mode.txt   1970-01-01 01:00:00.000000000 +0100
3 +++ linux-2.6.1-withlaptopmode/Documentation/laptop-mode.txt    2004-01-10 10:47:14.000000000 +0100
4 @@ -0,0 +1,475 @@
5 +How to conserve battery power using laptop-mode
6 +-----------------------------------------------
7 +
8 +Document Author: Bart Samwel (bart@samwel.tk)
9 +Date created: January 2, 2004
10 +
11 +Introduction
12 +------------
13 +
14 +Laptopmode is used to minimize the time that the hard disk needs to be spun up,
15 +to conserve battery power on laptops. It has been reported to cause significant
16 +power savings.
17 +
18 +Contents
19 +--------
20 +
21 +* Introduction
22 +* The short story
23 +* Caveats
24 +* The details
25 +* Tips & Tricks
26 +* Control script
27 +* ACPI integration
28 +* Monitoring tool
29 +
30 +
31 +The short story
32 +---------------
33 +
34 +If you just want to use it, run the laptop_mode control script (which is included
35 +at the end of this document) as follows:
36 +
37 +# laptop_mode start
38 +
39 +Then set your harddisk spindown time to a relatively low value with hdparm:
40 +
41 +hdparm -S 4 /dev/hda
42 +
43 +The value -S 4 means 20 seconds idle time before spindown. Your harddisk will
44 +now only spin up when a disk cache miss occurs, or at least once every 10
45 +minutes to write back any pending changes.
46 +
47 +To stop laptop_mode, remount your filesystems with regular commit intervals
48 +(e.g., 5 seconds), and run "laptop_mode stop".
49 +
50 +
51 +Caveats
52 +-------
53 +
54 +* The downside of laptop mode is that you have a chance of losing up
55 +  to 10 minutes of work. If you cannot afford this, don't use it!
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 +
70 +The details
71 +-----------
72 +
73 +Laptop-mode is controlled by the flag /proc/sys/vm/laptop_mode. When this
74 +flag is set, any physical disk read operation (that might have caused the
75 +hard disk to spin up) causes Linux to flush all dirty blocks. The result
76 +of this is that after a disk has spun down, it will not be spun up anymore
77 +to write dirty blocks, because those blocks had already been written
78 +immediately after the most recent read operation
79 +
80 +To increase the effectiveness of the laptop_mode strategy, the laptop_mode
81 +control script increases dirty_expire_centisecs and dirty_writeback_centisecs in
82 +/proc/sys/vm to about 10 minutes (by default), which means that pages that are
83 +dirtied are not forced to be written to disk as often. The control script also
84 +changes the dirty background ratio, so that background writeback of dirty pages
85 +is not done anymore. Combined with a higher commit value (also 10 minutes) for
86 +ext3 or ReiserFS filesystems (also done automatically by the control script),
87 +this results in concentration of disk activity in a small time interval which
88 +occurs only once every 10 minutes, or whenever the disk is forced to spin up by
89 +a cache miss. The disk can then be spun down in the periods of inactivity.
90 +
91 +If you want to find out which process caused the disk to spin up, you can
92 +gather information by setting the flag /proc/sys/vm/block_dump. When this flag
93 +is set, Linux reports all disk read and write operations that take place, and
94 +all block dirtyings done to files. This makes it possible to debug why a disk
95 +needs to spin up, and to increase battery life even more.
96 +
97 +If 10 minutes is too much or too little downtime for you, you can configure
98 +this downtime as follows. In the control script, set the MAX_AGE value to the
99 +maximum number of seconds of disk downtime that you would like. You should
100 +then set your filesystem's commit interval to the same value. The dirty ratio
101 +is also configurable from the control script.
102 +
103 +If you don't like the idea of the control script remounting your filesystems
104 +for you, you can change DO_REMOUNTS to 0 in the script.
105 +
106 +Thanks to Kiko Piris, the control script can be used to enable laptop mode on
107 +both the Linux 2.4 and 2.6 series.
108 +
109 +
110 +Tips & Tricks
111 +-------------
112 +
113 +* Bartek Kania reports getting up to 50 minutes of extra battery life (on top
114 +  of his regular 3 to 3.5 hours) using very aggressive power management (hdparm
115 +  -B1) and a spindown time of 5 seconds (hdparm -S1).
116 +
117 +* You can spin down the disk while playing MP3, by setting the disk readahead
118 +  to 8MB (hdparm -a 16384). Effectively, the disk will read a complete MP3 at
119 +  once, and will then spin down while the MP3 is playing. (Thanks to Bartek
120 +  Kania.)
121 +
122 +
123 +Control script
124 +--------------
125 +
126 +Please note that this control script works for the Linux 2.4 and 2.6 series.
127 +
128 +--------------------CONTROL SCRIPT BEGIN------------------------------------------
129 +#!/bin/sh
130 +
131 +# start or stop laptop_mode, best run by a power management daemon when
132 +# ac gets connected/disconnected from a laptop
133 +#
134 +# install as /sbin/laptop_mode
135 +#
136 +# Contributors to this script:   Kiko Piris
137 +#                               Bart Samwel
138 +#                               Dax Kelson
139 +# Original Linux 2.4 version by: Jens Axboe
140 +
141 +parse_mount_opts () {
142 +       echo "$*"                       | \
143 +       sed 's/.*/,&,/g'                | \
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 "Usage: $0 {start|stop}"
251 +               ;;
252 +
253 +esac
254 +
255 +exit 0
256 +--------------------CONTROL SCRIPT END--------------------------------------------
257 +
258 +
259 +ACPI integration
260 +----------------
261 +
262 +Dax Kelson submitted this so that the ACPI acpid daemon will
263 +kick off the laptop_mode script and run hdparm.
264 +
265 +---------------------------/etc/acpi/events/ac_adapter BEGIN-------------------------------------------
266 +event=ac_adapter
267 +action=/etc/acpi/actions/battery.sh
268 +---------------------------/etc/acpi/events/ac_adapter END-------------------------------------------
269 +
270 +---------------------------/etc/acpi/actions/battery.sh BEGIN-------------------------------------------
271 +#!/bin/sh
272 +
273 +# cpu throttling
274 +# cat /proc/acpi/processor/CPU0/throttling for more info
275 +ACAD_THR=0
276 +BATT_THR=2
277 +
278 +# spindown time for HD (man hdparm for valid values)
279 +# I prefer 2 hours for acad and 20 seconds for batt
280 +ACAD_HD=244
281 +BATT_HD=4
282
283 +# ac/battery event handler
284
285 +status=`awk '/^state: / { print $2 }' /proc/acpi/ac_adapter/AC/state`
286
287 +case $status in
288 +        "on-line")
289 +                echo "Setting HD spindown to 2 hours"
290 +                /sbin/laptop-mode stop
291 +                /sbin/hdparm -S $ACAD_HD /dev/hda > /dev/null 2>&1
292 +                /sbin/hdparm -B 255 /dev/hda > /dev/null 2>&1
293 +                #echo -n $ACAD_CPU:$ACAD_THR > /proc/acpi/processor/CPU0/limit
294 +                exit 0
295 +        ;;
296 +        "off-line")
297 +                echo "Setting HD spindown to 20 seconds"
298 +                /sbin/laptop-mode start
299 +                /sbin/hdparm -S $BATT_HD /dev/hda > /dev/null 2>&1
300 +                /sbin/hdparm -B 1 /dev/hda > /dev/null 2>&1
301 +                #echo -n $BATT_CPU:$BATT_THR > /proc/acpi/processor/CPU0/limit
302 +                exit 0
303 +        ;;
304 +esac
305 +---------------------------/etc/acpi/actions/battery.sh END-------------------------------------------
306 +
307 +Monitoring tool
308 +---------------
309 +
310 +Bartek Kania submitted this, it can be used to measure how much time your disk
311 +spends spun up/down.
312 +
313 +---------------------------dslm.c BEGIN-------------------------------------------
314 +/*
315 + * Simple Disk SLeep Monitor
316 + *  by Bartek Kania
317 + * Licenced under the GPL
318 + */
319 +#include <unistd.h>
320 +#include <stdlib.h>
321 +#include <stdio.h>
322 +#include <fcntl.h>
323 +#include <errno.h>
324 +#include <time.h>
325 +#include <string.h>
326 +#include <signal.h>
327 +#include <sys/ioctl.h>
328 +#include <linux/hdreg.h>
329 +
330 +#ifdef DEBUG
331 +#define D(x) x
332 +#else
333 +#define D(x)
334 +#endif
335 +
336 +int endit = 0;
337 +
338 +/* Check if the disk is in powersave-mode
339 + * Most of the code is stolen from hdparm.
340 + * 1 = active, 0 = standby/sleep, -1 = unknown */
341 +int check_powermode(int fd)
342 +{
343 +    unsigned char args[4] = {WIN_CHECKPOWERMODE1,0,0,0};
344 +    int state;
345 +
346 +    if (ioctl(fd, HDIO_DRIVE_CMD, &args)
347 +       && (args[0] = WIN_CHECKPOWERMODE2) /* try again with 0x98 */
348 +       && ioctl(fd, HDIO_DRIVE_CMD, &args)) {
349 +       if (errno != EIO || args[0] != 0 || args[1] != 0) {
350 +           state = -1; /* "unknown"; */
351 +       } else
352 +           state = 0; /* "sleeping"; */
353 +    } else {
354 +       state = (args[2] == 255) ? 1 : 0; 
355 +    }
356 +    D(printf(" drive state is:  %s\n", state));
357 +
358 +    return state;
359 +}
360 +
361 +char *state_name(int i)
362 +{
363 +    if (i == -1) return "unknown";
364 +    if (i == 0) return "sleeping";
365 +    if (i == 1) return "active";
366 +
367 +    return "internal error";
368 +}
369 +
370 +char *myctime(time_t time)
371 +{
372 +    char *ts = ctime(&time);
373 +    ts[strlen(ts) - 1] = 0;
374 +
375 +    return ts;
376 +}
377 +
378 +void measure(int fd)
379 +{
380 +    time_t start_time;
381 +    int last_state;  
382 +    time_t last_time;
383 +    int curr_state;
384 +    time_t curr_time = 0;
385 +    time_t time_diff;
386 +    time_t active_time = 0;
387 +    time_t sleep_time = 0;
388 +    time_t unknown_time = 0;
389 +    time_t total_time = 0;
390 +    int changes = 0;
391 +    float tmp;
392 +
393 +    printf("Starting measurements\n");
394 +
395 +    last_state = check_powermode(fd);
396 +    start_time = last_time = time(0);
397 +    printf("  System is in state %s\n\n", state_name(last_state));
398 +
399 +    while(!endit) {
400 +       sleep(1);
401 +       curr_state = check_powermode(fd);
402 +
403 +       if (curr_state != last_state || endit) {
404 +           changes++;
405 +           curr_time = time(0);
406 +           time_diff = curr_time - last_time;
407 +
408 +           if (last_state == 1) active_time += time_diff;
409 +           else if (last_state == 0) sleep_time += time_diff;
410 +           else unknown_time += time_diff;     
411 +
412 +           last_state = curr_state;
413 +           last_time = curr_time;
414 +
415 +           printf("%s: State-change to %s\n", myctime(curr_time),
416 +                  state_name(curr_state));
417 +       }
418 +    }
419 +    changes--; /* Compensate for SIGINT */
420 +
421 +    total_time = time(0) - start_time;
422 +    printf("\nTotal running time:  %lus\n", curr_time - start_time);
423 +    printf(" State changed %d times\n", changes);
424 +
425 +    tmp = (float)sleep_time / (float)total_time * 100;
426 +    printf(" Time in sleep state:   %lus (%.2f%%)\n", sleep_time, tmp);
427 +    tmp = (float)active_time / (float)total_time * 100;
428 +    printf(" Time in active state:  %lus (%.2f%%)\n", active_time, tmp);
429 +    tmp = (float)unknown_time / (float)total_time * 100;
430 +    printf(" Time in unknown state: %lus (%.2f%%)\n", unknown_time, tmp);
431 +}
432 +
433 +void ender(int s)
434 +{
435 +    endit = 1;
436 +}
437 +
438 +void usage()
439 +{
440 +    puts("usage: dslm [-w <time>] <disk>");
441 +    exit(0);
442 +}
443 +
444 +int main(int ac, char **av)
445 +{
446 +    int fd;
447 +    char *disk = 0;
448 +    int settle_time = 60;
449 +
450 +    /* Parse the simple command-line */
451 +    if (ac == 2) 
452 +       disk = av[1];
453 +    else if (ac == 4) {
454 +       settle_time = atoi(av[2]);
455 +       disk = av[3];
456 +    } else
457 +       usage();
458 +       
459 +    if (!(fd = open(disk, O_RDONLY|O_NONBLOCK))) {
460 +       printf("Can't open %s, because: %s\n", disk, strerror(errno));
461 +       exit(-1);
462 +    }
463 +
464 +    if (settle_time) {
465 +       printf("Waiting %d seconds for the system to settle down to "
466 +              "'normal'\n", settle_time);
467 +       sleep(settle_time);
468 +    } else
469 +       puts("Not waiting for system to settle down");
470 +
471 +    signal(SIGINT, ender);
472 +
473 +    measure(fd);
474 +
475 +    close(fd);
476 +
477 +    return 0;
478 +}
479 +---------------------------dslm.c END---------------------------------------------
480 diff -Nbaur linux-2.6.1/drivers/block/ll_rw_blk.c linux-2.6.1-withlaptopmode/drivers/block/ll_rw_blk.c
481 --- linux-2.6.1/drivers/block/ll_rw_blk.c       2004-01-09 20:29:05.000000000 +0100
482 +++ linux-2.6.1-withlaptopmode/drivers/block/ll_rw_blk.c        2004-01-09 20:29:39.000000000 +0100
483 @@ -27,6 +27,7 @@
484  #include <linux/completion.h>
485  #include <linux/slab.h>
486  #include <linux/swap.h>
487 +#include <linux/writeback.h>
488  
489  static void blk_unplug_work(void *data);
490  static void blk_unplug_timeout(unsigned long data);
491 @@ -2302,6 +2303,15 @@
492                 mod_page_state(pgpgout, count);
493         else
494                 mod_page_state(pgpgin, count);
495 +
496 +       if (unlikely(block_dump)) {
497 +               char b[BDEVNAME_SIZE];
498 +               printk("%s(%d): %s block %Lu on %s\n",
499 +                       current->comm, current->pid,
500 +                       (rw & WRITE) ? "WRITE" : "READ",
501 +                       (unsigned long long)bio->bi_sector, bdevname(bio->bi_bdev,b));
502 +       }
503 +
504         generic_make_request(bio);
505         return 1;
506  }
507 @@ -2593,6 +2603,12 @@
508                         disk_stat_add(disk, write_ticks, duration);
509                         break;
510                     case READ:
511 +                       /*
512 +                        * schedule the writeout of pending dirty data when the disk is idle.
513 +                        * (postpone writeback until system is quiescent again.)
514 +                        */
515 +                       if (unlikely(laptop_mode))
516 +                               disk_is_spun_up(1);
517                         disk_stat_inc(disk, reads);
518                         disk_stat_add(disk, read_ticks, duration);
519                         break;
520 diff -Nbaur linux-2.6.1/fs/buffer.c linux-2.6.1-withlaptopmode/fs/buffer.c
521 --- linux-2.6.1/fs/buffer.c     2004-01-09 20:29:10.000000000 +0100
522 +++ linux-2.6.1-withlaptopmode/fs/buffer.c      2004-01-09 20:29:45.000000000 +0100
523 @@ -855,10 +855,13 @@
524                 struct buffer_head *bh = head;
525  
526                 do {
527 -                       if (buffer_uptodate(bh))
528 +                       if (buffer_uptodate(bh)) {
529                                 set_buffer_dirty(bh);
530 -                       else
531 +                               if (unlikely(block_dump))
532 +                                       printk("%s(%d): dirtied buffer\n", current->comm, current->pid);
533 +                       } else {
534                                 buffer_error();
535 +                       }
536                         bh = bh->b_this_page;
537                 } while (bh != head);
538         }
539 diff -Nbaur linux-2.6.1/include/linux/sysctl.h linux-2.6.1-withlaptopmode/include/linux/sysctl.h
540 --- linux-2.6.1/include/linux/sysctl.h  2004-01-09 20:29:10.000000000 +0100
541 +++ linux-2.6.1-withlaptopmode/include/linux/sysctl.h   2004-01-09 20:29:46.000000000 +0100
542 @@ -154,6 +154,8 @@
543         VM_SWAPPINESS=19,       /* Tendency to steal mapped memory */
544         VM_LOWER_ZONE_PROTECTION=20,/* Amount of protection of lower zones */
545         VM_MIN_FREE_KBYTES=21,  /* Minimum free kilobytes to maintain */
546 +       VM_LAPTOP_MODE=22,      /* vm laptop mode */
547 +       VM_BLOCK_DUMP=23,       /* block dump mode */
548  };
549  
550  
551 diff -Nbaur linux-2.6.1/include/linux/writeback.h linux-2.6.1-withlaptopmode/include/linux/writeback.h
552 --- linux-2.6.1/include/linux/writeback.h       2003-12-24 05:19:46.000000000 +0100
553 +++ linux-2.6.1-withlaptopmode/include/linux/writeback.h        2004-01-04 12:10:58.000000000 +0100
554 @@ -71,12 +71,15 @@
555   * mm/page-writeback.c
556   */
557  int wakeup_bdflush(long nr_pages);
558 +void disk_is_spun_up(int postpone_writeback);
559  
560 -/* These 5 are exported to sysctl. */
561 +/* These are exported to sysctl. */
562  extern int dirty_background_ratio;
563  extern int vm_dirty_ratio;
564  extern int dirty_writeback_centisecs;
565  extern int dirty_expire_centisecs;
566 +extern int block_dump;
567 +extern int laptop_mode;
568  
569  struct ctl_table;
570  struct file;
571 diff -Nbaur linux-2.6.1/kernel/sysctl.c linux-2.6.1-withlaptopmode/kernel/sysctl.c
572 --- linux-2.6.1/kernel/sysctl.c 2003-12-24 05:19:46.000000000 +0100
573 +++ linux-2.6.1-withlaptopmode/kernel/sysctl.c  2003-12-24 06:24:53.000000000 +0100
574 @@ -700,6 +700,26 @@
575                 .strategy       = &sysctl_intvec,
576                 .extra1         = &zero,
577         },
578 +       {
579 +               .ctl_name       = VM_LAPTOP_MODE,
580 +               .procname       = "laptop_mode",
581 +               .data           = &laptop_mode,
582 +               .maxlen         = sizeof(laptop_mode),
583 +               .mode           = 0644,
584 +               .proc_handler   = &proc_dointvec,
585 +               .strategy       = &sysctl_intvec,
586 +               .extra1         = &zero,
587 +       },
588 +       {
589 +               .ctl_name       = VM_BLOCK_DUMP,
590 +               .procname       = "block_dump",
591 +               .data           = &block_dump,
592 +               .maxlen         = sizeof(block_dump),
593 +               .mode           = 0644,
594 +               .proc_handler   = &proc_dointvec,
595 +               .strategy       = &sysctl_intvec,
596 +               .extra1         = &zero,
597 +       },
598         { .ctl_name = 0 }
599  };
600  
601 diff -Nbaur linux-2.6.1/mm/page-writeback.c linux-2.6.1-withlaptopmode/mm/page-writeback.c
602 --- linux-2.6.1/mm/page-writeback.c     2003-12-24 05:19:46.000000000 +0100
603 +++ linux-2.6.1-withlaptopmode/mm/page-writeback.c      2004-01-04 17:50:03.000000000 +0100
604 @@ -28,6 +28,7 @@
605  #include <linux/smp.h>
606  #include <linux/sysctl.h>
607  #include <linux/cpu.h>
608 +#include <linux/quotaops.h>
609  
610  /*
611   * The maximum number of pages to writeout in a single bdflush/kupdate
612 @@ -81,6 +82,16 @@
613   */
614  int dirty_expire_centisecs = 30 * 100;
615  
616 +/*
617 + * Flag that makes the machine dump writes/reads and block dirtyings.
618 + */
619 +int block_dump;
620 +
621 +/*
622 + * Flag that puts the machine in "laptop mode".
623 + */
624 +int laptop_mode;
625 +
626  /* End of sysctl-exported parameters */
627  
628  
629 @@ -195,7 +206,18 @@
630         if (nr_reclaimable + ps.nr_writeback <= dirty_thresh)
631                 dirty_exceeded = 0;
632  
633 -       if (!writeback_in_progress(bdi) && nr_reclaimable > background_thresh)
634 +       if (unlikely(laptop_mode) && pages_written > 0) {
635 +               /*
636 +                * Schedule full writeout to happen soon. We don't postpone
637 +                * previously scheduled full writeouts, otherwise a writing
638 +                * process throttled by balance_dirty_pages will be able to
639 +                * postpone the full writeout indefinitely, keeping the disk
640 +                * spun up as a result.
641 +                */
642 +               disk_is_spun_up(0);
643 +       }
644 +
645 +       if (!unlikely(laptop_mode) && !writeback_in_progress(bdi) && nr_reclaimable > background_thresh)
646                 pdflush_operation(background_writeout, 0);
647  }
648  
649 @@ -327,6 +349,8 @@
650         oldest_jif = jiffies - (dirty_expire_centisecs * HZ) / 100;
651         start_jif = jiffies;
652         next_jif = start_jif + (dirty_writeback_centisecs * HZ) / 100;
653 +       if (laptop_mode)
654 +               wbc.older_than_this = NULL;
655         nr_to_write = ps.nr_dirty + ps.nr_unstable +
656                         (inodes_stat.nr_inodes - inodes_stat.nr_unused);
657         while (nr_to_write > 0) {
658 @@ -343,6 +367,11 @@
659         }
660         if (time_before(next_jif, jiffies + HZ))
661                 next_jif = jiffies + HZ;
662 +       if (laptop_mode) {
663 +               sync_inodes(0);
664 +               sync_filesystems(0);
665 +               DQUOT_SYNC(NULL);
666 +       }
667         if (dirty_writeback_centisecs)
668                 mod_timer(&wb_timer, next_jif);
669  }
670 @@ -363,6 +392,28 @@
671         return 0;
672  }
673  
674 +static struct timer_list laptop_mode_wb_timer;
675 +
676 +static void laptop_mode_wb_timer_fn(unsigned long unused)
677 +{
678 +       mod_timer(&wb_timer, jiffies);
679 +}
680 +
681 +/*
682 + * We've spun up the disk and we're in laptop mode: schedule writeback
683 + * of all dirty data in 5 seconds.
684 + *
685 + * Laptop mode writeback will be delayed if it has previously been
686 + * scheduled to occur within 5 seconds. That way, the writeback will
687 + * only be triggered if the system is truly quiet again.
688 + */
689 +void disk_is_spun_up(int postpone_writeback)
690 +{
691 +       if (postpone_writeback || !timer_pending(&laptop_mode_wb_timer))
692 +               mod_timer(&laptop_mode_wb_timer, jiffies + 5 * HZ);
693 +}
694 +
695 +
696  static void wb_timer_fn(unsigned long unused)
697  {
698         if (pdflush_operation(wb_kupdate, 0) < 0)
699 @@ -434,6 +485,11 @@
700         wb_timer.data = 0;
701         wb_timer.function = wb_timer_fn;
702         add_timer(&wb_timer);
703 +
704 +       init_timer(&laptop_mode_wb_timer);
705 +       laptop_mode_wb_timer.data = 0;
706 +       laptop_mode_wb_timer.function = laptop_mode_wb_timer_fn;
707 +
708         set_ratelimit();
709         register_cpu_notifier(&ratelimit_nb);
710  }
711 @@ -525,6 +581,8 @@
712                                 __mark_inode_dirty(mapping->host,
713                                                         I_DIRTY_PAGES);
714                 }
715 +               if (unlikely(block_dump))
716 +                       printk("%s(%d): dirtied page\n", current->comm, current->pid);
717         }
718         return ret;
719  }
This page took 0.09521 seconds and 3 git commands to generate.