162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci *
362306a36Sopenharmony_ci * Legacy blkg rwstat helpers enabled by CONFIG_BLK_CGROUP_RWSTAT.
462306a36Sopenharmony_ci * Do not use in new code.
562306a36Sopenharmony_ci */
662306a36Sopenharmony_ci#include "blk-cgroup-rwstat.h"
762306a36Sopenharmony_ci
862306a36Sopenharmony_ciint blkg_rwstat_init(struct blkg_rwstat *rwstat, gfp_t gfp)
962306a36Sopenharmony_ci{
1062306a36Sopenharmony_ci	int i, ret;
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci	for (i = 0; i < BLKG_RWSTAT_NR; i++) {
1362306a36Sopenharmony_ci		ret = percpu_counter_init(&rwstat->cpu_cnt[i], 0, gfp);
1462306a36Sopenharmony_ci		if (ret) {
1562306a36Sopenharmony_ci			while (--i >= 0)
1662306a36Sopenharmony_ci				percpu_counter_destroy(&rwstat->cpu_cnt[i]);
1762306a36Sopenharmony_ci			return ret;
1862306a36Sopenharmony_ci		}
1962306a36Sopenharmony_ci		atomic64_set(&rwstat->aux_cnt[i], 0);
2062306a36Sopenharmony_ci	}
2162306a36Sopenharmony_ci	return 0;
2262306a36Sopenharmony_ci}
2362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(blkg_rwstat_init);
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_civoid blkg_rwstat_exit(struct blkg_rwstat *rwstat)
2662306a36Sopenharmony_ci{
2762306a36Sopenharmony_ci	int i;
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_ci	for (i = 0; i < BLKG_RWSTAT_NR; i++)
3062306a36Sopenharmony_ci		percpu_counter_destroy(&rwstat->cpu_cnt[i]);
3162306a36Sopenharmony_ci}
3262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(blkg_rwstat_exit);
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci/**
3562306a36Sopenharmony_ci * __blkg_prfill_rwstat - prfill helper for a blkg_rwstat
3662306a36Sopenharmony_ci * @sf: seq_file to print to
3762306a36Sopenharmony_ci * @pd: policy private data of interest
3862306a36Sopenharmony_ci * @rwstat: rwstat to print
3962306a36Sopenharmony_ci *
4062306a36Sopenharmony_ci * Print @rwstat to @sf for the device assocaited with @pd.
4162306a36Sopenharmony_ci */
4262306a36Sopenharmony_ciu64 __blkg_prfill_rwstat(struct seq_file *sf, struct blkg_policy_data *pd,
4362306a36Sopenharmony_ci			 const struct blkg_rwstat_sample *rwstat)
4462306a36Sopenharmony_ci{
4562306a36Sopenharmony_ci	static const char *rwstr[] = {
4662306a36Sopenharmony_ci		[BLKG_RWSTAT_READ]	= "Read",
4762306a36Sopenharmony_ci		[BLKG_RWSTAT_WRITE]	= "Write",
4862306a36Sopenharmony_ci		[BLKG_RWSTAT_SYNC]	= "Sync",
4962306a36Sopenharmony_ci		[BLKG_RWSTAT_ASYNC]	= "Async",
5062306a36Sopenharmony_ci		[BLKG_RWSTAT_DISCARD]	= "Discard",
5162306a36Sopenharmony_ci	};
5262306a36Sopenharmony_ci	const char *dname = blkg_dev_name(pd->blkg);
5362306a36Sopenharmony_ci	u64 v;
5462306a36Sopenharmony_ci	int i;
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ci	if (!dname)
5762306a36Sopenharmony_ci		return 0;
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci	for (i = 0; i < BLKG_RWSTAT_NR; i++)
6062306a36Sopenharmony_ci		seq_printf(sf, "%s %s %llu\n", dname, rwstr[i],
6162306a36Sopenharmony_ci			   rwstat->cnt[i]);
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci	v = rwstat->cnt[BLKG_RWSTAT_READ] +
6462306a36Sopenharmony_ci		rwstat->cnt[BLKG_RWSTAT_WRITE] +
6562306a36Sopenharmony_ci		rwstat->cnt[BLKG_RWSTAT_DISCARD];
6662306a36Sopenharmony_ci	seq_printf(sf, "%s Total %llu\n", dname, v);
6762306a36Sopenharmony_ci	return v;
6862306a36Sopenharmony_ci}
6962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(__blkg_prfill_rwstat);
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci/**
7262306a36Sopenharmony_ci * blkg_prfill_rwstat - prfill callback for blkg_rwstat
7362306a36Sopenharmony_ci * @sf: seq_file to print to
7462306a36Sopenharmony_ci * @pd: policy private data of interest
7562306a36Sopenharmony_ci * @off: offset to the blkg_rwstat in @pd
7662306a36Sopenharmony_ci *
7762306a36Sopenharmony_ci * prfill callback for printing a blkg_rwstat.
7862306a36Sopenharmony_ci */
7962306a36Sopenharmony_ciu64 blkg_prfill_rwstat(struct seq_file *sf, struct blkg_policy_data *pd,
8062306a36Sopenharmony_ci		       int off)
8162306a36Sopenharmony_ci{
8262306a36Sopenharmony_ci	struct blkg_rwstat_sample rwstat = { };
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_ci	blkg_rwstat_read((void *)pd + off, &rwstat);
8562306a36Sopenharmony_ci	return __blkg_prfill_rwstat(sf, pd, &rwstat);
8662306a36Sopenharmony_ci}
8762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(blkg_prfill_rwstat);
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ci/**
9062306a36Sopenharmony_ci * blkg_rwstat_recursive_sum - collect hierarchical blkg_rwstat
9162306a36Sopenharmony_ci * @blkg: blkg of interest
9262306a36Sopenharmony_ci * @pol: blkcg_policy which contains the blkg_rwstat
9362306a36Sopenharmony_ci * @off: offset to the blkg_rwstat in blkg_policy_data or @blkg
9462306a36Sopenharmony_ci * @sum: blkg_rwstat_sample structure containing the results
9562306a36Sopenharmony_ci *
9662306a36Sopenharmony_ci * Collect the blkg_rwstat specified by @blkg, @pol and @off and all its
9762306a36Sopenharmony_ci * online descendants and their aux counts.  The caller must be holding the
9862306a36Sopenharmony_ci * queue lock for online tests.
9962306a36Sopenharmony_ci *
10062306a36Sopenharmony_ci * If @pol is NULL, blkg_rwstat is at @off bytes into @blkg; otherwise, it
10162306a36Sopenharmony_ci * is at @off bytes into @blkg's blkg_policy_data of the policy.
10262306a36Sopenharmony_ci */
10362306a36Sopenharmony_civoid blkg_rwstat_recursive_sum(struct blkcg_gq *blkg, struct blkcg_policy *pol,
10462306a36Sopenharmony_ci		int off, struct blkg_rwstat_sample *sum)
10562306a36Sopenharmony_ci{
10662306a36Sopenharmony_ci	struct blkcg_gq *pos_blkg;
10762306a36Sopenharmony_ci	struct cgroup_subsys_state *pos_css;
10862306a36Sopenharmony_ci	unsigned int i;
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ci	lockdep_assert_held(&blkg->q->queue_lock);
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_ci	memset(sum, 0, sizeof(*sum));
11362306a36Sopenharmony_ci	rcu_read_lock();
11462306a36Sopenharmony_ci	blkg_for_each_descendant_pre(pos_blkg, pos_css, blkg) {
11562306a36Sopenharmony_ci		struct blkg_rwstat *rwstat;
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_ci		if (!pos_blkg->online)
11862306a36Sopenharmony_ci			continue;
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_ci		if (pol)
12162306a36Sopenharmony_ci			rwstat = (void *)blkg_to_pd(pos_blkg, pol) + off;
12262306a36Sopenharmony_ci		else
12362306a36Sopenharmony_ci			rwstat = (void *)pos_blkg + off;
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_ci		for (i = 0; i < BLKG_RWSTAT_NR; i++)
12662306a36Sopenharmony_ci			sum->cnt[i] += blkg_rwstat_read_counter(rwstat, i);
12762306a36Sopenharmony_ci	}
12862306a36Sopenharmony_ci	rcu_read_unlock();
12962306a36Sopenharmony_ci}
13062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(blkg_rwstat_recursive_sum);
131