Commit b9c1133a authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'block-6.4-2023-06-15' of git://git.kernel.dk/linux

Pull block fix from Jens Axboe:
 "Just a single fix for blk-cg stats flushing"

* tag 'block-6.4-2023-06-15' of git://git.kernel.dk/linux:
  blk-cgroup: Flush stats before releasing blkcg_gq
parents 3a12faba 20cb1c2f
...@@ -34,6 +34,8 @@ ...@@ -34,6 +34,8 @@
#include "blk-ioprio.h" #include "blk-ioprio.h"
#include "blk-throttle.h" #include "blk-throttle.h"
static void __blkcg_rstat_flush(struct blkcg *blkcg, int cpu);
/* /*
* blkcg_pol_mutex protects blkcg_policy[] and policy [de]activation. * blkcg_pol_mutex protects blkcg_policy[] and policy [de]activation.
* blkcg_pol_register_mutex nests outside of it and synchronizes entire * blkcg_pol_register_mutex nests outside of it and synchronizes entire
...@@ -56,6 +58,8 @@ static LIST_HEAD(all_blkcgs); /* protected by blkcg_pol_mutex */ ...@@ -56,6 +58,8 @@ static LIST_HEAD(all_blkcgs); /* protected by blkcg_pol_mutex */
bool blkcg_debug_stats = false; bool blkcg_debug_stats = false;
static DEFINE_RAW_SPINLOCK(blkg_stat_lock);
#define BLKG_DESTROY_BATCH_SIZE 64 #define BLKG_DESTROY_BATCH_SIZE 64
/* /*
...@@ -163,10 +167,20 @@ static void blkg_free(struct blkcg_gq *blkg) ...@@ -163,10 +167,20 @@ static void blkg_free(struct blkcg_gq *blkg)
static void __blkg_release(struct rcu_head *rcu) static void __blkg_release(struct rcu_head *rcu)
{ {
struct blkcg_gq *blkg = container_of(rcu, struct blkcg_gq, rcu_head); struct blkcg_gq *blkg = container_of(rcu, struct blkcg_gq, rcu_head);
struct blkcg *blkcg = blkg->blkcg;
int cpu;
#ifdef CONFIG_BLK_CGROUP_PUNT_BIO #ifdef CONFIG_BLK_CGROUP_PUNT_BIO
WARN_ON(!bio_list_empty(&blkg->async_bios)); WARN_ON(!bio_list_empty(&blkg->async_bios));
#endif #endif
/*
* Flush all the non-empty percpu lockless lists before releasing
* us, given these stat belongs to us.
*
* blkg_stat_lock is for serializing blkg stat update
*/
for_each_possible_cpu(cpu)
__blkcg_rstat_flush(blkcg, cpu);
/* release the blkcg and parent blkg refs this blkg has been holding */ /* release the blkcg and parent blkg refs this blkg has been holding */
css_put(&blkg->blkcg->css); css_put(&blkg->blkcg->css);
...@@ -951,23 +965,26 @@ static void blkcg_iostat_update(struct blkcg_gq *blkg, struct blkg_iostat *cur, ...@@ -951,23 +965,26 @@ static void blkcg_iostat_update(struct blkcg_gq *blkg, struct blkg_iostat *cur,
u64_stats_update_end_irqrestore(&blkg->iostat.sync, flags); u64_stats_update_end_irqrestore(&blkg->iostat.sync, flags);
} }
static void blkcg_rstat_flush(struct cgroup_subsys_state *css, int cpu) static void __blkcg_rstat_flush(struct blkcg *blkcg, int cpu)
{ {
struct blkcg *blkcg = css_to_blkcg(css);
struct llist_head *lhead = per_cpu_ptr(blkcg->lhead, cpu); struct llist_head *lhead = per_cpu_ptr(blkcg->lhead, cpu);
struct llist_node *lnode; struct llist_node *lnode;
struct blkg_iostat_set *bisc, *next_bisc; struct blkg_iostat_set *bisc, *next_bisc;
/* Root-level stats are sourced from system-wide IO stats */
if (!cgroup_parent(css->cgroup))
return;
rcu_read_lock(); rcu_read_lock();
lnode = llist_del_all(lhead); lnode = llist_del_all(lhead);
if (!lnode) if (!lnode)
goto out; goto out;
/*
* For covering concurrent parent blkg update from blkg_release().
*
* When flushing from cgroup, cgroup_rstat_lock is always held, so
* this lock won't cause contention most of time.
*/
raw_spin_lock(&blkg_stat_lock);
/* /*
* Iterate only the iostat_cpu's queued in the lockless list. * Iterate only the iostat_cpu's queued in the lockless list.
*/ */
...@@ -991,13 +1008,19 @@ static void blkcg_rstat_flush(struct cgroup_subsys_state *css, int cpu) ...@@ -991,13 +1008,19 @@ static void blkcg_rstat_flush(struct cgroup_subsys_state *css, int cpu)
if (parent && parent->parent) if (parent && parent->parent)
blkcg_iostat_update(parent, &blkg->iostat.cur, blkcg_iostat_update(parent, &blkg->iostat.cur,
&blkg->iostat.last); &blkg->iostat.last);
percpu_ref_put(&blkg->refcnt);
} }
raw_spin_unlock(&blkg_stat_lock);
out: out:
rcu_read_unlock(); rcu_read_unlock();
} }
static void blkcg_rstat_flush(struct cgroup_subsys_state *css, int cpu)
{
/* Root-level stats are sourced from system-wide IO stats */
if (cgroup_parent(css->cgroup))
__blkcg_rstat_flush(css_to_blkcg(css), cpu);
}
/* /*
* We source root cgroup stats from the system-wide stats to avoid * We source root cgroup stats from the system-wide stats to avoid
* tracking the same information twice and incurring overhead when no * tracking the same information twice and incurring overhead when no
...@@ -2075,7 +2098,6 @@ void blk_cgroup_bio_start(struct bio *bio) ...@@ -2075,7 +2098,6 @@ void blk_cgroup_bio_start(struct bio *bio)
llist_add(&bis->lnode, lhead); llist_add(&bis->lnode, lhead);
WRITE_ONCE(bis->lqueued, true); WRITE_ONCE(bis->lqueued, true);
percpu_ref_get(&bis->blkg->refcnt);
} }
u64_stats_update_end_irqrestore(&bis->sync, flags); u64_stats_update_end_irqrestore(&bis->sync, flags);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment