aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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/*