aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatthew Garrett <mjg@redhat.com>2010-04-06 08:25:14 -0400
committerJens Axboe <jens.axboe@oracle.com>2010-04-06 08:25:14 -0400
commit31373d09da5b7fe21fe6f781e92bd534a3495f00 (patch)
tree38cd9896cfc6ce106a03431658a9b98a09129034
parent9195291e5f05e01d67f9a09c756b8aca8f009089 (diff)
laptop-mode: Make flushes per-device
One of the features of laptop-mode is that it forces a writeout of dirty pages if something else triggers a physical read or write from a device. The current implementation flushes pages on all devices, rather than only the one that triggered the flush. This patch alters the behaviour so that only the recently accessed block device is flushed, preventing other disks being spun up for no terribly good reason. Signed-off-by: Matthew Garrett <mjg@redhat.com> Signed-off-by: Jens Axboe <jens.axboe@oracle.com>
-rw-r--r--block/blk-core.c5
-rw-r--r--include/linux/backing-dev.h3
-rw-r--r--include/linux/writeback.h4
-rw-r--r--mm/page-writeback.c39
4 files changed, 30 insertions, 21 deletions
diff --git a/block/blk-core.c b/block/blk-core.c
index 1d94f15d7f0d..4b1b29ef2cb0 100644
--- a/block/blk-core.c
+++ b/block/blk-core.c
@@ -451,6 +451,7 @@ void blk_cleanup_queue(struct request_queue *q)
451 */ 451 */
452 blk_sync_queue(q); 452 blk_sync_queue(q);
453 453
454 del_timer_sync(&q->backing_dev_info.laptop_mode_wb_timer);
454 mutex_lock(&q->sysfs_lock); 455 mutex_lock(&q->sysfs_lock);
455 queue_flag_set_unlocked(QUEUE_FLAG_DEAD, q); 456 queue_flag_set_unlocked(QUEUE_FLAG_DEAD, q);
456 mutex_unlock(&q->sysfs_lock); 457 mutex_unlock(&q->sysfs_lock);
@@ -511,6 +512,8 @@ struct request_queue *blk_alloc_queue_node(gfp_t gfp_mask, int node_id)
511 return NULL; 512 return NULL;
512 } 513 }
513 514
515 setup_timer(&q->backing_dev_info.laptop_mode_wb_timer,
516 laptop_mode_timer_fn, (unsigned long) q);
514 init_timer(&q->unplug_timer); 517 init_timer(&q->unplug_timer);
515 setup_timer(&q->timeout, blk_rq_timed_out_timer, (unsigned long) q); 518 setup_timer(&q->timeout, blk_rq_timed_out_timer, (unsigned long) q);
516 INIT_LIST_HEAD(&q->timeout_list); 519 INIT_LIST_HEAD(&q->timeout_list);
@@ -2101,7 +2104,7 @@ static void blk_finish_request(struct request *req, int error)
2101 BUG_ON(blk_queued_rq(req)); 2104 BUG_ON(blk_queued_rq(req));
2102 2105
2103 if (unlikely(laptop_mode) && blk_fs_request(req)) 2106 if (unlikely(laptop_mode) && blk_fs_request(req))
2104 laptop_io_completion(); 2107 laptop_io_completion(&req->q->backing_dev_info);
2105 2108
2106 blk_delete_timer(req); 2109 blk_delete_timer(req);
2107 2110
diff --git a/include/linux/backing-dev.h b/include/linux/backing-dev.h
index fcbc26af00e4..2742e1adfc30 100644
--- a/include/linux/backing-dev.h
+++ b/include/linux/backing-dev.h
@@ -14,6 +14,7 @@
14#include <linux/kernel.h> 14#include <linux/kernel.h>
15#include <linux/fs.h> 15#include <linux/fs.h>
16#include <linux/sched.h> 16#include <linux/sched.h>
17#include <linux/timer.h>
17#include <linux/writeback.h> 18#include <linux/writeback.h>
18#include <asm/atomic.h> 19#include <asm/atomic.h>
19 20
@@ -88,6 +89,8 @@ struct backing_dev_info {
88 89
89 struct device *dev; 90 struct device *dev;
90 91
92 struct timer_list laptop_mode_wb_timer;
93
91#ifdef CONFIG_DEBUG_FS 94#ifdef CONFIG_DEBUG_FS
92 struct dentry *debug_dir; 95 struct dentry *debug_dir;
93 struct dentry *debug_stats; 96 struct dentry *debug_stats;
diff --git a/include/linux/writeback.h b/include/linux/writeback.h
index 36520ded3e06..eb38a2c645f6 100644
--- a/include/linux/writeback.h
+++ b/include/linux/writeback.h
@@ -96,8 +96,10 @@ static inline void inode_sync_wait(struct inode *inode)
96/* 96/*
97 * mm/page-writeback.c 97 * mm/page-writeback.c
98 */ 98 */
99void laptop_io_completion(void); 99void laptop_io_completion(struct backing_dev_info *info);
100void laptop_sync_completion(void); 100void laptop_sync_completion(void);
101void laptop_mode_sync(struct work_struct *work);
102void laptop_mode_timer_fn(unsigned long data);
101void throttle_vm_writeout(gfp_t gfp_mask); 103void throttle_vm_writeout(gfp_t gfp_mask);
102 104
103/* These are exported to sysctl. */ 105/* These are exported to sysctl. */
diff --git a/mm/page-writeback.c b/mm/page-writeback.c
index 0b19943ecf8b..d0f2b3765f8d 100644
--- a/mm/page-writeback.c
+++ b/mm/page-writeback.c
@@ -683,10 +683,6 @@ void throttle_vm_writeout(gfp_t gfp_mask)
683 } 683 }
684} 684}
685 685
686static void laptop_timer_fn(unsigned long unused);
687
688static DEFINE_TIMER(laptop_mode_wb_timer, laptop_timer_fn, 0, 0);
689
690/* 686/*
691 * sysctl handler for /proc/sys/vm/dirty_writeback_centisecs 687 * sysctl handler for /proc/sys/vm/dirty_writeback_centisecs
692 */ 688 */
@@ -697,21 +693,19 @@ int dirty_writeback_centisecs_handler(ctl_table *table, int write,
697 return 0; 693 return 0;
698} 694}
699 695
700static void do_laptop_sync(struct work_struct *work) 696void laptop_mode_timer_fn(unsigned long data)
701{ 697{
702 wakeup_flusher_threads(0); 698 struct request_queue *q = (struct request_queue *)data;
703 kfree(work); 699 int nr_pages = global_page_state(NR_FILE_DIRTY) +
704} 700 global_page_state(NR_UNSTABLE_NFS);
705 701
706static void laptop_timer_fn(unsigned long unused) 702 /*
707{ 703 * We want to write everything out, not just down to the dirty
708 struct work_struct *work; 704 * threshold
705 */
709 706
710 work = kmalloc(sizeof(*work), GFP_ATOMIC); 707 if (bdi_has_dirty_io(&q->backing_dev_info))
711 if (work) { 708 bdi_start_writeback(&q->backing_dev_info, NULL, nr_pages);
712 INIT_WORK(work, do_laptop_sync);
713 schedule_work(work);
714 }
715} 709}
716 710
717/* 711/*
@@ -719,9 +713,9 @@ static void laptop_timer_fn(unsigned long unused)
719 * of all dirty data a few seconds from now. If the flush is already scheduled 713 * of all dirty data a few seconds from now. If the flush is already scheduled
720 * then push it back - the user is still using the disk. 714 * then push it back - the user is still using the disk.
721 */ 715 */
722void laptop_io_completion(void) 716void laptop_io_completion(struct backing_dev_info *info)
723{ 717{
724 mod_timer(&laptop_mode_wb_timer, jiffies + laptop_mode); 718 mod_timer(&info->laptop_mode_wb_timer, jiffies + laptop_mode);
725} 719}
726 720
727/* 721/*
@@ -731,7 +725,14 @@ void laptop_io_completion(void)
731 */ 725 */
732void laptop_sync_completion(void) 726void laptop_sync_completion(void)
733{ 727{
734 del_timer(&laptop_mode_wb_timer); 728 struct backing_dev_info *bdi;
729
730 rcu_read_lock();
731
732 list_for_each_entry_rcu(bdi, &bdi_list, bdi_list)
733 del_timer(&bdi->laptop_mode_wb_timer);
734
735 rcu_read_unlock();
735} 736}
736 737
737/* 738/*