766 lines · 22.2 KB · C
RawDownload
/* SPDX-License-Identifier: GPL-2.0 */#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>#include <linux/percpu.h>#include <linux/percpu_counter.h>#include <linux/u64_stats_sync.h>#include <linux/seq_file.h>#include <linux/radix-tree.h>#include <linux/blkdev.h>#include <linux/atomic.h>#include <linux/kthread.h>#include <linux/fs.h> /* percpu_counter batch for blkg_[rw]stats, per-cpu drift doesn't matter */#define BLKG_STAT_CPU_BATCH	(INT_MAX / 2) /* Max limits for throttle policy */#define THROTL_IOPS_MAX		UINT_MAX #ifdef CONFIG_BLK_CGROUP enum blkg_iostat_type {	BLKG_IOSTAT_READ,	BLKG_IOSTAT_WRITE,	BLKG_IOSTAT_DISCARD, 	BLKG_IOSTAT_NR,}; struct blkcg_gq; struct blkcg {	struct cgroup_subsys_state	css;	spinlock_t			lock;	refcount_t			online_pin; 	struct radix_tree_root		blkg_tree;	struct blkcg_gq	__rcu		*blkg_hint;	struct hlist_head		blkg_list; 	struct blkcg_policy_data	*cpd[BLKCG_MAX_POLS]; 	struct list_head		all_blkcgs_node;#ifdef CONFIG_CGROUP_WRITEBACK	struct list_head		cgwb_list;#endif}; 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;}; /* * A blkcg_gq (blkg) is association between a block cgroup (blkcg) and a * request_queue (q).  This is used by blkcg policies which need to track * information per blkcg - q pair. * * There can be multiple active blkcg policies and each blkg:policy pair is * represented by a blkg_policy_data which is allocated and freed by each * policy's pd_alloc/free_fn() methods.  A policy can allocate private data * area by allocating larger data structure which embeds blkg_policy_data * at the beginning. */struct blkg_policy_data {	/* the blkg and policy id this per-policy data belongs to */	struct blkcg_gq			*blkg;	int				plid;}; /* * Policies that need to keep per-blkcg data which is independent from any * request_queue associated to it should implement cpd_alloc/free_fn() * methods.  A policy can allocate private data area by allocating larger * data structure which embeds blkcg_policy_data at the beginning. * cpd_init() is invoked to let each policy handle per-blkcg data. */struct blkcg_policy_data {	/* the blkcg and policy id this per-policy data belongs to */	struct blkcg			*blkcg;	int				plid;}; /* association between a blk cgroup and a request queue */struct blkcg_gq {	/* Pointer to the associated request_queue */	struct request_queue		*q;	struct list_head		q_node;	struct hlist_node		blkcg_node;	struct blkcg			*blkcg; 	/*	 * Each blkg gets congested separately and the congestion state is	 * propagated to the matching bdi_writeback_congested.	 */	struct bdi_writeback_congested	*wb_congested; 	/* all non-root blkcg_gq's are guaranteed to have access to parent */	struct blkcg_gq			*parent; 	/* reference count */	struct percpu_ref		refcnt; 	/* is this blkg online? protected by both blkcg and q locks */	bool				online; 	struct blkg_iostat_set __percpu	*iostat_cpu;	struct blkg_iostat_set		iostat; 	struct blkg_policy_data		*pd[BLKCG_MAX_POLS]; 	spinlock_t			async_bio_lock;	struct bio_list			async_bios;	struct work_struct		async_bio_work; 	atomic_t			use_delay;	atomic64_t			delay_nsec;	atomic64_t			delay_start;	u64				last_delay;	int				last_use; 	struct rcu_head			rcu_head;}; typedef struct blkcg_policy_data *(blkcg_pol_alloc_cpd_fn)(gfp_t gfp);typedef void (blkcg_pol_init_cpd_fn)(struct blkcg_policy_data *cpd);typedef void (blkcg_pol_free_cpd_fn)(struct blkcg_policy_data *cpd);typedef void (blkcg_pol_bind_cpd_fn)(struct blkcg_policy_data *cpd);typedef struct blkg_policy_data *(blkcg_pol_alloc_pd_fn)(gfp_t gfp,				struct request_queue *q, struct blkcg *blkcg);typedef void (blkcg_pol_init_pd_fn)(struct blkg_policy_data *pd);typedef void (blkcg_pol_online_pd_fn)(struct blkg_policy_data *pd);typedef void (blkcg_pol_offline_pd_fn)(struct blkg_policy_data *pd);typedef void (blkcg_pol_free_pd_fn)(struct blkg_policy_data *pd);typedef void (blkcg_pol_reset_pd_stats_fn)(struct blkg_policy_data *pd);typedef size_t (blkcg_pol_stat_pd_fn)(struct blkg_policy_data *pd, char *buf,				      size_t size); struct blkcg_policy {	int				plid;	/* cgroup files for the policy */	struct cftype			*dfl_cftypes;	struct cftype			*legacy_cftypes; 	/* operations */	blkcg_pol_alloc_cpd_fn		*cpd_alloc_fn;	blkcg_pol_init_cpd_fn		*cpd_init_fn;	blkcg_pol_free_cpd_fn		*cpd_free_fn;	blkcg_pol_bind_cpd_fn		*cpd_bind_fn; 	blkcg_pol_alloc_pd_fn		*pd_alloc_fn;	blkcg_pol_init_pd_fn		*pd_init_fn;	blkcg_pol_online_pd_fn		*pd_online_fn;	blkcg_pol_offline_pd_fn		*pd_offline_fn;	blkcg_pol_free_pd_fn		*pd_free_fn;	blkcg_pol_reset_pd_stats_fn	*pd_reset_stats_fn;	blkcg_pol_stat_pd_fn		*pd_stat_fn;}; extern struct blkcg blkcg_root;extern struct cgroup_subsys_state * const blkcg_root_css;extern bool blkcg_debug_stats; struct blkcg_gq *blkg_lookup_slowpath(struct blkcg *blkcg,				      struct request_queue *q, bool update_hint);struct blkcg_gq *__blkg_lookup_create(struct blkcg *blkcg,				      struct request_queue *q);struct blkcg_gq *blkg_lookup_create(struct blkcg *blkcg,				    struct request_queue *q);int blkcg_init_queue(struct request_queue *q);void blkcg_exit_queue(struct request_queue *q); /* Blkio controller policy registration */int blkcg_policy_register(struct blkcg_policy *pol);void blkcg_policy_unregister(struct blkcg_policy *pol);int blkcg_activate_policy(struct request_queue *q,			  const struct blkcg_policy *pol);void blkcg_deactivate_policy(struct request_queue *q,			     const struct blkcg_policy *pol); const char *blkg_dev_name(struct blkcg_gq *blkg);void blkcg_print_blkgs(struct seq_file *sf, struct blkcg *blkcg,		       u64 (*prfill)(struct seq_file *,				     struct blkg_policy_data *, int),		       const struct blkcg_policy *pol, int data,		       bool show_total);u64 __blkg_prfill_u64(struct seq_file *sf, struct blkg_policy_data *pd, u64 v); struct blkg_conf_ctx {	struct gendisk			*disk;	struct blkcg_gq			*blkg;	char				*body;}; struct gendisk *blkcg_conf_get_disk(char **inputp);int blkg_conf_prep(struct blkcg *blkcg, const struct blkcg_policy *pol,		   char *input, struct blkg_conf_ctx *ctx);void blkg_conf_finish(struct blkg_conf_ctx *ctx); /** * blkcg_css - find the current css * * Find the css associated with either the kthread or the current task. * This may return a dying css, so it is up to the caller to use tryget logic * to confirm it is alive and well. */static inline struct cgroup_subsys_state *blkcg_css(void){	struct cgroup_subsys_state *css; 	css = kthread_blkcg();	if (css)		return css;	return task_css(current, io_cgrp_id);} static inline struct blkcg *css_to_blkcg(struct cgroup_subsys_state *css){	return css ? container_of(css, struct blkcg, css) : NULL;} /** * __bio_blkcg - internal, inconsistent version to get blkcg * * DO NOT USE. * This function is inconsistent and consequently is dangerous to use.  The * first part of the function returns a blkcg where a reference is owned by the * bio.  This means it does not need to be rcu protected as it cannot go away * with the bio owning a reference to it.  However, the latter potentially gets * it from task_css().  This can race against task migration and the cgroup * dying.  It is also semantically different as it must be called rcu protected * and is susceptible to failure when trying to get a reference to it. * Therefore, it is not ok to assume that *_get() will always succeed on the * blkcg returned here. */static inline struct blkcg *__bio_blkcg(struct bio *bio){	if (bio && bio->bi_blkg)		return bio->bi_blkg->blkcg;	return css_to_blkcg(blkcg_css());} /** * 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){	if (bio && bio->bi_blkg)		return bio->bi_blkg->blkcg;	return NULL;} 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;} /** * bio_issue_as_root_blkg - see if this bio needs to be issued as root blkg * @return: true if this bio needs to be submitted with the root blkg context. * * In order to avoid priority inversions we sometimes need to issue a bio as if * it were attached to the root blkg, and then backcharge to the actual owning * blkg.  The idea is we do bio_blkcg() to look up the actual context for the * bio and attach the appropriate blkg to the bio.  Then we call this helper and * if it is true run with the root blkg for that queue and then do any * backcharging to the originating cgroup once the io is complete. */static inline bool bio_issue_as_root_blkg(struct bio *bio){	return (bio->bi_opf & (REQ_META | REQ_SWAP)) != 0;} /** * 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){	return css_to_blkcg(blkcg->css.parent);} /** * __blkg_lookup - internal version of blkg_lookup() * @blkcg: blkcg of interest * @q: request_queue of interest * @update_hint: whether to update lookup hint with the result or not * * This is internal version and shouldn't be used by policy * implementations.  Looks up blkgs for the @blkcg - @q pair regardless of * @q's bypass state.  If @update_hint is %true, the caller should be * holding @q->queue_lock and lookup hint is updated on success. */static inline struct blkcg_gq *__blkg_lookup(struct blkcg *blkcg,					     struct request_queue *q,					     bool update_hint){	struct blkcg_gq *blkg; 	if (blkcg == &blkcg_root)		return q->root_blkg; 	blkg = rcu_dereference(blkcg->blkg_hint);	if (blkg && blkg->q == q)		return blkg; 	return blkg_lookup_slowpath(blkcg, q, update_hint);} /** * blkg_lookup - lookup blkg for the specified blkcg - q pair * @blkcg: blkcg of interest * @q: request_queue of interest * * Lookup blkg for the @blkcg - @q pair.  This function should be called * under RCU read lock. */static inline struct blkcg_gq *blkg_lookup(struct blkcg *blkcg,					   struct request_queue *q){	WARN_ON_ONCE(!rcu_read_lock_held());	return __blkg_lookup(blkcg, q, false);} /** * blk_queue_root_blkg - return blkg for the (blkcg_root, @q) pair * @q: request_queue of interest * * Lookup blkg for @q at the root level. See also blkg_lookup(). */static inline struct blkcg_gq *blk_queue_root_blkg(struct request_queue *q){	return q->root_blkg;} /** * blkg_to_pdata - get policy private data * @blkg: blkg of interest * @pol: policy of interest * * Return pointer to private data associated with the @blkg-@pol pair. */static inline struct blkg_policy_data *blkg_to_pd(struct blkcg_gq *blkg,						  struct blkcg_policy *pol){	return blkg ? blkg->pd[pol->plid] : NULL;} static inline struct blkcg_policy_data *blkcg_to_cpd(struct blkcg *blkcg,						     struct blkcg_policy *pol){	return blkcg ? blkcg->cpd[pol->plid] : NULL;} /** * pdata_to_blkg - get blkg associated with policy private data * @pd: policy private data of interest * * @pd is policy private data.  Determine the blkg it's associated with. */static inline struct blkcg_gq *pd_to_blkg(struct blkg_policy_data *pd){	return pd ? pd->blkg : NULL;} static inline struct blkcg *cpd_to_blkcg(struct blkcg_policy_data *cpd){	return cpd ? cpd->blkcg : NULL;} extern void blkcg_destroy_blkgs(struct blkcg *blkcg); /** * blkcg_pin_online - pin online state * @blkcg: blkcg of interest * * 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. */static inline void blkcg_pin_online(struct blkcg *blkcg){	refcount_inc(&blkcg->online_pin);} /** * blkcg_unpin_online - unpin online state * @blkcg: blkcg of interest * * 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 * blkcg can continue destruction by calling blkcg_destroy_blkgs(). */static inline void blkcg_unpin_online(struct blkcg *blkcg){	do {		if (!refcount_dec_and_test(&blkcg->online_pin))			break;		blkcg_destroy_blkgs(blkcg);		blkcg = blkcg_parent(blkcg);	} while (blkcg);} /** * blkg_path - format cgroup path of blkg * @blkg: blkg of interest * @buf: target buffer * @buflen: target buffer length * * Format the path of the cgroup of @blkg into @buf. */static inline int blkg_path(struct blkcg_gq *blkg, char *buf, int buflen){	return cgroup_path(blkg->blkcg->css.cgroup, buf, buflen);} /** * blkg_get - get a blkg reference * @blkg: blkg to get * * The caller should be holding an existing reference. */static inline void blkg_get(struct blkcg_gq *blkg){	percpu_ref_get(&blkg->refcnt);} /** * blkg_tryget - try and get a blkg reference * @blkg: blkg to get * * This is for use when doing an RCU lookup of the blkg.  We may be in the midst * of freeing this blkg, so we can only use it if the refcnt is not zero. */static inline bool blkg_tryget(struct blkcg_gq *blkg){	return blkg && percpu_ref_tryget(&blkg->refcnt);} /** * blkg_tryget_closest - try and get a blkg ref on the closet blkg * @blkg: blkg to get * * This needs to be called rcu protected.  As the failure mode here is to walk * up the blkg tree, this ensure that the blkg->parent pointers are always * valid.  This returns the blkg that it ended up taking a reference on or %NULL * if no reference was taken. */static inline struct blkcg_gq *blkg_tryget_closest(struct blkcg_gq *blkg){	struct blkcg_gq *ret_blkg = NULL; 	WARN_ON_ONCE(!rcu_read_lock_held()); 	while (blkg) {		if (blkg_tryget(blkg)) {			ret_blkg = blkg;

Lines 1–500 of 766.

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t