diff options
| -rw-r--r-- | block/blk-core.c | 5 | ||||
| -rw-r--r-- | include/linux/backing-dev.h | 3 | ||||
| -rw-r--r-- | include/linux/writeback.h | 4 | ||||
| -rw-r--r-- | mm/page-writeback.c | 39 | 
4 files changed, 30 insertions, 21 deletions
diff --git a/block/blk-core.c b/block/blk-core.c index 1d94f15d7f0..4b1b29ef2cb 100644 --- a/block/blk-core.c +++ b/block/blk-core.c @@ -451,6 +451,7 @@ void blk_cleanup_queue(struct request_queue *q)  	 */  	blk_sync_queue(q); +	del_timer_sync(&q->backing_dev_info.laptop_mode_wb_timer);  	mutex_lock(&q->sysfs_lock);  	queue_flag_set_unlocked(QUEUE_FLAG_DEAD, q);  	mutex_unlock(&q->sysfs_lock); @@ -511,6 +512,8 @@ struct request_queue *blk_alloc_queue_node(gfp_t gfp_mask, int node_id)  		return NULL;  	} +	setup_timer(&q->backing_dev_info.laptop_mode_wb_timer, +		    laptop_mode_timer_fn, (unsigned long) q);  	init_timer(&q->unplug_timer);  	setup_timer(&q->timeout, blk_rq_timed_out_timer, (unsigned long) q);  	INIT_LIST_HEAD(&q->timeout_list); @@ -2101,7 +2104,7 @@ static void blk_finish_request(struct request *req, int error)  	BUG_ON(blk_queued_rq(req));  	if (unlikely(laptop_mode) && blk_fs_request(req)) -		laptop_io_completion(); +		laptop_io_completion(&req->q->backing_dev_info);  	blk_delete_timer(req); diff --git a/include/linux/backing-dev.h b/include/linux/backing-dev.h index fcbc26af00e..2742e1adfc3 100644 --- a/include/linux/backing-dev.h +++ b/include/linux/backing-dev.h @@ -14,6 +14,7 @@  #include <linux/kernel.h>  #include <linux/fs.h>  #include <linux/sched.h> +#include <linux/timer.h>  #include <linux/writeback.h>  #include <asm/atomic.h> @@ -88,6 +89,8 @@ struct backing_dev_info {  	struct device *dev; +	struct timer_list laptop_mode_wb_timer; +  #ifdef CONFIG_DEBUG_FS  	struct dentry *debug_dir;  	struct dentry *debug_stats; diff --git a/include/linux/writeback.h b/include/linux/writeback.h index 36520ded3e0..eb38a2c645f 100644 --- a/include/linux/writeback.h +++ b/include/linux/writeback.h @@ -96,8 +96,10 @@ static inline void inode_sync_wait(struct inode *inode)  /*   * mm/page-writeback.c   */ -void laptop_io_completion(void); +void laptop_io_completion(struct backing_dev_info *info);  void laptop_sync_completion(void); +void laptop_mode_sync(struct work_struct *work); +void laptop_mode_timer_fn(unsigned long data);  void throttle_vm_writeout(gfp_t gfp_mask);  /* These are exported to sysctl. */ diff --git a/mm/page-writeback.c b/mm/page-writeback.c index 0b19943ecf8..d0f2b3765f8 100644 --- a/mm/page-writeback.c +++ b/mm/page-writeback.c @@ -683,10 +683,6 @@ void throttle_vm_writeout(gfp_t gfp_mask)          }  } -static void laptop_timer_fn(unsigned long unused); - -static DEFINE_TIMER(laptop_mode_wb_timer, laptop_timer_fn, 0, 0); -  /*   * sysctl handler for /proc/sys/vm/dirty_writeback_centisecs   */ @@ -697,21 +693,19 @@ int dirty_writeback_centisecs_handler(ctl_table *table, int write,  	return 0;  } -static void do_laptop_sync(struct work_struct *work) +void laptop_mode_timer_fn(unsigned long data)  { -	wakeup_flusher_threads(0); -	kfree(work); -} +	struct request_queue *q = (struct request_queue *)data; +	int nr_pages = global_page_state(NR_FILE_DIRTY) + +		global_page_state(NR_UNSTABLE_NFS); -static void laptop_timer_fn(unsigned long unused) -{ -	struct work_struct *work; +	/* +	 * We want to write everything out, not just down to the dirty +	 * threshold +	 */ -	work = kmalloc(sizeof(*work), GFP_ATOMIC); -	if (work) { -		INIT_WORK(work, do_laptop_sync); -		schedule_work(work); -	} +	if (bdi_has_dirty_io(&q->backing_dev_info)) +		bdi_start_writeback(&q->backing_dev_info, NULL, nr_pages);  }  /* @@ -719,9 +713,9 @@ static void laptop_timer_fn(unsigned long unused)   * of all dirty data a few seconds from now.  If the flush is already scheduled   * then push it back - the user is still using the disk.   */ -void laptop_io_completion(void) +void laptop_io_completion(struct backing_dev_info *info)  { -	mod_timer(&laptop_mode_wb_timer, jiffies + laptop_mode); +	mod_timer(&info->laptop_mode_wb_timer, jiffies + laptop_mode);  }  /* @@ -731,7 +725,14 @@ void laptop_io_completion(void)   */  void laptop_sync_completion(void)  { -	del_timer(&laptop_mode_wb_timer); +	struct backing_dev_info *bdi; + +	rcu_read_lock(); + +	list_for_each_entry_rcu(bdi, &bdi_list, bdi_list) +		del_timer(&bdi->laptop_mode_wb_timer); + +	rcu_read_unlock();  }  /*  |