xref: /linux-6.15/include/linux/blk-cgroup.h (revision d578c770)
1b2441318SGreg Kroah-Hartman /* SPDX-License-Identifier: GPL-2.0 */
2eea8f41cSTejun Heo #ifndef _BLK_CGROUP_H
3eea8f41cSTejun Heo #define _BLK_CGROUP_H
4eea8f41cSTejun Heo /*
5eea8f41cSTejun Heo  * Common Block IO controller cgroup interface
6eea8f41cSTejun Heo  *
7eea8f41cSTejun Heo  * Based on ideas and code from CFQ, CFS and BFQ:
8eea8f41cSTejun Heo  * Copyright (C) 2003 Jens Axboe <[email protected]>
9eea8f41cSTejun Heo  *
10eea8f41cSTejun Heo  * Copyright (C) 2008 Fabio Checconi <[email protected]>
11eea8f41cSTejun Heo  *		      Paolo Valente <[email protected]>
12eea8f41cSTejun Heo  *
13eea8f41cSTejun Heo  * Copyright (C) 2009 Vivek Goyal <[email protected]>
14eea8f41cSTejun Heo  * 	              Nauman Rafique <[email protected]>
15eea8f41cSTejun Heo  */
16eea8f41cSTejun Heo 
17eea8f41cSTejun Heo #include <linux/cgroup.h>
18f7331648STejun Heo #include <linux/percpu.h>
1924bdb8efSTejun Heo #include <linux/percpu_counter.h>
20f7331648STejun Heo #include <linux/u64_stats_sync.h>
21eea8f41cSTejun Heo #include <linux/seq_file.h>
22eea8f41cSTejun Heo #include <linux/radix-tree.h>
23eea8f41cSTejun Heo #include <linux/blkdev.h>
24eea8f41cSTejun Heo #include <linux/atomic.h>
25902ec5b6SShaohua Li #include <linux/kthread.h>
265cdf2e3fSDennis Zhou #include <linux/fs.h>
27eea8f41cSTejun Heo 
28d2bcbeabSMuneendra Kumar #define FC_APPID_LEN              129
29d2bcbeabSMuneendra Kumar 
30eea8f41cSTejun Heo #ifdef CONFIG_BLK_CGROUP
31eea8f41cSTejun Heo 
32f7331648STejun Heo enum blkg_iostat_type {
33f7331648STejun Heo 	BLKG_IOSTAT_READ,
34f7331648STejun Heo 	BLKG_IOSTAT_WRITE,
35f7331648STejun Heo 	BLKG_IOSTAT_DISCARD,
36f7331648STejun Heo 
37f7331648STejun Heo 	BLKG_IOSTAT_NR,
38f7331648STejun Heo };
39f7331648STejun Heo 
40eea8f41cSTejun Heo struct blkcg_gq;
41672fdcf0SMing Lei struct blkg_policy_data;
42eea8f41cSTejun Heo 
43eea8f41cSTejun Heo struct blkcg {
44eea8f41cSTejun Heo 	struct cgroup_subsys_state	css;
45eea8f41cSTejun Heo 	spinlock_t			lock;
46d866dbf6STejun Heo 	refcount_t			online_pin;
47eea8f41cSTejun Heo 
48eea8f41cSTejun Heo 	struct radix_tree_root		blkg_tree;
4955679c8dSBart Van Assche 	struct blkcg_gq	__rcu		*blkg_hint;
50eea8f41cSTejun Heo 	struct hlist_head		blkg_list;
51eea8f41cSTejun Heo 
5281437648STejun Heo 	struct blkcg_policy_data	*cpd[BLKCG_MAX_POLS];
5352ebea74STejun Heo 
547876f930STejun Heo 	struct list_head		all_blkcgs_node;
55d2bcbeabSMuneendra Kumar #ifdef CONFIG_BLK_CGROUP_FC_APPID
56d2bcbeabSMuneendra Kumar 	char                            fc_app_id[FC_APPID_LEN];
57d2bcbeabSMuneendra Kumar #endif
5852ebea74STejun Heo #ifdef CONFIG_CGROUP_WRITEBACK
5952ebea74STejun Heo 	struct list_head		cgwb_list;
6052ebea74STejun Heo #endif
61eea8f41cSTejun Heo };
62eea8f41cSTejun Heo 
63f7331648STejun Heo struct blkg_iostat {
64f7331648STejun Heo 	u64				bytes[BLKG_IOSTAT_NR];
65f7331648STejun Heo 	u64				ios[BLKG_IOSTAT_NR];
66f7331648STejun Heo };
67f7331648STejun Heo 
68f7331648STejun Heo struct blkg_iostat_set {
69f7331648STejun Heo 	struct u64_stats_sync		sync;
70f7331648STejun Heo 	struct blkg_iostat		cur;
71f7331648STejun Heo 	struct blkg_iostat		last;
72f7331648STejun Heo };
73f7331648STejun Heo 
74eea8f41cSTejun Heo /* association between a blk cgroup and a request queue */
75eea8f41cSTejun Heo struct blkcg_gq {
76eea8f41cSTejun Heo 	/* Pointer to the associated request_queue */
77eea8f41cSTejun Heo 	struct request_queue		*q;
78eea8f41cSTejun Heo 	struct list_head		q_node;
79eea8f41cSTejun Heo 	struct hlist_node		blkcg_node;
80eea8f41cSTejun Heo 	struct blkcg			*blkcg;
81eea8f41cSTejun Heo 
82eea8f41cSTejun Heo 	/* all non-root blkcg_gq's are guaranteed to have access to parent */
83eea8f41cSTejun Heo 	struct blkcg_gq			*parent;
84eea8f41cSTejun Heo 
85eea8f41cSTejun Heo 	/* reference count */
867fcf2b03SDennis Zhou 	struct percpu_ref		refcnt;
87eea8f41cSTejun Heo 
88eea8f41cSTejun Heo 	/* is this blkg online? protected by both blkcg and q locks */
89eea8f41cSTejun Heo 	bool				online;
90eea8f41cSTejun Heo 
91f7331648STejun Heo 	struct blkg_iostat_set __percpu	*iostat_cpu;
92f7331648STejun Heo 	struct blkg_iostat_set		iostat;
9377ea7338STejun Heo 
94eea8f41cSTejun Heo 	struct blkg_policy_data		*pd[BLKCG_MAX_POLS];
95eea8f41cSTejun Heo 
96d3f77dfdSTejun Heo 	spinlock_t			async_bio_lock;
97d3f77dfdSTejun Heo 	struct bio_list			async_bios;
98*d578c770SMing Lei 	union {
99d3f77dfdSTejun Heo 		struct work_struct	async_bio_work;
100*d578c770SMing Lei 		struct work_struct	free_work;
101*d578c770SMing Lei 	};
102d09d8df3SJosef Bacik 
103d09d8df3SJosef Bacik 	atomic_t			use_delay;
104d09d8df3SJosef Bacik 	atomic64_t			delay_nsec;
105d09d8df3SJosef Bacik 	atomic64_t			delay_start;
106d09d8df3SJosef Bacik 	u64				last_delay;
107d09d8df3SJosef Bacik 	int				last_use;
108d3f77dfdSTejun Heo 
109d3f77dfdSTejun Heo 	struct rcu_head			rcu_head;
110eea8f41cSTejun Heo };
111eea8f41cSTejun Heo 
112496d5e75STejun Heo extern struct cgroup_subsys_state * const blkcg_root_css;
113eea8f41cSTejun Heo 
114672fdcf0SMing Lei void blkcg_destroy_blkgs(struct blkcg *blkcg);
115672fdcf0SMing Lei void blkcg_schedule_throttle(struct request_queue *q, bool use_memdelay);
116672fdcf0SMing Lei void blkcg_maybe_throttle_current(void);
1170fe061b9SDennis Zhou 
118eea8f41cSTejun Heo static inline struct blkcg *css_to_blkcg(struct cgroup_subsys_state *css)
119eea8f41cSTejun Heo {
120eea8f41cSTejun Heo 	return css ? container_of(css, struct blkcg, css) : NULL;
121eea8f41cSTejun Heo }
122eea8f41cSTejun Heo 
1230fe061b9SDennis Zhou /**
1240fe061b9SDennis Zhou  * bio_blkcg - grab the blkcg associated with a bio
1250fe061b9SDennis Zhou  * @bio: target bio
1260fe061b9SDennis Zhou  *
1270fe061b9SDennis Zhou  * This returns the blkcg associated with a bio, %NULL if not associated.
1280fe061b9SDennis Zhou  * Callers are expected to either handle %NULL or know association has been
1290fe061b9SDennis Zhou  * done prior to calling this.
1300fe061b9SDennis Zhou  */
1310fe061b9SDennis Zhou static inline struct blkcg *bio_blkcg(struct bio *bio)
1320fe061b9SDennis Zhou {
133db6638d7SDennis Zhou 	if (bio && bio->bi_blkg)
134db6638d7SDennis Zhou 		return bio->bi_blkg->blkcg;
1350fe061b9SDennis Zhou 	return NULL;
136fd383c2dSTejun Heo }
137fd383c2dSTejun Heo 
138d09d8df3SJosef Bacik static inline bool blk_cgroup_congested(void)
139d09d8df3SJosef Bacik {
140d09d8df3SJosef Bacik 	struct cgroup_subsys_state *css;
141d09d8df3SJosef Bacik 	bool ret = false;
142d09d8df3SJosef Bacik 
143d09d8df3SJosef Bacik 	rcu_read_lock();
144d09d8df3SJosef Bacik 	css = kthread_blkcg();
145d09d8df3SJosef Bacik 	if (!css)
146d09d8df3SJosef Bacik 		css = task_css(current, io_cgrp_id);
147d09d8df3SJosef Bacik 	while (css) {
148d09d8df3SJosef Bacik 		if (atomic_read(&css->cgroup->congestion_count)) {
149d09d8df3SJosef Bacik 			ret = true;
150d09d8df3SJosef Bacik 			break;
151d09d8df3SJosef Bacik 		}
152d09d8df3SJosef Bacik 		css = css->parent;
153d09d8df3SJosef Bacik 	}
154d09d8df3SJosef Bacik 	rcu_read_unlock();
155d09d8df3SJosef Bacik 	return ret;
156d09d8df3SJosef Bacik }
157d09d8df3SJosef Bacik 
158eea8f41cSTejun Heo /**
159eea8f41cSTejun Heo  * blkcg_parent - get the parent of a blkcg
160eea8f41cSTejun Heo  * @blkcg: blkcg of interest
161eea8f41cSTejun Heo  *
162eea8f41cSTejun Heo  * Return the parent blkcg of @blkcg.  Can be called anytime.
163eea8f41cSTejun Heo  */
164eea8f41cSTejun Heo static inline struct blkcg *blkcg_parent(struct blkcg *blkcg)
165eea8f41cSTejun Heo {
166eea8f41cSTejun Heo 	return css_to_blkcg(blkcg->css.parent);
167eea8f41cSTejun Heo }
168eea8f41cSTejun Heo 
169eea8f41cSTejun Heo /**
170d866dbf6STejun Heo  * blkcg_pin_online - pin online state
17159b57717SDennis Zhou (Facebook)  * @blkcg: blkcg of interest
17259b57717SDennis Zhou (Facebook)  *
173d866dbf6STejun Heo  * While pinned, a blkcg is kept online.  This is primarily used to
174d866dbf6STejun Heo  * impedance-match blkg and cgwb lifetimes so that blkg doesn't go offline
175d866dbf6STejun Heo  * while an associated cgwb is still active.
17659b57717SDennis Zhou (Facebook)  */
177d866dbf6STejun Heo static inline void blkcg_pin_online(struct blkcg *blkcg)
17859b57717SDennis Zhou (Facebook) {
179d866dbf6STejun Heo 	refcount_inc(&blkcg->online_pin);
18059b57717SDennis Zhou (Facebook) }
18159b57717SDennis Zhou (Facebook) 
18259b57717SDennis Zhou (Facebook) /**
183d866dbf6STejun Heo  * blkcg_unpin_online - unpin online state
18459b57717SDennis Zhou (Facebook)  * @blkcg: blkcg of interest
18559b57717SDennis Zhou (Facebook)  *
186d866dbf6STejun Heo  * This is primarily used to impedance-match blkg and cgwb lifetimes so
187d866dbf6STejun Heo  * that blkg doesn't go offline while an associated cgwb is still active.
188d866dbf6STejun Heo  * When this count goes to zero, all active cgwbs have finished so the
18959b57717SDennis Zhou (Facebook)  * blkcg can continue destruction by calling blkcg_destroy_blkgs().
19059b57717SDennis Zhou (Facebook)  */
191d866dbf6STejun Heo static inline void blkcg_unpin_online(struct blkcg *blkcg)
19259b57717SDennis Zhou (Facebook) {
1934308a434STejun Heo 	do {
1944308a434STejun Heo 		if (!refcount_dec_and_test(&blkcg->online_pin))
1954308a434STejun Heo 			break;
19659b57717SDennis Zhou (Facebook) 		blkcg_destroy_blkgs(blkcg);
1974308a434STejun Heo 		blkcg = blkcg_parent(blkcg);
1984308a434STejun Heo 	} while (blkcg);
19959b57717SDennis Zhou (Facebook) }
20059b57717SDennis Zhou (Facebook) 
201eea8f41cSTejun Heo #else	/* CONFIG_BLK_CGROUP */
202eea8f41cSTejun Heo 
203efa7d1c7STejun Heo struct blkcg {
204efa7d1c7STejun Heo };
205eea8f41cSTejun Heo 
206eea8f41cSTejun Heo struct blkcg_gq {
207eea8f41cSTejun Heo };
208eea8f41cSTejun Heo 
209496d5e75STejun Heo #define blkcg_root_css	((struct cgroup_subsys_state *)ERR_PTR(-EINVAL))
210496d5e75STejun Heo 
211d09d8df3SJosef Bacik static inline void blkcg_maybe_throttle_current(void) { }
212d09d8df3SJosef Bacik static inline bool blk_cgroup_congested(void) { return false; }
213d09d8df3SJosef Bacik 
214efa7d1c7STejun Heo #ifdef CONFIG_BLOCK
215d09d8df3SJosef Bacik static inline void blkcg_schedule_throttle(struct request_queue *q, bool use_memdelay) { }
216eea8f41cSTejun Heo static inline struct blkcg *bio_blkcg(struct bio *bio) { return NULL; }
217efa7d1c7STejun Heo #endif /* CONFIG_BLOCK */
218672fdcf0SMing Lei 
219eea8f41cSTejun Heo #endif	/* CONFIG_BLK_CGROUP */
220d2bcbeabSMuneendra Kumar 
221d2bcbeabSMuneendra Kumar #ifdef CONFIG_BLK_CGROUP_FC_APPID
222d2bcbeabSMuneendra Kumar /*
223d2bcbeabSMuneendra Kumar  * Sets the fc_app_id field associted to blkcg
224d2bcbeabSMuneendra Kumar  * @app_id: application identifier
225d2bcbeabSMuneendra Kumar  * @cgrp_id: cgroup id
226d2bcbeabSMuneendra Kumar  * @app_id_len: size of application identifier
227d2bcbeabSMuneendra Kumar  */
228d2bcbeabSMuneendra Kumar static inline int blkcg_set_fc_appid(char *app_id, u64 cgrp_id, size_t app_id_len)
229d2bcbeabSMuneendra Kumar {
230d2bcbeabSMuneendra Kumar 	struct cgroup *cgrp;
231d2bcbeabSMuneendra Kumar 	struct cgroup_subsys_state *css;
232d2bcbeabSMuneendra Kumar 	struct blkcg *blkcg;
233d2bcbeabSMuneendra Kumar 	int ret  = 0;
234d2bcbeabSMuneendra Kumar 
235d2bcbeabSMuneendra Kumar 	if (app_id_len > FC_APPID_LEN)
236d2bcbeabSMuneendra Kumar 		return -EINVAL;
237d2bcbeabSMuneendra Kumar 
238d2bcbeabSMuneendra Kumar 	cgrp = cgroup_get_from_id(cgrp_id);
239d2bcbeabSMuneendra Kumar 	if (!cgrp)
240d2bcbeabSMuneendra Kumar 		return -ENOENT;
241d2bcbeabSMuneendra Kumar 	css = cgroup_get_e_css(cgrp, &io_cgrp_subsys);
242d2bcbeabSMuneendra Kumar 	if (!css) {
243d2bcbeabSMuneendra Kumar 		ret = -ENOENT;
244d2bcbeabSMuneendra Kumar 		goto out_cgrp_put;
245d2bcbeabSMuneendra Kumar 	}
246d2bcbeabSMuneendra Kumar 	blkcg = css_to_blkcg(css);
247d2bcbeabSMuneendra Kumar 	/*
248d2bcbeabSMuneendra Kumar 	 * There is a slight race condition on setting the appid.
249d2bcbeabSMuneendra Kumar 	 * Worst case an I/O may not find the right id.
250d2bcbeabSMuneendra Kumar 	 * This is no different from the I/O we let pass while obtaining
251d2bcbeabSMuneendra Kumar 	 * the vmid from the fabric.
252d2bcbeabSMuneendra Kumar 	 * Adding the overhead of a lock is not necessary.
253d2bcbeabSMuneendra Kumar 	 */
254d2bcbeabSMuneendra Kumar 	strlcpy(blkcg->fc_app_id, app_id, app_id_len);
255d2bcbeabSMuneendra Kumar 	css_put(css);
256d2bcbeabSMuneendra Kumar out_cgrp_put:
257d2bcbeabSMuneendra Kumar 	cgroup_put(cgrp);
258d2bcbeabSMuneendra Kumar 	return ret;
259d2bcbeabSMuneendra Kumar }
260d2bcbeabSMuneendra Kumar 
261d2bcbeabSMuneendra Kumar /**
262d2bcbeabSMuneendra Kumar  * blkcg_get_fc_appid - get the fc app identifier associated with a bio
263d2bcbeabSMuneendra Kumar  * @bio: target bio
264d2bcbeabSMuneendra Kumar  *
265d2bcbeabSMuneendra Kumar  * On success return the fc_app_id, on failure return NULL
266d2bcbeabSMuneendra Kumar  */
267d2bcbeabSMuneendra Kumar static inline char *blkcg_get_fc_appid(struct bio *bio)
268d2bcbeabSMuneendra Kumar {
269d2bcbeabSMuneendra Kumar 	if (bio && bio->bi_blkg &&
270d2bcbeabSMuneendra Kumar 		(bio->bi_blkg->blkcg->fc_app_id[0] != '\0'))
271d2bcbeabSMuneendra Kumar 		return bio->bi_blkg->blkcg->fc_app_id;
272d2bcbeabSMuneendra Kumar 	return NULL;
273d2bcbeabSMuneendra Kumar }
274d2bcbeabSMuneendra Kumar #else
275d2bcbeabSMuneendra Kumar static inline int blkcg_set_fc_appid(char *buf, u64 id, size_t len) { return -EINVAL; }
276d2bcbeabSMuneendra Kumar static inline char *blkcg_get_fc_appid(struct bio *bio) { return NULL; }
277d2bcbeabSMuneendra Kumar #endif /*CONFIG_BLK_CGROUP_FC_APPID*/
278eea8f41cSTejun Heo #endif	/* _BLK_CGROUP_H */
279