blk-cgroup: move blkcg_{pin,unpin}_online out of line
ANBZ: #13060
commit 397c9f46ee
upstream.
Move these two functions out of line as there is no good reason
to inline them. Also switch to passing a cgroup_subsys_state
instead of doing the conversion in the caller to prepare for making
the blkcg structure private to blk-cgroup.
[ Backport Notes]
This is as a dependent of "blk-cgroup: Fix UAF in blkcg_unpin_online()",
which is the right fix for CVE-2024-56672.
Signed-off-by: Christoph Hellwig <hch@lst.de>
Acked-by: Tejun Heo <tj@kernel.org>
Link: https://lore.kernel.org/r/20220420042723.1010598-7-hch@lst.de
Signed-off-by: Jens Axboe <axboe@kernel.dk>
Fixes: CVE-2024-56672
Signed-off-by: Joseph Qi <joseph.qi@linux.alibaba.com>
Reviewed-by: Ferry Meng <mengferry@linux.alibaba.com>
Link: https://gitee.com/anolis/cloud-kernel/pulls/4448
This commit is contained in:
parent
d96ddd9f27
commit
b941f72491
|
@ -139,6 +139,17 @@ static void blkg_async_bio_workfn(struct work_struct *work)
|
|||
blk_finish_plug(&plug);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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_alloc - allocate a blkg
|
||||
* @blkcg: block cgroup the new blkg is associated with
|
||||
|
@ -985,25 +996,6 @@ static struct cftype blkcg_legacy_files[] = {
|
|||
* This finally frees the blkcg.
|
||||
*/
|
||||
|
||||
/**
|
||||
* blkcg_css_offline - cgroup css_offline callback
|
||||
* @css: css of interest
|
||||
*
|
||||
* This function is called when @css is about to go away. Here the cgwbs are
|
||||
* offlined first and only once writeback associated with the blkcg has
|
||||
* finished do we start step 2 (see above).
|
||||
*/
|
||||
static void blkcg_css_offline(struct cgroup_subsys_state *css)
|
||||
{
|
||||
struct blkcg *blkcg = css_to_blkcg(css);
|
||||
|
||||
/* this prevents anyone from attaching or migrating to this blkcg */
|
||||
wb_blkcg_offline(blkcg);
|
||||
|
||||
/* put the base online pin allowing step 2 to be triggered */
|
||||
blkcg_unpin_online(blkcg);
|
||||
}
|
||||
|
||||
/**
|
||||
* blkcg_destroy_blkgs - responsible for shooting down blkgs
|
||||
* @blkcg: blkcg of interest
|
||||
|
@ -1015,7 +1007,7 @@ static void blkcg_css_offline(struct cgroup_subsys_state *css)
|
|||
*
|
||||
* This is the blkcg counterpart of ioc_release_fn().
|
||||
*/
|
||||
void blkcg_destroy_blkgs(struct blkcg *blkcg)
|
||||
static void blkcg_destroy_blkgs(struct blkcg *blkcg)
|
||||
{
|
||||
might_sleep();
|
||||
|
||||
|
@ -1045,6 +1037,57 @@ void blkcg_destroy_blkgs(struct blkcg *blkcg)
|
|||
spin_unlock_irq(&blkcg->lock);
|
||||
}
|
||||
|
||||
/**
|
||||
* blkcg_pin_online - pin online state
|
||||
* @blkcg_css: 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.
|
||||
*/
|
||||
void blkcg_pin_online(struct cgroup_subsys_state *blkcg_css)
|
||||
{
|
||||
refcount_inc(&css_to_blkcg(blkcg_css)->online_pin);
|
||||
}
|
||||
|
||||
/**
|
||||
* blkcg_unpin_online - unpin online state
|
||||
* @blkcg_css: 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().
|
||||
*/
|
||||
void blkcg_unpin_online(struct cgroup_subsys_state *blkcg_css)
|
||||
{
|
||||
struct blkcg *blkcg = css_to_blkcg(blkcg_css);
|
||||
|
||||
do {
|
||||
if (!refcount_dec_and_test(&blkcg->online_pin))
|
||||
break;
|
||||
blkcg_destroy_blkgs(blkcg);
|
||||
blkcg = blkcg_parent(blkcg);
|
||||
} while (blkcg);
|
||||
}
|
||||
|
||||
/**
|
||||
* blkcg_css_offline - cgroup css_offline callback
|
||||
* @css: css of interest
|
||||
*
|
||||
* This function is called when @css is about to go away. Here the cgwbs are
|
||||
* offlined first and only once writeback associated with the blkcg has
|
||||
* finished do we start step 2 (see above).
|
||||
*/
|
||||
static void blkcg_css_offline(struct cgroup_subsys_state *css)
|
||||
{
|
||||
/* this prevents anyone from attaching or migrating to this blkcg */
|
||||
wb_blkcg_offline(css_to_blkcg(css));
|
||||
|
||||
/* put the base online pin allowing step 2 to be triggered */
|
||||
blkcg_unpin_online(css);
|
||||
}
|
||||
|
||||
static void blkcg_css_free(struct cgroup_subsys_state *css)
|
||||
{
|
||||
struct blkcg *blkcg = css_to_blkcg(css);
|
||||
|
@ -1133,8 +1176,7 @@ unlock:
|
|||
|
||||
static int blkcg_css_online(struct cgroup_subsys_state *css)
|
||||
{
|
||||
struct blkcg *blkcg = css_to_blkcg(css);
|
||||
struct blkcg *parent = blkcg_parent(blkcg);
|
||||
struct blkcg *parent = blkcg_parent(css_to_blkcg(css));
|
||||
|
||||
/*
|
||||
* blkcg_pin_online() is used to delay blkcg offline so that blkgs
|
||||
|
@ -1142,7 +1184,7 @@ static int blkcg_css_online(struct cgroup_subsys_state *css)
|
|||
* parent so that offline always happens towards the root.
|
||||
*/
|
||||
if (parent)
|
||||
blkcg_pin_online(parent);
|
||||
blkcg_pin_online(css);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -317,17 +317,6 @@ 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
|
||||
|
@ -416,39 +405,8 @@ 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);
|
||||
}
|
||||
void blkcg_pin_online(struct cgroup_subsys_state *blkcg_css);
|
||||
void blkcg_unpin_online(struct cgroup_subsys_state *blkcg_css);
|
||||
|
||||
/**
|
||||
* blkg_path - format cgroup path of blkg
|
||||
|
|
|
@ -735,7 +735,6 @@ static void cgwb_release_workfn(struct work_struct *work)
|
|||
{
|
||||
struct bdi_writeback *wb = container_of(work, struct bdi_writeback,
|
||||
release_work);
|
||||
struct blkcg *blkcg = css_to_blkcg(wb->blkcg_css);
|
||||
struct backing_dev_info *bdi = wb->bdi;
|
||||
|
||||
mutex_lock(&wb->bdi->cgwb_release_mutex);
|
||||
|
@ -746,7 +745,7 @@ static void cgwb_release_workfn(struct work_struct *work)
|
|||
mutex_unlock(&wb->bdi->cgwb_release_mutex);
|
||||
|
||||
/* triggers blkg destruction if no online users left */
|
||||
blkcg_unpin_online(blkcg);
|
||||
blkcg_unpin_online(wb->blkcg_css);
|
||||
|
||||
fprop_local_destroy_percpu(&wb->memcg_completions);
|
||||
|
||||
|
@ -858,7 +857,7 @@ static int cgwb_create(struct backing_dev_info *bdi,
|
|||
list_add_tail_rcu(&wb->bdi_node, &bdi->wb_list);
|
||||
list_add(&wb->memcg_node, memcg_cgwb_list);
|
||||
list_add(&wb->blkcg_node, blkcg_cgwb_list);
|
||||
blkcg_pin_online(blkcg);
|
||||
blkcg_pin_online(blkcg_css);
|
||||
css_get(memcg_css);
|
||||
css_get(blkcg_css);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue