* [PATCH] laptop mode, #2
@ 2003-05-16 11:33 Jens Axboe
2003-05-16 19:55 ` Pavel Machek
2003-05-17 22:47 ` Andreas Dilger
0 siblings, 2 replies; 5+ messages in thread
From: Jens Axboe @ 2003-05-16 11:33 UTC (permalink / raw)
To: Linux Kernel
[-- Attachment #1: Type: text/plain, Size: 430 bytes --]
Hi,
Made a few tweaks and adjustments:
- If block_dump is set, also dump who is marking a page/buffer as dirty.
akpm recommended this.
- Don't touch default bdflush parameters (see script)
That's about it. I've gotten several mails who really like the patch and
that it really adds a non-significant amount of extra battery time. I
consider the patch final at this point.
Patch is against 2.4.21-rc2 (ish)
--
Jens Axboe
[-- Attachment #2: laptop-mode --]
[-- Type: text/plain, Size: 856 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 [ ! -w /proc/sys/vm/laptop_mode ]; then
echo "Kernel is not patched with laptop_mode patch"
exit 1
fi
case "$1" in
start)
AGE=$((100*$MAX_AGE))
echo -n "Starting laptop mode"
echo "1" > /proc/sys/vm/laptop_mode
echo "30 500 0 0 $AGE $AGE 60 20 0" > /proc/sys/vm/bdflush
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 "30 500 0 0 $U_AGE $B_AGE 60 20 0" > /proc/sys/vm/bdflush
echo "."
;;
*)
echo "$0 {start|stop}"
;;
esac
exit 0
[-- Attachment #3: laptop-mode-4 --]
[-- Type: text/plain, Size: 7756 bytes --]
# This is a BitKeeper generated patch for the following project:
# Project Name: Linux kernel tree
# This patch format is intended for GNU patch command version 2.5 or higher.
# This patch includes the following deltas:
# ChangeSet 1.1209 -> 1.1210
# include/linux/sysctl.h 1.23 -> 1.24
# drivers/block/ll_rw_blk.c 1.44 -> 1.45
# kernel/sysctl.c 1.19 -> 1.20
# include/linux/fs.h 1.74 -> 1.75
# fs/jbd/transaction.c 1.13 -> 1.14
# mm/filemap.c 1.76 -> 1.77
# fs/buffer.c 1.82 -> 1.83
#
# The following is the BitKeeper ChangeSet Log
# --------------------------------------------
# 03/05/16 axboe@smithers.home.kernel.dk 1.1210
# laptop mode #2
# --------------------------------------------
#
diff -Nru a/drivers/block/ll_rw_blk.c b/drivers/block/ll_rw_blk.c
--- a/drivers/block/ll_rw_blk.c Fri May 16 13:32:56 2003
+++ b/drivers/block/ll_rw_blk.c Fri May 16 13:32:56 2003
@@ -121,6 +121,10 @@
unsigned long blk_max_low_pfn, blk_max_pfn;
int blk_nohighio = 0;
+int block_dump = 0;
+
+static struct timer_list writeback_timer;
+
static inline int get_max_sectors(kdev_t dev)
{
if (!max_sectors[MAJOR(dev)])
@@ -1207,6 +1211,9 @@
kstat.pgpgin += count;
break;
}
+
+ if (block_dump)
+ printk("%s: %s block %lu/%u on %s\n", current->comm, rw == WRITE ? "WRITE" : "READ", bh->b_rsector, count, kdevname(bh->b_rdev));
}
/**
@@ -1318,6 +1325,11 @@
extern int stram_device_init (void);
#endif
+static void blk_writeback_timer(unsigned long data)
+{
+ wakeup_bdflush();
+ wakeup_kupdate();
+}
/**
* end_that_request_first - end I/O on one buffer.
@@ -1373,10 +1385,18 @@
return 0;
}
+extern int laptop_mode;
+
void end_that_request_last(struct request *req)
{
struct completion *waiting = req->waiting;
+ /*
+ * schedule the writeout of pending dirty data when the disk is idle
+ */
+ if (laptop_mode && req->cmd == READ)
+ mod_timer(&writeback_timer, jiffies + 5 * HZ);
+
req_finished_io(req);
blkdev_release_request(req);
if (waiting)
@@ -1403,6 +1423,9 @@
blk_max_low_pfn = max_low_pfn - 1;
blk_max_pfn = max_pfn - 1;
+
+ init_timer(&writeback_timer);
+ writeback_timer.function = blk_writeback_timer;
#ifdef CONFIG_AMIGA_Z2RAM
z2_init();
diff -Nru a/fs/buffer.c b/fs/buffer.c
--- a/fs/buffer.c Fri May 16 13:32:56 2003
+++ b/fs/buffer.c Fri May 16 13:32:56 2003
@@ -88,6 +88,13 @@
static int osync_buffers_list(struct list_head *);
static void __refile_buffer(struct buffer_head *);
+/*
+ * A global sysctl-controlled flag which puts the machine into "laptop mode"
+ */
+int laptop_mode;
+
+static DECLARE_WAIT_QUEUE_HEAD(kupdate_wait);
+
/* This is used by some architectures to estimate available memory. */
atomic_t buffermem_pages = ATOMIC_INIT(0);
@@ -995,7 +1002,7 @@
dirty *= 100;
dirty_limit = tot * bdf_prm.b_un.nfract_stop_bdflush;
- if (dirty > dirty_limit)
+ if (!laptop_mode && dirty > dirty_limit)
return 0;
return 1;
}
@@ -1044,6 +1051,8 @@
void mark_buffer_dirty(struct buffer_head *bh)
{
if (!atomic_set_buffer_dirty(bh)) {
+ if (block_dump)
+ printk("%s: dirtied buffer\n", current->comm);
__mark_dirty(bh);
balance_dirty();
}
@@ -1055,6 +1064,13 @@
}
EXPORT_SYMBOL(set_buffer_flushtime);
+unsigned long get_buffer_flushtime(void)
+{
+ return bdf_prm.b_un.age_buffer;
+}
+EXPORT_SYMBOL(get_buffer_flushtime);
+
+
/*
* A buffer may need to be moved from one buffer list to another
* (e.g. in case it is not shared any more). Handle this.
@@ -2815,6 +2831,12 @@
wake_up_interruptible(&bdflush_wait);
}
+void wakeup_kupdate(void)
+{
+ if (waitqueue_active(&kupdate_wait))
+ wake_up(&kupdate_wait);
+}
+
/*
* Here we attempt to write back old buffers. We also try to flush inodes
* and supers as well, since this function is essentially "update", and
@@ -2835,7 +2857,9 @@
spin_lock(&lru_list_lock);
bh = lru_list[BUF_DIRTY];
- if (!bh || time_before(jiffies, bh->b_flushtime))
+ if (!bh)
+ break;
+ if (time_before(jiffies, bh->b_flushtime) && !laptop_mode)
break;
if (write_some_buffers(NODEV))
continue;
@@ -2983,6 +3007,10 @@
complete((struct completion *)startup);
for (;;) {
+ DECLARE_WAITQUEUE(wait, tsk);
+
+ add_wait_queue(&kupdate_wait, &wait);
+
/* update interval */
interval = bdf_prm.b_un.interval;
if (interval) {
@@ -2993,6 +3021,7 @@
tsk->state = TASK_STOPPED;
schedule(); /* wait for SIGCONT */
}
+ remove_wait_queue(&kupdate_wait, &wait);
/* check for sigstop */
if (signal_pending(tsk)) {
int stopped = 0;
@@ -3010,6 +3039,8 @@
printk(KERN_DEBUG "kupdate() activated...\n");
#endif
sync_old_buffers();
+ if (laptop_mode)
+ fsync_dev(NODEV);
run_task_queue(&tq_disk);
}
}
diff -Nru a/fs/jbd/transaction.c b/fs/jbd/transaction.c
--- a/fs/jbd/transaction.c Fri May 16 13:32:56 2003
+++ b/fs/jbd/transaction.c Fri May 16 13:32:56 2003
@@ -56,7 +56,11 @@
transaction->t_journal = journal;
transaction->t_state = T_RUNNING;
transaction->t_tid = journal->j_transaction_sequence++;
- transaction->t_expires = jiffies + journal->j_commit_interval;
+ /*
+ * have to do it here, otherwise changed age_buffers since boot
+ * wont have any effect
+ */
+ transaction->t_expires = jiffies + get_buffer_flushtime();
INIT_LIST_HEAD(&transaction->t_jcb);
/* Set up the commit timer for the new transaction. */
diff -Nru a/include/linux/fs.h b/include/linux/fs.h
--- a/include/linux/fs.h Fri May 16 13:32:56 2003
+++ b/include/linux/fs.h Fri May 16 13:32:56 2003
@@ -1238,6 +1238,7 @@
}
extern void set_buffer_flushtime(struct buffer_head *);
+extern unsigned long get_buffer_flushtime(void);
extern void balance_dirty(void);
extern int check_disk_change(kdev_t);
extern int invalidate_inodes(struct super_block *);
@@ -1427,8 +1428,10 @@
return get_hash_table(sb->s_dev, block, sb->s_blocksize);
}
extern void wakeup_bdflush(void);
+extern void wakeup_kupdate(void);
extern void put_unused_buffer_head(struct buffer_head * bh);
extern struct buffer_head * get_unused_buffer_head(int async);
+extern int block_dump;
extern int brw_page(int, struct page *, kdev_t, int [], int);
diff -Nru a/include/linux/sysctl.h b/include/linux/sysctl.h
--- a/include/linux/sysctl.h Fri May 16 13:32:56 2003
+++ b/include/linux/sysctl.h Fri May 16 13:32:56 2003
@@ -144,6 +144,8 @@
VM_MAX_MAP_COUNT=11, /* int: Maximum number of active map areas */
VM_MIN_READAHEAD=12, /* Min file readahead */
VM_MAX_READAHEAD=13, /* Max file readahead */
+ VM_LAPTOP_MODE=14, /* vm laptop mode */
+ VM_BLOCK_DUMP=15, /* dump data read/write and dirtying */
};
diff -Nru a/kernel/sysctl.c b/kernel/sysctl.c
--- a/kernel/sysctl.c Fri May 16 13:32:56 2003
+++ b/kernel/sysctl.c Fri May 16 13:32:56 2003
@@ -51,6 +51,8 @@
extern int core_uses_pid;
extern char core_pattern[];
extern int cad_pid;
+extern int laptop_mode;
+extern int block_dump;
/* this is needed for the proc_dointvec_minmax for [fs_]overflow UID and GID */
static int maxolduid = 65535;
@@ -280,6 +282,10 @@
&vm_max_readahead,sizeof(int), 0644, NULL, &proc_dointvec},
{VM_MAX_MAP_COUNT, "max_map_count",
&max_map_count, sizeof(int), 0644, NULL, &proc_dointvec},
+ {VM_LAPTOP_MODE, "laptop_mode",
+ &laptop_mode, sizeof(int), 0644, NULL, &proc_dointvec},
+ {VM_BLOCK_DUMP, "block_dump",
+ &block_dump, sizeof(int), 0644, NULL, &proc_dointvec},
{0}
};
diff -Nru a/mm/filemap.c b/mm/filemap.c
--- a/mm/filemap.c Fri May 16 13:32:56 2003
+++ b/mm/filemap.c Fri May 16 13:32:56 2003
@@ -166,6 +166,8 @@
if (mapping && mapping->host)
mark_inode_dirty_pages(mapping->host);
+ if (block_dump)
+ printk("%s: dirtied page\n", current->comm);
}
}
}
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH] laptop mode, #2
2003-05-16 11:33 [PATCH] laptop mode, #2 Jens Axboe
@ 2003-05-16 19:55 ` Pavel Machek
2003-05-17 8:16 ` Jens Axboe
2003-05-17 22:47 ` Andreas Dilger
1 sibling, 1 reply; 5+ messages in thread
From: Pavel Machek @ 2003-05-16 19:55 UTC (permalink / raw)
To: Jens Axboe; +Cc: Linux Kernel
Hi!
> Made a few tweaks and adjustments:
>
> - If block_dump is set, also dump who is marking a page/buffer as dirty.
> akpm recommended this.
>
> - Don't touch default bdflush parameters (see script)
>
> That's about it. I've gotten several mails who really like the patch and
> that it really adds a non-significant amount of extra battery
> time. I
Non-significant? Like it adds no time at all?
> consider the patch final at this point.
>
> Patch is against 2.4.21-rc2 (ish)
It looks nice, but without Documentation/laptop_mode, I can't say much
more ;-)))).
Pavel
--
When do you have a heart between your knees?
[Johanka's followup: and *two* hearts?]
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH] laptop mode, #2
2003-05-16 19:55 ` Pavel Machek
@ 2003-05-17 8:16 ` Jens Axboe
0 siblings, 0 replies; 5+ messages in thread
From: Jens Axboe @ 2003-05-17 8:16 UTC (permalink / raw)
To: Pavel Machek; +Cc: Linux Kernel
On Fri, May 16 2003, Pavel Machek wrote:
> Hi!
>
> > Made a few tweaks and adjustments:
> >
> > - If block_dump is set, also dump who is marking a page/buffer as dirty.
> > akpm recommended this.
> >
> > - Don't touch default bdflush parameters (see script)
> >
> > That's about it. I've gotten several mails who really like the patch and
> > that it really adds a non-significant amount of extra battery
> > time. I
>
> Non-significant? Like it adds no time at all?
Woops, that was reversed :)
> > consider the patch final at this point.
> >
> > Patch is against 2.4.21-rc2 (ish)
>
> It looks nice, but without Documentation/laptop_mode, I can't say much
> more ;-)))).
The attached script basically explained everything, but yes I will add a
laptop_mode file as well.
--
Jens Axboe
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH] laptop mode, #2
2003-05-16 11:33 [PATCH] laptop mode, #2 Jens Axboe
2003-05-16 19:55 ` Pavel Machek
@ 2003-05-17 22:47 ` Andreas Dilger
2003-05-18 6:11 ` Jens Axboe
1 sibling, 1 reply; 5+ messages in thread
From: Andreas Dilger @ 2003-05-17 22:47 UTC (permalink / raw)
To: Jens Axboe; +Cc: Linux Kernel
On May 16, 2003 13:33 +0200, Jens Axboe wrote:
> + if (block_dump)
> + printk("%s: %s block %lu/%u on %s\n", current->comm, rw == WRITE ? "WRITE" : "READ", bh->b_rsector, count, kdevname(bh->b_rdev));
This should be changed to KERN_DEBUG or similar, since if you are logging
kernel messages to disk you get stuck in an infinite loop with block_dump:
kjournald: WRITE block 67416/8 on 03:05
kjournald: WRITE block 67424/8 on 03:05
kjournald: WRITE block 67432/8 on 03:05
kjournald: WRITE block 548144/8 on 03:05
kjournald: WRITE block 67440/8 on 03:05
kjournald: WRITE block 67448/8 on 03:05
kjournald: WRITE block 67456/8 on 03:05
:
:
Cheers, Andreas
--
Andreas Dilger
http://sourceforge.net/projects/ext2resize/
http://www-mddsp.enel.ucalgary.ca/People/adilger/
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH] laptop mode, #2
2003-05-17 22:47 ` Andreas Dilger
@ 2003-05-18 6:11 ` Jens Axboe
0 siblings, 0 replies; 5+ messages in thread
From: Jens Axboe @ 2003-05-18 6:11 UTC (permalink / raw)
To: Linux Kernel
On Sat, May 17 2003, Andreas Dilger wrote:
> On May 16, 2003 13:33 +0200, Jens Axboe wrote:
> > + if (block_dump)
> > + printk("%s: %s block %lu/%u on %s\n", current->comm, rw == WRITE ? "WRITE" : "READ", bh->b_rsector, count, kdevname(bh->b_rdev));
>
> This should be changed to KERN_DEBUG or similar, since if you are logging
> kernel messages to disk you get stuck in an infinite loop with block_dump:
>
> kjournald: WRITE block 67416/8 on 03:05
> kjournald: WRITE block 67424/8 on 03:05
> kjournald: WRITE block 67432/8 on 03:05
> kjournald: WRITE block 548144/8 on 03:05
> kjournald: WRITE block 67440/8 on 03:05
> kjournald: WRITE block 67448/8 on 03:05
> kjournald: WRITE block 67456/8 on 03:05
Or just stop syslog, I did mention you had to be careful with it.
--
Jens Axboe
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2003-05-18 5:58 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2003-05-16 11:33 [PATCH] laptop mode, #2 Jens Axboe
2003-05-16 19:55 ` Pavel Machek
2003-05-17 8:16 ` Jens Axboe
2003-05-17 22:47 ` Andreas Dilger
2003-05-18 6:11 ` Jens Axboe
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).