* Attempt at laptop-mode for 2.6.0
@ 2003-12-23 15:24 Bart Samwel
2003-12-23 16:38 ` Jens Axboe
0 siblings, 1 reply; 3+ messages in thread
From: Bart Samwel @ 2003-12-23 15:24 UTC (permalink / raw)
To: linux-kernel; +Cc: axboe
[-- Attachment #1: Type: text/plain, Size: 2561 bytes --]
Hi guys,
Even though I don't own a laptop, I find it very irritating that my hard
drive is active so much. Wanting to fix this, I found the Jens Axboe's
"laptop-mode" patch. Unfortunately it hadn't been ported to Linux
2.6.0 yet, and I'm using that as my primary kernel now. I gave porting
it a shot, and here is the result. I'm running it right now, and my hard
drive has been spun down for the complete time I have been writing this
message. Still, I'm not sure whether it really works as advertised. :)
The reason is that my PC is also a mail server for my personal e-mail,
and I receive e-mails more than once every 10 minutes (fscking spam!).
Still, the tests that I've done seem to indicate that it works.
I've done some things differently than in Jens's patch (my port is based
on v4 of the patch BTW):
* The block dirtying reporting is not there. As an alternative,
you can write a number N higher than 1 into /proc/sys/vm/laptop_mode,
which will give you reports on N-1 actual read/write operations,
including the pid+command that caused them. This gives you a way
to put a reasonable bound on the number of messages you're going to get.
You're only interested in the first one (the one that spins up your
disk) anyway. The messages look like this:
ll_rw_block: (107 reports left) READ requested by imapd (pid 1137)
* When laptop mode is on, wb_kupdate() also performs all of the other
actions mentioned in do_sync(). I don't know whether this is really
necessary because I don't know the full implications of all those
actions, but at least it REALLY makes sure that everything is synced.
* The script writes to different values in /proc/sys/vm, because the
Linux 2.6 VM has different controls.
* The patch does not modify the ext3 journal commit timeout; you have to
mount your filesystem with commit=600 (or whatever your preferred value
is) to get the correct effect. The 2.4 patch modified the expiration of
an ext3 transaction, I've removed this as I don't see the use if you're
going to have to mount the fs with "commit=" anyway. The default
expiration time of an ext3 transaction is equal to the commit interval,
which is very reasonable. Usually you'd set your commit interval to the
same as the dirty_writeback_centisecs value (in seconds, then), so it
would boil down to the same thing.
Disclaimer: I'm not a very experienced kernel developer, and I may have
made mistakes. Don't kill me if it doesn't work. :) I'd appreciate some
feedback, so if it works or doesn't work for you, please let me know!
Bart Samwel
[-- Attachment #2: laptop-mode-2.6.0.patch --]
[-- Type: text/plain, Size: 7175 bytes --]
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 <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,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 <linux/smp_lock.h>
#include <linux/mm.h>
#include <linux/highmem.h>
+#include <linux/writeback.h>
/*
* 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 <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
@@ -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)
[-- Attachment #3: laptop_mode --]
[-- Type: text/plain, Size: 1070 bytes --]
#!/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 "2" > /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
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: Attempt at laptop-mode for 2.6.0
2003-12-23 15:24 Attempt at laptop-mode for 2.6.0 Bart Samwel
@ 2003-12-23 16:38 ` Jens Axboe
2003-12-23 18:48 ` Bart Samwel
0 siblings, 1 reply; 3+ messages in thread
From: Jens Axboe @ 2003-12-23 16:38 UTC (permalink / raw)
To: Bart Samwel, linux-kernel
On Tue, Dec 23 2003, Bart Samwel wrote:
> Hi guys,
>
> Even though I don't own a laptop, I find it very irritating that my hard
> drive is active so much. Wanting to fix this, I found the Jens Axboe's
> "laptop-mode" patch. Unfortunately it hadn't been ported to Linux
> 2.6.0 yet, and I'm using that as my primary kernel now. I gave porting
> it a shot, and here is the result. I'm running it right now, and my hard
> drive has been spun down for the complete time I have been writing this
> message. Still, I'm not sure whether it really works as advertised. :)
> The reason is that my PC is also a mail server for my personal e-mail,
> and I receive e-mails more than once every 10 minutes (fscking spam!).
> Still, the tests that I've done seem to indicate that it works.
Thanks for getting this started. I'm not particularly fond of the
behaviourial changes you made, I guess most are due to it being
incomplete?
The block dirtying is the most interesting aspect of the dump
functionality, reporting WRITEs don't give you the info you need
to fix your setup.
Jens
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: Attempt at laptop-mode for 2.6.0
2003-12-23 16:38 ` Jens Axboe
@ 2003-12-23 18:48 ` Bart Samwel
0 siblings, 0 replies; 3+ messages in thread
From: Bart Samwel @ 2003-12-23 18:48 UTC (permalink / raw)
To: Jens Axboe; +Cc: linux-kernel
Jens Axboe wrote:
>>Even though I don't own a laptop, I find it very irritating that my hard
>>drive is active so much. Wanting to fix this, I found the Jens Axboe's
>>"laptop-mode" patch. Unfortunately it hadn't been ported to Linux
>>2.6.0 yet, and I'm using that as my primary kernel now. I gave porting
>>it a shot, and here is the result. I'm running it right now, and my hard
>>drive has been spun down for the complete time I have been writing this
>>message. Still, I'm not sure whether it really works as advertised. :)
>>The reason is that my PC is also a mail server for my personal e-mail,
>>and I receive e-mails more than once every 10 minutes (fscking spam!).
>>Still, the tests that I've done seem to indicate that it works.
>
> Thanks for getting this started. I'm not particularly fond of the
> behaviourial changes you made, I guess most are due to it being
> incomplete?
Is it only the block dirtyings that you're missing, or is there more? I
might have used an old 2.4 patch as reference -- what was the latest
version again?
> The block dirtying is the most interesting aspect of the dump
> functionality, reporting WRITEs don't give you the info you need
> to fix your setup.
OK, that depends on your point of view. At this point it weren't the
WRITEs that were interesting to me, it were the READs. The WRITEs just
came as a bonus. The reason: what bugged me during development were the
programs that read new data from disk, and I wanted to find out what to
turn off in order to keep the disk from spinning up all the time. And
when the disk DID spin up, I wanted to know if it was my fault or if it
was some daemon messing up my tests again. This is due to my not
actually working on a laptop but on a home server machine. :) I guess
that when you're going for disk-spindowns of longer than 10 minutes
(which is what the block dirtying dumps are for, presumably?) dirtyings
start to become interesting. I'll see if I can port that bit as well,
shouldn't be that much work.
Bart
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2003-12-23 18:49 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2003-12-23 15:24 Attempt at laptop-mode for 2.6.0 Bart Samwel
2003-12-23 16:38 ` Jens Axboe
2003-12-23 18:48 ` Bart Samwel
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox