mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 02:30:34 +02:00 
			
		
		
		
	Merge branch 'for-linus' of git://git.kernel.dk/linux-2.6-block
* 'for-linus' of git://git.kernel.dk/linux-2.6-block: block: Range check cpu in blk_cpu_to_group scatterlist: prevent invalid free when alloc fails writeback: Fix lost wake-up shutting down writeback thread writeback: do not lose wakeup events when forking bdi threads cciss: fix reporting of max queue depth since init block: switch s390 tape_block and mg_disk to elevator_change() block: add function call to switch the IO scheduler from a driver fs/bio-integrity.c: return -ENOMEM on kmalloc failure bio-integrity.c: remove dependency on __GFP_NOFAIL BLOCK: fix bio.bi_rw handling block: put dev->kobj in blk_register_queue fail path cciss: handle allocation failure cfq-iosched: Documentation help for new tunables cfq-iosched: blktrace print per slice sector stats cfq-iosched: Implement tunable group_idle cfq-iosched: Do group share accounting in IOPS when slice_idle=0 cfq-iosched: Do not idle if slice_idle=0 cciss: disable doorbell reset on reset_devices blkio: Fix return code for mkdir calls
This commit is contained in:
		
						commit
						ff3cb3fec3
					
				
					 17 changed files with 238 additions and 46 deletions
				
			
		
							
								
								
									
										45
									
								
								Documentation/block/cfq-iosched.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								Documentation/block/cfq-iosched.txt
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,45 @@
 | 
			
		|||
CFQ ioscheduler tunables
 | 
			
		||||
========================
 | 
			
		||||
 | 
			
		||||
slice_idle
 | 
			
		||||
----------
 | 
			
		||||
This specifies how long CFQ should idle for next request on certain cfq queues
 | 
			
		||||
(for sequential workloads) and service trees (for random workloads) before
 | 
			
		||||
queue is expired and CFQ selects next queue to dispatch from.
 | 
			
		||||
 | 
			
		||||
By default slice_idle is a non-zero value. That means by default we idle on
 | 
			
		||||
queues/service trees. This can be very helpful on highly seeky media like
 | 
			
		||||
single spindle SATA/SAS disks where we can cut down on overall number of
 | 
			
		||||
seeks and see improved throughput.
 | 
			
		||||
 | 
			
		||||
Setting slice_idle to 0 will remove all the idling on queues/service tree
 | 
			
		||||
level and one should see an overall improved throughput on faster storage
 | 
			
		||||
devices like multiple SATA/SAS disks in hardware RAID configuration. The down
 | 
			
		||||
side is that isolation provided from WRITES also goes down and notion of
 | 
			
		||||
IO priority becomes weaker.
 | 
			
		||||
 | 
			
		||||
So depending on storage and workload, it might be useful to set slice_idle=0.
 | 
			
		||||
In general I think for SATA/SAS disks and software RAID of SATA/SAS disks
 | 
			
		||||
keeping slice_idle enabled should be useful. For any configurations where
 | 
			
		||||
there are multiple spindles behind single LUN (Host based hardware RAID
 | 
			
		||||
controller or for storage arrays), setting slice_idle=0 might end up in better
 | 
			
		||||
throughput and acceptable latencies.
 | 
			
		||||
 | 
			
		||||
CFQ IOPS Mode for group scheduling
 | 
			
		||||
===================================
 | 
			
		||||
Basic CFQ design is to provide priority based time slices. Higher priority
 | 
			
		||||
process gets bigger time slice and lower priority process gets smaller time
 | 
			
		||||
slice. Measuring time becomes harder if storage is fast and supports NCQ and
 | 
			
		||||
it would be better to dispatch multiple requests from multiple cfq queues in
 | 
			
		||||
request queue at a time. In such scenario, it is not possible to measure time
 | 
			
		||||
consumed by single queue accurately.
 | 
			
		||||
 | 
			
		||||
What is possible though is to measure number of requests dispatched from a
 | 
			
		||||
single queue and also allow dispatch from multiple cfq queue at the same time.
 | 
			
		||||
This effectively becomes the fairness in terms of IOPS (IO operations per
 | 
			
		||||
second).
 | 
			
		||||
 | 
			
		||||
If one sets slice_idle=0 and if storage supports NCQ, CFQ internally switches
 | 
			
		||||
to IOPS mode and starts providing fairness in terms of number of requests
 | 
			
		||||
dispatched. Note that this mode switching takes effect only for group
 | 
			
		||||
scheduling. For non-cgroup users nothing should change.
 | 
			
		||||
| 
						 | 
				
			
			@ -217,6 +217,7 @@ Details of cgroup files
 | 
			
		|||
CFQ sysfs tunable
 | 
			
		||||
=================
 | 
			
		||||
/sys/block/<disk>/queue/iosched/group_isolation
 | 
			
		||||
-----------------------------------------------
 | 
			
		||||
 | 
			
		||||
If group_isolation=1, it provides stronger isolation between groups at the
 | 
			
		||||
expense of throughput. By default group_isolation is 0. In general that
 | 
			
		||||
| 
						 | 
				
			
			@ -243,6 +244,33 @@ By default one should run with group_isolation=0. If that is not sufficient
 | 
			
		|||
and one wants stronger isolation between groups, then set group_isolation=1
 | 
			
		||||
but this will come at cost of reduced throughput.
 | 
			
		||||
 | 
			
		||||
/sys/block/<disk>/queue/iosched/slice_idle
 | 
			
		||||
------------------------------------------
 | 
			
		||||
On a faster hardware CFQ can be slow, especially with sequential workload.
 | 
			
		||||
This happens because CFQ idles on a single queue and single queue might not
 | 
			
		||||
drive deeper request queue depths to keep the storage busy. In such scenarios
 | 
			
		||||
one can try setting slice_idle=0 and that would switch CFQ to IOPS
 | 
			
		||||
(IO operations per second) mode on NCQ supporting hardware.
 | 
			
		||||
 | 
			
		||||
That means CFQ will not idle between cfq queues of a cfq group and hence be
 | 
			
		||||
able to driver higher queue depth and achieve better throughput. That also
 | 
			
		||||
means that cfq provides fairness among groups in terms of IOPS and not in
 | 
			
		||||
terms of disk time.
 | 
			
		||||
 | 
			
		||||
/sys/block/<disk>/queue/iosched/group_idle
 | 
			
		||||
------------------------------------------
 | 
			
		||||
If one disables idling on individual cfq queues and cfq service trees by
 | 
			
		||||
setting slice_idle=0, group_idle kicks in. That means CFQ will still idle
 | 
			
		||||
on the group in an attempt to provide fairness among groups.
 | 
			
		||||
 | 
			
		||||
By default group_idle is same as slice_idle and does not do anything if
 | 
			
		||||
slice_idle is enabled.
 | 
			
		||||
 | 
			
		||||
One can experience an overall throughput drop if you have created multiple
 | 
			
		||||
groups and put applications in that group which are not driving enough
 | 
			
		||||
IO to keep disk busy. In that case set group_idle=0, and CFQ will not idle
 | 
			
		||||
on individual groups and throughput should improve.
 | 
			
		||||
 | 
			
		||||
What works
 | 
			
		||||
==========
 | 
			
		||||
- Currently only sync IO queues are support. All the buffered writes are
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -966,7 +966,7 @@ blkiocg_create(struct cgroup_subsys *subsys, struct cgroup *cgroup)
 | 
			
		|||
 | 
			
		||||
	/* Currently we do not support hierarchy deeper than two level (0,1) */
 | 
			
		||||
	if (parent != cgroup->top_cgroup)
 | 
			
		||||
		return ERR_PTR(-EINVAL);
 | 
			
		||||
		return ERR_PTR(-EPERM);
 | 
			
		||||
 | 
			
		||||
	blkcg = kzalloc(sizeof(*blkcg), GFP_KERNEL);
 | 
			
		||||
	if (!blkcg)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1198,9 +1198,9 @@ static int __make_request(struct request_queue *q, struct bio *bio)
 | 
			
		|||
	int el_ret;
 | 
			
		||||
	unsigned int bytes = bio->bi_size;
 | 
			
		||||
	const unsigned short prio = bio_prio(bio);
 | 
			
		||||
	const bool sync = (bio->bi_rw & REQ_SYNC);
 | 
			
		||||
	const bool unplug = (bio->bi_rw & REQ_UNPLUG);
 | 
			
		||||
	const unsigned int ff = bio->bi_rw & REQ_FAILFAST_MASK;
 | 
			
		||||
	const bool sync = !!(bio->bi_rw & REQ_SYNC);
 | 
			
		||||
	const bool unplug = !!(bio->bi_rw & REQ_UNPLUG);
 | 
			
		||||
	const unsigned long ff = bio->bi_rw & REQ_FAILFAST_MASK;
 | 
			
		||||
	int rw_flags;
 | 
			
		||||
 | 
			
		||||
	if ((bio->bi_rw & REQ_HARDBARRIER) &&
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -511,6 +511,7 @@ int blk_register_queue(struct gendisk *disk)
 | 
			
		|||
		kobject_uevent(&q->kobj, KOBJ_REMOVE);
 | 
			
		||||
		kobject_del(&q->kobj);
 | 
			
		||||
		blk_trace_remove_sysfs(disk_to_dev(disk));
 | 
			
		||||
		kobject_put(&dev->kobj);
 | 
			
		||||
		return ret;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -142,14 +142,18 @@ static inline int queue_congestion_off_threshold(struct request_queue *q)
 | 
			
		|||
 | 
			
		||||
static inline int blk_cpu_to_group(int cpu)
 | 
			
		||||
{
 | 
			
		||||
	int group = NR_CPUS;
 | 
			
		||||
#ifdef CONFIG_SCHED_MC
 | 
			
		||||
	const struct cpumask *mask = cpu_coregroup_mask(cpu);
 | 
			
		||||
	return cpumask_first(mask);
 | 
			
		||||
	group = cpumask_first(mask);
 | 
			
		||||
#elif defined(CONFIG_SCHED_SMT)
 | 
			
		||||
	return cpumask_first(topology_thread_cpumask(cpu));
 | 
			
		||||
	group = cpumask_first(topology_thread_cpumask(cpu));
 | 
			
		||||
#else
 | 
			
		||||
	return cpu;
 | 
			
		||||
#endif
 | 
			
		||||
	if (likely(group < NR_CPUS))
 | 
			
		||||
		return group;
 | 
			
		||||
	return cpu;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -30,6 +30,7 @@ static const int cfq_slice_sync = HZ / 10;
 | 
			
		|||
static int cfq_slice_async = HZ / 25;
 | 
			
		||||
static const int cfq_slice_async_rq = 2;
 | 
			
		||||
static int cfq_slice_idle = HZ / 125;
 | 
			
		||||
static int cfq_group_idle = HZ / 125;
 | 
			
		||||
static const int cfq_target_latency = HZ * 3/10; /* 300 ms */
 | 
			
		||||
static const int cfq_hist_divisor = 4;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -147,6 +148,8 @@ struct cfq_queue {
 | 
			
		|||
	struct cfq_queue *new_cfqq;
 | 
			
		||||
	struct cfq_group *cfqg;
 | 
			
		||||
	struct cfq_group *orig_cfqg;
 | 
			
		||||
	/* Number of sectors dispatched from queue in single dispatch round */
 | 
			
		||||
	unsigned long nr_sectors;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
| 
						 | 
				
			
			@ -198,6 +201,8 @@ struct cfq_group {
 | 
			
		|||
	struct hlist_node cfqd_node;
 | 
			
		||||
	atomic_t ref;
 | 
			
		||||
#endif
 | 
			
		||||
	/* number of requests that are on the dispatch list or inside driver */
 | 
			
		||||
	int dispatched;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
| 
						 | 
				
			
			@ -271,6 +276,7 @@ struct cfq_data {
 | 
			
		|||
	unsigned int cfq_slice[2];
 | 
			
		||||
	unsigned int cfq_slice_async_rq;
 | 
			
		||||
	unsigned int cfq_slice_idle;
 | 
			
		||||
	unsigned int cfq_group_idle;
 | 
			
		||||
	unsigned int cfq_latency;
 | 
			
		||||
	unsigned int cfq_group_isolation;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -378,6 +384,21 @@ CFQ_CFQQ_FNS(wait_busy);
 | 
			
		|||
			&cfqg->service_trees[i][j]: NULL) \
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static inline bool iops_mode(struct cfq_data *cfqd)
 | 
			
		||||
{
 | 
			
		||||
	/*
 | 
			
		||||
	 * If we are not idling on queues and it is a NCQ drive, parallel
 | 
			
		||||
	 * execution of requests is on and measuring time is not possible
 | 
			
		||||
	 * in most of the cases until and unless we drive shallower queue
 | 
			
		||||
	 * depths and that becomes a performance bottleneck. In such cases
 | 
			
		||||
	 * switch to start providing fairness in terms of number of IOs.
 | 
			
		||||
	 */
 | 
			
		||||
	if (!cfqd->cfq_slice_idle && cfqd->hw_tag)
 | 
			
		||||
		return true;
 | 
			
		||||
	else
 | 
			
		||||
		return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline enum wl_prio_t cfqq_prio(struct cfq_queue *cfqq)
 | 
			
		||||
{
 | 
			
		||||
	if (cfq_class_idle(cfqq))
 | 
			
		||||
| 
						 | 
				
			
			@ -906,7 +927,6 @@ static inline unsigned int cfq_cfqq_slice_usage(struct cfq_queue *cfqq)
 | 
			
		|||
			slice_used = cfqq->allocated_slice;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	cfq_log_cfqq(cfqq->cfqd, cfqq, "sl_used=%u", slice_used);
 | 
			
		||||
	return slice_used;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -914,19 +934,21 @@ static void cfq_group_served(struct cfq_data *cfqd, struct cfq_group *cfqg,
 | 
			
		|||
				struct cfq_queue *cfqq)
 | 
			
		||||
{
 | 
			
		||||
	struct cfq_rb_root *st = &cfqd->grp_service_tree;
 | 
			
		||||
	unsigned int used_sl, charge_sl;
 | 
			
		||||
	unsigned int used_sl, charge;
 | 
			
		||||
	int nr_sync = cfqg->nr_cfqq - cfqg_busy_async_queues(cfqd, cfqg)
 | 
			
		||||
			- cfqg->service_tree_idle.count;
 | 
			
		||||
 | 
			
		||||
	BUG_ON(nr_sync < 0);
 | 
			
		||||
	used_sl = charge_sl = cfq_cfqq_slice_usage(cfqq);
 | 
			
		||||
	used_sl = charge = cfq_cfqq_slice_usage(cfqq);
 | 
			
		||||
 | 
			
		||||
	if (!cfq_cfqq_sync(cfqq) && !nr_sync)
 | 
			
		||||
		charge_sl = cfqq->allocated_slice;
 | 
			
		||||
	if (iops_mode(cfqd))
 | 
			
		||||
		charge = cfqq->slice_dispatch;
 | 
			
		||||
	else if (!cfq_cfqq_sync(cfqq) && !nr_sync)
 | 
			
		||||
		charge = cfqq->allocated_slice;
 | 
			
		||||
 | 
			
		||||
	/* Can't update vdisktime while group is on service tree */
 | 
			
		||||
	cfq_rb_erase(&cfqg->rb_node, st);
 | 
			
		||||
	cfqg->vdisktime += cfq_scale_slice(charge_sl, cfqg);
 | 
			
		||||
	cfqg->vdisktime += cfq_scale_slice(charge, cfqg);
 | 
			
		||||
	__cfq_group_service_tree_add(st, cfqg);
 | 
			
		||||
 | 
			
		||||
	/* This group is being expired. Save the context */
 | 
			
		||||
| 
						 | 
				
			
			@ -940,6 +962,9 @@ static void cfq_group_served(struct cfq_data *cfqd, struct cfq_group *cfqg,
 | 
			
		|||
 | 
			
		||||
	cfq_log_cfqg(cfqd, cfqg, "served: vt=%llu min_vt=%llu", cfqg->vdisktime,
 | 
			
		||||
					st->min_vdisktime);
 | 
			
		||||
	cfq_log_cfqq(cfqq->cfqd, cfqq, "sl_used=%u disp=%u charge=%u iops=%u"
 | 
			
		||||
			" sect=%u", used_sl, cfqq->slice_dispatch, charge,
 | 
			
		||||
			iops_mode(cfqd), cfqq->nr_sectors);
 | 
			
		||||
	cfq_blkiocg_update_timeslice_used(&cfqg->blkg, used_sl);
 | 
			
		||||
	cfq_blkiocg_set_start_empty_time(&cfqg->blkg);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1587,6 +1612,7 @@ static void __cfq_set_active_queue(struct cfq_data *cfqd,
 | 
			
		|||
		cfqq->allocated_slice = 0;
 | 
			
		||||
		cfqq->slice_end = 0;
 | 
			
		||||
		cfqq->slice_dispatch = 0;
 | 
			
		||||
		cfqq->nr_sectors = 0;
 | 
			
		||||
 | 
			
		||||
		cfq_clear_cfqq_wait_request(cfqq);
 | 
			
		||||
		cfq_clear_cfqq_must_dispatch(cfqq);
 | 
			
		||||
| 
						 | 
				
			
			@ -1839,6 +1865,9 @@ static bool cfq_should_idle(struct cfq_data *cfqd, struct cfq_queue *cfqq)
 | 
			
		|||
	BUG_ON(!service_tree);
 | 
			
		||||
	BUG_ON(!service_tree->count);
 | 
			
		||||
 | 
			
		||||
	if (!cfqd->cfq_slice_idle)
 | 
			
		||||
		return false;
 | 
			
		||||
 | 
			
		||||
	/* We never do for idle class queues. */
 | 
			
		||||
	if (prio == IDLE_WORKLOAD)
 | 
			
		||||
		return false;
 | 
			
		||||
| 
						 | 
				
			
			@ -1863,7 +1892,7 @@ static void cfq_arm_slice_timer(struct cfq_data *cfqd)
 | 
			
		|||
{
 | 
			
		||||
	struct cfq_queue *cfqq = cfqd->active_queue;
 | 
			
		||||
	struct cfq_io_context *cic;
 | 
			
		||||
	unsigned long sl;
 | 
			
		||||
	unsigned long sl, group_idle = 0;
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * SSD device without seek penalty, disable idling. But only do so
 | 
			
		||||
| 
						 | 
				
			
			@ -1879,8 +1908,13 @@ static void cfq_arm_slice_timer(struct cfq_data *cfqd)
 | 
			
		|||
	/*
 | 
			
		||||
	 * idle is disabled, either manually or by past process history
 | 
			
		||||
	 */
 | 
			
		||||
	if (!cfqd->cfq_slice_idle || !cfq_should_idle(cfqd, cfqq))
 | 
			
		||||
		return;
 | 
			
		||||
	if (!cfq_should_idle(cfqd, cfqq)) {
 | 
			
		||||
		/* no queue idling. Check for group idling */
 | 
			
		||||
		if (cfqd->cfq_group_idle)
 | 
			
		||||
			group_idle = cfqd->cfq_group_idle;
 | 
			
		||||
		else
 | 
			
		||||
			return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * still active requests from this queue, don't idle
 | 
			
		||||
| 
						 | 
				
			
			@ -1907,13 +1941,21 @@ static void cfq_arm_slice_timer(struct cfq_data *cfqd)
 | 
			
		|||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* There are other queues in the group, don't do group idle */
 | 
			
		||||
	if (group_idle && cfqq->cfqg->nr_cfqq > 1)
 | 
			
		||||
		return;
 | 
			
		||||
 | 
			
		||||
	cfq_mark_cfqq_wait_request(cfqq);
 | 
			
		||||
 | 
			
		||||
	sl = cfqd->cfq_slice_idle;
 | 
			
		||||
	if (group_idle)
 | 
			
		||||
		sl = cfqd->cfq_group_idle;
 | 
			
		||||
	else
 | 
			
		||||
		sl = cfqd->cfq_slice_idle;
 | 
			
		||||
 | 
			
		||||
	mod_timer(&cfqd->idle_slice_timer, jiffies + sl);
 | 
			
		||||
	cfq_blkiocg_update_set_idle_time_stats(&cfqq->cfqg->blkg);
 | 
			
		||||
	cfq_log_cfqq(cfqd, cfqq, "arm_idle: %lu", sl);
 | 
			
		||||
	cfq_log_cfqq(cfqd, cfqq, "arm_idle: %lu group_idle: %d", sl,
 | 
			
		||||
			group_idle ? 1 : 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
| 
						 | 
				
			
			@ -1929,9 +1971,11 @@ static void cfq_dispatch_insert(struct request_queue *q, struct request *rq)
 | 
			
		|||
	cfqq->next_rq = cfq_find_next_rq(cfqd, cfqq, rq);
 | 
			
		||||
	cfq_remove_request(rq);
 | 
			
		||||
	cfqq->dispatched++;
 | 
			
		||||
	(RQ_CFQG(rq))->dispatched++;
 | 
			
		||||
	elv_dispatch_sort(q, rq);
 | 
			
		||||
 | 
			
		||||
	cfqd->rq_in_flight[cfq_cfqq_sync(cfqq)]++;
 | 
			
		||||
	cfqq->nr_sectors += blk_rq_sectors(rq);
 | 
			
		||||
	cfq_blkiocg_update_dispatch_stats(&cfqq->cfqg->blkg, blk_rq_bytes(rq),
 | 
			
		||||
					rq_data_dir(rq), rq_is_sync(rq));
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -2198,7 +2242,7 @@ static struct cfq_queue *cfq_select_queue(struct cfq_data *cfqd)
 | 
			
		|||
			cfqq = NULL;
 | 
			
		||||
			goto keep_queue;
 | 
			
		||||
		} else
 | 
			
		||||
			goto expire;
 | 
			
		||||
			goto check_group_idle;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
| 
						 | 
				
			
			@ -2226,8 +2270,23 @@ static struct cfq_queue *cfq_select_queue(struct cfq_data *cfqd)
 | 
			
		|||
	 * flight or is idling for a new request, allow either of these
 | 
			
		||||
	 * conditions to happen (or time out) before selecting a new queue.
 | 
			
		||||
	 */
 | 
			
		||||
	if (timer_pending(&cfqd->idle_slice_timer) ||
 | 
			
		||||
	    (cfqq->dispatched && cfq_should_idle(cfqd, cfqq))) {
 | 
			
		||||
	if (timer_pending(&cfqd->idle_slice_timer)) {
 | 
			
		||||
		cfqq = NULL;
 | 
			
		||||
		goto keep_queue;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (cfqq->dispatched && cfq_should_idle(cfqd, cfqq)) {
 | 
			
		||||
		cfqq = NULL;
 | 
			
		||||
		goto keep_queue;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * If group idle is enabled and there are requests dispatched from
 | 
			
		||||
	 * this group, wait for requests to complete.
 | 
			
		||||
	 */
 | 
			
		||||
check_group_idle:
 | 
			
		||||
	if (cfqd->cfq_group_idle && cfqq->cfqg->nr_cfqq == 1
 | 
			
		||||
	    && cfqq->cfqg->dispatched) {
 | 
			
		||||
		cfqq = NULL;
 | 
			
		||||
		goto keep_queue;
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -3375,6 +3434,7 @@ static void cfq_completed_request(struct request_queue *q, struct request *rq)
 | 
			
		|||
	WARN_ON(!cfqq->dispatched);
 | 
			
		||||
	cfqd->rq_in_driver--;
 | 
			
		||||
	cfqq->dispatched--;
 | 
			
		||||
	(RQ_CFQG(rq))->dispatched--;
 | 
			
		||||
	cfq_blkiocg_update_completion_stats(&cfqq->cfqg->blkg,
 | 
			
		||||
			rq_start_time_ns(rq), rq_io_start_time_ns(rq),
 | 
			
		||||
			rq_data_dir(rq), rq_is_sync(rq));
 | 
			
		||||
| 
						 | 
				
			
			@ -3404,7 +3464,10 @@ static void cfq_completed_request(struct request_queue *q, struct request *rq)
 | 
			
		|||
		 * the queue.
 | 
			
		||||
		 */
 | 
			
		||||
		if (cfq_should_wait_busy(cfqd, cfqq)) {
 | 
			
		||||
			cfqq->slice_end = jiffies + cfqd->cfq_slice_idle;
 | 
			
		||||
			unsigned long extend_sl = cfqd->cfq_slice_idle;
 | 
			
		||||
			if (!cfqd->cfq_slice_idle)
 | 
			
		||||
				extend_sl = cfqd->cfq_group_idle;
 | 
			
		||||
			cfqq->slice_end = jiffies + extend_sl;
 | 
			
		||||
			cfq_mark_cfqq_wait_busy(cfqq);
 | 
			
		||||
			cfq_log_cfqq(cfqd, cfqq, "will busy wait");
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			@ -3850,6 +3913,7 @@ static void *cfq_init_queue(struct request_queue *q)
 | 
			
		|||
	cfqd->cfq_slice[1] = cfq_slice_sync;
 | 
			
		||||
	cfqd->cfq_slice_async_rq = cfq_slice_async_rq;
 | 
			
		||||
	cfqd->cfq_slice_idle = cfq_slice_idle;
 | 
			
		||||
	cfqd->cfq_group_idle = cfq_group_idle;
 | 
			
		||||
	cfqd->cfq_latency = 1;
 | 
			
		||||
	cfqd->cfq_group_isolation = 0;
 | 
			
		||||
	cfqd->hw_tag = -1;
 | 
			
		||||
| 
						 | 
				
			
			@ -3922,6 +3986,7 @@ SHOW_FUNCTION(cfq_fifo_expire_async_show, cfqd->cfq_fifo_expire[0], 1);
 | 
			
		|||
SHOW_FUNCTION(cfq_back_seek_max_show, cfqd->cfq_back_max, 0);
 | 
			
		||||
SHOW_FUNCTION(cfq_back_seek_penalty_show, cfqd->cfq_back_penalty, 0);
 | 
			
		||||
SHOW_FUNCTION(cfq_slice_idle_show, cfqd->cfq_slice_idle, 1);
 | 
			
		||||
SHOW_FUNCTION(cfq_group_idle_show, cfqd->cfq_group_idle, 1);
 | 
			
		||||
SHOW_FUNCTION(cfq_slice_sync_show, cfqd->cfq_slice[1], 1);
 | 
			
		||||
SHOW_FUNCTION(cfq_slice_async_show, cfqd->cfq_slice[0], 1);
 | 
			
		||||
SHOW_FUNCTION(cfq_slice_async_rq_show, cfqd->cfq_slice_async_rq, 0);
 | 
			
		||||
| 
						 | 
				
			
			@ -3954,6 +4019,7 @@ STORE_FUNCTION(cfq_back_seek_max_store, &cfqd->cfq_back_max, 0, UINT_MAX, 0);
 | 
			
		|||
STORE_FUNCTION(cfq_back_seek_penalty_store, &cfqd->cfq_back_penalty, 1,
 | 
			
		||||
		UINT_MAX, 0);
 | 
			
		||||
STORE_FUNCTION(cfq_slice_idle_store, &cfqd->cfq_slice_idle, 0, UINT_MAX, 1);
 | 
			
		||||
STORE_FUNCTION(cfq_group_idle_store, &cfqd->cfq_group_idle, 0, UINT_MAX, 1);
 | 
			
		||||
STORE_FUNCTION(cfq_slice_sync_store, &cfqd->cfq_slice[1], 1, UINT_MAX, 1);
 | 
			
		||||
STORE_FUNCTION(cfq_slice_async_store, &cfqd->cfq_slice[0], 1, UINT_MAX, 1);
 | 
			
		||||
STORE_FUNCTION(cfq_slice_async_rq_store, &cfqd->cfq_slice_async_rq, 1,
 | 
			
		||||
| 
						 | 
				
			
			@ -3975,6 +4041,7 @@ static struct elv_fs_entry cfq_attrs[] = {
 | 
			
		|||
	CFQ_ATTR(slice_async),
 | 
			
		||||
	CFQ_ATTR(slice_async_rq),
 | 
			
		||||
	CFQ_ATTR(slice_idle),
 | 
			
		||||
	CFQ_ATTR(group_idle),
 | 
			
		||||
	CFQ_ATTR(low_latency),
 | 
			
		||||
	CFQ_ATTR(group_isolation),
 | 
			
		||||
	__ATTR_NULL
 | 
			
		||||
| 
						 | 
				
			
			@ -4028,6 +4095,12 @@ static int __init cfq_init(void)
 | 
			
		|||
	if (!cfq_slice_idle)
 | 
			
		||||
		cfq_slice_idle = 1;
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_CFQ_GROUP_IOSCHED
 | 
			
		||||
	if (!cfq_group_idle)
 | 
			
		||||
		cfq_group_idle = 1;
 | 
			
		||||
#else
 | 
			
		||||
		cfq_group_idle = 0;
 | 
			
		||||
#endif
 | 
			
		||||
	if (cfq_slab_setup())
 | 
			
		||||
		return -ENOMEM;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1009,18 +1009,19 @@ static int elevator_switch(struct request_queue *q, struct elevator_type *new_e)
 | 
			
		|||
{
 | 
			
		||||
	struct elevator_queue *old_elevator, *e;
 | 
			
		||||
	void *data;
 | 
			
		||||
	int err;
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Allocate new elevator
 | 
			
		||||
	 */
 | 
			
		||||
	e = elevator_alloc(q, new_e);
 | 
			
		||||
	if (!e)
 | 
			
		||||
		return 0;
 | 
			
		||||
		return -ENOMEM;
 | 
			
		||||
 | 
			
		||||
	data = elevator_init_queue(q, e);
 | 
			
		||||
	if (!data) {
 | 
			
		||||
		kobject_put(&e->kobj);
 | 
			
		||||
		return 0;
 | 
			
		||||
		return -ENOMEM;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
| 
						 | 
				
			
			@ -1043,7 +1044,8 @@ static int elevator_switch(struct request_queue *q, struct elevator_type *new_e)
 | 
			
		|||
 | 
			
		||||
	__elv_unregister_queue(old_elevator);
 | 
			
		||||
 | 
			
		||||
	if (elv_register_queue(q))
 | 
			
		||||
	err = elv_register_queue(q);
 | 
			
		||||
	if (err)
 | 
			
		||||
		goto fail_register;
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
| 
						 | 
				
			
			@ -1056,7 +1058,7 @@ static int elevator_switch(struct request_queue *q, struct elevator_type *new_e)
 | 
			
		|||
 | 
			
		||||
	blk_add_trace_msg(q, "elv switch: %s", e->elevator_type->elevator_name);
 | 
			
		||||
 | 
			
		||||
	return 1;
 | 
			
		||||
	return 0;
 | 
			
		||||
 | 
			
		||||
fail_register:
 | 
			
		||||
	/*
 | 
			
		||||
| 
						 | 
				
			
			@ -1071,17 +1073,19 @@ static int elevator_switch(struct request_queue *q, struct elevator_type *new_e)
 | 
			
		|||
	queue_flag_clear(QUEUE_FLAG_ELVSWITCH, q);
 | 
			
		||||
	spin_unlock_irq(q->queue_lock);
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
	return err;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ssize_t elv_iosched_store(struct request_queue *q, const char *name,
 | 
			
		||||
			  size_t count)
 | 
			
		||||
/*
 | 
			
		||||
 * Switch this queue to the given IO scheduler.
 | 
			
		||||
 */
 | 
			
		||||
int elevator_change(struct request_queue *q, const char *name)
 | 
			
		||||
{
 | 
			
		||||
	char elevator_name[ELV_NAME_MAX];
 | 
			
		||||
	struct elevator_type *e;
 | 
			
		||||
 | 
			
		||||
	if (!q->elevator)
 | 
			
		||||
		return count;
 | 
			
		||||
		return -ENXIO;
 | 
			
		||||
 | 
			
		||||
	strlcpy(elevator_name, name, sizeof(elevator_name));
 | 
			
		||||
	e = elevator_get(strstrip(elevator_name));
 | 
			
		||||
| 
						 | 
				
			
			@ -1092,13 +1096,27 @@ ssize_t elv_iosched_store(struct request_queue *q, const char *name,
 | 
			
		|||
 | 
			
		||||
	if (!strcmp(elevator_name, q->elevator->elevator_type->elevator_name)) {
 | 
			
		||||
		elevator_put(e);
 | 
			
		||||
		return count;
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!elevator_switch(q, e))
 | 
			
		||||
		printk(KERN_ERR "elevator: switch to %s failed\n",
 | 
			
		||||
							elevator_name);
 | 
			
		||||
	return count;
 | 
			
		||||
	return elevator_switch(q, e);
 | 
			
		||||
}
 | 
			
		||||
EXPORT_SYMBOL(elevator_change);
 | 
			
		||||
 | 
			
		||||
ssize_t elv_iosched_store(struct request_queue *q, const char *name,
 | 
			
		||||
			  size_t count)
 | 
			
		||||
{
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
	if (!q->elevator)
 | 
			
		||||
		return count;
 | 
			
		||||
 | 
			
		||||
	ret = elevator_change(q, name);
 | 
			
		||||
	if (!ret)
 | 
			
		||||
		return count;
 | 
			
		||||
 | 
			
		||||
	printk(KERN_ERR "elevator: switch to %s failed\n", name);
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ssize_t elv_iosched_show(struct request_queue *q, char *name)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -297,6 +297,8 @@ static void enqueue_cmd_and_start_io(ctlr_info_t *h,
 | 
			
		|||
	spin_lock_irqsave(&h->lock, flags);
 | 
			
		||||
	addQ(&h->reqQ, c);
 | 
			
		||||
	h->Qdepth++;
 | 
			
		||||
	if (h->Qdepth > h->maxQsinceinit)
 | 
			
		||||
		h->maxQsinceinit = h->Qdepth;
 | 
			
		||||
	start_io(h);
 | 
			
		||||
	spin_unlock_irqrestore(&h->lock, flags);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -4519,6 +4521,12 @@ static __devinit int cciss_kdump_hard_reset_controller(struct pci_dev *pdev)
 | 
			
		|||
	misc_fw_support = readl(&cfgtable->misc_fw_support);
 | 
			
		||||
	use_doorbell = misc_fw_support & MISC_FW_DOORBELL_RESET;
 | 
			
		||||
 | 
			
		||||
	/* The doorbell reset seems to cause lockups on some Smart
 | 
			
		||||
	 * Arrays (e.g. P410, P410i, maybe others).  Until this is
 | 
			
		||||
	 * fixed or at least isolated, avoid the doorbell reset.
 | 
			
		||||
	 */
 | 
			
		||||
	use_doorbell = 0;
 | 
			
		||||
 | 
			
		||||
	rc = cciss_controller_hard_reset(pdev, vaddr, use_doorbell);
 | 
			
		||||
	if (rc)
 | 
			
		||||
		goto unmap_cfgtable;
 | 
			
		||||
| 
						 | 
				
			
			@ -4712,6 +4720,9 @@ static int __devinit cciss_init_one(struct pci_dev *pdev,
 | 
			
		|||
	h->scatter_list = kmalloc(h->max_commands *
 | 
			
		||||
						sizeof(struct scatterlist *),
 | 
			
		||||
						GFP_KERNEL);
 | 
			
		||||
	if (!h->scatter_list)
 | 
			
		||||
		goto clean4;
 | 
			
		||||
 | 
			
		||||
	for (k = 0; k < h->nr_cmds; k++) {
 | 
			
		||||
		h->scatter_list[k] = kmalloc(sizeof(struct scatterlist) *
 | 
			
		||||
							h->maxsgentries,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -477,7 +477,7 @@ static int do_bio_filebacked(struct loop_device *lo, struct bio *bio)
 | 
			
		|||
	pos = ((loff_t) bio->bi_sector << 9) + lo->lo_offset;
 | 
			
		||||
 | 
			
		||||
	if (bio_rw(bio) == WRITE) {
 | 
			
		||||
		bool barrier = (bio->bi_rw & REQ_HARDBARRIER);
 | 
			
		||||
		bool barrier = !!(bio->bi_rw & REQ_HARDBARRIER);
 | 
			
		||||
		struct file *file = lo->lo_backing_file;
 | 
			
		||||
 | 
			
		||||
		if (barrier) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -974,8 +974,7 @@ static int mg_probe(struct platform_device *plat_dev)
 | 
			
		|||
	host->breq->queuedata = host;
 | 
			
		||||
 | 
			
		||||
	/* mflash is random device, thanx for the noop */
 | 
			
		||||
	elevator_exit(host->breq->elevator);
 | 
			
		||||
	err = elevator_init(host->breq, "noop");
 | 
			
		||||
	err = elevator_change(host->breq, "noop");
 | 
			
		||||
	if (err) {
 | 
			
		||||
		printk(KERN_ERR "%s:%d (elevator_init) fail\n",
 | 
			
		||||
				__func__, __LINE__);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -217,8 +217,7 @@ tapeblock_setup_device(struct tape_device * device)
 | 
			
		|||
	if (!blkdat->request_queue)
 | 
			
		||||
		return -ENOMEM;
 | 
			
		||||
 | 
			
		||||
	elevator_exit(blkdat->request_queue->elevator);
 | 
			
		||||
	rc = elevator_init(blkdat->request_queue, "noop");
 | 
			
		||||
	rc = elevator_change(blkdat->request_queue, "noop");
 | 
			
		||||
	if (rc)
 | 
			
		||||
		goto cleanup_queue;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -413,10 +413,10 @@ int bio_integrity_prep(struct bio *bio)
 | 
			
		|||
 | 
			
		||||
	/* Allocate kernel buffer for protection data */
 | 
			
		||||
	len = sectors * blk_integrity_tuple_size(bi);
 | 
			
		||||
	buf = kmalloc(len, GFP_NOIO | __GFP_NOFAIL | q->bounce_gfp);
 | 
			
		||||
	buf = kmalloc(len, GFP_NOIO | q->bounce_gfp);
 | 
			
		||||
	if (unlikely(buf == NULL)) {
 | 
			
		||||
		printk(KERN_ERR "could not allocate integrity buffer\n");
 | 
			
		||||
		return -EIO;
 | 
			
		||||
		return -ENOMEM;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	end = (((unsigned long) buf) + len + PAGE_SIZE - 1) >> PAGE_SHIFT;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -808,7 +808,7 @@ int bdi_writeback_thread(void *data)
 | 
			
		|||
			wb->last_active = jiffies;
 | 
			
		||||
 | 
			
		||||
		set_current_state(TASK_INTERRUPTIBLE);
 | 
			
		||||
		if (!list_empty(&bdi->work_list)) {
 | 
			
		||||
		if (!list_empty(&bdi->work_list) || kthread_should_stop()) {
 | 
			
		||||
			__set_current_state(TASK_RUNNING);
 | 
			
		||||
			continue;
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -136,6 +136,7 @@ extern ssize_t elv_iosched_store(struct request_queue *, const char *, size_t);
 | 
			
		|||
 | 
			
		||||
extern int elevator_init(struct request_queue *, char *);
 | 
			
		||||
extern void elevator_exit(struct elevator_queue *);
 | 
			
		||||
extern int elevator_change(struct request_queue *, const char *);
 | 
			
		||||
extern int elv_rq_merge_ok(struct request *, struct bio *);
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -248,8 +248,18 @@ int __sg_alloc_table(struct sg_table *table, unsigned int nents,
 | 
			
		|||
		left -= sg_size;
 | 
			
		||||
 | 
			
		||||
		sg = alloc_fn(alloc_size, gfp_mask);
 | 
			
		||||
		if (unlikely(!sg))
 | 
			
		||||
			return -ENOMEM;
 | 
			
		||||
		if (unlikely(!sg)) {
 | 
			
		||||
			/*
 | 
			
		||||
			 * Adjust entry count to reflect that the last
 | 
			
		||||
			 * entry of the previous table won't be used for
 | 
			
		||||
			 * linkage.  Without this, sg_kfree() may get
 | 
			
		||||
			 * confused.
 | 
			
		||||
			 */
 | 
			
		||||
			if (prv)
 | 
			
		||||
				table->nents = ++table->orig_nents;
 | 
			
		||||
 | 
			
		||||
 			return -ENOMEM;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		sg_init_table(sg, alloc_size);
 | 
			
		||||
		table->nents = table->orig_nents += sg_size;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -445,8 +445,8 @@ static int bdi_forker_thread(void *ptr)
 | 
			
		|||
		switch (action) {
 | 
			
		||||
		case FORK_THREAD:
 | 
			
		||||
			__set_current_state(TASK_RUNNING);
 | 
			
		||||
			task = kthread_run(bdi_writeback_thread, &bdi->wb, "flush-%s",
 | 
			
		||||
					   dev_name(bdi->dev));
 | 
			
		||||
			task = kthread_create(bdi_writeback_thread, &bdi->wb,
 | 
			
		||||
					      "flush-%s", dev_name(bdi->dev));
 | 
			
		||||
			if (IS_ERR(task)) {
 | 
			
		||||
				/*
 | 
			
		||||
				 * If thread creation fails, force writeout of
 | 
			
		||||
| 
						 | 
				
			
			@ -457,10 +457,13 @@ static int bdi_forker_thread(void *ptr)
 | 
			
		|||
				/*
 | 
			
		||||
				 * The spinlock makes sure we do not lose
 | 
			
		||||
				 * wake-ups when racing with 'bdi_queue_work()'.
 | 
			
		||||
				 * And as soon as the bdi thread is visible, we
 | 
			
		||||
				 * can start it.
 | 
			
		||||
				 */
 | 
			
		||||
				spin_lock_bh(&bdi->wb_lock);
 | 
			
		||||
				bdi->wb.task = task;
 | 
			
		||||
				spin_unlock_bh(&bdi->wb_lock);
 | 
			
		||||
				wake_up_process(task);
 | 
			
		||||
			}
 | 
			
		||||
			break;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue