|  | @@ -350,3 +350,161 @@ struct request_list *__blk_queue_next_rl(struct request_list *rl,
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  	blkg = container_of(ent, struct blkcg_gq, q_node);
 | 
	
		
			
				|  |  |  	return &blkg->rl;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static int blkcg_reset_stats(struct cgroup *cgroup, struct cftype *cftype,
 | 
	
		
			
				|  |  | +			     u64 val)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	struct blkcg *blkcg = cgroup_to_blkcg(cgroup);
 | 
	
		
			
				|  |  | +	struct blkcg_gq *blkg;
 | 
	
		
			
				|  |  | +	struct hlist_node *n;
 | 
	
		
			
				|  |  | +	int i;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	mutex_lock(&blkcg_pol_mutex);
 | 
	
		
			
				|  |  | +	spin_lock_irq(&blkcg->lock);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	/*
 | 
	
		
			
				|  |  | +	 * Note that stat reset is racy - it doesn't synchronize against
 | 
	
		
			
				|  |  | +	 * stat updates.  This is a debug feature which shouldn't exist
 | 
	
		
			
				|  |  | +	 * anyway.  If you get hit by a race, retry.
 | 
	
		
			
				|  |  | +	 */
 | 
	
		
			
				|  |  | +	hlist_for_each_entry(blkg, n, &blkcg->blkg_list, blkcg_node) {
 | 
	
		
			
				|  |  | +		for (i = 0; i < BLKCG_MAX_POLS; i++) {
 | 
	
		
			
				|  |  | +			struct blkcg_policy *pol = blkcg_policy[i];
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +			if (blkcg_policy_enabled(blkg->q, pol) &&
 | 
	
		
			
				|  |  | +			    pol->pd_reset_stats_fn)
 | 
	
		
			
				|  |  | +				pol->pd_reset_stats_fn(blkg);
 | 
	
		
			
				|  |  | +		}
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	spin_unlock_irq(&blkcg->lock);
 | 
	
		
			
				|  |  | +	mutex_unlock(&blkcg_pol_mutex);
 | 
	
		
			
				|  |  | +	return 0;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +static const char *blkg_dev_name(struct blkcg_gq *blkg)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	/* some drivers (floppy) instantiate a queue w/o disk registered */
 | 
	
		
			
				|  |  | +	if (blkg->q->backing_dev_info.dev)
 | 
	
		
			
				|  |  | +		return dev_name(blkg->q->backing_dev_info.dev);
 | 
	
		
			
				|  |  | +	return NULL;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +/**
 | 
	
		
			
				|  |  | + * blkcg_print_blkgs - helper for printing per-blkg data
 | 
	
		
			
				|  |  | + * @sf: seq_file to print to
 | 
	
		
			
				|  |  | + * @blkcg: blkcg of interest
 | 
	
		
			
				|  |  | + * @prfill: fill function to print out a blkg
 | 
	
		
			
				|  |  | + * @pol: policy in question
 | 
	
		
			
				|  |  | + * @data: data to be passed to @prfill
 | 
	
		
			
				|  |  | + * @show_total: to print out sum of prfill return values or not
 | 
	
		
			
				|  |  | + *
 | 
	
		
			
				|  |  | + * This function invokes @prfill on each blkg of @blkcg if pd for the
 | 
	
		
			
				|  |  | + * policy specified by @pol exists.  @prfill is invoked with @sf, the
 | 
	
		
			
				|  |  | + * policy data and @data.  If @show_total is %true, the sum of the return
 | 
	
		
			
				|  |  | + * values from @prfill is printed with "Total" label at the end.
 | 
	
		
			
				|  |  | + *
 | 
	
		
			
				|  |  | + * This is to be used to construct print functions for
 | 
	
		
			
				|  |  | + * cftype->read_seq_string method.
 | 
	
		
			
				|  |  | + */
 | 
	
		
			
				|  |  | +void blkcg_print_blkgs(struct seq_file *sf, struct blkcg *blkcg,
 | 
	
		
			
				|  |  | +		       u64 (*prfill)(struct seq_file *,
 | 
	
		
			
				|  |  | +				     struct blkg_policy_data *, int),
 | 
	
		
			
				|  |  | +		       const struct blkcg_policy *pol, int data,
 | 
	
		
			
				|  |  | +		       bool show_total)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	struct blkcg_gq *blkg;
 | 
	
		
			
				|  |  | +	struct hlist_node *n;
 | 
	
		
			
				|  |  | +	u64 total = 0;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	spin_lock_irq(&blkcg->lock);
 | 
	
		
			
				|  |  | +	hlist_for_each_entry(blkg, n, &blkcg->blkg_list, blkcg_node)
 | 
	
		
			
				|  |  | +		if (blkcg_policy_enabled(blkg->q, pol))
 | 
	
		
			
				|  |  | +			total += prfill(sf, blkg->pd[pol->plid], data);
 | 
	
		
			
				|  |  | +	spin_unlock_irq(&blkcg->lock);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	if (show_total)
 | 
	
		
			
				|  |  | +		seq_printf(sf, "Total %llu\n", (unsigned long long)total);
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +EXPORT_SYMBOL_GPL(blkcg_print_blkgs);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +/**
 | 
	
		
			
				|  |  | + * __blkg_prfill_u64 - prfill helper for a single u64 value
 | 
	
		
			
				|  |  | + * @sf: seq_file to print to
 | 
	
		
			
				|  |  | + * @pd: policy private data of interest
 | 
	
		
			
				|  |  | + * @v: value to print
 | 
	
		
			
				|  |  | + *
 | 
	
		
			
				|  |  | + * Print @v to @sf for the device assocaited with @pd.
 | 
	
		
			
				|  |  | + */
 | 
	
		
			
				|  |  | +u64 __blkg_prfill_u64(struct seq_file *sf, struct blkg_policy_data *pd, u64 v)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	const char *dname = blkg_dev_name(pd->blkg);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	if (!dname)
 | 
	
		
			
				|  |  | +		return 0;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	seq_printf(sf, "%s %llu\n", dname, (unsigned long long)v);
 | 
	
		
			
				|  |  | +	return v;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +EXPORT_SYMBOL_GPL(__blkg_prfill_u64);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +/**
 | 
	
		
			
				|  |  | + * __blkg_prfill_rwstat - prfill helper for a blkg_rwstat
 | 
	
		
			
				|  |  | + * @sf: seq_file to print to
 | 
	
		
			
				|  |  | + * @pd: policy private data of interest
 | 
	
		
			
				|  |  | + * @rwstat: rwstat to print
 | 
	
		
			
				|  |  | + *
 | 
	
		
			
				|  |  | + * Print @rwstat to @sf for the device assocaited with @pd.
 | 
	
		
			
				|  |  | + */
 | 
	
		
			
				|  |  | +u64 __blkg_prfill_rwstat(struct seq_file *sf, struct blkg_policy_data *pd,
 | 
	
		
			
				|  |  | +			 const struct blkg_rwstat *rwstat)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	static const char *rwstr[] = {
 | 
	
		
			
				|  |  | +		[BLKG_RWSTAT_READ]	= "Read",
 | 
	
		
			
				|  |  | +		[BLKG_RWSTAT_WRITE]	= "Write",
 | 
	
		
			
				|  |  | +		[BLKG_RWSTAT_SYNC]	= "Sync",
 | 
	
		
			
				|  |  | +		[BLKG_RWSTAT_ASYNC]	= "Async",
 | 
	
		
			
				|  |  | +	};
 | 
	
		
			
				|  |  | +	const char *dname = blkg_dev_name(pd->blkg);
 | 
	
		
			
				|  |  | +	u64 v;
 | 
	
		
			
				|  |  | +	int i;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	if (!dname)
 | 
	
		
			
				|  |  | +		return 0;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	for (i = 0; i < BLKG_RWSTAT_NR; i++)
 | 
	
		
			
				|  |  | +		seq_printf(sf, "%s %s %llu\n", dname, rwstr[i],
 | 
	
		
			
				|  |  | +			   (unsigned long long)rwstat->cnt[i]);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +	v = rwstat->cnt[BLKG_RWSTAT_READ] + rwstat->cnt[BLKG_RWSTAT_WRITE];
 | 
	
		
			
				|  |  | +	seq_printf(sf, "%s Total %llu\n", dname, (unsigned long long)v);
 | 
	
		
			
				|  |  | +	return v;
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +/**
 | 
	
		
			
				|  |  | + * blkg_prfill_stat - prfill callback for blkg_stat
 | 
	
		
			
				|  |  | + * @sf: seq_file to print to
 | 
	
		
			
				|  |  | + * @pd: policy private data of interest
 | 
	
		
			
				|  |  | + * @off: offset to the blkg_stat in @pd
 | 
	
		
			
				|  |  | + *
 | 
	
		
			
				|  |  | + * prfill callback for printing a blkg_stat.
 | 
	
		
			
				|  |  | + */
 | 
	
		
			
				|  |  | +u64 blkg_prfill_stat(struct seq_file *sf, struct blkg_policy_data *pd, int off)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	return __blkg_prfill_u64(sf, pd, blkg_stat_read((void *)pd + off));
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +EXPORT_SYMBOL_GPL(blkg_prfill_stat);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +/**
 | 
	
		
			
				|  |  | + * blkg_prfill_rwstat - prfill callback for blkg_rwstat
 | 
	
		
			
				|  |  | + * @sf: seq_file to print to
 | 
	
		
			
				|  |  | + * @pd: policy private data of interest
 | 
	
		
			
				|  |  | + * @off: offset to the blkg_rwstat in @pd
 | 
	
		
			
				|  |  | + *
 | 
	
		
			
				|  |  | + * prfill callback for printing a blkg_rwstat.
 | 
	
		
			
				|  |  | + */
 | 
	
		
			
				|  |  | +u64 blkg_prfill_rwstat(struct seq_file *sf, struct blkg_policy_data *pd,
 | 
	
		
			
				|  |  | +		       int off)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	struct blkg_rwstat rwstat = blkg_rwstat_read((void *)pd + off);
 |