* [PATCH] laptop-mode for 2.6, version 2
@ 2003-12-24 5:33 Bart Samwel
2003-12-24 11:16 ` Jens Axboe
2003-12-24 13:51 ` [PATCH] laptop-mode for 2.6, version 2 Hugang
0 siblings, 2 replies; 14+ messages in thread
From: Bart Samwel @ 2003-12-24 5:33 UTC (permalink / raw)
To: linux-kernel; +Cc: Jens Axboe
[-- Attachment #1: Type: text/plain, Size: 514 bytes --]
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
[-- Attachment #2: 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 "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
[-- Attachment #3: laptop-mode-2.6.0-2.patch --]
[-- Type: text/plain, Size: 6917 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-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)
^ permalink raw reply [flat|nested] 14+ messages in thread* Re: [PATCH] laptop-mode for 2.6, version 2 2003-12-24 5:33 [PATCH] laptop-mode for 2.6, version 2 Bart Samwel @ 2003-12-24 11:16 ` Jens Axboe 2003-12-24 15:25 ` [PATCH] laptop-mode for 2.6, version 3 Bart Samwel 2003-12-24 13:51 ` [PATCH] laptop-mode for 2.6, version 2 Hugang 1 sibling, 1 reply; 14+ messages in thread From: Jens Axboe @ 2003-12-24 11:16 UTC (permalink / raw) To: Bart Samwel; +Cc: linux-kernel On Wed, Dec 24 2003, Bart Samwel wrote: > 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)? It looks better, getting there! Some comments further down. > 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); > + } Probably want to move this to the actual set_page_dirty() function(s). > } > > /* > @@ -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 You don't want this in submit_bh(), that hardly matters at all anymore. It wants to be in submit_bio(). And you should follow the brace placement style. And just dump device+offset, b_count is not interesting. > 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) The rest looks ok, apart from style. -- Jens Axboe ^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH] laptop-mode for 2.6, version 3 2003-12-24 11:16 ` Jens Axboe @ 2003-12-24 15:25 ` Bart Samwel 2003-12-25 10:06 ` Arnaldo Carvalho de Melo 0 siblings, 1 reply; 14+ messages in thread From: Bart Samwel @ 2003-12-24 15:25 UTC (permalink / raw) To: Jens Axboe; +Cc: linux-kernel [-- Attachment #1: Type: text/plain, Size: 760 bytes --] Jens Axboe wrote: > It looks better, getting there! Thx! [block_dump code in set_buffer_dirty()] > Probably want to move this to the actual set_page_dirty() function(s). Done. Works better, seeing a bit more output as well. [block_dump code in submit_bh()] > You don't want this in submit_bh(), that hardly matters at all anymore. > It wants to be in submit_bio(). And you should follow the brace > placement style. And just dump device+offset, b_count is not > interesting. Done. This gives some extra output as well, which is good. > The rest looks ok, apart from style. I've changed it to use the correct bracing style. Is it OK now? Thanks for the feedback. Do you see any more problems with the current patch, or is it OK like this? Bart [-- Attachment #2: laptop-mode-2.6.0-3.patch --] [-- Type: text/plain, Size: 7061 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-24 05:19:46.000000000 +0100 +++ linux-2.6.0-withlaptopmode/drivers/block/ll_rw_blk.c 2003-12-24 15:54:37.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); @@ -2307,6 +2308,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" : (rw == READA ? "READA" : "READ"), + bio->bi_sector, bdevname(bio->bi_bdev,b)); + } + generic_make_request(bio); return 1; } @@ -2582,6 +2592,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 +2616,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 +2712,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 15:46:30.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 -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 15:49:55.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,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 +382,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) @@ -525,6 +553,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; } ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH] laptop-mode for 2.6, version 3 2003-12-24 15:25 ` [PATCH] laptop-mode for 2.6, version 3 Bart Samwel @ 2003-12-25 10:06 ` Arnaldo Carvalho de Melo 2003-12-25 15:12 ` [PATCH] laptop-mode for 2.6, version 4 + smart_spindown Bart Samwel 0 siblings, 1 reply; 14+ messages in thread From: Arnaldo Carvalho de Melo @ 2003-12-25 10:06 UTC (permalink / raw) To: Bart Samwel; +Cc: Jens Axboe, linux-kernel Minor nitpicks below Em Wed, Dec 24, 2003 at 04:25:48PM +0100, Bart Samwel escreveu: > 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 15:49:55.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; > + No need to set a global variable to 0, if you don't set it'll go to the .bss section and the kernel will zero it out for us, and we reclaim 2 * sizeof(int) from the kernel image. This is common style in most parts of the kernel. - Arnaldo ^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH] laptop-mode for 2.6, version 4 + smart_spindown 2003-12-25 10:06 ` Arnaldo Carvalho de Melo @ 2003-12-25 15:12 ` Bart Samwel 2003-12-25 17:04 ` John Bradford 2003-12-27 10:57 ` A couple of questions about laptop-mode for 2.6, version 4 Kiko Piris 0 siblings, 2 replies; 14+ messages in thread From: Bart Samwel @ 2003-12-25 15:12 UTC (permalink / raw) To: Arnaldo Carvalho de Melo; +Cc: Jens Axboe, linux-kernel [-- Attachment #1: Type: text/plain, Size: 2942 bytes --] Arnaldo Carvalho de Melo wrote: > Minor nitpicks below [...] >>+int laptop_mode = 0; > > No need to set a global variable to 0, if you don't set it'll go to the > .bss section and the kernel will zero it out for us, and we reclaim > 2 * sizeof(int) from the kernel image. This is common style in most parts > of the kernel. Thanks, I've fixed this. Here is the resulting patch. I've got another problem getting this stuff to work. The problem lies with my HD: it just doesn't respect the spindown time, I've got it set to hdparm -S 4 and it just doesn't spin down, even though there's no activity whatsoever! hdparm -B 254 gives me: /dev/hdb: setting Advanced Power Management level to 0xFE (254) HDIO_DRIVE_CMD failed: Input/output error It's funny, because hdparm -I gives me: Commands/features: Enabled Supported: [...] * Power Management feature set So, it should support this. Apparently it doesn't. :( The drive is a WD 800BB. Does anyone have any clue what could cause this? Anyway, I've built myself a solution called "smart_spindown". This script monitors the read activity on a drive, and if there hasn't been any read activity in a while it spins down the drive. The amount of read-inactivity needed is subjected to an exponential backoff algorithm: when spun-down periods last shorter, the amount of inactivity needed for triggering a spindown increases. When the system is low on activity, the script is more aggressive w.r.t. spinning down the disk, and when you're using the system it usually doesn't spin down the disk. The algorithm can be tuned to your personal needs, so you can set it to be more aggressive if you want to. Interestingly, I found out that this script removes my need for laptop_mode. I've added an option to the beginning called NO_LAPTOP_MODE, if you set that to true it will sync just before spinning the disk down. This even adds a bit of spun-down time, as the sync takes place just before spinning down the disk instead of just after the last read. The only downside to this is that it syncs ALL disks, not only the disk that it monitors. However, this is really getting me spun-down times of about 595 seconds, while my expires are set to 600 seconds. This makes me a very happy bunny indeed! Short explanation of how the script can be used: * Edit the script to set: 1. the disk name (DISK=) 2. the stats file (STATSFILE=), if your sysfs isn't mounted on /sys. 3. the device name (DEVNAME=), if the device isn't /dev/$DISK. * Tune the OUTLEVEL1 and OUTLEVEL2 values to set the verbosity. * Tune other parameters as needed. See the comments in the script. * Run it as root, or as someone who can run hdparm. :) If you want to use the script as a replacement of laptop_mode, you must adjust the VM parameters yourself, like it is done in the laptop_mode control script; see the comments above NO_LAPTOP_MODE in the script. Bart [-- Attachment #2: laptop-mode-2.6.0-4.patch --] [-- Type: text/plain, Size: 7053 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-24 05:19:46.000000000 +0100 +++ linux-2.6.0-withlaptopmode/drivers/block/ll_rw_blk.c 2003-12-24 15:54:37.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); @@ -2307,6 +2308,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" : (rw == READA ? "READA" : "READ"), + bio->bi_sector, bdevname(bio->bi_bdev,b)); + } + generic_make_request(bio); return 1; } @@ -2582,6 +2592,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 +2616,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 +2712,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 15:46:30.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 -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-25 13:36:29.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 */ @@ -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,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 +382,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) @@ -525,6 +553,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; } [-- Attachment #3: smart_spindown --] [-- Type: text/plain, Size: 6112 bytes --] #! /bin/bash # # smart_spindown rev. 1 # # Copyright (C) 2003 by Bart Samwel # # You may do with this file (and parts thereof) whatever you want, as long # as my copyright notice is retained. # # # How it works: This program monitors the read activity on a disk. If there # is no read activity for a while, the disk is spun down. The time without # read activity that is required is dynamic, using a backoff factor. When # the recent spun-down periods are relatively short, this means that the # machine might be busy with something, so the script tries to wait for # longer periods without activity before spinning down again. When spun-down # periods are long, the backoff factor is decreased, and the disk is spun # down after shorter periods without read activity. # # This script REQUIRES that laptop_mode is enabled on your kernel. This is # because it assumes that after a couple of seconds without read activity, # all dirty blocks will be flushed. If this is not done, the disc will # spin up at random times # # Configuration # # Output levels. Level 2 is verbose, level 1 is normal output. # Enable all levels you would like to see. OUTLEVEL1=true OUTLEVEL2=false # Disk to monitor. DISK=hdb # Device name for the disk. DEVNAME=/dev/$DISK # Stats file: the file used to monitor the disk's read activity. # The first entry in this stats file must represent the read activity. STATSFILE=/sys/block/$DISK/stat # Multiplication factor for the backoff after a spinup, in percentages. # Default is 300 = factor 3. BACKOFF_INCREASE_PCT=300 # Multiplication factor for the backoff at every poll that shows that # the disk is spun down. This determines how fast the backoff value # decreases. BACKOFF_DECREASE_PCT=96 # The base "no reads" wait time (in seconds). This is multiplied by # the backoff factor to determine the real "no reads" wait time. WAITTIME=20 # The maximum "no reads" wait time (in seconds). # This also limits the backoff factor: the backoff factor cannot increase # above a value that makes the "no reads" wait time larger than MAXWAIT. # Default is 120 seconds. MAXWAIT=120 # Time (in seconds) between polls to see if the disk is active again. # Default is 10 seconds. POLLTIME=10 # Enable this if you don't use laptop_mode. This will make the script # sync before spinning down the disc. To make this work, you must # ensure that: # 1. /proc/sys/vm/dirty_expire_centisecs is set to a high value. You can # use 60000 for 10 minutes. # 2. /proc/sys/vm/dirty_writeback_centisecs is set to the same value. # 3. Your ext3 filesystems are mounted with "commit=n", where n is the # number of seconds between commit. Use 600 for 10 minutes. NO_LAPTOP_MODE=false # # Let's go! # # Number of poll times that the disc was found to be spun down. POLLSSPUNDOWN=0 # Number of spindowns performed SPINDOWNS=0 # Number of times (*100) the WAITTIME of no-reads required before spindown BACKOFF_FACTOR=100 # Stats: Total time the disk has been up. UPTIME=0 # Total duration of last spun-down period. LASTDOWNTIME=0 # Total duration of the last spun-up period. LASTUPTIME=0 # Duration of the last poll. Always equal to POLLTIME except the first # time around. LASTPOLLTIME=0 # Make sure the stuff we use is in the cache. I've seen it happen # that the script spun the disk down, and then "sleep" wasn't in # the cache and the disk spun right up again. :) true false sleep 1 $OUTLEVEL1 && echo Monitoring spindown opportunities for disk $DISK. if ($OUTLEVEL1) ; then hdparm -C $DEVNAME |grep active >/dev/null if [ "$?" == "0" ] ; then echo Drive is currently spun up. ; else echo Drive is currently spun down. ; fi ; fi while [[ /sbin/true ]]; do hdparm -C $DEVNAME |grep active >/dev/null if [ "$?" == "0" ] ; then THISWAIT=$(($WAITTIME*$BACKOFF_FACTOR/100)) ; if [[ $THISWAIT -gt $MAXWAIT ]] ; then THISWAIT=$MAXWAIT ; fi ; # Increase the backoff irrespective of whether we failed # or not. The backoff should drop again by the lack of # spinups afterwards. BACKOFF_FACTOR=$(($BACKOFF_FACTOR*$BACKOFF_INCREASE_PCT/100)) ; if [[ $(($BACKOFF_FACTOR*$WAITTIME/100)) -gt $MAXWAIT ]] ; then BACKOFF_FACTOR=$(($MAXWAIT*100/$WAITTIME)) ; fi ; UPTIME=$(($UPTIME+$LASTPOLLTIME)) ; LASTUPTIME=$(($LASTUPTIME+$LASTPOLLTIME)) ; if [ "$LASTDOWNTIME" != "0" ] ; then $OUTLEVEL1 && echo Drive spun up after $LASTDOWNTIME seconds. ; fi PREVIOUS_READS=-1 ; NUM_EQUALS=0 ; $OUTLEVEL2 && echo Waiting for $THISWAIT seconds of read inactivity... ; PREVIOUS_READS=`cat $STATSFILE |awk '{ print $1; }'` ; while [[ $(($NUM_EQUALS*5)) -lt $THISWAIT ]]; do sleep 5 ; UPTIME=$(($UPTIME+5)) ; LASTUPTIME=$(($LASTUPTIME+5)) ; NEXT_READS=`cat $STATSFILE |awk '{ print $1; }'` ; if [[ $PREVIOUS_READS -ne $NEXT_READS ]] ; then NUM_EQUALS=0 ; PREVIOUS_READS=$NEXT_READS $OUTLEVEL2 && echo Restarting... ; else NUM_EQUALS=$(($NUM_EQUALS+1)) ; $OUTLEVEL2 && echo Seconds of quiet: $(($NUM_EQUALS*5)) ; fi done # We've just had $THISWAIT seconds of read inactivity. Writes can be # cached, reads always spin up the disk; the inactivity indicates # that we're ready to go to sleep. Laptop mode will have synced all # writes for us after the last read, so we don't have to explicitly # sync. if ( $NO_LAPTOP_MODE ) ; then sync ; fi ; hdparm -q -y $DEVNAME ; SPINDOWNS=$(($SPINDOWNS+1)) ; $OUTLEVEL1 && echo Drive spun down after $LASTUPTIME seconds \(with $THISWAIT seconds of inactivity\). ; LASTUPTIME=0 ; LASTDOWNTIME=0 ; else POLLSSPUNDOWN=$(($POLLSSPUNDOWN+1)) ; if [[ $SPINDOWNS -eq 0 ]] ; then SPINDOWNS=1 ; fi LASTDOWNTIME=$(($LASTDOWNTIME+$LASTPOLLTIME)) ; BACKOFF_FACTOR=$(($BACKOFF_FACTOR*$BACKOFF_DECREASE_PCT/100)) ; if [ $BACKOFF_FACTOR -lt 100 ] ; then BACKOFF_FACTOR=100 ; fi fi ; if ( $OUTLEVEL2 ) ; then echo -n spindowns: $SPINDOWNS, time up/down: $UPTIME/$(($POLLSSPUNDOWN*$POLLTIME)), backoff $BACKOFF_FACTOR, down for $LASTDOWNTIME \(avg $(($POLLSSPUNDOWN*$POLLTIME/$SPINDOWNS))\). ; fi ; sleep $POLLTIME ; LASTPOLLTIME=$POLLTIME ; done ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH] laptop-mode for 2.6, version 4 + smart_spindown 2003-12-25 15:12 ` [PATCH] laptop-mode for 2.6, version 4 + smart_spindown Bart Samwel @ 2003-12-25 17:04 ` John Bradford 2003-12-25 21:39 ` Bart Samwel 2003-12-27 10:57 ` A couple of questions about laptop-mode for 2.6, version 4 Kiko Piris 1 sibling, 1 reply; 14+ messages in thread From: John Bradford @ 2003-12-25 17:04 UTC (permalink / raw) To: Bart Samwel, Arnaldo Carvalho de Melo; +Cc: Jens Axboe, linux-kernel > I've got another problem getting this stuff to work. The problem lies > with my HD: it just doesn't respect the spindown time, I've got it set > to hdparm -S 4 and it just doesn't spin down, even though there's no > activity whatsoever! hdparm -B 254 gives me: > > /dev/hdb: > setting Advanced Power Management level to 0xFE (254) > HDIO_DRIVE_CMD failed: Input/output error > > It's funny, because hdparm -I gives me: > > Commands/features: > Enabled Supported: > [...] > * Power Management feature set > > So, it should support this. Apparently it doesn't. :( The drive is a WD > 800BB. Does anyone have any clue what could cause this? No, but I've definitely seen other drives, (old Toshiba ~100 MB ones), which respect 'spin down immediately' commands, and don't support the spin down inactivity timer. I can't remember whether they report Power Management feature set supported or not, though. John. ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH] laptop-mode for 2.6, version 4 + smart_spindown 2003-12-25 17:04 ` John Bradford @ 2003-12-25 21:39 ` Bart Samwel 0 siblings, 0 replies; 14+ messages in thread From: Bart Samwel @ 2003-12-25 21:39 UTC (permalink / raw) To: John Bradford; +Cc: linux-kernel John Bradford wrote: > No, but I've definitely seen other drives, (old Toshiba ~100 MB ones), > which respect 'spin down immediately' commands, and don't support the > spin down inactivity timer. I can't remember whether they report > Power Management feature set supported or not, though. Hmmm, I think I've found the problem, hidden in the drive info. hdparm -I also says: Capabilities: [...] Standby timer values: spec'd by Standard, with device specific minimum I think it's the device specific minimum that got me, -S 4 equals 20 seconds, which is probably a lower value than the drive is capable of supporting. A bit nasty that the drive accepts the -S 4 setting, but just doesn't do anything with it. An error would have been nice. Anyway, the smart_spindown script does work for lower values, so I guess I'll use that instead. It has some added benefits as well, so I'm not too disappointed. Bart ^ permalink raw reply [flat|nested] 14+ messages in thread
* A couple of questions about laptop-mode for 2.6, version 4 2003-12-25 15:12 ` [PATCH] laptop-mode for 2.6, version 4 + smart_spindown Bart Samwel 2003-12-25 17:04 ` John Bradford @ 2003-12-27 10:57 ` Kiko Piris 1 sibling, 0 replies; 14+ messages in thread From: Kiko Piris @ 2003-12-27 10:57 UTC (permalink / raw) To: linux-kernel On 25/12/2003 at 16:12, Bart Samwel wrote: > Thanks, I've fixed this. Here is the resulting patch. > > I've got another problem getting this stuff to work. The problem lies > with my HD: it just doesn't respect the spindown time, I've got it set > to hdparm -S 4 and it just doesn't spin down, even though there's no > activity whatsoever! hdparm -B 254 gives me: Hi, since laptop-mode was a feature from 2.4 wich I was missing in 2.6, I've decided to give it a try. However, I have not a clue about kernel programming (and neither about filesystems implementations), so looking at the source code is useless to me (as I do not understand anything :-[). So, please forgive-me if I'm asking obvious questions: 1.- I've used the patch posted in the message I'm replying (From: Bart Samwel, Date: Thu, 25 Dec 2003 16:12:38 +0100). Hope this is the correct one. 2.- I plan to use cpudyn (http://mnm.uib.es/~gallir/cpudyn) to spin down the disks (as I did in 2.4). If I have understood it correctly, that functionality is what the smart_spindown script does. I guess there will be no problems with that. 3.- As I use mainly ext3 partitions, I read in the first post regarding laptop-mode with ext3, that I had to mount my filesystems with commit=$MAX_AGE (beeing that $MAX_AGE, the value used in linux-2.4/Documentation/laptop-mode.sh). Is this correct? If the previous answer is yes, what do you think would be the best way to do so? I don't like modifying /etc/fstab, because if I boot another (non laptop-mode) kernel (or I want to disable laptop-mode when doing something important); I guess nasty things could happen if I forget to remount my ext3 filesystems appropiately. I was thinking in modifying laptop-mode.sh to read /proc/mounts and remount ext3 partitions with the appropiate parameter (on start and also on stop). But I quite don't like this method, it seems "ugly" to me (and does not solve the problem of mounting filesystems after activating/deactivating laptop-mode). Do you have a better idea? I know this last question is a userspace problem, but AFAICS it's tightly related to the way laptop-mode is implemented in the kernel (always suposing the answer to 3.- is yes). Thanks in advance! -- Kiko ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH] laptop-mode for 2.6, version 2 2003-12-24 5:33 [PATCH] laptop-mode for 2.6, version 2 Bart Samwel 2003-12-24 11:16 ` Jens Axboe @ 2003-12-24 13:51 ` Hugang 2003-12-24 14:24 ` Nikita Danilov 1 sibling, 1 reply; 14+ messages in thread From: Hugang @ 2003-12-24 13:51 UTC (permalink / raw) To: Bart Samwel, linux-kernel, Jens Axboe [-- Attachment #1: Type: text/plain, Size: 801 bytes --] On Wed, 24 Dec 2003 06:33:11 +0100 Bart Samwel <bart@samwel.tk> wrote: > 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)? Here is hacker patch do laptop mode on reiserfs file system. Any comments are welcome. -- Hu Gang / Steve RLU# : 204016 [1999] (Registered Linux user) GPG Public Key: http://soulinfo.com/~hugang/HuGang.asc [-- Attachment #2: reiserfs_laptop_mode --] [-- Type: application/octet-stream, Size: 2445 bytes --] Index: linux-2.6.0/fs/reiserfs/super.c =================================================================== --- linux-2.6.0/fs/reiserfs/super.c (revision 94) +++ linux-2.6.0/fs/reiserfs/super.c (working copy) @@ -662,6 +662,7 @@ {"resize", 'r', 0, 0, 0}, {"jdev", 'j', 0, 0, 0}, {"nolargeio", 'w', 0, 0, 0}, + {"commit", 'c', 0, 0, 0}, {NULL, 0, 0, 0, 0} }; @@ -690,6 +691,21 @@ } } + if ( c == 'c' ) { + extern int reiserfs_default_max_commit_age; + char *p = 0; + int val = simple_strtoul (arg, &p, 0); + + if ( *p != '\0') { + printk ("reiserfs_parse_options: bad value %s\n", arg); + return 0; + } + if ( val ) + reiserfs_default_max_commit_age = val; + else + reiserfs_default_max_commit_age = -1; + } + if ( c == 'w' ) { char *p=0; int val = simple_strtoul (arg, &p, 0); Index: linux-2.6.0/fs/reiserfs/journal.c =================================================================== --- linux-2.6.0/fs/reiserfs/journal.c (revision 94) +++ linux-2.6.0/fs/reiserfs/journal.c (working copy) @@ -1964,6 +1964,8 @@ return result; } +int reiserfs_default_max_commit_age = -1; + /* ** must be called once on fs mount. calls journal_read for you */ @@ -2032,7 +2034,11 @@ SB_JOURNAL_TRANS_MAX(p_s_sb) = le32_to_cpu (jh->jh_journal.jp_journal_trans_max); SB_JOURNAL_MAX_BATCH(p_s_sb) = le32_to_cpu (jh->jh_journal.jp_journal_max_batch); - SB_JOURNAL_MAX_COMMIT_AGE(p_s_sb) = le32_to_cpu (jh->jh_journal.jp_journal_max_commit_age); + if (reiserfs_default_max_commit_age != -1) { + SB_JOURNAL_MAX_COMMIT_AGE(p_s_sb) = reiserfs_default_max_commit_age; + } else { + SB_JOURNAL_MAX_COMMIT_AGE(p_s_sb) = le32_to_cpu (jh->jh_journal.jp_journal_max_commit_age); + } SB_JOURNAL_MAX_TRANS_AGE(p_s_sb) = JOURNAL_MAX_TRANS_AGE; if (SB_JOURNAL_TRANS_MAX(p_s_sb)) { Index: linux-2.6.0/fs/reiserfs/procfs.c =================================================================== --- linux-2.6.0/fs/reiserfs/procfs.c (revision 94) +++ linux-2.6.0/fs/reiserfs/procfs.c (working copy) @@ -401,7 +401,7 @@ DJP( jp_journal_trans_max ), DJP( jp_journal_magic ), DJP( jp_journal_max_batch ), - DJP( jp_journal_max_commit_age ), + SB_JOURNAL_MAX_COMMIT_AGE(sb), DJP( jp_journal_max_trans_age ), JF( j_1st_reserved_block ), ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH] laptop-mode for 2.6, version 2 2003-12-24 13:51 ` [PATCH] laptop-mode for 2.6, version 2 Hugang @ 2003-12-24 14:24 ` Nikita Danilov 2003-12-25 2:59 ` Hugang 0 siblings, 1 reply; 14+ messages in thread From: Nikita Danilov @ 2003-12-24 14:24 UTC (permalink / raw) To: Hugang; +Cc: Bart Samwel, linux-kernel, Jens Axboe Hugang writes: > On Wed, 24 Dec 2003 06:33:11 +0100 > Bart Samwel <bart@samwel.tk> wrote: > > > 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)? > > Here is hacker patch do laptop mode on reiserfs file system. Any comments are welcome. >From patch: +int reiserfs_default_max_commit_age = -1; + I am not sure that global variable is a good idea here. What if several file systems are mounted? You should either pass value as an argument to the journal initialization code, or just initialize SB_JOURNAL_MAX_COMMIT_AGE(sb) when parsing options. > > -- > Hu Gang / Steve Nikita. ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH] laptop-mode for 2.6, version 2 2003-12-24 14:24 ` Nikita Danilov @ 2003-12-25 2:59 ` Hugang [not found] ` <16362.43831.569086.825899@laputa.namesys.com> 0 siblings, 1 reply; 14+ messages in thread From: Hugang @ 2003-12-25 2:59 UTC (permalink / raw) To: Nikita Danilov; +Cc: Bart Samwel, linux-kernel, Jens Axboe [-- Attachment #1: Type: text/plain, Size: 557 bytes --] On Wed, 24 Dec 2003 17:24:04 +0300 Nikita Danilov <Nikita@Namesys.COM> wrote: > +int reiserfs_default_max_commit_age = -1; > + > > I am not sure that global variable is a good idea here. What if several > file systems are mounted? You should either pass value as an argument to > the journal initialization code, or just initialize > SB_JOURNAL_MAX_COMMIT_AGE(sb) when parsing options. this patch do it, pls check. thanks. -- Hu Gang / Steve RLU# : 204016 [1999] (Registered Linux user) GPG Public Key: http://soulinfo.com/~hugang/HuGang.asc [-- Attachment #2: reiserfs_laptop_mode --] [-- Type: application/octet-stream, Size: 5479 bytes --] Index: linux-2.6.0/include/linux/reiserfs_fs.h =================================================================== --- linux-2.6.0/include/linux/reiserfs_fs.h (revision 94) +++ linux-2.6.0/include/linux/reiserfs_fs.h (working copy) @@ -1719,7 +1719,7 @@ void reiserfs_check_lock_depth(char *caller) ; void reiserfs_prepare_for_journal(struct super_block *, struct buffer_head *bh, int wait) ; void reiserfs_restore_prepared_buffer(struct super_block *, struct buffer_head *bh) ; -int journal_init(struct super_block *, const char * j_dev_name, int old_format) ; +int journal_init(struct super_block *, const char * j_dev_name, int old_format, unsigned int) ; int journal_release(struct reiserfs_transaction_handle*, struct super_block *) ; int journal_release_error(struct reiserfs_transaction_handle*, struct super_block *) ; int journal_end(struct reiserfs_transaction_handle *, struct super_block *, unsigned long) ; Index: linux-2.6.0/fs/reiserfs/super.c =================================================================== --- linux-2.6.0/fs/reiserfs/super.c (revision 94) +++ linux-2.6.0/fs/reiserfs/super.c (working copy) @@ -645,7 +645,8 @@ collection of bitflags defining what mount options were selected. */ unsigned long * blocks, /* strtol-ed from NNN of resize=NNN */ - char ** jdev_name) + char ** jdev_name, + unsigned int * commit_max_age) { int c; char * arg = NULL; @@ -662,6 +663,7 @@ {"resize", 'r', 0, 0, 0}, {"jdev", 'j', 0, 0, 0}, {"nolargeio", 'w', 0, 0, 0}, + {"commit", 'c', 0, 0, 0}, {NULL, 0, 0, 0, 0} }; @@ -690,6 +692,19 @@ } } + if ( c == 'c' ) { + char *p = 0; + int val = simple_strtoul (arg, &p, 0); + + if ( *p != '\0') { + printk ("reiserfs_parse_options: bad value %s\n", arg); + return 0; + } + if ( val ) { + *commit_max_age = val; + } + } + if ( c == 'w' ) { char *p=0; int val = simple_strtoul (arg, &p, 0); @@ -743,10 +758,11 @@ unsigned long blocks; unsigned long mount_options = REISERFS_SB(s)->s_mount_opt; unsigned long safe_mask = 0; + unsigned int commit_max_age = -1; rs = SB_DISK_SUPER_BLOCK (s); - if (!reiserfs_parse_options(s, arg, &mount_options, &blocks, NULL)) + if (!reiserfs_parse_options(s, arg, &mount_options, &blocks, NULL, &commit_max_age)) return -EINVAL; handle_attrs(s); @@ -764,6 +780,10 @@ * the bits we're not allowed to change here */ REISERFS_SB(s)->s_mount_opt = (REISERFS_SB(s)->s_mount_opt & ~safe_mask) | (mount_options & safe_mask); + if(commit_max_age != -1) { + SB_JOURNAL_MAX_COMMIT_AGE(s) = commit_max_age; + } + if(blocks) { int rc = reiserfs_resize(s, blocks); if (rc != 0) @@ -1213,6 +1233,7 @@ struct reiserfs_transaction_handle th ; int old_format = 0; unsigned long blocks; + unsigned int commit_max_age = -1; int jinit_done = 0 ; struct reiserfs_iget_args args ; struct reiserfs_super_block * rs; @@ -1237,7 +1258,7 @@ REISERFS_SB(s)->s_alloc_options.preallocsize = 9; jdev_name = NULL; - if (reiserfs_parse_options (s, (char *) data, &(sbi->s_mount_opt), &blocks, &jdev_name) == 0) { + if (reiserfs_parse_options (s, (char *) data, &(sbi->s_mount_opt), &blocks, &jdev_name, &commit_max_age) == 0) { goto error; } @@ -1279,7 +1300,7 @@ #endif // set_device_ro(s->s_dev, 1) ; - if( journal_init(s, jdev_name, old_format) ) { + if( journal_init(s, jdev_name, old_format, commit_max_age) ) { printk("sh-2022: reiserfs_fill_super: unable to initialize journal space\n") ; goto error ; } else { Index: linux-2.6.0/fs/reiserfs/journal.c =================================================================== --- linux-2.6.0/fs/reiserfs/journal.c (revision 94) +++ linux-2.6.0/fs/reiserfs/journal.c (working copy) @@ -1967,7 +1967,7 @@ /* ** must be called once on fs mount. calls journal_read for you */ -int journal_init(struct super_block *p_s_sb, const char * j_dev_name, int old_format) { +int journal_init(struct super_block *p_s_sb, const char * j_dev_name, int old_format, unsigned int commit_max_age) { int num_cnodes = SB_ONDISK_JOURNAL_SIZE(p_s_sb) * 2 ; struct buffer_head *bhjh; struct reiserfs_super_block * rs; @@ -2032,7 +2032,11 @@ SB_JOURNAL_TRANS_MAX(p_s_sb) = le32_to_cpu (jh->jh_journal.jp_journal_trans_max); SB_JOURNAL_MAX_BATCH(p_s_sb) = le32_to_cpu (jh->jh_journal.jp_journal_max_batch); - SB_JOURNAL_MAX_COMMIT_AGE(p_s_sb) = le32_to_cpu (jh->jh_journal.jp_journal_max_commit_age); + if (commit_max_age != -1) { + SB_JOURNAL_MAX_COMMIT_AGE(p_s_sb) = commit_max_age; + } else { + SB_JOURNAL_MAX_COMMIT_AGE(p_s_sb) = le32_to_cpu (jh->jh_journal.jp_journal_max_commit_age); + } SB_JOURNAL_MAX_TRANS_AGE(p_s_sb) = JOURNAL_MAX_TRANS_AGE; if (SB_JOURNAL_TRANS_MAX(p_s_sb)) { Index: linux-2.6.0/fs/reiserfs/procfs.c =================================================================== --- linux-2.6.0/fs/reiserfs/procfs.c (revision 94) +++ linux-2.6.0/fs/reiserfs/procfs.c (working copy) @@ -401,7 +401,7 @@ DJP( jp_journal_trans_max ), DJP( jp_journal_magic ), DJP( jp_journal_max_batch ), - DJP( jp_journal_max_commit_age ), + SB_JOURNAL_MAX_COMMIT_AGE(sb), DJP( jp_journal_max_trans_age ), JF( j_1st_reserved_block ), ^ permalink raw reply [flat|nested] 14+ messages in thread
[parent not found: <16362.43831.569086.825899@laputa.namesys.com>]
* Re: [PATCH] laptop-mode for 2.6, version 2 [not found] ` <16362.43831.569086.825899@laputa.namesys.com> @ 2003-12-25 9:40 ` Hugang 2003-12-25 10:27 ` Nikita Danilov 0 siblings, 1 reply; 14+ messages in thread From: Hugang @ 2003-12-25 9:40 UTC (permalink / raw) To: Nikita Danilov, Linux Kernel Mailing List [-- Attachment #1: Type: text/plain, Size: 1265 bytes --] On Thu, 25 Dec 2003 12:17:43 +0300 Nikita Danilov <Nikita@Namesys.COM> wrote: > > unsigned long blocks; > > unsigned long mount_options = REISERFS_SB(s)->s_mount_opt; > > unsigned long safe_mask = 0; > > + unsigned int commit_max_age = -1; > > Assigning -1 to the unsigned int looks strange. Let's use 0, it is > invalid anyway. Yes, must change to -1, fixed. > I think that it would be better to first > > SB_JOURNAL_MAX_COMMIT_AGE(p_s_sb) = val > > in the parse_options() (after checking for validity), and in > journal_init() do something like > > if (SB_JOURNAL_MAX_COMMIT_AGE(p_s_sb) == 0) { > SB_JOURNAL_MAX_COMMIT_AGE(p_s_sb) = le32_to_cpu (jh->jh_journal.jp_journal_max_commit_age); > } > > This will also get rid of > > + if(commit_max_age != -1) { > + SB_JOURNAL_MAX_COMMIT_AGE(s) = commit_max_age; > + } > + > > piece in reiserfs_remount. > > Otherwise patch looks ok. Have you tested it? > In the parse_options() can not assigning commit max age to super block, the journal memory not malloc, so I pass a it to journal_init. Yes, It works in my laptop for 1 days. Every thinks is fine. Thanks. -- Hu Gang / Steve RLU# : 204016 [1999] (Registered Linux user) GPG Public Key: http://soulinfo.com/~hugang/HuGang.asc [-- Attachment #2: reiserfs_laptop_mode --] [-- Type: application/octet-stream, Size: 5479 bytes --] Index: linux-2.6.0/include/linux/reiserfs_fs.h =================================================================== --- linux-2.6.0/include/linux/reiserfs_fs.h (revision 94) +++ linux-2.6.0/include/linux/reiserfs_fs.h (working copy) @@ -1719,7 +1719,7 @@ void reiserfs_check_lock_depth(char *caller) ; void reiserfs_prepare_for_journal(struct super_block *, struct buffer_head *bh, int wait) ; void reiserfs_restore_prepared_buffer(struct super_block *, struct buffer_head *bh) ; -int journal_init(struct super_block *, const char * j_dev_name, int old_format) ; +int journal_init(struct super_block *, const char * j_dev_name, int old_format, unsigned int) ; int journal_release(struct reiserfs_transaction_handle*, struct super_block *) ; int journal_release_error(struct reiserfs_transaction_handle*, struct super_block *) ; int journal_end(struct reiserfs_transaction_handle *, struct super_block *, unsigned long) ; Index: linux-2.6.0/fs/reiserfs/super.c =================================================================== --- linux-2.6.0/fs/reiserfs/super.c (revision 94) +++ linux-2.6.0/fs/reiserfs/super.c (working copy) @@ -645,7 +645,8 @@ collection of bitflags defining what mount options were selected. */ unsigned long * blocks, /* strtol-ed from NNN of resize=NNN */ - char ** jdev_name) + char ** jdev_name, + unsigned int * commit_max_age) { int c; char * arg = NULL; @@ -662,6 +663,7 @@ {"resize", 'r', 0, 0, 0}, {"jdev", 'j', 0, 0, 0}, {"nolargeio", 'w', 0, 0, 0}, + {"commit", 'c', 0, 0, 0}, {NULL, 0, 0, 0, 0} }; @@ -690,6 +692,19 @@ } } + if ( c == 'c' ) { + char *p = 0; + int val = simple_strtoul (arg, &p, 0); + + if ( *p != '\0') { + printk ("reiserfs_parse_options: bad value %s\n", arg); + return 0; + } + if ( val > 0 ) { + *commit_max_age = val; + } + } + if ( c == 'w' ) { char *p=0; int val = simple_strtoul (arg, &p, 0); @@ -743,10 +758,11 @@ unsigned long blocks; unsigned long mount_options = REISERFS_SB(s)->s_mount_opt; unsigned long safe_mask = 0; + unsigned int commit_max_age = 0; rs = SB_DISK_SUPER_BLOCK (s); - if (!reiserfs_parse_options(s, arg, &mount_options, &blocks, NULL)) + if (!reiserfs_parse_options(s, arg, &mount_options, &blocks, NULL, &commit_max_age)) return -EINVAL; handle_attrs(s); @@ -764,6 +780,10 @@ * the bits we're not allowed to change here */ REISERFS_SB(s)->s_mount_opt = (REISERFS_SB(s)->s_mount_opt & ~safe_mask) | (mount_options & safe_mask); + if(commit_max_age != 0) { + SB_JOURNAL_MAX_COMMIT_AGE(s) = commit_max_age; + } + if(blocks) { int rc = reiserfs_resize(s, blocks); if (rc != 0) @@ -1213,6 +1233,7 @@ struct reiserfs_transaction_handle th ; int old_format = 0; unsigned long blocks; + unsigned int commit_max_age = 0; int jinit_done = 0 ; struct reiserfs_iget_args args ; struct reiserfs_super_block * rs; @@ -1237,7 +1258,7 @@ REISERFS_SB(s)->s_alloc_options.preallocsize = 9; jdev_name = NULL; - if (reiserfs_parse_options (s, (char *) data, &(sbi->s_mount_opt), &blocks, &jdev_name) == 0) { + if (reiserfs_parse_options (s, (char *) data, &(sbi->s_mount_opt), &blocks, &jdev_name, &commit_max_age) == 0) { goto error; } @@ -1279,7 +1300,7 @@ #endif // set_device_ro(s->s_dev, 1) ; - if( journal_init(s, jdev_name, old_format) ) { + if( journal_init(s, jdev_name, old_format, commit_max_age) ) { printk("sh-2022: reiserfs_fill_super: unable to initialize journal space\n") ; goto error ; } else { Index: linux-2.6.0/fs/reiserfs/journal.c =================================================================== --- linux-2.6.0/fs/reiserfs/journal.c (revision 94) +++ linux-2.6.0/fs/reiserfs/journal.c (working copy) @@ -1967,7 +1967,7 @@ /* ** must be called once on fs mount. calls journal_read for you */ -int journal_init(struct super_block *p_s_sb, const char * j_dev_name, int old_format) { +int journal_init(struct super_block *p_s_sb, const char * j_dev_name, int old_format, unsigned int commit_max_age) { int num_cnodes = SB_ONDISK_JOURNAL_SIZE(p_s_sb) * 2 ; struct buffer_head *bhjh; struct reiserfs_super_block * rs; @@ -2032,7 +2032,11 @@ SB_JOURNAL_TRANS_MAX(p_s_sb) = le32_to_cpu (jh->jh_journal.jp_journal_trans_max); SB_JOURNAL_MAX_BATCH(p_s_sb) = le32_to_cpu (jh->jh_journal.jp_journal_max_batch); - SB_JOURNAL_MAX_COMMIT_AGE(p_s_sb) = le32_to_cpu (jh->jh_journal.jp_journal_max_commit_age); + if (commit_max_age != 0) { + SB_JOURNAL_MAX_COMMIT_AGE(p_s_sb) = commit_max_age; + } else { + SB_JOURNAL_MAX_COMMIT_AGE(p_s_sb) = le32_to_cpu (jh->jh_journal.jp_journal_max_commit_age); + } SB_JOURNAL_MAX_TRANS_AGE(p_s_sb) = JOURNAL_MAX_TRANS_AGE; if (SB_JOURNAL_TRANS_MAX(p_s_sb)) { Index: linux-2.6.0/fs/reiserfs/procfs.c =================================================================== --- linux-2.6.0/fs/reiserfs/procfs.c (revision 94) +++ linux-2.6.0/fs/reiserfs/procfs.c (working copy) @@ -401,7 +401,7 @@ DJP( jp_journal_trans_max ), DJP( jp_journal_magic ), DJP( jp_journal_max_batch ), - DJP( jp_journal_max_commit_age ), + SB_JOURNAL_MAX_COMMIT_AGE(sb), DJP( jp_journal_max_trans_age ), JF( j_1st_reserved_block ), ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH] laptop-mode for 2.6, version 2 2003-12-25 9:40 ` Hugang @ 2003-12-25 10:27 ` Nikita Danilov 2003-12-25 10:59 ` Hugang 0 siblings, 1 reply; 14+ messages in thread From: Nikita Danilov @ 2003-12-25 10:27 UTC (permalink / raw) To: Hugang; +Cc: Linux Kernel Mailing List Hugang writes: > On Thu, 25 Dec 2003 12:17:43 +0300 > Nikita Danilov <Nikita@Namesys.COM> wrote: > > > > unsigned long blocks; > > > unsigned long mount_options = REISERFS_SB(s)->s_mount_opt; > > > unsigned long safe_mask = 0; > > > + unsigned int commit_max_age = -1; > > > > Assigning -1 to the unsigned int looks strange. Let's use 0, it is > > invalid anyway. > Yes, must change to -1, fixed. > > > I think that it would be better to first > > > > SB_JOURNAL_MAX_COMMIT_AGE(p_s_sb) = val > > > > in the parse_options() (after checking for validity), and in > > journal_init() do something like > > > > if (SB_JOURNAL_MAX_COMMIT_AGE(p_s_sb) == 0) { > > SB_JOURNAL_MAX_COMMIT_AGE(p_s_sb) = le32_to_cpu (jh->jh_journal.jp_journal_max_commit_age); > > } > > > > This will also get rid of > > > > + if(commit_max_age != -1) { > > + SB_JOURNAL_MAX_COMMIT_AGE(s) = commit_max_age; > > + } > > + > > > > piece in reiserfs_remount. > > > > Otherwise patch looks ok. Have you tested it? > > > In the parse_options() can not assigning commit max age to super block, > the journal memory not malloc, so I pass a it to journal_init. > > Yes, It works in my laptop for 1 days. Every thinks is fine. + if ( val > 0 ) { + *commit_max_age = val; + } here warning should be issued, and mount refused, if val == 0. > > Thanks. Nikita. ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH] laptop-mode for 2.6, version 2 2003-12-25 10:27 ` Nikita Danilov @ 2003-12-25 10:59 ` Hugang 0 siblings, 0 replies; 14+ messages in thread From: Hugang @ 2003-12-25 10:59 UTC (permalink / raw) To: Nikita Danilov, linux-kernel [-- Attachment #1: Type: text/plain, Size: 380 bytes --] On Thu, 25 Dec 2003 13:27:30 +0300 Nikita Danilov <Nikita@Namesys.COM> wrote: > + if ( val > 0 ) { > + *commit_max_age = val; > + } > > here warning should be issued, and mount refused, if val == 0. Adding a message for it. here is it. thanks. -- Hu Gang / Steve RLU# : 204016 [1999] (Registered Linux user) GPG Public Key: http://soulinfo.com/~hugang/HuGang.asc [-- Attachment #2: reiserfs_laptop_mode --] [-- Type: application/octet-stream, Size: 5581 bytes --] Index: linux-2.6.0/include/linux/reiserfs_fs.h =================================================================== --- linux-2.6.0/include/linux/reiserfs_fs.h (revision 94) +++ linux-2.6.0/include/linux/reiserfs_fs.h (working copy) @@ -1719,7 +1719,7 @@ void reiserfs_check_lock_depth(char *caller) ; void reiserfs_prepare_for_journal(struct super_block *, struct buffer_head *bh, int wait) ; void reiserfs_restore_prepared_buffer(struct super_block *, struct buffer_head *bh) ; -int journal_init(struct super_block *, const char * j_dev_name, int old_format) ; +int journal_init(struct super_block *, const char * j_dev_name, int old_format, unsigned int) ; int journal_release(struct reiserfs_transaction_handle*, struct super_block *) ; int journal_release_error(struct reiserfs_transaction_handle*, struct super_block *) ; int journal_end(struct reiserfs_transaction_handle *, struct super_block *, unsigned long) ; Index: linux-2.6.0/fs/reiserfs/super.c =================================================================== --- linux-2.6.0/fs/reiserfs/super.c (revision 94) +++ linux-2.6.0/fs/reiserfs/super.c (working copy) @@ -645,7 +645,8 @@ collection of bitflags defining what mount options were selected. */ unsigned long * blocks, /* strtol-ed from NNN of resize=NNN */ - char ** jdev_name) + char ** jdev_name, + unsigned int * commit_max_age) { int c; char * arg = NULL; @@ -662,6 +663,7 @@ {"resize", 'r', 0, 0, 0}, {"jdev", 'j', 0, 0, 0}, {"nolargeio", 'w', 0, 0, 0}, + {"commit", 'c', 0, 0, 0}, {NULL, 0, 0, 0, 0} }; @@ -690,6 +692,22 @@ } } + if ( c == 'c' ) { + char *p = 0; + int val = simple_strtoul (arg, &p, 0); + + if ( *p != '\0') { + printk ("reiserfs_parse_options: bad value %s\n", arg); + return 0; + } + if ( val == 0 ) { + printk ("reiserfs_parse_options: invalid commit max age, ignore it\n"); + } + if ( val > 0 ) { + *commit_max_age = val; + } + } + if ( c == 'w' ) { char *p=0; int val = simple_strtoul (arg, &p, 0); @@ -743,10 +761,11 @@ unsigned long blocks; unsigned long mount_options = REISERFS_SB(s)->s_mount_opt; unsigned long safe_mask = 0; + unsigned int commit_max_age = 0; rs = SB_DISK_SUPER_BLOCK (s); - if (!reiserfs_parse_options(s, arg, &mount_options, &blocks, NULL)) + if (!reiserfs_parse_options(s, arg, &mount_options, &blocks, NULL, &commit_max_age)) return -EINVAL; handle_attrs(s); @@ -764,6 +783,10 @@ * the bits we're not allowed to change here */ REISERFS_SB(s)->s_mount_opt = (REISERFS_SB(s)->s_mount_opt & ~safe_mask) | (mount_options & safe_mask); + if(commit_max_age != 0) { + SB_JOURNAL_MAX_COMMIT_AGE(s) = commit_max_age; + } + if(blocks) { int rc = reiserfs_resize(s, blocks); if (rc != 0) @@ -1213,6 +1236,7 @@ struct reiserfs_transaction_handle th ; int old_format = 0; unsigned long blocks; + unsigned int commit_max_age = 0; int jinit_done = 0 ; struct reiserfs_iget_args args ; struct reiserfs_super_block * rs; @@ -1237,7 +1261,7 @@ REISERFS_SB(s)->s_alloc_options.preallocsize = 9; jdev_name = NULL; - if (reiserfs_parse_options (s, (char *) data, &(sbi->s_mount_opt), &blocks, &jdev_name) == 0) { + if (reiserfs_parse_options (s, (char *) data, &(sbi->s_mount_opt), &blocks, &jdev_name, &commit_max_age) == 0) { goto error; } @@ -1279,7 +1303,7 @@ #endif // set_device_ro(s->s_dev, 1) ; - if( journal_init(s, jdev_name, old_format) ) { + if( journal_init(s, jdev_name, old_format, commit_max_age) ) { printk("sh-2022: reiserfs_fill_super: unable to initialize journal space\n") ; goto error ; } else { Index: linux-2.6.0/fs/reiserfs/journal.c =================================================================== --- linux-2.6.0/fs/reiserfs/journal.c (revision 94) +++ linux-2.6.0/fs/reiserfs/journal.c (working copy) @@ -1967,7 +1967,7 @@ /* ** must be called once on fs mount. calls journal_read for you */ -int journal_init(struct super_block *p_s_sb, const char * j_dev_name, int old_format) { +int journal_init(struct super_block *p_s_sb, const char * j_dev_name, int old_format, unsigned int commit_max_age) { int num_cnodes = SB_ONDISK_JOURNAL_SIZE(p_s_sb) * 2 ; struct buffer_head *bhjh; struct reiserfs_super_block * rs; @@ -2032,7 +2032,11 @@ SB_JOURNAL_TRANS_MAX(p_s_sb) = le32_to_cpu (jh->jh_journal.jp_journal_trans_max); SB_JOURNAL_MAX_BATCH(p_s_sb) = le32_to_cpu (jh->jh_journal.jp_journal_max_batch); - SB_JOURNAL_MAX_COMMIT_AGE(p_s_sb) = le32_to_cpu (jh->jh_journal.jp_journal_max_commit_age); + if (commit_max_age != 0) { + SB_JOURNAL_MAX_COMMIT_AGE(p_s_sb) = commit_max_age; + } else { + SB_JOURNAL_MAX_COMMIT_AGE(p_s_sb) = le32_to_cpu (jh->jh_journal.jp_journal_max_commit_age); + } SB_JOURNAL_MAX_TRANS_AGE(p_s_sb) = JOURNAL_MAX_TRANS_AGE; if (SB_JOURNAL_TRANS_MAX(p_s_sb)) { Index: linux-2.6.0/fs/reiserfs/procfs.c =================================================================== --- linux-2.6.0/fs/reiserfs/procfs.c (revision 94) +++ linux-2.6.0/fs/reiserfs/procfs.c (working copy) @@ -401,7 +401,7 @@ DJP( jp_journal_trans_max ), DJP( jp_journal_magic ), DJP( jp_journal_max_batch ), - DJP( jp_journal_max_commit_age ), + SB_JOURNAL_MAX_COMMIT_AGE(sb), DJP( jp_journal_max_trans_age ), JF( j_1st_reserved_block ), ^ permalink raw reply [flat|nested] 14+ messages in thread
end of thread, other threads:[~2003-12-27 10:57 UTC | newest]
Thread overview: 14+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2003-12-24 5:33 [PATCH] laptop-mode for 2.6, version 2 Bart Samwel
2003-12-24 11:16 ` Jens Axboe
2003-12-24 15:25 ` [PATCH] laptop-mode for 2.6, version 3 Bart Samwel
2003-12-25 10:06 ` Arnaldo Carvalho de Melo
2003-12-25 15:12 ` [PATCH] laptop-mode for 2.6, version 4 + smart_spindown Bart Samwel
2003-12-25 17:04 ` John Bradford
2003-12-25 21:39 ` Bart Samwel
2003-12-27 10:57 ` A couple of questions about laptop-mode for 2.6, version 4 Kiko Piris
2003-12-24 13:51 ` [PATCH] laptop-mode for 2.6, version 2 Hugang
2003-12-24 14:24 ` Nikita Danilov
2003-12-25 2:59 ` Hugang
[not found] ` <16362.43831.569086.825899@laputa.namesys.com>
2003-12-25 9:40 ` Hugang
2003-12-25 10:27 ` Nikita Danilov
2003-12-25 10:59 ` Hugang
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox