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; 41*672fdcf0SMing 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; 98d3f77dfdSTejun Heo struct work_struct async_bio_work; 99d09d8df3SJosef Bacik 100d09d8df3SJosef Bacik atomic_t use_delay; 101d09d8df3SJosef Bacik atomic64_t delay_nsec; 102d09d8df3SJosef Bacik atomic64_t delay_start; 103d09d8df3SJosef Bacik u64 last_delay; 104d09d8df3SJosef Bacik int last_use; 105d3f77dfdSTejun Heo 106d3f77dfdSTejun Heo struct rcu_head rcu_head; 107eea8f41cSTejun Heo }; 108eea8f41cSTejun Heo 109496d5e75STejun Heo extern struct cgroup_subsys_state * const blkcg_root_css; 110eea8f41cSTejun Heo 111*672fdcf0SMing Lei void blkcg_destroy_blkgs(struct blkcg *blkcg); 112*672fdcf0SMing Lei void blkcg_schedule_throttle(struct request_queue *q, bool use_memdelay); 113*672fdcf0SMing Lei void blkcg_maybe_throttle_current(void); 1140fe061b9SDennis Zhou 115eea8f41cSTejun Heo static inline struct blkcg *css_to_blkcg(struct cgroup_subsys_state *css) 116eea8f41cSTejun Heo { 117eea8f41cSTejun Heo return css ? container_of(css, struct blkcg, css) : NULL; 118eea8f41cSTejun Heo } 119eea8f41cSTejun Heo 1200fe061b9SDennis Zhou /** 1210fe061b9SDennis Zhou * bio_blkcg - grab the blkcg associated with a bio 1220fe061b9SDennis Zhou * @bio: target bio 1230fe061b9SDennis Zhou * 1240fe061b9SDennis Zhou * This returns the blkcg associated with a bio, %NULL if not associated. 1250fe061b9SDennis Zhou * Callers are expected to either handle %NULL or know association has been 1260fe061b9SDennis Zhou * done prior to calling this. 1270fe061b9SDennis Zhou */ 1280fe061b9SDennis Zhou static inline struct blkcg *bio_blkcg(struct bio *bio) 1290fe061b9SDennis Zhou { 130db6638d7SDennis Zhou if (bio && bio->bi_blkg) 131db6638d7SDennis Zhou return bio->bi_blkg->blkcg; 1320fe061b9SDennis Zhou return NULL; 133fd383c2dSTejun Heo } 134fd383c2dSTejun Heo 135d09d8df3SJosef Bacik static inline bool blk_cgroup_congested(void) 136d09d8df3SJosef Bacik { 137d09d8df3SJosef Bacik struct cgroup_subsys_state *css; 138d09d8df3SJosef Bacik bool ret = false; 139d09d8df3SJosef Bacik 140d09d8df3SJosef Bacik rcu_read_lock(); 141d09d8df3SJosef Bacik css = kthread_blkcg(); 142d09d8df3SJosef Bacik if (!css) 143d09d8df3SJosef Bacik css = task_css(current, io_cgrp_id); 144d09d8df3SJosef Bacik while (css) { 145d09d8df3SJosef Bacik if (atomic_read(&css->cgroup->congestion_count)) { 146d09d8df3SJosef Bacik ret = true; 147d09d8df3SJosef Bacik break; 148d09d8df3SJosef Bacik } 149d09d8df3SJosef Bacik css = css->parent; 150d09d8df3SJosef Bacik } 151d09d8df3SJosef Bacik rcu_read_unlock(); 152d09d8df3SJosef Bacik return ret; 153d09d8df3SJosef Bacik } 154d09d8df3SJosef Bacik 155eea8f41cSTejun Heo /** 156eea8f41cSTejun Heo * blkcg_parent - get the parent of a blkcg 157eea8f41cSTejun Heo * @blkcg: blkcg of interest 158eea8f41cSTejun Heo * 159eea8f41cSTejun Heo * Return the parent blkcg of @blkcg. Can be called anytime. 160eea8f41cSTejun Heo */ 161eea8f41cSTejun Heo static inline struct blkcg *blkcg_parent(struct blkcg *blkcg) 162eea8f41cSTejun Heo { 163eea8f41cSTejun Heo return css_to_blkcg(blkcg->css.parent); 164eea8f41cSTejun Heo } 165eea8f41cSTejun Heo 166eea8f41cSTejun Heo /** 167d866dbf6STejun Heo * blkcg_pin_online - pin online state 16859b57717SDennis Zhou (Facebook) * @blkcg: blkcg of interest 16959b57717SDennis Zhou (Facebook) * 170d866dbf6STejun Heo * While pinned, a blkcg is kept online. This is primarily used to 171d866dbf6STejun Heo * impedance-match blkg and cgwb lifetimes so that blkg doesn't go offline 172d866dbf6STejun Heo * while an associated cgwb is still active. 17359b57717SDennis Zhou (Facebook) */ 174d866dbf6STejun Heo static inline void blkcg_pin_online(struct blkcg *blkcg) 17559b57717SDennis Zhou (Facebook) { 176d866dbf6STejun Heo refcount_inc(&blkcg->online_pin); 17759b57717SDennis Zhou (Facebook) } 17859b57717SDennis Zhou (Facebook) 17959b57717SDennis Zhou (Facebook) /** 180d866dbf6STejun Heo * blkcg_unpin_online - unpin online state 18159b57717SDennis Zhou (Facebook) * @blkcg: blkcg of interest 18259b57717SDennis Zhou (Facebook) * 183d866dbf6STejun Heo * This is primarily used to impedance-match blkg and cgwb lifetimes so 184d866dbf6STejun Heo * that blkg doesn't go offline while an associated cgwb is still active. 185d866dbf6STejun Heo * When this count goes to zero, all active cgwbs have finished so the 18659b57717SDennis Zhou (Facebook) * blkcg can continue destruction by calling blkcg_destroy_blkgs(). 18759b57717SDennis Zhou (Facebook) */ 188d866dbf6STejun Heo static inline void blkcg_unpin_online(struct blkcg *blkcg) 18959b57717SDennis Zhou (Facebook) { 1904308a434STejun Heo do { 1914308a434STejun Heo if (!refcount_dec_and_test(&blkcg->online_pin)) 1924308a434STejun Heo break; 19359b57717SDennis Zhou (Facebook) blkcg_destroy_blkgs(blkcg); 1944308a434STejun Heo blkcg = blkcg_parent(blkcg); 1954308a434STejun Heo } while (blkcg); 19659b57717SDennis Zhou (Facebook) } 19759b57717SDennis Zhou (Facebook) 198eea8f41cSTejun Heo #else /* CONFIG_BLK_CGROUP */ 199eea8f41cSTejun Heo 200efa7d1c7STejun Heo struct blkcg { 201efa7d1c7STejun Heo }; 202eea8f41cSTejun Heo 203eea8f41cSTejun Heo struct blkcg_gq { 204eea8f41cSTejun Heo }; 205eea8f41cSTejun Heo 206496d5e75STejun Heo #define blkcg_root_css ((struct cgroup_subsys_state *)ERR_PTR(-EINVAL)) 207496d5e75STejun Heo 208d09d8df3SJosef Bacik static inline void blkcg_maybe_throttle_current(void) { } 209d09d8df3SJosef Bacik static inline bool blk_cgroup_congested(void) { return false; } 210d09d8df3SJosef Bacik 211efa7d1c7STejun Heo #ifdef CONFIG_BLOCK 212d09d8df3SJosef Bacik static inline void blkcg_schedule_throttle(struct request_queue *q, bool use_memdelay) { } 213eea8f41cSTejun Heo static inline struct blkcg *bio_blkcg(struct bio *bio) { return NULL; } 214efa7d1c7STejun Heo #endif /* CONFIG_BLOCK */ 215*672fdcf0SMing Lei 216eea8f41cSTejun Heo #endif /* CONFIG_BLK_CGROUP */ 217d2bcbeabSMuneendra Kumar 218d2bcbeabSMuneendra Kumar #ifdef CONFIG_BLK_CGROUP_FC_APPID 219d2bcbeabSMuneendra Kumar /* 220d2bcbeabSMuneendra Kumar * Sets the fc_app_id field associted to blkcg 221d2bcbeabSMuneendra Kumar * @app_id: application identifier 222d2bcbeabSMuneendra Kumar * @cgrp_id: cgroup id 223d2bcbeabSMuneendra Kumar * @app_id_len: size of application identifier 224d2bcbeabSMuneendra Kumar */ 225d2bcbeabSMuneendra Kumar static inline int blkcg_set_fc_appid(char *app_id, u64 cgrp_id, size_t app_id_len) 226d2bcbeabSMuneendra Kumar { 227d2bcbeabSMuneendra Kumar struct cgroup *cgrp; 228d2bcbeabSMuneendra Kumar struct cgroup_subsys_state *css; 229d2bcbeabSMuneendra Kumar struct blkcg *blkcg; 230d2bcbeabSMuneendra Kumar int ret = 0; 231d2bcbeabSMuneendra Kumar 232d2bcbeabSMuneendra Kumar if (app_id_len > FC_APPID_LEN) 233d2bcbeabSMuneendra Kumar return -EINVAL; 234d2bcbeabSMuneendra Kumar 235d2bcbeabSMuneendra Kumar cgrp = cgroup_get_from_id(cgrp_id); 236d2bcbeabSMuneendra Kumar if (!cgrp) 237d2bcbeabSMuneendra Kumar return -ENOENT; 238d2bcbeabSMuneendra Kumar css = cgroup_get_e_css(cgrp, &io_cgrp_subsys); 239d2bcbeabSMuneendra Kumar if (!css) { 240d2bcbeabSMuneendra Kumar ret = -ENOENT; 241d2bcbeabSMuneendra Kumar goto out_cgrp_put; 242d2bcbeabSMuneendra Kumar } 243d2bcbeabSMuneendra Kumar blkcg = css_to_blkcg(css); 244d2bcbeabSMuneendra Kumar /* 245d2bcbeabSMuneendra Kumar * There is a slight race condition on setting the appid. 246d2bcbeabSMuneendra Kumar * Worst case an I/O may not find the right id. 247d2bcbeabSMuneendra Kumar * This is no different from the I/O we let pass while obtaining 248d2bcbeabSMuneendra Kumar * the vmid from the fabric. 249d2bcbeabSMuneendra Kumar * Adding the overhead of a lock is not necessary. 250d2bcbeabSMuneendra Kumar */ 251d2bcbeabSMuneendra Kumar strlcpy(blkcg->fc_app_id, app_id, app_id_len); 252d2bcbeabSMuneendra Kumar css_put(css); 253d2bcbeabSMuneendra Kumar out_cgrp_put: 254d2bcbeabSMuneendra Kumar cgroup_put(cgrp); 255d2bcbeabSMuneendra Kumar return ret; 256d2bcbeabSMuneendra Kumar } 257d2bcbeabSMuneendra Kumar 258d2bcbeabSMuneendra Kumar /** 259d2bcbeabSMuneendra Kumar * blkcg_get_fc_appid - get the fc app identifier associated with a bio 260d2bcbeabSMuneendra Kumar * @bio: target bio 261d2bcbeabSMuneendra Kumar * 262d2bcbeabSMuneendra Kumar * On success return the fc_app_id, on failure return NULL 263d2bcbeabSMuneendra Kumar */ 264d2bcbeabSMuneendra Kumar static inline char *blkcg_get_fc_appid(struct bio *bio) 265d2bcbeabSMuneendra Kumar { 266d2bcbeabSMuneendra Kumar if (bio && bio->bi_blkg && 267d2bcbeabSMuneendra Kumar (bio->bi_blkg->blkcg->fc_app_id[0] != '\0')) 268d2bcbeabSMuneendra Kumar return bio->bi_blkg->blkcg->fc_app_id; 269d2bcbeabSMuneendra Kumar return NULL; 270d2bcbeabSMuneendra Kumar } 271d2bcbeabSMuneendra Kumar #else 272d2bcbeabSMuneendra Kumar static inline int blkcg_set_fc_appid(char *buf, u64 id, size_t len) { return -EINVAL; } 273d2bcbeabSMuneendra Kumar static inline char *blkcg_get_fc_appid(struct bio *bio) { return NULL; } 274d2bcbeabSMuneendra Kumar #endif /*CONFIG_BLK_CGROUP_FC_APPID*/ 275eea8f41cSTejun Heo #endif /* _BLK_CGROUP_H */ 276