xref: /linux/block/blk-cgroup-rwstat.c (revision 4f44657d)
11d156646STejun Heo /* SPDX-License-Identifier: GPL-2.0
21d156646STejun Heo  *
31d156646STejun Heo  * Legacy blkg rwstat helpers enabled by CONFIG_BLK_CGROUP_RWSTAT.
41d156646STejun Heo  * Do not use in new code.
51d156646STejun Heo  */
61d156646STejun Heo #include "blk-cgroup-rwstat.h"
71d156646STejun Heo 
blkg_rwstat_init(struct blkg_rwstat * rwstat,gfp_t gfp)81d156646STejun Heo int blkg_rwstat_init(struct blkg_rwstat *rwstat, gfp_t gfp)
91d156646STejun Heo {
101d156646STejun Heo 	int i, ret;
111d156646STejun Heo 
121d156646STejun Heo 	for (i = 0; i < BLKG_RWSTAT_NR; i++) {
131d156646STejun Heo 		ret = percpu_counter_init(&rwstat->cpu_cnt[i], 0, gfp);
141d156646STejun Heo 		if (ret) {
151d156646STejun Heo 			while (--i >= 0)
161d156646STejun Heo 				percpu_counter_destroy(&rwstat->cpu_cnt[i]);
171d156646STejun Heo 			return ret;
181d156646STejun Heo 		}
191d156646STejun Heo 		atomic64_set(&rwstat->aux_cnt[i], 0);
201d156646STejun Heo 	}
211d156646STejun Heo 	return 0;
221d156646STejun Heo }
231d156646STejun Heo EXPORT_SYMBOL_GPL(blkg_rwstat_init);
241d156646STejun Heo 
blkg_rwstat_exit(struct blkg_rwstat * rwstat)251d156646STejun Heo void blkg_rwstat_exit(struct blkg_rwstat *rwstat)
261d156646STejun Heo {
271d156646STejun Heo 	int i;
281d156646STejun Heo 
291d156646STejun Heo 	for (i = 0; i < BLKG_RWSTAT_NR; i++)
301d156646STejun Heo 		percpu_counter_destroy(&rwstat->cpu_cnt[i]);
311d156646STejun Heo }
321d156646STejun Heo EXPORT_SYMBOL_GPL(blkg_rwstat_exit);
331d156646STejun Heo 
341d156646STejun Heo /**
351d156646STejun Heo  * __blkg_prfill_rwstat - prfill helper for a blkg_rwstat
361d156646STejun Heo  * @sf: seq_file to print to
371d156646STejun Heo  * @pd: policy private data of interest
381d156646STejun Heo  * @rwstat: rwstat to print
391d156646STejun Heo  *
401d156646STejun Heo  * Print @rwstat to @sf for the device assocaited with @pd.
411d156646STejun Heo  */
__blkg_prfill_rwstat(struct seq_file * sf,struct blkg_policy_data * pd,const struct blkg_rwstat_sample * rwstat)421d156646STejun Heo u64 __blkg_prfill_rwstat(struct seq_file *sf, struct blkg_policy_data *pd,
431d156646STejun Heo 			 const struct blkg_rwstat_sample *rwstat)
441d156646STejun Heo {
451d156646STejun Heo 	static const char *rwstr[] = {
461d156646STejun Heo 		[BLKG_RWSTAT_READ]	= "Read",
471d156646STejun Heo 		[BLKG_RWSTAT_WRITE]	= "Write",
481d156646STejun Heo 		[BLKG_RWSTAT_SYNC]	= "Sync",
491d156646STejun Heo 		[BLKG_RWSTAT_ASYNC]	= "Async",
501d156646STejun Heo 		[BLKG_RWSTAT_DISCARD]	= "Discard",
511d156646STejun Heo 	};
521d156646STejun Heo 	const char *dname = blkg_dev_name(pd->blkg);
531d156646STejun Heo 	u64 v;
541d156646STejun Heo 	int i;
551d156646STejun Heo 
561d156646STejun Heo 	if (!dname)
571d156646STejun Heo 		return 0;
581d156646STejun Heo 
591d156646STejun Heo 	for (i = 0; i < BLKG_RWSTAT_NR; i++)
601d156646STejun Heo 		seq_printf(sf, "%s %s %llu\n", dname, rwstr[i],
611d156646STejun Heo 			   rwstat->cnt[i]);
621d156646STejun Heo 
631d156646STejun Heo 	v = rwstat->cnt[BLKG_RWSTAT_READ] +
641d156646STejun Heo 		rwstat->cnt[BLKG_RWSTAT_WRITE] +
651d156646STejun Heo 		rwstat->cnt[BLKG_RWSTAT_DISCARD];
661d156646STejun Heo 	seq_printf(sf, "%s Total %llu\n", dname, v);
671d156646STejun Heo 	return v;
681d156646STejun Heo }
691d156646STejun Heo EXPORT_SYMBOL_GPL(__blkg_prfill_rwstat);
701d156646STejun Heo 
711d156646STejun Heo /**
721d156646STejun Heo  * blkg_prfill_rwstat - prfill callback for blkg_rwstat
731d156646STejun Heo  * @sf: seq_file to print to
741d156646STejun Heo  * @pd: policy private data of interest
751d156646STejun Heo  * @off: offset to the blkg_rwstat in @pd
761d156646STejun Heo  *
771d156646STejun Heo  * prfill callback for printing a blkg_rwstat.
781d156646STejun Heo  */
blkg_prfill_rwstat(struct seq_file * sf,struct blkg_policy_data * pd,int off)791d156646STejun Heo u64 blkg_prfill_rwstat(struct seq_file *sf, struct blkg_policy_data *pd,
801d156646STejun Heo 		       int off)
811d156646STejun Heo {
821d156646STejun Heo 	struct blkg_rwstat_sample rwstat = { };
831d156646STejun Heo 
841d156646STejun Heo 	blkg_rwstat_read((void *)pd + off, &rwstat);
851d156646STejun Heo 	return __blkg_prfill_rwstat(sf, pd, &rwstat);
861d156646STejun Heo }
871d156646STejun Heo EXPORT_SYMBOL_GPL(blkg_prfill_rwstat);
881d156646STejun Heo 
891d156646STejun Heo /**
901d156646STejun Heo  * blkg_rwstat_recursive_sum - collect hierarchical blkg_rwstat
911d156646STejun Heo  * @blkg: blkg of interest
921d156646STejun Heo  * @pol: blkcg_policy which contains the blkg_rwstat
931d156646STejun Heo  * @off: offset to the blkg_rwstat in blkg_policy_data or @blkg
941d156646STejun Heo  * @sum: blkg_rwstat_sample structure containing the results
951d156646STejun Heo  *
961d156646STejun Heo  * Collect the blkg_rwstat specified by @blkg, @pol and @off and all its
971d156646STejun Heo  * online descendants and their aux counts.  The caller must be holding the
981d156646STejun Heo  * queue lock for online tests.
991d156646STejun Heo  *
1001d156646STejun Heo  * If @pol is NULL, blkg_rwstat is at @off bytes into @blkg; otherwise, it
1011d156646STejun Heo  * is at @off bytes into @blkg's blkg_policy_data of the policy.
1021d156646STejun Heo  */
blkg_rwstat_recursive_sum(struct blkcg_gq * blkg,struct blkcg_policy * pol,int off,struct blkg_rwstat_sample * sum)1031d156646STejun Heo void blkg_rwstat_recursive_sum(struct blkcg_gq *blkg, struct blkcg_policy *pol,
1041d156646STejun Heo 		int off, struct blkg_rwstat_sample *sum)
1051d156646STejun Heo {
1061d156646STejun Heo 	struct blkcg_gq *pos_blkg;
1071d156646STejun Heo 	struct cgroup_subsys_state *pos_css;
1081d156646STejun Heo 	unsigned int i;
1091d156646STejun Heo 
1101d156646STejun Heo 	lockdep_assert_held(&blkg->q->queue_lock);
1111d156646STejun Heo 
112*4f44657dSXunlei Pang 	memset(sum, 0, sizeof(*sum));
1131d156646STejun Heo 	rcu_read_lock();
1141d156646STejun Heo 	blkg_for_each_descendant_pre(pos_blkg, pos_css, blkg) {
1151d156646STejun Heo 		struct blkg_rwstat *rwstat;
1161d156646STejun Heo 
1171d156646STejun Heo 		if (!pos_blkg->online)
1181d156646STejun Heo 			continue;
1191d156646STejun Heo 
1201d156646STejun Heo 		if (pol)
1211d156646STejun Heo 			rwstat = (void *)blkg_to_pd(pos_blkg, pol) + off;
1221d156646STejun Heo 		else
1231d156646STejun Heo 			rwstat = (void *)pos_blkg + off;
1241d156646STejun Heo 
1251d156646STejun Heo 		for (i = 0; i < BLKG_RWSTAT_NR; i++)
126*4f44657dSXunlei Pang 			sum->cnt[i] += blkg_rwstat_read_counter(rwstat, i);
1271d156646STejun Heo 	}
1281d156646STejun Heo 	rcu_read_unlock();
1291d156646STejun Heo }
1301d156646STejun Heo EXPORT_SYMBOL_GPL(blkg_rwstat_recursive_sum);
131