]> git.pld-linux.org Git - packages/kernel.git/commitdiff
260040cbae7ceb420ea293fac4f4e416 laptop-mode-2.6.1-7.patch
authorcieciwa <cieciwa@pld-linux.org>
Sat, 10 Jan 2004 13:58:57 +0000 (13:58 +0000)
committercvs2git <feedback@pld-linux.org>
Sun, 24 Jun 2012 12:13:13 +0000 (12:13 +0000)
Changed files:
    laptop-mode-2.6.1-7.patch -> 1.1

laptop-mode-2.6.1-7.patch [new file with mode: 0644]

diff --git a/laptop-mode-2.6.1-7.patch b/laptop-mode-2.6.1-7.patch
new file mode 100644 (file)
index 0000000..06ca7a0
--- /dev/null
@@ -0,0 +1,719 @@
+diff -Nbaur linux-2.6.1/Documentation/laptop-mode.txt linux-2.6.1-withlaptopmode/Documentation/laptop-mode.txt
+--- linux-2.6.1/Documentation/laptop-mode.txt  1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.1-withlaptopmode/Documentation/laptop-mode.txt   2004-01-10 10:47:14.000000000 +0100
+@@ -0,0 +1,475 @@
++How to conserve battery power using laptop-mode
++-----------------------------------------------
++
++Document Author: Bart Samwel (bart@samwel.tk)
++Date created: January 2, 2004
++
++Introduction
++------------
++
++Laptopmode is used to minimize the time that the hard disk needs to be spun up,
++to conserve battery power on laptops. It has been reported to cause significant
++power savings.
++
++Contents
++--------
++
++* Introduction
++* The short story
++* Caveats
++* The details
++* Tips & Tricks
++* Control script
++* ACPI integration
++* Monitoring tool
++
++
++The short story
++---------------
++
++If you just want to use it, run the laptop_mode control script (which is included
++at the end of this document) as follows:
++
++# laptop_mode start
++
++Then set your harddisk spindown time to a relatively low value with hdparm:
++
++hdparm -S 4 /dev/hda
++
++The value -S 4 means 20 seconds idle time before spindown. Your harddisk will
++now only spin up when a disk cache miss occurs, or at least once every 10
++minutes to write back any pending changes.
++
++To stop laptop_mode, remount your filesystems with regular commit intervals
++(e.g., 5 seconds), and run "laptop_mode stop".
++
++
++Caveats
++-------
++
++* The downside of laptop mode is that you have a chance of losing up
++  to 10 minutes of work. If you cannot afford this, don't use it!
++
++* Most desktop hard drives have a very limited lifetime measured in spindown
++  cycles, typically about 50.000 times (it's usually listed on the spec sheet).
++  Check your drive's rating, and don't wear down your drive's lifetime if you
++  don't need to.
++
++* If you mount some of your ext3/reiserfs filesystems with the -n option, then
++  the control script will not be able to remount them correctly. You must set
++  DO_REMOUNTS=0 in the control script, otherwise it will remount them with the
++  wrong options -- or it will fail because it cannot write to /etc/mtab.
++
++* If you have your filesystems listed as type "auto" in fstab, like I did, then
++  the control script will not recognize them as filesystems that need remounting.
++
++The details
++-----------
++
++Laptop-mode is controlled by the flag /proc/sys/vm/laptop_mode. When this
++flag is set, any physical disk read operation (that might have caused the
++hard disk to spin up) causes Linux to flush all dirty blocks. The result
++of this is that after a disk has spun down, it will not be spun up anymore
++to write dirty blocks, because those blocks had already been written
++immediately after the most recent read operation
++
++To increase the effectiveness of the laptop_mode strategy, the laptop_mode
++control script increases dirty_expire_centisecs and dirty_writeback_centisecs in
++/proc/sys/vm to about 10 minutes (by default), which means that pages that are
++dirtied are not forced to be written to disk as often. The control script also
++changes the dirty background ratio, so that background writeback of dirty pages
++is not done anymore. Combined with a higher commit value (also 10 minutes) for
++ext3 or ReiserFS filesystems (also done automatically by the control script),
++this results in concentration of disk activity in a small time interval which
++occurs only once every 10 minutes, or whenever the disk is forced to spin up by
++a cache miss. The disk can then be spun down in the periods of inactivity.
++
++If you want to find out which process caused the disk to spin up, you can
++gather information by setting the flag /proc/sys/vm/block_dump. When this flag
++is set, Linux reports all disk read and write operations that take place, and
++all block dirtyings done to files. This makes it possible to debug why a disk
++needs to spin up, and to increase battery life even more.
++
++If 10 minutes is too much or too little downtime for you, you can configure
++this downtime as follows. In the control script, set the MAX_AGE value to the
++maximum number of seconds of disk downtime that you would like. You should
++then set your filesystem's commit interval to the same value. The dirty ratio
++is also configurable from the control script.
++
++If you don't like the idea of the control script remounting your filesystems
++for you, you can change DO_REMOUNTS to 0 in the script.
++
++Thanks to Kiko Piris, the control script can be used to enable laptop mode on
++both the Linux 2.4 and 2.6 series.
++
++
++Tips & Tricks
++-------------
++
++* Bartek Kania reports getting up to 50 minutes of extra battery life (on top
++  of his regular 3 to 3.5 hours) using very aggressive power management (hdparm
++  -B1) and a spindown time of 5 seconds (hdparm -S1).
++
++* You can spin down the disk while playing MP3, by setting the disk readahead
++  to 8MB (hdparm -a 16384). Effectively, the disk will read a complete MP3 at
++  once, and will then spin down while the MP3 is playing. (Thanks to Bartek
++  Kania.)
++
++
++Control script
++--------------
++
++Please note that this control script works for the Linux 2.4 and 2.6 series.
++
++--------------------CONTROL SCRIPT BEGIN------------------------------------------
++#!/bin/sh
++
++# 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
++#                              Dax Kelson
++# Original Linux 2.4 version by: Jens Axboe
++
++parse_mount_opts () {
++      echo "$*"                       | \
++      sed 's/.*/,&,/g'                | \
++      sed 's/,commit=[0-9]*,/,/g'     | \
++      sed 's/,,*/,/g'                 | \
++      sed 's/^,//'                    | \
++      sed 's/,$//'                    | \
++      cat -
++}
++
++KLEVEL="$(uname -r | cut -c1-3)"
++case "$KLEVEL" in
++      "2.4")
++              true
++              ;;
++      "2.6")
++              true
++              ;;
++      *)
++              echo "Unhandled kernel level: $KLEVEL ('uname -r' = '$(uname -r)')"
++              exit 1
++              ;;
++esac
++
++# Shall we remount journaled fs. with appropiate commit interval? (1=yes)
++DO_REMOUNTS=1
++
++# age time, in seconds. should be put into a sysconfig file
++MAX_AGE=600
++
++# Allowed dirty ratio, in pct. should be put into a sysconfig file as well.
++DIRTY_RATIO=40
++
++# kernel default dirty buffer age
++DEF_AGE=30
++DEF_UPDATE=5
++DEF_DIRTY_BACKGROUND_RATIO=10
++DEF_DIRTY_RATIO=40
++
++
++if [ ! -e /proc/sys/vm/laptop_mode ]; then
++      echo "Kernel is not patched with laptop_mode patch."
++      exit 1
++fi
++
++if [ ! -w /proc/sys/vm/laptop_mode ]; then
++      echo "You do not have enough privileges to enable laptop_mode."
++      exit 1
++fi
++
++case "$1" in
++      start)
++              AGE=$((100*$MAX_AGE))
++              echo -n "Starting laptop_mode"
++              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 "1"                                > /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_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")"
++                              case "$FST" in
++                                      "ext3")         mount $DEV -t $FST $MP -o remount,$PARSEDOPTS,commit=$MAX_AGE ;;
++                                      "reiserfs")     mount $DEV -t $FST $MP -o remount,$PARSEDOPTS,commit=$MAX_AGE ;;
++                                      "xfs")          mount $DEV -t $FST $MP -o remount,$PARSEDOPTS,commit=$MAX_AGE ;;
++                              esac
++                      done
++              fi
++              echo "."
++              ;;
++      stop)
++              U_AGE=$((100*$DEF_UPDATE))
++              B_AGE=$((100*$DEF_AGE))
++              echo -n "Stopping laptop_mode"
++              case "$KLEVEL" in
++                      "2.4")
++                              echo "0"                                > /proc/sys/vm/laptop_mode
++                              echo "30 500 0 0 $U_AGE $B_AGE 60 20 0" > /proc/sys/vm/bdflush
++                              ;;
++                      "2.6")
++                              echo "0"                                > /proc/sys/vm/laptop_mode
++                              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
++                              PARSEDOPTS="$(parse_mount_opts "$OPTS")"
++                              case "$FST" in
++                                      "ext3")         mount $DEV -t $FST $MP -o remount,$PARSEDOPTS ;;
++                                      "reiserfs")     mount $DEV -t $FST $MP -o remount,$PARSEDOPTS ;;
++                                      "xfs")          mount $DEV -t $FST $MP -o remount,$PARSEDOPTS ;;
++                              esac
++                      done
++              fi
++              echo "."
++              ;;
++      *)
++              echo "Usage: $0 {start|stop}"
++              ;;
++
++esac
++
++exit 0
++--------------------CONTROL SCRIPT END--------------------------------------------
++
++
++ACPI integration
++----------------
++
++Dax Kelson submitted this so that the ACPI acpid daemon will
++kick off the laptop_mode script and run hdparm.
++
++---------------------------/etc/acpi/events/ac_adapter BEGIN-------------------------------------------
++event=ac_adapter
++action=/etc/acpi/actions/battery.sh
++---------------------------/etc/acpi/events/ac_adapter END-------------------------------------------
++
++---------------------------/etc/acpi/actions/battery.sh BEGIN-------------------------------------------
++#!/bin/sh
++
++# cpu throttling
++# cat /proc/acpi/processor/CPU0/throttling for more info
++ACAD_THR=0
++BATT_THR=2
++
++# spindown time for HD (man hdparm for valid values)
++# I prefer 2 hours for acad and 20 seconds for batt
++ACAD_HD=244
++BATT_HD=4
++ 
++# ac/battery event handler
++ 
++status=`awk '/^state: / { print $2 }' /proc/acpi/ac_adapter/AC/state`
++ 
++case $status in
++        "on-line")
++                echo "Setting HD spindown to 2 hours"
++                /sbin/laptop-mode stop
++                /sbin/hdparm -S $ACAD_HD /dev/hda > /dev/null 2>&1
++                /sbin/hdparm -B 255 /dev/hda > /dev/null 2>&1
++                #echo -n $ACAD_CPU:$ACAD_THR > /proc/acpi/processor/CPU0/limit
++                exit 0
++        ;;
++        "off-line")
++                echo "Setting HD spindown to 20 seconds"
++                /sbin/laptop-mode start
++                /sbin/hdparm -S $BATT_HD /dev/hda > /dev/null 2>&1
++                /sbin/hdparm -B 1 /dev/hda > /dev/null 2>&1
++                #echo -n $BATT_CPU:$BATT_THR > /proc/acpi/processor/CPU0/limit
++                exit 0
++        ;;
++esac
++---------------------------/etc/acpi/actions/battery.sh END-------------------------------------------
++
++Monitoring tool
++---------------
++
++Bartek Kania submitted this, it can be used to measure how much time your disk
++spends spun up/down.
++
++---------------------------dslm.c BEGIN-------------------------------------------
++/*
++ * Simple Disk SLeep Monitor
++ *  by Bartek Kania
++ * Licenced under the GPL
++ */
++#include <unistd.h>
++#include <stdlib.h>
++#include <stdio.h>
++#include <fcntl.h>
++#include <errno.h>
++#include <time.h>
++#include <string.h>
++#include <signal.h>
++#include <sys/ioctl.h>
++#include <linux/hdreg.h>
++
++#ifdef DEBUG
++#define D(x) x
++#else
++#define D(x)
++#endif
++
++int endit = 0;
++
++/* Check if the disk is in powersave-mode
++ * Most of the code is stolen from hdparm.
++ * 1 = active, 0 = standby/sleep, -1 = unknown */
++int check_powermode(int fd)
++{
++    unsigned char args[4] = {WIN_CHECKPOWERMODE1,0,0,0};
++    int state;
++
++    if (ioctl(fd, HDIO_DRIVE_CMD, &args)
++      && (args[0] = WIN_CHECKPOWERMODE2) /* try again with 0x98 */
++      && ioctl(fd, HDIO_DRIVE_CMD, &args)) {
++      if (errno != EIO || args[0] != 0 || args[1] != 0) {
++          state = -1; /* "unknown"; */
++      } else
++          state = 0; /* "sleeping"; */
++    } else {
++      state = (args[2] == 255) ? 1 : 0; 
++    }
++    D(printf(" drive state is:  %s\n", state));
++
++    return state;
++}
++
++char *state_name(int i)
++{
++    if (i == -1) return "unknown";
++    if (i == 0) return "sleeping";
++    if (i == 1) return "active";
++
++    return "internal error";
++}
++
++char *myctime(time_t time)
++{
++    char *ts = ctime(&time);
++    ts[strlen(ts) - 1] = 0;
++
++    return ts;
++}
++
++void measure(int fd)
++{
++    time_t start_time;
++    int last_state;  
++    time_t last_time;
++    int curr_state;
++    time_t curr_time = 0;
++    time_t time_diff;
++    time_t active_time = 0;
++    time_t sleep_time = 0;
++    time_t unknown_time = 0;
++    time_t total_time = 0;
++    int changes = 0;
++    float tmp;
++
++    printf("Starting measurements\n");
++
++    last_state = check_powermode(fd);
++    start_time = last_time = time(0);
++    printf("  System is in state %s\n\n", state_name(last_state));
++
++    while(!endit) {
++      sleep(1);
++      curr_state = check_powermode(fd);
++
++      if (curr_state != last_state || endit) {
++          changes++;
++          curr_time = time(0);
++          time_diff = curr_time - last_time;
++
++          if (last_state == 1) active_time += time_diff;
++          else if (last_state == 0) sleep_time += time_diff;
++          else unknown_time += time_diff;     
++
++          last_state = curr_state;
++          last_time = curr_time;
++
++          printf("%s: State-change to %s\n", myctime(curr_time),
++                 state_name(curr_state));
++      }
++    }
++    changes--; /* Compensate for SIGINT */
++
++    total_time = time(0) - start_time;
++    printf("\nTotal running time:  %lus\n", curr_time - start_time);
++    printf(" State changed %d times\n", changes);
++
++    tmp = (float)sleep_time / (float)total_time * 100;
++    printf(" Time in sleep state:   %lus (%.2f%%)\n", sleep_time, tmp);
++    tmp = (float)active_time / (float)total_time * 100;
++    printf(" Time in active state:  %lus (%.2f%%)\n", active_time, tmp);
++    tmp = (float)unknown_time / (float)total_time * 100;
++    printf(" Time in unknown state: %lus (%.2f%%)\n", unknown_time, tmp);
++}
++
++void ender(int s)
++{
++    endit = 1;
++}
++
++void usage()
++{
++    puts("usage: dslm [-w <time>] <disk>");
++    exit(0);
++}
++
++int main(int ac, char **av)
++{
++    int fd;
++    char *disk = 0;
++    int settle_time = 60;
++
++    /* Parse the simple command-line */
++    if (ac == 2) 
++      disk = av[1];
++    else if (ac == 4) {
++      settle_time = atoi(av[2]);
++      disk = av[3];
++    } else
++      usage();
++      
++    if (!(fd = open(disk, O_RDONLY|O_NONBLOCK))) {
++      printf("Can't open %s, because: %s\n", disk, strerror(errno));
++      exit(-1);
++    }
++
++    if (settle_time) {
++      printf("Waiting %d seconds for the system to settle down to "
++             "'normal'\n", settle_time);
++      sleep(settle_time);
++    } else
++      puts("Not waiting for system to settle down");
++
++    signal(SIGINT, ender);
++
++    measure(fd);
++
++    close(fd);
++
++    return 0;
++}
++---------------------------dslm.c END---------------------------------------------
+diff -Nbaur linux-2.6.1/drivers/block/ll_rw_blk.c linux-2.6.1-withlaptopmode/drivers/block/ll_rw_blk.c
+--- linux-2.6.1/drivers/block/ll_rw_blk.c      2004-01-09 20:29:05.000000000 +0100
++++ linux-2.6.1-withlaptopmode/drivers/block/ll_rw_blk.c       2004-01-09 20:29:39.000000000 +0100
+@@ -27,6 +27,7 @@
+ #include <linux/completion.h>
+ #include <linux/slab.h>
+ #include <linux/swap.h>
++#include <linux/writeback.h>
+ static void blk_unplug_work(void *data);
+ static void blk_unplug_timeout(unsigned long data);
+@@ -2302,6 +2303,15 @@
+               mod_page_state(pgpgout, count);
+       else
+               mod_page_state(pgpgin, count);
++
++      if (unlikely(block_dump)) {
++              char b[BDEVNAME_SIZE];
++              printk("%s(%d): %s block %Lu on %s\n",
++                      current->comm, current->pid,
++                      (rw & WRITE) ? "WRITE" : "READ",
++                      (unsigned long long)bio->bi_sector, bdevname(bio->bi_bdev,b));
++      }
++
+       generic_make_request(bio);
+       return 1;
+ }
+@@ -2593,6 +2603,12 @@
+                       disk_stat_add(disk, write_ticks, duration);
+                       break;
+                   case READ:
++                      /*
++                       * schedule the writeout of pending dirty data when the disk is idle.
++                       * (postpone writeback until system is quiescent again.)
++                       */
++                      if (unlikely(laptop_mode))
++                              disk_is_spun_up(1);
+                       disk_stat_inc(disk, reads);
+                       disk_stat_add(disk, read_ticks, duration);
+                       break;
+diff -Nbaur linux-2.6.1/fs/buffer.c linux-2.6.1-withlaptopmode/fs/buffer.c
+--- linux-2.6.1/fs/buffer.c    2004-01-09 20:29:10.000000000 +0100
++++ linux-2.6.1-withlaptopmode/fs/buffer.c     2004-01-09 20:29:45.000000000 +0100
+@@ -855,10 +855,13 @@
+               struct buffer_head *bh = head;
+               do {
+-                      if (buffer_uptodate(bh))
++                      if (buffer_uptodate(bh)) {
+                               set_buffer_dirty(bh);
+-                      else
++                              if (unlikely(block_dump))
++                                      printk("%s(%d): dirtied buffer\n", current->comm, current->pid);
++                      } else {
+                               buffer_error();
++                      }
+                       bh = bh->b_this_page;
+               } while (bh != head);
+       }
+diff -Nbaur linux-2.6.1/include/linux/sysctl.h linux-2.6.1-withlaptopmode/include/linux/sysctl.h
+--- linux-2.6.1/include/linux/sysctl.h 2004-01-09 20:29:10.000000000 +0100
++++ linux-2.6.1-withlaptopmode/include/linux/sysctl.h  2004-01-09 20:29:46.000000000 +0100
+@@ -154,6 +154,8 @@
+       VM_SWAPPINESS=19,       /* Tendency to steal mapped memory */
+       VM_LOWER_ZONE_PROTECTION=20,/* Amount of protection of lower zones */
+       VM_MIN_FREE_KBYTES=21,  /* Minimum free kilobytes to maintain */
++      VM_LAPTOP_MODE=22,      /* vm laptop mode */
++      VM_BLOCK_DUMP=23,       /* block dump mode */
+ };
+diff -Nbaur linux-2.6.1/include/linux/writeback.h linux-2.6.1-withlaptopmode/include/linux/writeback.h
+--- linux-2.6.1/include/linux/writeback.h      2003-12-24 05:19:46.000000000 +0100
++++ linux-2.6.1-withlaptopmode/include/linux/writeback.h       2004-01-04 12:10:58.000000000 +0100
+@@ -71,12 +71,15 @@
+  * mm/page-writeback.c
+  */
+ int wakeup_bdflush(long nr_pages);
++void disk_is_spun_up(int postpone_writeback);
+-/* These 5 are exported to sysctl. */
++/* These are exported to sysctl. */
+ extern int dirty_background_ratio;
+ extern int vm_dirty_ratio;
+ extern int dirty_writeback_centisecs;
+ extern int dirty_expire_centisecs;
++extern int block_dump;
++extern int laptop_mode;
+ struct ctl_table;
+ struct file;
+diff -Nbaur linux-2.6.1/kernel/sysctl.c linux-2.6.1-withlaptopmode/kernel/sysctl.c
+--- linux-2.6.1/kernel/sysctl.c        2003-12-24 05:19:46.000000000 +0100
++++ linux-2.6.1-withlaptopmode/kernel/sysctl.c 2003-12-24 06:24:53.000000000 +0100
+@@ -700,6 +700,26 @@
+               .strategy       = &sysctl_intvec,
+               .extra1         = &zero,
+       },
++      {
++              .ctl_name       = VM_LAPTOP_MODE,
++              .procname       = "laptop_mode",
++              .data           = &laptop_mode,
++              .maxlen         = sizeof(laptop_mode),
++              .mode           = 0644,
++              .proc_handler   = &proc_dointvec,
++              .strategy       = &sysctl_intvec,
++              .extra1         = &zero,
++      },
++      {
++              .ctl_name       = VM_BLOCK_DUMP,
++              .procname       = "block_dump",
++              .data           = &block_dump,
++              .maxlen         = sizeof(block_dump),
++              .mode           = 0644,
++              .proc_handler   = &proc_dointvec,
++              .strategy       = &sysctl_intvec,
++              .extra1         = &zero,
++      },
+       { .ctl_name = 0 }
+ };
+diff -Nbaur linux-2.6.1/mm/page-writeback.c linux-2.6.1-withlaptopmode/mm/page-writeback.c
+--- linux-2.6.1/mm/page-writeback.c    2003-12-24 05:19:46.000000000 +0100
++++ linux-2.6.1-withlaptopmode/mm/page-writeback.c     2004-01-04 17:50:03.000000000 +0100
+@@ -28,6 +28,7 @@
+ #include <linux/smp.h>
+ #include <linux/sysctl.h>
+ #include <linux/cpu.h>
++#include <linux/quotaops.h>
+ /*
+  * The maximum number of pages to writeout in a single bdflush/kupdate
+@@ -81,6 +82,16 @@
+  */
+ int dirty_expire_centisecs = 30 * 100;
++/*
++ * Flag that makes the machine dump writes/reads and block dirtyings.
++ */
++int block_dump;
++
++/*
++ * Flag that puts the machine in "laptop mode".
++ */
++int laptop_mode;
++
+ /* End of sysctl-exported parameters */
+@@ -195,7 +206,18 @@
+       if (nr_reclaimable + ps.nr_writeback <= dirty_thresh)
+               dirty_exceeded = 0;
+-      if (!writeback_in_progress(bdi) && nr_reclaimable > background_thresh)
++      if (unlikely(laptop_mode) && pages_written > 0) {
++              /*
++               * Schedule full writeout to happen soon. We don't postpone
++               * previously scheduled full writeouts, otherwise a writing
++               * process throttled by balance_dirty_pages will be able to
++               * postpone the full writeout indefinitely, keeping the disk
++               * spun up as a result.
++               */
++              disk_is_spun_up(0);
++      }
++
++      if (!unlikely(laptop_mode) && !writeback_in_progress(bdi) && nr_reclaimable > background_thresh)
+               pdflush_operation(background_writeout, 0);
+ }
+@@ -327,6 +349,8 @@
+       oldest_jif = jiffies - (dirty_expire_centisecs * HZ) / 100;
+       start_jif = jiffies;
+       next_jif = start_jif + (dirty_writeback_centisecs * HZ) / 100;
++      if (laptop_mode)
++              wbc.older_than_this = NULL;
+       nr_to_write = ps.nr_dirty + ps.nr_unstable +
+                       (inodes_stat.nr_inodes - inodes_stat.nr_unused);
+       while (nr_to_write > 0) {
+@@ -343,6 +367,11 @@
+       }
+       if (time_before(next_jif, jiffies + HZ))
+               next_jif = jiffies + HZ;
++      if (laptop_mode) {
++              sync_inodes(0);
++              sync_filesystems(0);
++              DQUOT_SYNC(NULL);
++      }
+       if (dirty_writeback_centisecs)
+               mod_timer(&wb_timer, next_jif);
+ }
+@@ -363,6 +392,28 @@
+       return 0;
+ }
++static struct timer_list laptop_mode_wb_timer;
++
++static void laptop_mode_wb_timer_fn(unsigned long unused)
++{
++      mod_timer(&wb_timer, jiffies);
++}
++
++/*
++ * We've spun up the disk and we're in laptop mode: schedule writeback
++ * of all dirty data in 5 seconds.
++ *
++ * Laptop mode writeback will be delayed if it has previously been
++ * scheduled to occur within 5 seconds. That way, the writeback will
++ * only be triggered if the system is truly quiet again.
++ */
++void disk_is_spun_up(int postpone_writeback)
++{
++      if (postpone_writeback || !timer_pending(&laptop_mode_wb_timer))
++              mod_timer(&laptop_mode_wb_timer, jiffies + 5 * HZ);
++}
++
++
+ static void wb_timer_fn(unsigned long unused)
+ {
+       if (pdflush_operation(wb_kupdate, 0) < 0)
+@@ -434,6 +485,11 @@
+       wb_timer.data = 0;
+       wb_timer.function = wb_timer_fn;
+       add_timer(&wb_timer);
++
++      init_timer(&laptop_mode_wb_timer);
++      laptop_mode_wb_timer.data = 0;
++      laptop_mode_wb_timer.function = laptop_mode_wb_timer_fn;
++
+       set_ratelimit();
+       register_cpu_notifier(&ratelimit_nb);
+ }
+@@ -525,6 +581,8 @@
+                               __mark_inode_dirty(mapping->host,
+                                                       I_DIRTY_PAGES);
+               }
++              if (unlikely(block_dump))
++                      printk("%s(%d): dirtied page\n", current->comm, current->pid);
+       }
+       return ret;
+ }
This page took 0.087146 seconds and 4 git commands to generate.