cgroup/for-4.17: Make cgroup_rstat available to controllers
Tejun Heo
maintainerPATCH 1/1 cgroup/for-4.17: Make cgroup_rstat available to controllers
Hello,
cgroup has scalable recursive stat mechanism implemented in kernel/stat.c. It's currently only used to track cpu consumptions and difficult to use outside of cgroup core. This patchset generalizes the mechanism and exposes it as cgroup_rstat so that controllers can use it.
This patchset contains the following eight patches. A follow-up patchset will add usages.
0001-cgroup-Rename-kernel-cgroup-stat.c-to-kernel-cgroup-.patch 0002-cgroup-Rename-stat-to-rstat.patch 0003-cgroup-Distinguish-base-resource-stat-implementation.patch 0004-cgroup-Reorganize-kernel-cgroup-rstat.c.patch 0005-cgroup-Factor-out-and-expose-cgroup_rstat_-interface.patch 0006-cgroup-Replace-cgroup_rstat_mutex-with-a-spinlock.patch 0007-cgroup-Add-cgroup_subsys-css_rstat_flush.patch 0008-cgroup-Add-memory-barriers-to-plug-cgroup_rstat_upda.patch
This patchset is also available in the following git branch.
git://git.kernel.org/pub/scm/linux/kernel/git/tj/cgroup.git review-cgroup_rstat
diffstat follows.
include/linux/cgroup-defs.h | 50 ++-- include/linux/cgroup.h | 12 - kernel/cgroup/Makefile | 2 kernel/cgroup/cgroup-internal.h | 11 - kernel/cgroup/cgroup.c | 29 ++ kernel/cgroup/rstat.c | 410 ++++++++++++++++++++++++++++++++++++++++ kernel/cgroup/stat.c | 338 -------------------------------- 7 files changed, 477 insertions(+), 375 deletions(-)
Thanks.
--
tejun
Tejun Heo
maintainerPATCH 1/8 cgroup: Rename kernel/cgroup/stat.c to kernel/cgroup/rstat.c
stat is too generic a name and ends up causing subtle confusions. It'll be made generic so that controllers can plug into it, which will make the problem worse. Let's rename it to something more specific - cgroup_rstat for cgroup recursive stat.
First, rename kernel/cgroup/stat.c to kernel/cgroup/rstat.c. No content changes.
---
kernel/cgroup/Makefile | 2 +-
kernel/cgroup/{stat.c => rstat.c} | 0
2 files changed, 1 insertion(+), 1 deletion(-)
rename kernel/cgroup/{stat.c => rstat.c} (100%)kernel/cgroup/Makefile +1 -1
@@ -1,5 +1,5 @@ # SPDX-License-Identifier: GPL-2.0 -obj-y := cgroup.o stat.o namespace.o cgroup-v1.o +obj-y := cgroup.o rstat.o namespace.o cgroup-v1.o obj-$(CONFIG_CGROUP_FREEZER) += freezer.o obj-$(CONFIG_CGROUP_PIDS) += pids.o
kernel/cgroup/rstat.c renamed from kernel/cgroup/stat.c +0 -0
Signature · 1 line
2.9.5
Tejun Heo
maintainerPATCH 2/8 cgroup: Rename stat to rstat
In reply to Tejun Heostat is too generic a name and ends up causing subtle confusions. It'll be made generic so that controllers can plug into it, which will make the problem worse. Let's rename it to something more specific - cgroup_rstat for cgroup recursive stat.
This patch does the following renames. No other changes.
* cpu_stat -> rstat_cpu
* stat -> rstat
* ?cstat -> ?rstatc
Note that the renames are selective. The unrenamed are the ones which implement basic resource statistics on top of rstat. This will be further cleaned up in the following patches.
--- include/linux/cgroup-defs.h | 16 ++-- kernel/cgroup/cgroup-internal.h | 10 +-- kernel/cgroup/cgroup.c | 14 ++-- kernel/cgroup/rstat.c | 180 ++++++++++++++++++++-------------------- 4 files changed, 112 insertions(+), 108 deletions(-)
include/linux/cgroup-defs.h +9 -7
@@ -259,11 +259,11 @@ struct css_set { };/* -* cgroup basic resource usage statistics. Accounting is done per-cpu in -* cgroup_cpu_stat which is then lazily propagated up the hierarchy on -* reads. +* rstat - cgroup scalable recursive statistics. Accounting is done +* per-cpu in cgroup_rstat_cpu which is then lazily propagated up the +* hierarchy on reads. * -* When a stat gets updated, the cgroup_cpu_stat and its ancestors are +* When a stat gets updated, the cgroup_rstat_cpu and its ancestors are * linked into the updated tree. On the following read, propagation only * considers and consumes the updated tree. This makes reading O(the * number of descendants which have been active since last read) instead of
@@ -274,7 +274,7 @@ struct css_set {* become very expensive. By propagating selectively, increasing reading * frequency decreases the cost of each read. */ -struct cgroup_cpu_stat { +struct cgroup_rstat_cpu {/* * ->sync protects all the current counters. These are the only * fields which get updated in the hot path.
@@ -297,7 +297,7 @@ struct cgroup_cpu_stat {* to the cgroup makes it unnecessary for each per-cpu struct to * point back to the associated cgroup. * -* Protected by per-cpu cgroup_cpu_stat_lock. +* Protected by per-cpu cgroup_rstat_cpu_lock. */ struct cgroup *updated_children;/* terminated by self cgroup */ struct cgroup *updated_next;/* NULL iff not on the list */
@@ -408,8 +408,10 @@ struct cgroup {*/ struct cgroup *dom_cgrp; +/* per-cpu recursive resource statistics */ +struct cgroup_rstat_cpu __percpu *rstat_cpu; +/* cgroup basic resource statistics */ -struct cgroup_cpu_stat __percpu *cpu_stat;struct cgroup_stat pending_stat;/* pending from children */ struct cgroup_stat stat;
kernel/cgroup/cgroup-internal.h +5 -5
@@ -201,13 +201,13 @@ int cgroup_show_path(struct seq_file *sf, struct kernfs_node *kf_node,int cgroup_task_count (const struct cgroup *cgrp);/* -* stat.c +* rstat.c */ -void cgroup_stat_flush (struct cgroup *cgrp); -int cgroup_stat_init (struct cgroup *cgrp); -void cgroup_stat_exit (struct cgroup *cgrp); +void cgroup_rstat_flush (struct cgroup *cgrp); +int cgroup_rstat_init (struct cgroup *cgrp); +void cgroup_rstat_exit (struct cgroup *cgrp);void cgroup_stat_show_cputime (struct seq_file *seq); -void cgroup_stat_boot (void ); +void cgroup_rstat_boot (void );/* * namespace.c
kernel/cgroup/cgroup.c +7 -7
@@ -144,14 +144,14 @@ static struct static_key_true *cgroup_subsys_on_dfl_key[] = { };#undef SUBSYS -static DEFINE_PER_CPU(struct cgroup_cpu_stat, cgrp_dfl_root_cpu_stat); +static DEFINE_PER_CPU(struct cgroup_rstat_cpu, cgrp_dfl_root_rstat_cpu);/* * The default hierarchy, reserved for the subsystems that are otherwise * unattached - it never has more than a single cgroup, and all tasks are * part of that cgroup. */ -struct cgroup_root cgrp_dfl_root = { .cgrp.cpu_stat = &cgrp_dfl_root_cpu_stat }; +struct cgroup_root cgrp_dfl_root = { .cgrp.rstat_cpu = &cgrp_dfl_root_rstat_cpu };EXPORT_SYMBOL_GPL (cgrp_dfl_root);/*
@@ -4592,7 +4592,7 @@ static void css_free_work_fn(struct work_struct *work)cgroup_put (cgroup_parent (cgrp));kernfs_put (cgrp->kn);if (cgroup_on_dfl (cgrp)) -cgroup_stat_exit (cgrp); +cgroup_rstat_exit (cgrp);kfree (cgrp); }else {/*
@@ -4638,7 +4638,7 @@ static void css_release_work_fn(struct work_struct *work)trace_cgroup_release (cgrp);if (cgroup_on_dfl (cgrp)) -cgroup_stat_flush (cgrp); +cgroup_rstat_flush (cgrp);for (tcgrp =cgroup_parent (cgrp); tcgrp; tcgrp =cgroup_parent (tcgrp))
@@ -4824,7 +4824,7 @@ static struct cgroup *cgroup_create(struct cgroup *parent) goto out_free_cgrp;if (cgroup_on_dfl (parent)) { - ret =cgroup_stat_init (cgrp); + ret =cgroup_rstat_init (cgrp);if (ret) goto out_cancel_ref; }
@@ -4889,7 +4889,7 @@ static struct cgroup *cgroup_create(struct cgroup *parent)cgroup_idr_remove (&root->cgroup_idr, cgrp->id); out_stat_exit:if (cgroup_on_dfl (parent)) -cgroup_stat_exit (cgrp); +cgroup_rstat_exit (cgrp); out_cancel_ref:percpu_ref_exit (&cgrp->self.refcnt); out_free_cgrp:
@@ -5282,7 +5282,7 @@ int __init cgroup_init(void)BUG_ON (cgroup_init_cftypes (NULL , cgroup_base_files));BUG_ON (cgroup_init_cftypes (NULL , cgroup1_base_files)); -cgroup_stat_boot (); +cgroup_rstat_boot ();/* * The latency of the synchronize_sched() is too high for cgroups,
kernel/cgroup/rstat.c +91 -89
374 lines not on this page · raw message
Signature · 1 line
2.9.5
Tejun Heo
maintainerPATCH 3/8 cgroup: Distinguish base resource stat implementation from rstat
In reply to Tejun HeoBase resource stat accounts universial (not specific to any controller) resource consumptions on top of rstat. Currently, its implementation is intermixed with rstat implementation making the code confusing to follow.
This patch clarifies the distintion by doing the followings.
* Encapsulate base resource stat counters, currently only cputime, in struct cgroup_base_stat.
* Move prev_cputime into struct cgroup and initialize it with cgroup.
* Rename the related functions so that they start with cgroup_base_stat.
* Prefix the related variables and field names with b.
This patch doesn't make any functional changes.
--- include/linux/cgroup-defs.h | 29 ++++++++++-------- kernel/cgroup/cgroup-internal.h | 2 +- kernel/cgroup/cgroup.c | 4 ++- kernel/cgroup/rstat.c | 67 ++++++++++++++++++++--------------------- 4 files changed, 52 insertions(+), 50 deletions(-)
include/linux/cgroup-defs.h +16 -13
@@ -258,6 +258,10 @@ struct css_set {struct rcu_head rcu_head; }; +struct cgroup_base_stat { +struct task_cputime cputime; +}; +/* * rstat - cgroup scalable recursive statistics. Accounting is done * per-cpu in cgroup_rstat_cpu which is then lazily propagated up the
@@ -273,20 +277,24 @@ struct css_set {* aren't active and stat may be read frequently. The combination can * become very expensive. By propagating selectively, increasing reading * frequency decreases the cost of each read. +* +* This struct hosts both the fields which implement the above - +* updated_children and updated_next - and the fields which track basic +* resource statistics on top of it - bsync, bstat and last_bstat. */ struct cgroup_rstat_cpu {/* -* ->sync protects all the current counters. These are the only -* fields which get updated in the hot path. +* ->bsync protects ->bstat. These are the only fields which get +* updated in the hot path. */ -struct u64_stats_sync sync; -struct task_cputime cputime; +struct u64_stats_sync bsync; +struct cgroup_base_stat bstat;/* * Snapshots at the last reading. These are used to calculate the * deltas to propagate to the global counters. */ -struct task_cputime last_cputime; +struct cgroup_base_stat last_bstat;/* * Child cgroups with stat updates on this cpu since the last read
@@ -303,12 +311,6 @@ struct cgroup_rstat_cpu {struct cgroup *updated_next;/* NULL iff not on the list */ }; -struct cgroup_stat { -/* per-cpu statistics are collected into the folowing global counters */ -struct task_cputime cputime; -struct prev_cputime prev_cputime; -}; -struct cgroup {/* self css with NULL ->ss, points back to this cgroup */ struct cgroup_subsys_state self;
@@ -412,8 +414,9 @@ struct cgroup {struct cgroup_rstat_cpu __percpu *rstat_cpu;/* cgroup basic resource statistics */ -struct cgroup_stat pending_stat;/* pending from children */ -struct cgroup_stat stat; +struct cgroup_base_stat pending_bstat;/* pending from children */ +struct cgroup_base_stat bstat; +struct prev_cputime prev_cputime;/* for printing out cputime */ /* * list of pidlists, up to two for each namespace (one for procs, one
kernel/cgroup/cgroup-internal.h +1 -1
@@ -206,7 +206,7 @@ int cgroup_task_count(const struct cgroup *cgrp);void cgroup_rstat_flush (struct cgroup *cgrp);int cgroup_rstat_init (struct cgroup *cgrp);void cgroup_rstat_exit (struct cgroup *cgrp); -void cgroup_stat_show_cputime (struct seq_file *seq); +void cgroup_base_stat_cputime_show (struct seq_file *seq);void cgroup_rstat_boot (void );/*
kernel/cgroup/cgroup.c +3 -1
@@ -54,6 +54,7 @@#include <linux/proc_ns.h> #include <linux/nsproxy.h> #include <linux/file.h> +#include <linux/sched/cputime.h> #include <net/sock.h> #define CREATE_TRACE_POINTS
@@ -1859,6 +1860,7 @@ static void init_cgroup_housekeeping(struct cgroup *cgrp) cgrp->dom_cgrp = cgrp; cgrp->max_descendants =INT_MAX ; cgrp->max_depth =INT_MAX ; +prev_cputime_init (&cgrp->prev_cputime);for_each_subsys (ss, ssid)INIT_LIST_HEAD (&cgrp->e_csets[ssid]);
@@ -3396,7 +3398,7 @@ static int cpu_stat_show(struct seq_file *seq, void *v)struct cgroup __maybe_unused *cgrp =seq_css (seq)->cgroup;int ret =0 ; -cgroup_stat_show_cputime (seq); +cgroup_base_stat_cputime_show (seq);#ifdef CONFIG_CGROUP_SCHED ret =cgroup_extra_stat_show (seq, cgrp, cpu_cgrp_id);#endif
kernel/cgroup/rstat.c +32 -35
156 lines not on this page · raw message
Signature · 1 line
2.9.5
Tejun Heo
maintainerPATCH 4/8 cgroup: Reorganize kernel/cgroup/rstat.c
In reply to Tejun HeoCurrently, rstat.c has rstat and base stat implementations intermixed. Collect base stat implementation at the end of the file. Also, reorder the prototypes.
This patch doesn't make any functional changes.
--- kernel/cgroup/cgroup-internal.h | 2 +- kernel/cgroup/rstat.c | 182 +++++++++++++++++++++------------------- 2 files changed, 95 insertions(+), 89 deletions(-)
kernel/cgroup/cgroup-internal.h +1 -1
@@ -206,8 +206,8 @@ int cgroup_task_count(const struct cgroup *cgrp);void cgroup_rstat_flush (struct cgroup *cgrp);int cgroup_rstat_init (struct cgroup *cgrp);void cgroup_rstat_exit (struct cgroup *cgrp); -void cgroup_base_stat_cputime_show (struct seq_file *seq);void cgroup_rstat_boot (void ); +void cgroup_base_stat_cputime_show (struct seq_file *seq);/* * namespace.c
kernel/cgroup/rstat.c +94 -88
203 lines not on this page · raw message
Signature · 1 line
2.9.5
Tejun Heo
maintainerPATCH 5/8 cgroup: Factor out and expose cgroup_rstat_*() interface functions
In reply to Tejun Heocgroup_rstat is being generalized so that controllers can use it too. This patch factors out and exposes the following interface functions.
* cgroup_rstat_updated(): Renamed from cgroup_rstat_cpu_updated() for consistency.
* cgroup_rstat_flush_hold/release(): Factored out from base stat implementation.
* cgroup_rstat_flush(): Verbatim expose.
While at it, drop assert on cgroup_rstat_mutex in cgroup_base_stat_flush() as it crosses layers and make a minor comment update.
--- include/linux/cgroup.h | 11 +++++++++-- kernel/cgroup/cgroup-internal.h | 1 - kernel/cgroup/rstat.c | 41 +++++++++++++++++++++++++++++------------ 3 files changed, 38 insertions(+), 15 deletions(-)
include/linux/cgroup.h +9 -2
@@ -690,11 +690,18 @@ static inline void cgroup_path_from_kernfs_id(const union kernfs_node_id *id, char *buf, size_t buflen) {}#endif /* !CONFIG_CGROUPS */ +#ifdef CONFIG_CGROUPS /* -* Basic resource stats. +* cgroup scalable recursive statistics. */ -#ifdef CONFIG_CGROUPS +void cgroup_rstat_updated (struct cgroup *cgrp,int cpu); +void cgroup_rstat_flush (struct cgroup *cgrp); +void cgroup_rstat_flush_hold (struct cgroup *cgrp); +void cgroup_rstat_flush_release (void ); +/* +* Basic resource stats. +*/ #ifdef CONFIG_CGROUP_CPUACCT void cpuacct_charge (struct task_struct *tsk,u64 cputime);void cpuacct_account_field (struct task_struct *tsk,int index,u64 val);
kernel/cgroup/cgroup-internal.h +0 -1
@@ -203,7 +203,6 @@ int cgroup_task_count(const struct cgroup *cgrp);/* * rstat.c */ -void cgroup_rstat_flush (struct cgroup *cgrp);int cgroup_rstat_init (struct cgroup *cgrp);void cgroup_rstat_exit (struct cgroup *cgrp);void cgroup_rstat_boot (void );
kernel/cgroup/rstat.c +29 -12
85 lines not on this page · raw message
Signature · 1 line
2.9.5
Tejun Heo
maintainerPATCH v2 5/8 cgroup: Factor out and expose cgroup_rstat_*() interface functions
From 6139f87ac4a5650fed5c8be5611becbce96d7f1c Mon Sep 17 00:00:00 2001
From: Tejun Heo <[email protected]>
Date: Sat, 24 Mar 2018 13:39:36 -0700
cgroup_rstat is being generalized so that controllers can use it too. This patch factors out and exposes the following interface functions.
* cgroup_rstat_updated(): Renamed from cgroup_rstat_cpu_updated() for consistency.
* cgroup_rstat_flush_hold/release(): Factored out from base stat implementation.
* cgroup_rstat_flush(): Verbatim expose.
While at it, drop assert on cgroup_rstat_mutex in cgroup_base_stat_flush() as it crosses layers and make a minor comment update.
v2: Added EXPORT_SYMBOL_GPL(cgroup_rstat_updated) to fix a build bug.
--- include/linux/cgroup.h | 11 +++++++++-- kernel/cgroup/cgroup-internal.h | 1 - kernel/cgroup/rstat.c | 42 +++++++++++++++++++++++++++++------------ 3 files changed, 39 insertions(+), 15 deletions(-)
include/linux/cgroup.h +9 -2
@@ -690,11 +690,18 @@ static inline void cgroup_path_from_kernfs_id(const union kernfs_node_id *id, char *buf, size_t buflen) {}#endif /* !CONFIG_CGROUPS */ +#ifdef CONFIG_CGROUPS /* -* Basic resource stats. +* cgroup scalable recursive statistics. */ -#ifdef CONFIG_CGROUPS +void cgroup_rstat_updated (struct cgroup *cgrp,int cpu); +void cgroup_rstat_flush (struct cgroup *cgrp); +void cgroup_rstat_flush_hold (struct cgroup *cgrp); +void cgroup_rstat_flush_release (void ); +/* +* Basic resource stats. +*/ #ifdef CONFIG_CGROUP_CPUACCT void cpuacct_charge (struct task_struct *tsk,u64 cputime);void cpuacct_account_field (struct task_struct *tsk,int index,u64 val);
kernel/cgroup/cgroup-internal.h +0 -1
@@ -203,7 +203,6 @@ int cgroup_task_count(const struct cgroup *cgrp);/* * rstat.c */ -void cgroup_rstat_flush (struct cgroup *cgrp);int cgroup_rstat_init (struct cgroup *cgrp);void cgroup_rstat_exit (struct cgroup *cgrp);void cgroup_rstat_boot (void );
kernel/cgroup/rstat.c +30 -12
92 lines not on this page · raw message
Signature · 1 line
2.9.5
Tejun Heo
maintainerPATCH 6/8 cgroup: Replace cgroup_rstat_mutex with a spinlock
In reply to Tejun HeoCurrently, rstat flush path is protected with a mutex which is fine as all the existing users are from interface file show path. However, rstat is being generalized for use by controllers and flushing from atomic contexts will be necessary.
This patch replaces cgroup_rstat_mutex with a spinlock and adds a irq-safe flush function - cgroup_rstat_flush_irqsafe(). Explicit yield handling is added to the flush path so that other flush functions can yield to other threads and flushers.
--- include/linux/cgroup.h | 1 + kernel/cgroup/rstat.c | 57 ++++++++++++++++++++++++++++++++++++++------------ 2 files changed, 45 insertions(+), 13 deletions(-)
include/linux/cgroup.h +1 -0
@@ -696,6 +696,7 @@ static inline void cgroup_path_from_kernfs_id(const union kernfs_node_id *id,*/ void cgroup_rstat_updated (struct cgroup *cgrp,int cpu);void cgroup_rstat_flush (struct cgroup *cgrp); +void cgroup_rstat_flush_irqsafe (struct cgroup *cgrp);void cgroup_rstat_flush_hold (struct cgroup *cgrp);void cgroup_rstat_flush_release (void );
kernel/cgroup/rstat.c +44 -13
105 lines not on this page · raw message
Signature · 1 line
2.9.5
Tejun Heo
maintainerPATCH 7/8 cgroup: Add cgroup_subsys->css_rstat_flush()
In reply to Tejun HeoThis patch adds cgroup_subsys->css_rstat_flush(). If a subsystem has this callback, its csses are linked on cgrp->css_rstat_list and rstat will call the function whenever the associated cgroup is flushed. Flush is also performed when such csses are released so that residual counts aren't lost.
Combined with the rstat API previous patches factored out, this allows controllers to plug into rstat to manage their statistics in a scalable way.
--- include/linux/cgroup-defs.h | 5 +++++ kernel/cgroup/cgroup.c | 11 +++++++++++ kernel/cgroup/rstat.c | 11 ++++++++++- 3 files changed, 26 insertions(+), 1 deletion(-)
include/linux/cgroup-defs.h +5 -0
@@ -130,6 +130,9 @@ struct cgroup_subsys_state {struct list_head sibling;struct list_head children; +/* flush target list anchored at cgrp->rstat_css_list */ +struct list_head rstat_css_node; +/* * PI: Subsys-unique ID. 0 is unused and root is always 1. The * matching css can be looked up using css_from_id().
@@ -412,6 +415,7 @@ struct cgroup {/* per-cpu recursive resource statistics */ struct cgroup_rstat_cpu __percpu *rstat_cpu; +struct list_head rstat_css_list;/* cgroup basic resource statistics */ struct cgroup_base_stat pending_bstat;/* pending from children */
@@ -577,6 +581,7 @@ struct cgroup_subsys {void (*css_released)(struct cgroup_subsys_state *css);void (*css_free)(struct cgroup_subsys_state *css);void (*css_reset)(struct cgroup_subsys_state *css); +void (*css_rstat_flush)(struct cgroup_subsys_state *css,int cpu);int (*css_extra_stat_show)(struct seq_file *seq,struct cgroup_subsys_state *css);
kernel/cgroup/cgroup.c +11 -0
@@ -1860,6 +1860,7 @@ static void init_cgroup_housekeeping(struct cgroup *cgrp) cgrp->dom_cgrp = cgrp; cgrp->max_descendants =INT_MAX ; cgrp->max_depth =INT_MAX ; +INIT_LIST_HEAD (&cgrp->rstat_css_list);prev_cputime_init (&cgrp->prev_cputime);for_each_subsys (ss, ssid)
@@ -4630,6 +4631,11 @@ static void css_release_work_fn(struct work_struct *work)if (ss) {/* css release path */ +if (!list_empty (&css->rstat_css_node)) { +cgroup_rstat_flush (cgrp); +list_del_rcu (&css->rstat_css_node); + } +cgroup_idr_replace (&ss->css_idr,NULL , css->id);if (ss->css_released) ss->css_released (css);
@@ -4690,6 +4696,7 @@ static void init_and_link_css(struct cgroup_subsys_state *css, css->id =-1 ;INIT_LIST_HEAD (&css->sibling);INIT_LIST_HEAD (&css->children); +INIT_LIST_HEAD (&css->rstat_css_node); css->serial_nr = css_serial_nr_next++;atomic_set (&css->online_cnt,0 );
@@ -4698,6 +4705,9 @@ static void init_and_link_css(struct cgroup_subsys_state *css,css_get (css->parent); } +if (cgroup_on_dfl (cgrp) && ss->css_rstat_flush) +list_add_rcu (&css->rstat_css_node, &cgrp->rstat_css_list); +BUG_ON (cgroup_css (cgrp, ss)); }
@@ -4799,6 +4809,7 @@ static struct cgroup_subsys_state *css_create(struct cgroup *cgrp, err_list_del:list_del_rcu (&css->sibling); err_free_css: +list_del_rcu (&css->rstat_css_node);call_rcu (&css->rcu_head, css_free_rcu_fn);return ERR_PTR (err); }
kernel/cgroup/rstat.c +10 -1
@@ -143,8 +143,17 @@ static void cgroup_rstat_flush_locked(struct cgroup *cgrp, bool may_sleep)struct cgroup *pos =NULL ;raw_spin_lock (cpu_lock); -while ((pos =cgroup_rstat_cpu_pop_updated (pos, cgrp, cpu))) +while ((pos =cgroup_rstat_cpu_pop_updated (pos, cgrp, cpu))) { +struct cgroup_subsys_state *css; +cgroup_base_stat_flush (pos, cpu); + +rcu_read_lock (); +list_for_each_entry_rcu (css, &pos->rstat_css_list, + rstat_css_node) + css->ss->css_rstat_flush (css, cpu); +rcu_read_unlock (); + }raw_spin_unlock (cpu_lock);/* if @may_sleep, play nice and yield if necessary */
Signature · 1 line
2.9.5
Tejun Heo
maintainerPATCH 8/8 cgroup: Add memory barriers to plug cgroup_rstat_updated() race window
In reply to Tejun Heocgroup_rstat_updated() has a small race window where an updated signaling can race with flush and could be lost till the next update. This wasn't a problem for the existing usages, but we plan to use rstat to track counters which need to be accurate.
This patch plugs the race window by synchronizing cgroup_rstat_updated() and flush path with memory barriers around cgroup_rstat_cpu->updated_next pointer.
--- kernel/cgroup/rstat.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-)
kernel/cgroup/rstat.c +13 -3
@@ -28,9 +28,12 @@ void cgroup_rstat_updated(struct cgroup *cgrp, int cpu)unsigned long flags;/* -* Speculative already-on-list test. This may race leading to -* temporary inaccuracies, which is fine. -* +* Paired with the one in cgroup_rstat_cpu_pop_upated(). Either we +* see NULL updated_next or they see our updated stat. +*/ +smp_mb (); + +/* * Because @parent's updated_children is terminated with @parent * instead of NULL, we can tell whether @cgrp is on the list by * testing the next pointer for NULL.
@@ -125,6 +128,13 @@ static struct cgroup *cgroup_rstat_cpu_pop_updated(struct cgroup *pos, *nextp = rstatc->updated_next; rstatc->updated_next =NULL ; + +/* +* Paired with the one in cgroup_rstat_cpu_updated(). +* Either they see NULL updated_next or we see their +* updated stat. +*/ +smp_mb (); }return pos;
Signature · 1 line
2.9.5
Tejun Heo
maintainerPATCH 1/1 cgroup: Make cgroup_rstat_updated() ready for root cgroup usage
In reply to Tejun HeoFrom b7be022bf811d02605098fa61b7545bc146b78e7 Mon Sep 17 00:00:00 2001
From: Tejun Heo <[email protected]>
Date: Mon, 2 Apr 2018 14:45:20 -0700
cgroup_rstat_updated() ensures that the cgroup's rstat is linked to the parent. If there's no parent, it never gets linked and the function ends up grabbing and releasing the cgroup_rstat_lock each time for no reason which can be expensive.
This hasn't been a problem till now because nobody was calling the function for the root cgroup but rstat is gonna be exposed to controllers and use cases, so let's get ready. Make cgroup_rstat_updated() an no-op for the root cgroup.
---
Hello,
This should address the scalability issue reported by kenrel test bot. All git branches updated accordingly.
Thanks.
kernel/cgroup/rstat.c | 4 ++++ 1 file changed, 4 insertions(+)
kernel/cgroup/rstat.c +4 -0
@@ -27,6 +27,10 @@ void cgroup_rstat_updated(struct cgroup *cgrp, int cpu)struct cgroup *parent;unsigned long flags; +/* nothing to do for root */ +if (!cgroup_parent (cgrp)) +return ; +/* * Paired with the one in cgroup_rstat_cpu_pop_upated(). Either we * see NULL updated_next or they see our updated stat.
Signature · 1 line
2.9.5
Re: [PATCH] cgroup: Make cgroup_rstat_updated() ready for root cgroup usage
Quoted 9 lines · Tejun Heo
From
b7be022bf811d02605098fa61b7545bc146b78e7Mon Sep 17 00:00:00 2001
From: Tejun Heo <[email protected]>
Date: Mon, 2 Apr 2018 14:45:20 -0700
cgroup_rstat_updated()ensures that the cgroup's rstat is linked to the parent. If there's no parent, it never gets linked and the function ends up grabbing and releasing thecgroup_rstat_lockeach time for no reason which can be expensive.
Quoted 6 lines
This hasn't been a problem till now because nobody was calling the function for the root cgroup but rstat is gonna be exposed to controllers and use cases, so let's get ready. Make
cgroup_rstat_updated()an no-op for the root cgroup.Signed-off-by Tejun Heo <[email protected]>
Applied to cgroup/for-4.18.
Thanks.
Signature · 1 line
tejun
Tejun Heo
maintainerQuoted 11 lines · Tejun Heo
Hello,
cgroup has scalable recursive stat mechanism implemented in
kernel/stat.c. It's currently only used to track cpu consumptions and difficult to use outside of cgroup core. This patchset generalizes the mechanism and exposes it ascgroup_rstatso that controllers can use it.This patchset contains the following eight patches. A follow-up patchset will add usages.
Quoted 8 lines
0001-cgroup-Rename-kernel-cgroup-stat.c-to-kernel-cgroup-.patch 0002-cgroup-Rename-stat-to-rstat.patch 0003-cgroup-Distinguish-base-resource-stat-implementation.patch 0004-cgroup-Reorganize-kernel-cgroup-rstat.c.patch 0005-cgroup-Factor-out-and-expose-cgroup_rstat_-interface.patch 0006-cgroup-Replace-cgroup_rstat_mutex-with-a-spinlock.patch 0007-cgroup-Add-cgroup_subsys-css_rstat_flush.patch 0008-cgroup-Add-memory-barriers-to-plug-cgroup_rstat_upda.patch
Applied 1-8 to cgroup/for-4.18.
Thanks.
Signature · 1 line
tejun