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-18 03:58:08.000000000 +0100 +++ linux-2.6.0-withlaptopmode/drivers/block/ll_rw_blk.c 2003-12-23 15:21:29.000000000 +0100 @@ -27,6 +27,7 @@ #include #include #include +#include static void blk_unplug_work(void *data); static void blk_unplug_timeout(unsigned long data); @@ -2582,6 +2583,16 @@ 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(); +} + +extern int laptop_mode; + /* * queue lock must be held */ @@ -2598,6 +2609,11 @@ disk_stat_add(disk, write_ticks, duration); break; case READ: + /* + * schedule the writeout of pending dirty data when the disk is idle + */ + if (laptop_mode) + mod_timer(&writeback_timer, jiffies + 5 * HZ); disk_stat_inc(disk, reads); disk_stat_add(disk, read_ticks, duration); break; @@ -2689,6 +2705,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-18 03:58:57.000000000 +0100 +++ linux-2.6.0-withlaptopmode/fs/buffer.c 2003-12-23 15:14:08.000000000 +0100 @@ -44,6 +44,11 @@ #define BH_ENTRY(list) list_entry((list), struct buffer_head, b_assoc_buffers) /* + * A global sysctl-controlled flag which puts the machine into "laptop mode" + */ +int laptop_mode; + +/* * Hashed waitqueue_head's for wait_on_buffer() */ #define BH_WAIT_TABLE_ORDER 7 @@ -2720,6 +2725,16 @@ { int i; + if (laptop_mode > 1) + { + /* Set laptop_mode to any value higher than one + * to report on just about that many reads/writes. + * Watch out: this is not really threadsafe. + */ + printk("ll_rw_block: (%d reports left) %s requested by %s (pid %d)\n", + laptop_mode - 1, rw == READ ? "READ" : "WRITE", current->comm, current->pid); + --laptop_mode; + } for (i = 0; i < nr; i++) { struct buffer_head *bh = bhs[i]; diff -baur --speed-large-files linux-2.6.0/fs/jbd/transaction.c linux-2.6.0-withlaptopmode/fs/jbd/transaction.c --- linux-2.6.0/fs/jbd/transaction.c 2003-12-18 03:58:39.000000000 +0100 +++ linux-2.6.0-withlaptopmode/fs/jbd/transaction.c 2003-12-23 15:45:19.000000000 +0100 @@ -26,6 +26,7 @@ #include #include #include +#include /* * get_transaction: obtain a new transaction_t object. 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-18 03:58:56.000000000 +0100 +++ linux-2.6.0-withlaptopmode/include/linux/sysctl.h 2003-12-21 17:05:40.000000000 +0100 @@ -154,6 +154,7 @@ 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 */ }; 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-18 03:58:15.000000000 +0100 +++ linux-2.6.0-withlaptopmode/include/linux/writeback.h 2003-12-21 17:17:14.000000000 +0100 @@ -71,6 +71,7 @@ * mm/page-writeback.c */ int wakeup_bdflush(long nr_pages); +int wakeup_kupdate(void); /* These 5 are exported to sysctl. */ extern int dirty_background_ratio; 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-18 03:58:08.000000000 +0100 +++ linux-2.6.0-withlaptopmode/kernel/sysctl.c 2003-12-21 17:07:42.000000000 +0100 @@ -60,6 +60,7 @@ extern int pid_max; extern int sysctl_lower_zone_protection; extern int min_free_kbytes; +extern int laptop_mode; /* this is needed for the proc_dointvec_minmax for [fs_]overflow UID and GID */ static int maxolduid = 65535; @@ -700,6 +701,16 @@ .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 = 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-18 03:59:05.000000000 +0100 +++ linux-2.6.0-withlaptopmode/mm/page-writeback.c 2003-12-23 13:35:30.000000000 +0100 @@ -28,6 +28,7 @@ #include #include #include +#include /* * The maximum number of pages to writeout in a single bdflush/kupdate @@ -139,6 +140,8 @@ *pdirty = dirty; } +extern int laptop_mode; + /* * balance_dirty_pages() must be called by processes which are generating dirty * data. It looks at the number of dirty pages in the machine and will force @@ -167,7 +170,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 +195,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); } @@ -290,6 +294,8 @@ static struct timer_list wb_timer; +extern int laptop_mode; + /* * Periodic writeback of "old" data. * @@ -327,6 +333,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 +351,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 +377,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)