aboutsummaryrefslogtreecommitdiffstats
path: root/mm/page-writeback.c
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 /mm/page-writeback.c
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>
Diffstat (limited to 'mm/page-writeback.c')
-rw-r--r--mm/page-writeback.c39
1 files changed, 20 insertions, 19 deletions
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/*