blk-cgroup.h 6.7 KB
Newer Older
1
/* SPDX-License-Identifier: GPL-2.0 */
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
#ifndef _BLK_CGROUP_H
#define _BLK_CGROUP_H
/*
 * Common Block IO controller cgroup interface
 *
 * Based on ideas and code from CFQ, CFS and BFQ:
 * Copyright (C) 2003 Jens Axboe <axboe@kernel.dk>
 *
 * Copyright (C) 2008 Fabio Checconi <fabio@gandalf.sssup.it>
 *		      Paolo Valente <paolo.valente@unimore.it>
 *
 * Copyright (C) 2009 Vivek Goyal <vgoyal@redhat.com>
 * 	              Nauman Rafique <nauman@google.com>
 */

#include <linux/cgroup.h>
18
#include <linux/percpu.h>
T
Tejun Heo 已提交
19
#include <linux/percpu_counter.h>
20
#include <linux/u64_stats_sync.h>
21
#include <linux/seq_file.h>
22
#include <linux/radix-tree.h>
23
#include <linux/blkdev.h>
24
#include <linux/atomic.h>
25
#include <linux/kthread.h>
26
#include <linux/fs.h>
27

28 29
#define FC_APPID_LEN              129

T
Tejun Heo 已提交
30 31
#ifdef CONFIG_BLK_CGROUP

32 33 34 35 36 37 38 39
enum blkg_iostat_type {
	BLKG_IOSTAT_READ,
	BLKG_IOSTAT_WRITE,
	BLKG_IOSTAT_DISCARD,

	BLKG_IOSTAT_NR,
};

40
struct blkcg_gq;
41
struct blkg_policy_data;
42

T
Tejun Heo 已提交
43
struct blkcg {
44 45
	struct cgroup_subsys_state	css;
	spinlock_t			lock;
46
	refcount_t			online_pin;
47 48

	struct radix_tree_root		blkg_tree;
49
	struct blkcg_gq	__rcu		*blkg_hint;
50
	struct hlist_head		blkg_list;
T
Tejun Heo 已提交
51

52
	struct blkcg_policy_data	*cpd[BLKCG_MAX_POLS];
53

T
Tejun Heo 已提交
54
	struct list_head		all_blkcgs_node;
55 56 57
#ifdef CONFIG_BLK_CGROUP_FC_APPID
	char                            fc_app_id[FC_APPID_LEN];
#endif
58 59 60
#ifdef CONFIG_CGROUP_WRITEBACK
	struct list_head		cgwb_list;
#endif
61 62
};

63 64 65 66 67 68 69 70 71 72 73
struct blkg_iostat {
	u64				bytes[BLKG_IOSTAT_NR];
	u64				ios[BLKG_IOSTAT_NR];
};

struct blkg_iostat_set {
	struct u64_stats_sync		sync;
	struct blkg_iostat		cur;
	struct blkg_iostat		last;
};

T
Tejun Heo 已提交
74 75
/* association between a blk cgroup and a request queue */
struct blkcg_gq {
T
Tejun Heo 已提交
76
	/* Pointer to the associated request_queue */
77 78 79
	struct request_queue		*q;
	struct list_head		q_node;
	struct hlist_node		blkcg_node;
T
Tejun Heo 已提交
80
	struct blkcg			*blkcg;
T
Tejun Heo 已提交
81 82 83 84

	/* all non-root blkcg_gq's are guaranteed to have access to parent */
	struct blkcg_gq			*parent;

T
Tejun Heo 已提交
85
	/* reference count */
86
	struct percpu_ref		refcnt;
87

88 89 90
	/* is this blkg online? protected by both blkcg and q locks */
	bool				online;

91 92
	struct blkg_iostat_set __percpu	*iostat_cpu;
	struct blkg_iostat_set		iostat;
93

94
	struct blkg_policy_data		*pd[BLKCG_MAX_POLS];
T
Tejun Heo 已提交
95

T
Tejun Heo 已提交
96 97
	spinlock_t			async_bio_lock;
	struct bio_list			async_bios;
98 99 100 101
	union {
		struct work_struct	async_bio_work;
		struct work_struct	free_work;
	};
102 103 104 105 106 107

	atomic_t			use_delay;
	atomic64_t			delay_nsec;
	atomic64_t			delay_start;
	u64				last_delay;
	int				last_use;
T
Tejun Heo 已提交
108 109

	struct rcu_head			rcu_head;
110 111
};

T
Tejun Heo 已提交
112
extern struct cgroup_subsys_state * const blkcg_root_css;
113

114 115 116
void blkcg_destroy_blkgs(struct blkcg *blkcg);
void blkcg_schedule_throttle(struct request_queue *q, bool use_memdelay);
void blkcg_maybe_throttle_current(void);
117

118 119 120 121 122
static inline struct blkcg *css_to_blkcg(struct cgroup_subsys_state *css)
{
	return css ? container_of(css, struct blkcg, css) : NULL;
}

123 124 125 126 127 128 129 130 131 132
/**
 * bio_blkcg - grab the blkcg associated with a bio
 * @bio: target bio
 *
 * This returns the blkcg associated with a bio, %NULL if not associated.
 * Callers are expected to either handle %NULL or know association has been
 * done prior to calling this.
 */
static inline struct blkcg *bio_blkcg(struct bio *bio)
{
133 134
	if (bio && bio->bi_blkg)
		return bio->bi_blkg->blkcg;
135
	return NULL;
136 137
}

138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157
static inline bool blk_cgroup_congested(void)
{
	struct cgroup_subsys_state *css;
	bool ret = false;

	rcu_read_lock();
	css = kthread_blkcg();
	if (!css)
		css = task_css(current, io_cgrp_id);
	while (css) {
		if (atomic_read(&css->cgroup->congestion_count)) {
			ret = true;
			break;
		}
		css = css->parent;
	}
	rcu_read_unlock();
	return ret;
}

T
Tejun Heo 已提交
158 159 160 161 162 163 164 165
/**
 * blkcg_parent - get the parent of a blkcg
 * @blkcg: blkcg of interest
 *
 * Return the parent blkcg of @blkcg.  Can be called anytime.
 */
static inline struct blkcg *blkcg_parent(struct blkcg *blkcg)
{
T
Tejun Heo 已提交
166
	return css_to_blkcg(blkcg->css.parent);
T
Tejun Heo 已提交
167 168
}

169
/**
170
 * blkcg_pin_online - pin online state
171 172
 * @blkcg: blkcg of interest
 *
173 174 175
 * While pinned, a blkcg is kept online.  This is primarily used to
 * impedance-match blkg and cgwb lifetimes so that blkg doesn't go offline
 * while an associated cgwb is still active.
176
 */
177
static inline void blkcg_pin_online(struct blkcg *blkcg)
178
{
179
	refcount_inc(&blkcg->online_pin);
180 181 182
}

/**
183
 * blkcg_unpin_online - unpin online state
184 185
 * @blkcg: blkcg of interest
 *
186 187 188
 * This is primarily used to impedance-match blkg and cgwb lifetimes so
 * that blkg doesn't go offline while an associated cgwb is still active.
 * When this count goes to zero, all active cgwbs have finished so the
189 190
 * blkcg can continue destruction by calling blkcg_destroy_blkgs().
 */
191
static inline void blkcg_unpin_online(struct blkcg *blkcg)
192
{
193 194 195
	do {
		if (!refcount_dec_and_test(&blkcg->online_pin))
			break;
196
		blkcg_destroy_blkgs(blkcg);
197 198
		blkcg = blkcg_parent(blkcg);
	} while (blkcg);
199 200
}

201 202
#else	/* CONFIG_BLK_CGROUP */

203 204
struct blkcg {
};
205

T
Tejun Heo 已提交
206
struct blkcg_gq {
207 208
};

T
Tejun Heo 已提交
209 210
#define blkcg_root_css	((struct cgroup_subsys_state *)ERR_PTR(-EINVAL))

211 212 213
static inline void blkcg_maybe_throttle_current(void) { }
static inline bool blk_cgroup_congested(void) { return false; }

214
#ifdef CONFIG_BLOCK
215
static inline void blkcg_schedule_throttle(struct request_queue *q, bool use_memdelay) { }
216
static inline struct blkcg *bio_blkcg(struct bio *bio) { return NULL; }
217
#endif /* CONFIG_BLOCK */
218

219
#endif	/* CONFIG_BLK_CGROUP */
220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277

#ifdef CONFIG_BLK_CGROUP_FC_APPID
/*
 * Sets the fc_app_id field associted to blkcg
 * @app_id: application identifier
 * @cgrp_id: cgroup id
 * @app_id_len: size of application identifier
 */
static inline int blkcg_set_fc_appid(char *app_id, u64 cgrp_id, size_t app_id_len)
{
	struct cgroup *cgrp;
	struct cgroup_subsys_state *css;
	struct blkcg *blkcg;
	int ret  = 0;

	if (app_id_len > FC_APPID_LEN)
		return -EINVAL;

	cgrp = cgroup_get_from_id(cgrp_id);
	if (!cgrp)
		return -ENOENT;
	css = cgroup_get_e_css(cgrp, &io_cgrp_subsys);
	if (!css) {
		ret = -ENOENT;
		goto out_cgrp_put;
	}
	blkcg = css_to_blkcg(css);
	/*
	 * There is a slight race condition on setting the appid.
	 * Worst case an I/O may not find the right id.
	 * This is no different from the I/O we let pass while obtaining
	 * the vmid from the fabric.
	 * Adding the overhead of a lock is not necessary.
	 */
	strlcpy(blkcg->fc_app_id, app_id, app_id_len);
	css_put(css);
out_cgrp_put:
	cgroup_put(cgrp);
	return ret;
}

/**
 * blkcg_get_fc_appid - get the fc app identifier associated with a bio
 * @bio: target bio
 *
 * On success return the fc_app_id, on failure return NULL
 */
static inline char *blkcg_get_fc_appid(struct bio *bio)
{
	if (bio && bio->bi_blkg &&
		(bio->bi_blkg->blkcg->fc_app_id[0] != '\0'))
		return bio->bi_blkg->blkcg->fc_app_id;
	return NULL;
}
#else
static inline int blkcg_set_fc_appid(char *buf, u64 id, size_t len) { return -EINVAL; }
static inline char *blkcg_get_fc_appid(struct bio *bio) { return NULL; }
#endif /*CONFIG_BLK_CGROUP_FC_APPID*/
278
#endif	/* _BLK_CGROUP_H */