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