Messages in this thread Patch in this message | | | Date | Wed, 24 Dec 2003 06:33:11 +0100 | From | Bart Samwel <> | Subject | [PATCH] laptop-mode for 2.6, version 2 |
| |
Hi Jens,
Here's a new version of the laptop-mode patch (and control script). I've made a couple of improvements because of your comments. The block_dump functionality (including block dirtying) is back, and my alternative functionality has gone. There's just one bit of the block dumping patch that I couldn't place, the bit in filemap.c. The 2.6 code is so different here that I really couldn't figure out what I should do with it. Do you have any idea where this has gone (and if it is still needed)?
Bart
#!/bin/sh # # start of stop laptop mode, best run by a power management daemon when # ac gets connected/disconnected from a laptop # # FIXME: assumes HZ == 100
# age time, in seconds. should be put into a sysconfig file MAX_AGE=600
# kernel default dirty buffer age DEF_AGE=30 DEF_UPDATE=5
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" echo "1" > /proc/sys/vm/laptop_mode echo "$AGE" > /proc/sys/vm/dirty_expire_centisecs echo "$AGE" > /proc/sys/vm/dirty_writeback_centisecs echo "." ;; stop) U_AGE=$((100*$DEF_UPDATE)) B_AGE=$((100*$DEF_AGE)) echo -n "Stopping laptop mode" echo "0" > /proc/sys/vm/laptop_mode echo "$B_AGE" > /proc/sys/vm/dirty_writeback_centisecs echo "$U_AGE" > /proc/sys/vm/dirty_expire_centisecs echo "." ;; *) echo "$0 {start|stop}" ;;
esac
exit 0
diff -baur --speed-large-files linux-2.6.0/drivers/block/ll_rw_blk.c linux-2.6.0-withlaptopmode/drivers/block/ll_rw_blk.c --- linux-2.6.0/drivers/block/ll_rw_blk.c 2003-12-24 05:19:46.000000000 +0100 +++ linux-2.6.0-withlaptopmode/drivers/block/ll_rw_blk.c 2003-12-24 06:00:16.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); @@ -2582,6 +2583,14 @@ EXPORT_SYMBOL(end_that_request_chunk); +static struct timer_list writeback_timer; + +static void blk_writeback_timer(unsigned long data) +{ + wakeup_bdflush(0); + wakeup_kupdate(); +} + /* * queue lock must be held */ @@ -2598,6 +2607,11 @@ disk_stat_add(disk, write_ticks, duration); break; case READ: + /* + * schedule the writeout of pending dirty data when the disk is idle + */ + if (unlikely(laptop_mode)) + mod_timer(&writeback_timer, jiffies + 5 * HZ); disk_stat_inc(disk, reads); disk_stat_add(disk, read_ticks, duration); break; @@ -2689,6 +2703,10 @@ for (i = 0; i < ARRAY_SIZE(congestion_wqh); i++) init_waitqueue_head(&congestion_wqh[i]); + + init_timer(&writeback_timer); + writeback_timer.function = blk_writeback_timer; + return 0; } diff -baur --speed-large-files linux-2.6.0/fs/buffer.c linux-2.6.0-withlaptopmode/fs/buffer.c --- linux-2.6.0/fs/buffer.c 2003-12-24 05:19:46.000000000 +0100 +++ linux-2.6.0-withlaptopmode/fs/buffer.c 2003-12-24 06:06:18.000000000 +0100 @@ -1259,7 +1259,11 @@ if (!buffer_uptodate(bh)) buffer_error(); if (!buffer_dirty(bh) && !test_set_buffer_dirty(bh)) + { __set_page_dirty_nobuffers(bh->b_page); + if (unlikely(block_dump)) + printk("%s(%d): dirtied buffer\n", current->comm, current->pid); + } } /* @@ -2669,6 +2673,16 @@ if (test_set_buffer_req(bh) && rw == WRITE) clear_buffer_write_io_error(bh); + if (unlikely(block_dump)) + { + char b[BDEVNAME_SIZE]; + printk("%s(%d): %s block %lu/%u on %s\n", + current->comm, current->pid, + rw == WRITE ? "WRITE" : (rw == READA ? "READA" : "READ"), + bh->b_blocknr, atomic_read(&bh->b_count), + bdevname(bh->b_bdev,b)); + } + /* * from here on down, it's all bio -- do the initial mapping, * submit_bio -> generic_make_request may further map this bio around diff -baur --speed-large-files linux-2.6.0/include/linux/sysctl.h linux-2.6.0-withlaptopmode/include/linux/sysctl.h --- linux-2.6.0/include/linux/sysctl.h 2003-12-24 05:19:46.000000000 +0100 +++ linux-2.6.0-withlaptopmode/include/linux/sysctl.h 2003-12-24 03:17:36.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 -baur --speed-large-files linux-2.6.0/include/linux/writeback.h linux-2.6.0-withlaptopmode/include/linux/writeback.h --- linux-2.6.0/include/linux/writeback.h 2003-12-24 05:19:46.000000000 +0100 +++ linux-2.6.0-withlaptopmode/include/linux/writeback.h 2003-12-24 06:01:47.000000000 +0100 @@ -71,12 +71,15 @@ * mm/page-writeback.c */ int wakeup_bdflush(long nr_pages); +int wakeup_kupdate(void); -/* 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 -baur --speed-large-files linux-2.6.0/kernel/sysctl.c linux-2.6.0-withlaptopmode/kernel/sysctl.c --- linux-2.6.0/kernel/sysctl.c 2003-12-24 05:19:46.000000000 +0100 +++ linux-2.6.0-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 -baur --speed-large-files linux-2.6.0/mm/page-writeback.c linux-2.6.0-withlaptopmode/mm/page-writeback.c --- linux-2.6.0/mm/page-writeback.c 2003-12-24 05:19:46.000000000 +0100 +++ linux-2.6.0-withlaptopmode/mm/page-writeback.c 2003-12-24 06:03:22.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 = 0; + +/* + * Flag that puts the machine in "laptop mode". + */ +int laptop_mode = 0; + /* End of sysctl-exported parameters */ @@ -167,7 +178,7 @@ get_dirty_limits(&ps, &background_thresh, &dirty_thresh); nr_reclaimable = ps.nr_dirty + ps.nr_unstable; - if (nr_reclaimable + ps.nr_writeback <= dirty_thresh) + if (laptop_mode || nr_reclaimable + ps.nr_writeback <= dirty_thresh) break; dirty_exceeded = 1; @@ -192,10 +203,11 @@ blk_congestion_wait(WRITE, HZ/10); } - if (nr_reclaimable + ps.nr_writeback <= dirty_thresh) + if (laptop_mode || nr_reclaimable + ps.nr_writeback <= dirty_thresh) dirty_exceeded = 0; - if (!writeback_in_progress(bdi) && nr_reclaimable > background_thresh) + if (!laptop_mode && + !writeback_in_progress(bdi) && nr_reclaimable > background_thresh) pdflush_operation(background_writeout, 0); } @@ -327,6 +339,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 +357,12 @@ } 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 +383,15 @@ return 0; } +/* + * Set the kupdate timer to run it as soon as possible. + */ +int wakeup_kupdate(void) +{ + mod_timer(&wb_timer, jiffies); + return 0; +} + static void wb_timer_fn(unsigned long unused) { if (pdflush_operation(wb_kupdate, 0) < 0) | |