diff options
Diffstat (limited to 'mm/backing-dev.c')
| -rw-r--r-- | mm/backing-dev.c | 82 | 
1 files changed, 52 insertions, 30 deletions
diff --git a/mm/backing-dev.c b/mm/backing-dev.c index 8290b1e8825..d6edf8d14f9 100644 --- a/mm/backing-dev.c +++ b/mm/backing-dev.c @@ -45,6 +45,17 @@ static struct timer_list sync_supers_timer;  static int bdi_sync_supers(void *);  static void sync_supers_timer_fn(unsigned long); +void bdi_lock_two(struct bdi_writeback *wb1, struct bdi_writeback *wb2) +{ +	if (wb1 < wb2) { +		spin_lock(&wb1->list_lock); +		spin_lock_nested(&wb2->list_lock, 1); +	} else { +		spin_lock(&wb2->list_lock); +		spin_lock_nested(&wb1->list_lock, 1); +	} +} +  #ifdef CONFIG_DEBUG_FS  #include <linux/debugfs.h>  #include <linux/seq_file.h> @@ -67,34 +78,42 @@ static int bdi_debug_stats_show(struct seq_file *m, void *v)  	struct inode *inode;  	nr_dirty = nr_io = nr_more_io = 0; -	spin_lock(&inode_wb_list_lock); +	spin_lock(&wb->list_lock);  	list_for_each_entry(inode, &wb->b_dirty, i_wb_list)  		nr_dirty++;  	list_for_each_entry(inode, &wb->b_io, i_wb_list)  		nr_io++;  	list_for_each_entry(inode, &wb->b_more_io, i_wb_list)  		nr_more_io++; -	spin_unlock(&inode_wb_list_lock); +	spin_unlock(&wb->list_lock);  	global_dirty_limits(&background_thresh, &dirty_thresh);  	bdi_thresh = bdi_dirty_limit(bdi, dirty_thresh);  #define K(x) ((x) << (PAGE_SHIFT - 10))  	seq_printf(m, -		   "BdiWriteback:     %8lu kB\n" -		   "BdiReclaimable:   %8lu kB\n" -		   "BdiDirtyThresh:   %8lu kB\n" -		   "DirtyThresh:      %8lu kB\n" -		   "BackgroundThresh: %8lu kB\n" -		   "b_dirty:          %8lu\n" -		   "b_io:             %8lu\n" -		   "b_more_io:        %8lu\n" -		   "bdi_list:         %8u\n" -		   "state:            %8lx\n", +		   "BdiWriteback:       %10lu kB\n" +		   "BdiReclaimable:     %10lu kB\n" +		   "BdiDirtyThresh:     %10lu kB\n" +		   "DirtyThresh:        %10lu kB\n" +		   "BackgroundThresh:   %10lu kB\n" +		   "BdiWritten:         %10lu kB\n" +		   "BdiWriteBandwidth:  %10lu kBps\n" +		   "b_dirty:            %10lu\n" +		   "b_io:               %10lu\n" +		   "b_more_io:          %10lu\n" +		   "bdi_list:           %10u\n" +		   "state:              %10lx\n",  		   (unsigned long) K(bdi_stat(bdi, BDI_WRITEBACK)),  		   (unsigned long) K(bdi_stat(bdi, BDI_RECLAIMABLE)), -		   K(bdi_thresh), K(dirty_thresh), -		   K(background_thresh), nr_dirty, nr_io, nr_more_io, +		   K(bdi_thresh), +		   K(dirty_thresh), +		   K(background_thresh), +		   (unsigned long) K(bdi_stat(bdi, BDI_WRITTEN)), +		   (unsigned long) K(bdi->write_bandwidth), +		   nr_dirty, +		   nr_io, +		   nr_more_io,  		   !list_empty(&bdi->bdi_list), bdi->state);  #undef K @@ -249,18 +268,6 @@ int bdi_has_dirty_io(struct backing_dev_info *bdi)  	return wb_has_dirty_io(&bdi->wb);  } -static void bdi_flush_io(struct backing_dev_info *bdi) -{ -	struct writeback_control wbc = { -		.sync_mode		= WB_SYNC_NONE, -		.older_than_this	= NULL, -		.range_cyclic		= 1, -		.nr_to_write		= 1024, -	}; - -	writeback_inodes_wb(&bdi->wb, &wbc); -} -  /*   * kupdated() used to do this. We cannot do it from the bdi_forker_thread()   * or we risk deadlocking on ->s_umount. The longer term solution would be @@ -446,9 +453,10 @@ static int bdi_forker_thread(void *ptr)  			if (IS_ERR(task)) {  				/*  				 * If thread creation fails, force writeout of -				 * the bdi from the thread. +				 * the bdi from the thread. Hopefully 1024 is +				 * large enough for efficient IO.  				 */ -				bdi_flush_io(bdi); +				writeback_inodes_wb(&bdi->wb, 1024);  			} else {  				/*  				 * The spinlock makes sure we do not lose @@ -629,9 +637,15 @@ static void bdi_wb_init(struct bdi_writeback *wb, struct backing_dev_info *bdi)  	INIT_LIST_HEAD(&wb->b_dirty);  	INIT_LIST_HEAD(&wb->b_io);  	INIT_LIST_HEAD(&wb->b_more_io); +	spin_lock_init(&wb->list_lock);  	setup_timer(&wb->wakeup_timer, wakeup_timer_fn, (unsigned long)bdi);  } +/* + * Initial write bandwidth: 100 MB/s + */ +#define INIT_BW		(100 << (20 - PAGE_SHIFT)) +  int bdi_init(struct backing_dev_info *bdi)  {  	int i, err; @@ -654,6 +668,13 @@ int bdi_init(struct backing_dev_info *bdi)  	}  	bdi->dirty_exceeded = 0; + +	bdi->bw_time_stamp = jiffies; +	bdi->written_stamp = 0; + +	bdi->write_bandwidth = INIT_BW; +	bdi->avg_write_bandwidth = INIT_BW; +  	err = prop_local_init_percpu(&bdi->completions);  	if (err) { @@ -677,11 +698,12 @@ void bdi_destroy(struct backing_dev_info *bdi)  	if (bdi_has_dirty_io(bdi)) {  		struct bdi_writeback *dst = &default_backing_dev_info.wb; -		spin_lock(&inode_wb_list_lock); +		bdi_lock_two(&bdi->wb, dst);  		list_splice(&bdi->wb.b_dirty, &dst->b_dirty);  		list_splice(&bdi->wb.b_io, &dst->b_io);  		list_splice(&bdi->wb.b_more_io, &dst->b_more_io); -		spin_unlock(&inode_wb_list_lock); +		spin_unlock(&bdi->wb.list_lock); +		spin_unlock(&dst->list_lock);  	}  	bdi_unregister(bdi);  |