Merge tag 'block-5.15-2021-09-05' of git://git.kernel.dk/linux-block
[linux-2.6-microblaze.git] / block / blk-cgroup-rwstat.c
1 /* SPDX-License-Identifier: GPL-2.0
2  *
3  * Legacy blkg rwstat helpers enabled by CONFIG_BLK_CGROUP_RWSTAT.
4  * Do not use in new code.
5  */
6 #include "blk-cgroup-rwstat.h"
7
8 int blkg_rwstat_init(struct blkg_rwstat *rwstat, gfp_t gfp)
9 {
10         int i, ret;
11
12         for (i = 0; i < BLKG_RWSTAT_NR; i++) {
13                 ret = percpu_counter_init(&rwstat->cpu_cnt[i], 0, gfp);
14                 if (ret) {
15                         while (--i >= 0)
16                                 percpu_counter_destroy(&rwstat->cpu_cnt[i]);
17                         return ret;
18                 }
19                 atomic64_set(&rwstat->aux_cnt[i], 0);
20         }
21         return 0;
22 }
23 EXPORT_SYMBOL_GPL(blkg_rwstat_init);
24
25 void blkg_rwstat_exit(struct blkg_rwstat *rwstat)
26 {
27         int i;
28
29         for (i = 0; i < BLKG_RWSTAT_NR; i++)
30                 percpu_counter_destroy(&rwstat->cpu_cnt[i]);
31 }
32 EXPORT_SYMBOL_GPL(blkg_rwstat_exit);
33
34 /**
35  * __blkg_prfill_rwstat - prfill helper for a blkg_rwstat
36  * @sf: seq_file to print to
37  * @pd: policy private data of interest
38  * @rwstat: rwstat to print
39  *
40  * Print @rwstat to @sf for the device assocaited with @pd.
41  */
42 u64 __blkg_prfill_rwstat(struct seq_file *sf, struct blkg_policy_data *pd,
43                          const struct blkg_rwstat_sample *rwstat)
44 {
45         static const char *rwstr[] = {
46                 [BLKG_RWSTAT_READ]      = "Read",
47                 [BLKG_RWSTAT_WRITE]     = "Write",
48                 [BLKG_RWSTAT_SYNC]      = "Sync",
49                 [BLKG_RWSTAT_ASYNC]     = "Async",
50                 [BLKG_RWSTAT_DISCARD]   = "Discard",
51         };
52         const char *dname = blkg_dev_name(pd->blkg);
53         u64 v;
54         int i;
55
56         if (!dname)
57                 return 0;
58
59         for (i = 0; i < BLKG_RWSTAT_NR; i++)
60                 seq_printf(sf, "%s %s %llu\n", dname, rwstr[i],
61                            rwstat->cnt[i]);
62
63         v = rwstat->cnt[BLKG_RWSTAT_READ] +
64                 rwstat->cnt[BLKG_RWSTAT_WRITE] +
65                 rwstat->cnt[BLKG_RWSTAT_DISCARD];
66         seq_printf(sf, "%s Total %llu\n", dname, v);
67         return v;
68 }
69 EXPORT_SYMBOL_GPL(__blkg_prfill_rwstat);
70
71 /**
72  * blkg_prfill_rwstat - prfill callback for blkg_rwstat
73  * @sf: seq_file to print to
74  * @pd: policy private data of interest
75  * @off: offset to the blkg_rwstat in @pd
76  *
77  * prfill callback for printing a blkg_rwstat.
78  */
79 u64 blkg_prfill_rwstat(struct seq_file *sf, struct blkg_policy_data *pd,
80                        int off)
81 {
82         struct blkg_rwstat_sample rwstat = { };
83
84         blkg_rwstat_read((void *)pd + off, &rwstat);
85         return __blkg_prfill_rwstat(sf, pd, &rwstat);
86 }
87 EXPORT_SYMBOL_GPL(blkg_prfill_rwstat);
88
89 /**
90  * blkg_rwstat_recursive_sum - collect hierarchical blkg_rwstat
91  * @blkg: blkg of interest
92  * @pol: blkcg_policy which contains the blkg_rwstat
93  * @off: offset to the blkg_rwstat in blkg_policy_data or @blkg
94  * @sum: blkg_rwstat_sample structure containing the results
95  *
96  * Collect the blkg_rwstat specified by @blkg, @pol and @off and all its
97  * online descendants and their aux counts.  The caller must be holding the
98  * queue lock for online tests.
99  *
100  * If @pol is NULL, blkg_rwstat is at @off bytes into @blkg; otherwise, it
101  * is at @off bytes into @blkg's blkg_policy_data of the policy.
102  */
103 void blkg_rwstat_recursive_sum(struct blkcg_gq *blkg, struct blkcg_policy *pol,
104                 int off, struct blkg_rwstat_sample *sum)
105 {
106         struct blkcg_gq *pos_blkg;
107         struct cgroup_subsys_state *pos_css;
108         unsigned int i;
109
110         lockdep_assert_held(&blkg->q->queue_lock);
111
112         memset(sum, 0, sizeof(*sum));
113         rcu_read_lock();
114         blkg_for_each_descendant_pre(pos_blkg, pos_css, blkg) {
115                 struct blkg_rwstat *rwstat;
116
117                 if (!pos_blkg->online)
118                         continue;
119
120                 if (pol)
121                         rwstat = (void *)blkg_to_pd(pos_blkg, pol) + off;
122                 else
123                         rwstat = (void *)pos_blkg + off;
124
125                 for (i = 0; i < BLKG_RWSTAT_NR; i++)
126                         sum->cnt[i] += blkg_rwstat_read_counter(rwstat, i);
127         }
128         rcu_read_unlock();
129 }
130 EXPORT_SYMBOL_GPL(blkg_rwstat_recursive_sum);