Re: [RFC PATCH v1 1/3] blk-cgroup: add helpers for bio cgroup state

Jan Kara <[email protected]>
Newsgroups org.kernel.vger.linux-raid,dev.linux.lists.dm-devel,dev.linux.lists.gfs2,dev.linux.lists.nvdimm,dev.linux.lists.virtualization,org.kernel.vger.cgroups,org.kernel.vger.linux-bcache,org.kernel.vger.linux-block,org.kernel.vger.linux-doc,org.kernel.vger.linux-fsdevel,org.kernel.vger.linux-kernel
Message-ID <prx5s4rwbgoeh7wtgyo7vwydh5iwqn6qc2utamowirsplspfmp@e3eteq5xwuyf>
On Tue 04-08-26 14:53:11, Yu Kuai wrote:
> From: Yu Kuai <[email protected]>
> 
> blk-cgroup users open-code bio->bi_blkg throughout the policy and
> accounting paths.  Some users need the blkg itself, while others
> immediately dereference it to get the associated blkcg.  The bio release
> paths also open-code the CONFIG_BLK_CGROUP guarded blkg reference drop
> and field clear.
> 
> Add bio_blkg(), bio_blkcg() and bio_clear_blkg() helpers.  Convert the
> read-side users to use the accessors, and use bio_clear_blkg() from
> bio_uninit() and bio_endio() so the release path no longer needs to know
> about CONFIG_BLK_CGROUP.  Keep the direct bio->bi_blkg stores in the
> association and initialization paths, as those paths still assign the
> stored association.
> 
> This keeps the current behavior unchanged while preparing for changing
> what cgroup state a bio stores internally.
> 
> Signed-off-by: Yu Kuai <[email protected]>

Mostly looks good. Just I think bio_blkcg() should gracefully handle the
case where bio->bi_blkg is NULL (and return NULL in that case). That way
you can also get rid of somewhat odd pattern:

	if (!bio_blkg(bio))
		return ...;
	do something with bio_blkcg(bio)

You can then just check bio_blkcg(bio) directly which is much more obvious.

								Honza

> ---
>  block/bfq-cgroup.c          |  4 ++--
>  block/bio.c                 | 14 ++------------
>  block/blk-cgroup-fc-appid.c | 11 +++++++++--
>  block/blk-cgroup.c          | 19 ++++++++++---------
>  block/blk-cgroup.h          | 19 ++++++++++++++++++-
>  block/blk-iocost.c          |  6 +++---
>  block/blk-iolatency.c       |  6 +++---
>  block/blk-ioprio.c          |  2 +-
>  block/blk-throttle.c        |  2 +-
>  block/blk-throttle.h        |  2 +-
>  include/linux/bio.h         | 10 ++++++++++
>  11 files changed, 60 insertions(+), 35 deletions(-)
> 
> diff --git a/block/bfq-cgroup.c b/block/bfq-cgroup.c
> index e82ff03bda02..7e65fe6844ee 100644
> --- a/block/bfq-cgroup.c
> +++ b/block/bfq-cgroup.c
> @@ -363,7 +363,7 @@ void bfqg_and_blkg_put(struct bfq_group *bfqg)
>  
>  void bfqg_stats_update_legacy_io(struct request_queue *q, struct request *rq)
>  {
> -	struct bfq_group *bfqg = blkg_to_bfqg(rq->bio->bi_blkg);
> +	struct bfq_group *bfqg = blkg_to_bfqg(bio_blkg(rq->bio));
>  
>  	if (!bfqg)
>  		return;
> @@ -606,7 +606,7 @@ static void bfq_link_bfqg(struct bfq_data *bfqd, struct bfq_group *bfqg)
>  
>  struct bfq_group *bfq_bio_bfqg(struct bfq_data *bfqd, struct bio *bio)
>  {
> -	struct blkcg_gq *blkg = bio->bi_blkg;
> +	struct blkcg_gq *blkg = bio_blkg(bio);
>  	struct bfq_group *bfqg;
>  
>  	while (blkg) {
> diff --git a/block/bio.c b/block/bio.c
> index 6a2f6fc3413e..c207b248edba 100644
> --- a/block/bio.c
> +++ b/block/bio.c
> @@ -179,12 +179,7 @@ static inline gfp_t try_alloc_gfp(gfp_t gfp)
>  
>  void bio_uninit(struct bio *bio)
>  {
> -#ifdef CONFIG_BLK_CGROUP
> -	if (bio->bi_blkg) {
> -		blkg_put(bio->bi_blkg);
> -		bio->bi_blkg = NULL;
> -	}
> -#endif
> +	bio_clear_blkg(bio);
>  	if (bio_integrity(bio))
>  		bio_integrity_free(bio);
>  
> @@ -1803,17 +1798,12 @@ void bio_endio(struct bio *bio)
>  		goto again;
>  	}
>  
> -#ifdef CONFIG_BLK_CGROUP
>  	/*
>  	 * Release cgroup info.  We shouldn't have to do this here, but quite
>  	 * a few callers of bio_init fail to call bio_uninit, so we cover up
>  	 * for that here at least for now.
>  	 */
> -	if (bio->bi_blkg) {
> -		blkg_put(bio->bi_blkg);
> -		bio->bi_blkg = NULL;
> -	}
> -#endif
> +	bio_clear_blkg(bio);
>  
>  	if (bio->bi_end_io)
>  		bio->bi_end_io(bio);
> diff --git a/block/blk-cgroup-fc-appid.c b/block/blk-cgroup-fc-appid.c
> index 3ec21333f393..b2e16e9a7a6c 100644
> --- a/block/blk-cgroup-fc-appid.c
> +++ b/block/blk-cgroup-fc-appid.c
> @@ -50,8 +50,15 @@ EXPORT_SYMBOL_GPL(blkcg_set_fc_appid);
>   */
>  char *blkcg_get_fc_appid(struct bio *bio)
>  {
> -	if (!bio->bi_blkg || bio->bi_blkg->blkcg->fc_app_id[0] == '\0')
> +	struct blkcg *blkcg;
> +
> +	if (!bio_blkg(bio))
>  		return NULL;
> -	return bio->bi_blkg->blkcg->fc_app_id;
> +
> +	blkcg = bio_blkcg(bio);
> +	if (blkcg->fc_app_id[0] == '\0')
> +		return NULL;
> +
> +	return blkcg->fc_app_id;
>  }
>  EXPORT_SYMBOL_GPL(blkcg_get_fc_appid);
> diff --git a/block/blk-cgroup.c b/block/blk-cgroup.c
> index 354637f3b158..753a3bdd0e8c 100644
> --- a/block/blk-cgroup.c
> +++ b/block/blk-cgroup.c
> @@ -239,7 +239,7 @@ static void blkg_async_bio_workfn(struct work_struct *work)
>   */
>  void blkcg_punt_bio_submit(struct bio *bio)
>  {
> -	struct blkcg_gq *blkg = bio->bi_blkg;
> +	struct blkcg_gq *blkg = bio_blkg(bio);
>  
>  	if (blkg->parent) {
>  		spin_lock(&blkg->async_bio_lock);
> @@ -275,9 +275,9 @@ subsys_initcall(blkcg_punt_bio_init);
>   */
>  struct cgroup_subsys_state *bio_blkcg_css(struct bio *bio)
>  {
> -	if (!bio || !bio->bi_blkg)
> +	if (!bio || !bio_blkg(bio))
>  		return NULL;
> -	return &bio->bi_blkg->blkcg->css;
> +	return &bio_blkcg(bio)->css;
>  }
>  EXPORT_SYMBOL_GPL(bio_blkcg_css);
>  
> @@ -2118,8 +2118,8 @@ static inline struct blkcg_gq *blkg_tryget_closest(struct bio *bio,
>  void bio_associate_blkg_from_css(struct bio *bio,
>  				 struct cgroup_subsys_state *css)
>  {
> -	if (bio->bi_blkg)
> -		blkg_put(bio->bi_blkg);
> +	if (bio_blkg(bio))
> +		blkg_put(bio_blkg(bio));
>  
>  	if (css && css->parent) {
>  		bio->bi_blkg = blkg_tryget_closest(bio, css);
> @@ -2146,7 +2146,7 @@ void bio_associate_blkg(struct bio *bio)
>  	if (blk_op_is_passthrough(bio->bi_opf))
>  		return;
>  
> -	if (bio->bi_blkg) {
> +	if (bio_blkg(bio)) {
>  		css = bio_blkcg_css(bio);
>  		bio_associate_blkg_from_css(bio, css);
>  	} else {
> @@ -2170,7 +2170,7 @@ EXPORT_SYMBOL_GPL(bio_associate_blkg);
>   */
>  void bio_clone_blkg_association(struct bio *dst, struct bio *src)
>  {
> -	if (src->bi_blkg)
> +	if (bio_blkg(src))
>  		bio_associate_blkg_from_css(dst, bio_blkcg_css(src));
>  }
>  EXPORT_SYMBOL_GPL(bio_clone_blkg_association);
> @@ -2186,7 +2186,8 @@ static int blk_cgroup_io_type(struct bio *bio)
>  
>  void blk_cgroup_bio_start(struct bio *bio)
>  {
> -	struct blkcg *blkcg = bio->bi_blkg->blkcg;
> +	struct blkcg_gq *blkg = bio_blkg(bio);
> +	struct blkcg *blkcg = bio_blkcg(bio);
>  	int rwd = blk_cgroup_io_type(bio), cpu;
>  	struct blkg_iostat_set *bis;
>  	unsigned long flags;
> @@ -2199,7 +2200,7 @@ void blk_cgroup_bio_start(struct bio *bio)
>  		return;
>  
>  	cpu = get_cpu();
> -	bis = per_cpu_ptr(bio->bi_blkg->iostat_cpu, cpu);
> +	bis = per_cpu_ptr(blkg->iostat_cpu, cpu);
>  	flags = u64_stats_update_begin_irqsave(&bis->sync);
>  
>  	/*
> diff --git a/block/blk-cgroup.h b/block/blk-cgroup.h
> index 615390f751aa..1e80b0a73233 100644
> --- a/block/blk-cgroup.h
> +++ b/block/blk-cgroup.h
> @@ -124,6 +124,11 @@ static inline struct blkcg *css_to_blkcg(struct cgroup_subsys_state *css)
>  	return css ? container_of(css, struct blkcg, css) : NULL;
>  }
>  
> +static inline struct blkcg *bio_blkcg(struct bio *bio)
> +{
> +	return bio_blkg(bio)->blkcg;
> +}
> +
>  /*
>   * 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
> @@ -343,6 +348,16 @@ static inline void blkg_put(struct blkcg_gq *blkg)
>  	percpu_ref_put(&blkg->refcnt);
>  }
>  
> +static inline void bio_clear_blkg(struct bio *bio)
> +{
> +	struct blkcg_gq *blkg = bio_blkg(bio);
> +
> +	if (blkg) {
> +		blkg_put(blkg);
> +		bio->bi_blkg = NULL;
> +	}
> +}
> +
>  /**
>   * blkg_for_each_descendant_pre - pre-order walk of a blkg's descendants
>   * @d_blkg: loop cursor pointing to the current descendant
> @@ -455,7 +470,7 @@ static inline void blkcg_clear_delay(struct blkcg_gq *blkg)
>   */
>  static inline bool blk_cgroup_mergeable(struct request *rq, struct bio *bio)
>  {
> -	return rq->bio->bi_blkg == bio->bi_blkg &&
> +	return bio_blkg(rq->bio) == bio_blkg(bio) &&
>  		bio_issue_as_root_blkg(rq->bio) == bio_issue_as_root_blkg(bio);
>  }
>  
> @@ -481,6 +496,7 @@ struct blkcg_policy {
>  struct blkcg {
>  };
>  
> +static inline struct blkcg *bio_blkcg(struct bio *bio) { return NULL; }
>  static inline struct blkcg_gq *blkg_lookup(struct blkcg *blkcg, void *key) { return NULL; }
>  static inline void blkg_init_queue(struct request_queue *q) { }
>  static inline int blkcg_init_disk(struct gendisk *disk) { return 0; }
> @@ -497,6 +513,7 @@ static inline struct blkg_policy_data *blkg_to_pd(struct blkcg_gq *blkg,
>  static inline struct blkcg_gq *pd_to_blkg(struct blkg_policy_data *pd) { return NULL; }
>  static inline void blkg_get(struct blkcg_gq *blkg) { }
>  static inline void blkg_put(struct blkcg_gq *blkg) { }
> +static inline void bio_clear_blkg(struct bio *bio) { }
>  static inline void blk_cgroup_bio_start(struct bio *bio) { }
>  static inline bool blk_cgroup_mergeable(struct request *rq, struct bio *bio) { return true; }
>  
> diff --git a/block/blk-iocost.c b/block/blk-iocost.c
> index 8b2aeba2e1e3..d4470476bcd0 100644
> --- a/block/blk-iocost.c
> +++ b/block/blk-iocost.c
> @@ -2686,7 +2686,7 @@ iocg_handle_over_budget(struct rq_qos *rqos, struct ioc_gq *iocg,
>  
>  static void ioc_rqos_throttle(struct rq_qos *rqos, struct bio *bio)
>  {
> -	struct blkcg_gq *blkg = bio->bi_blkg;
> +	struct blkcg_gq *blkg = bio_blkg(bio);
>  	struct ioc *ioc = rqos_to_ioc(rqos);
>  	struct ioc_gq *iocg = blkg_to_iocg(blkg);
>  	struct ioc_now now;
> @@ -2775,7 +2775,7 @@ static void ioc_rqos_throttle(struct rq_qos *rqos, struct bio *bio)
>  static void ioc_rqos_merge(struct rq_qos *rqos, struct request *rq,
>  			   struct bio *bio)
>  {
> -	struct ioc_gq *iocg = blkg_to_iocg(bio->bi_blkg);
> +	struct ioc_gq *iocg = blkg_to_iocg(bio_blkg(bio));
>  	struct ioc *ioc = rqos_to_ioc(rqos);
>  	sector_t bio_end = bio_end_sector(bio);
>  	struct ioc_now now;
> @@ -2833,7 +2833,7 @@ static void ioc_rqos_merge(struct rq_qos *rqos, struct request *rq,
>  
>  static void ioc_rqos_done_bio(struct rq_qos *rqos, struct bio *bio)
>  {
> -	struct ioc_gq *iocg = blkg_to_iocg(bio->bi_blkg);
> +	struct ioc_gq *iocg = blkg_to_iocg(bio_blkg(bio));
>  
>  	if (iocg && bio->bi_iocost_cost)
>  		atomic64_add(bio->bi_iocost_cost, &iocg->done_vtime);
> diff --git a/block/blk-iolatency.c b/block/blk-iolatency.c
> index cef02b6c5fa9..c0d8d5f6bdba 100644
> --- a/block/blk-iolatency.c
> +++ b/block/blk-iolatency.c
> @@ -463,7 +463,7 @@ static void check_scale_change(struct iolatency_grp *iolat)
>  static void blkcg_iolatency_throttle(struct rq_qos *rqos, struct bio *bio)
>  {
>  	struct blk_iolatency *blkiolat = BLKIOLATENCY(rqos);
> -	struct blkcg_gq *blkg = bio->bi_blkg;
> +	struct blkcg_gq *blkg = bio_blkg(bio);
>  	bool issue_as_root = bio_issue_as_root_blkg(bio);
>  
>  	if (!blkiolat->enabled)
> @@ -590,11 +590,11 @@ static void blkcg_iolatency_done_bio(struct rq_qos *rqos, struct bio *bio)
>  	bool issue_as_root = bio_issue_as_root_blkg(bio);
>  	int inflight = 0;
>  
> -	blkg = bio->bi_blkg;
> +	blkg = bio_blkg(bio);
>  	if (!blkg || !bio_flagged(bio, BIO_QOS_THROTTLED))
>  		return;
>  
> -	iolat = blkg_to_lat(bio->bi_blkg);
> +	iolat = blkg_to_lat(blkg);
>  	if (!iolat)
>  		return;
>  
> diff --git a/block/blk-ioprio.c b/block/blk-ioprio.c
> index 8fa8bca35062..5e3f8e49550d 100644
> --- a/block/blk-ioprio.c
> +++ b/block/blk-ioprio.c
> @@ -132,7 +132,7 @@ static struct blkcg_policy ioprio_policy = {
>  
>  void blkcg_set_ioprio(struct bio *bio)
>  {
> -	struct ioprio_blkcg *blkcg = blkcg_to_ioprio_blkcg(bio->bi_blkg->blkcg);
> +	struct ioprio_blkcg *blkcg = blkcg_to_ioprio_blkcg(bio_blkcg(bio));
>  	u16 prio;
>  
>  	if (!blkcg || blkcg->prio_policy == POLICY_NO_CHANGE)
> diff --git a/block/blk-throttle.c b/block/blk-throttle.c
> index ffc3b70065d4..3828c3857900 100644
> --- a/block/blk-throttle.c
> +++ b/block/blk-throttle.c
> @@ -1792,7 +1792,7 @@ static bool tg_within_limit(struct throtl_grp *tg, struct bio *bio, bool rw)
>  bool __blk_throtl_bio(struct bio *bio)
>  {
>  	struct request_queue *q = bdev_get_queue(bio->bi_bdev);
> -	struct blkcg_gq *blkg = bio->bi_blkg;
> +	struct blkcg_gq *blkg = bio_blkg(bio);
>  	struct throtl_qnode *qn = NULL;
>  	struct throtl_grp *tg = blkg_to_tg(blkg);
>  	struct throtl_service_queue *sq;
> diff --git a/block/blk-throttle.h b/block/blk-throttle.h
> index 9d7a42c039a1..609a126c7ccb 100644
> --- a/block/blk-throttle.h
> +++ b/block/blk-throttle.h
> @@ -173,7 +173,7 @@ static inline bool blk_should_throtl(struct bio *bio)
>  	if (!blk_throtl_activated(bio->bi_bdev->bd_queue))
>  		return false;
>  
> -	tg = blkg_to_tg(bio->bi_blkg);
> +	tg = blkg_to_tg(bio_blkg(bio));
>  	if (!cgroup_subsys_on_dfl(io_cgrp_subsys)) {
>  		if (!bio_flagged(bio, BIO_CGROUP_ACCT)) {
>  			bio_set_flag(bio, BIO_CGROUP_ACCT);
> diff --git a/include/linux/bio.h b/include/linux/bio.h
> index 8f33f717b14f..dc4baa3602b7 100644
> --- a/include/linux/bio.h
> +++ b/include/linux/bio.h
> @@ -503,12 +503,22 @@ static inline void bio_release_pages(struct bio *bio, bool mark_dirty)
>  	disk_devt((bio)->bi_bdev->bd_disk)
>  
>  #ifdef CONFIG_BLK_CGROUP
> +static inline struct blkcg_gq *bio_blkg(struct bio *bio)
> +{
> +	return bio->bi_blkg;
> +}
> +
>  void bio_associate_blkg(struct bio *bio);
>  void bio_associate_blkg_from_css(struct bio *bio,
>  				 struct cgroup_subsys_state *css);
>  void bio_clone_blkg_association(struct bio *dst, struct bio *src);
>  void blkcg_punt_bio_submit(struct bio *bio);
>  #else	/* CONFIG_BLK_CGROUP */
> +static inline struct blkcg_gq *bio_blkg(struct bio *bio)
> +{
> +	return NULL;
> +}
> +
>  static inline void bio_associate_blkg(struct bio *bio) { }
>  static inline void bio_associate_blkg_from_css(struct bio *bio,
>  					       struct cgroup_subsys_state *css)
> -- 
> 2.51.0
> 
-- 
Jan Kara <[email protected]>
SUSE Labs, CR
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.