linux-doc.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/2] sched/fair: Reset incompatible burst on quota change
@ 2026-08-20  3:32 Zhe Liu
  2026-08-20  3:32 ` [PATCH 1/2] " Zhe Liu
  2026-08-20  3:32 ` [PATCH 2/2] Documentation: describe burst reset on quota changes Zhe Liu
  0 siblings, 2 replies; 10+ messages in thread
From: Zhe Liu @ 2026-08-20  3:32 UTC (permalink / raw)
  To: tj, hannes, mkoutny, corbet, mingo, peterz, juri.lelli,
	vincent.guittot
  Cc: skhan, dietmar.eggemann, rostedt, bsegall, mgorman, vschneid,
	kprateek.nayak, cgroups, linux-doc, linux-kselftest, linux-kernel,
	Zhe Liu

A burst configured while a cgroup has unlimited CPU bandwidth can prevent
a later finite quota from being installed.  On cgroup v2, for instance:

  # echo 100000000 > cpu.max.burst
  # echo "50000 100000" > cpu.max
  sh: write error: Invalid argument

The quota stays unlimited because tg_set_bandwidth() validates the existing
burst against the new quota, and the only recovery is for userspace to know
that it must clear the burst before retrying the quota update.  cgroup v1 has
the same problem through cpu.cfs_quota_us.

Patch 1 resets the existing burst to zero when a valid finite quota is written
that the burst is incompatible with, while preserving it when it remains
compatible or when the new quota is unlimited.  This lets a quota update take
effect regardless of the order in which userspace writes the two files, and
still allows a burst to be staged before bandwidth control is enabled.  A
cgroup v2 selftest is added for the behavior.

Patch 2 documents the reset behavior in the cgroup v1 and v2 CPU bandwidth
documentation.

Zhe Liu (2):
  sched/fair: Reset incompatible burst on quota change
  Documentation: describe burst reset on quota changes

 Documentation/admin-guide/cgroup-v2.rst   |  5 +-
 Documentation/scheduler/sched-bwc.rst     | 14 ++---
 kernel/sched/core.c                       | 17 ++++++-
 tools/testing/selftests/cgroup/test_cpu.c | 62 +++++++++++++++++++++++
 4 files changed, 90 insertions(+), 8 deletions(-)

-- 
2.25.1


^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH 1/2] sched/fair: Reset incompatible burst on quota change
  2026-08-20  3:32 [PATCH 0/2] sched/fair: Reset incompatible burst on quota change Zhe Liu
@ 2026-08-20  3:32 ` Zhe Liu
  2026-08-20 11:43   ` Michal Koutný
  2026-08-20  3:32 ` [PATCH 2/2] Documentation: describe burst reset on quota changes Zhe Liu
  1 sibling, 1 reply; 10+ messages in thread
From: Zhe Liu @ 2026-08-20  3:32 UTC (permalink / raw)
  To: tj, hannes, mkoutny, corbet, mingo, peterz, juri.lelli,
	vincent.guittot
  Cc: skhan, dietmar.eggemann, rostedt, bsegall, mgorman, vschneid,
	kprateek.nayak, cgroups, linux-doc, linux-kselftest, linux-kernel,
	Zhe Liu

A burst configured while a cgroup has unlimited CPU bandwidth can prevent
a later finite quota from being installed.  For example, on cgroup v2:

  # echo 100000000 > cpu.max.burst
  # echo "50000 100000" > cpu.max
  sh: write error: Invalid argument

The quota remains unlimited because tg_set_bandwidth() validates the
existing burst against the new quota.  Recovering requires userspace to
know that it must clear the burst before retrying the quota update.  The
same problem affects cpu.cfs_quota_us on cgroup v1.

When changing the quota, reset the existing burst to zero if it is
incompatible with a valid finite quota.  Preserve it when it remains
compatible or when the new quota is unlimited.  This lets a quota update
take effect without depending on the order in which userspace writes the
two files.

Rejecting the quota would retain this ordering dependency.  Clamping the
burst would instead silently choose a different nonzero policy on behalf
of userspace.  Resetting it to zero provides the existing no-burst default
while leaving compatible bursts untouched.  Keeping the burst while the
quota is unlimited also allows userspace to stage a burst before enabling
bandwidth control.

Add a cgroup v2 regression test for the quota update behavior.

Fixes: f4183717b370 ("sched/fair: Introduce the burstable CFS controller")
Signed-off-by: Zhe Liu <liuzhe1@kylinos.cn>
---
 kernel/sched/core.c                       | 17 ++++++-
 tools/testing/selftests/cgroup/test_cpu.c | 62 +++++++++++++++++++++++
 2 files changed, 78 insertions(+), 1 deletion(-)

diff --git a/kernel/sched/core.c b/kernel/sched/core.c
index 2e7cde033a31..324a4d22f8d1 100644
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -10081,6 +10081,18 @@ static u64 cpu_period_read_u64(struct cgroup_subsys_state *css,
 	return period_us;
 }
 
+static u64 tg_burst_on_quota_change(u64 quota_us, u64 burst_us)
+{
+	if (quota_us == RUNTIME_INF || quota_us > max_bw_runtime_us)
+		return burst_us;
+
+	if (burst_us > quota_us ||
+	    burst_us > max_bw_runtime_us - quota_us)
+		return 0;
+
+	return burst_us;
+}
+
 static int tg_set_bandwidth(struct task_group *tg,
 			    u64 period_us, u64 quota_us, u64 burst_us)
 {
@@ -10169,6 +10181,7 @@ static int cpu_quota_write_s64(struct cgroup_subsys_state *css,
 		quota_us = RUNTIME_INF;
 
 	tg_bandwidth(tg, &period_us, NULL, &burst_us);
+	burst_us = tg_burst_on_quota_change(quota_us, burst_us);
 	return tg_set_bandwidth(tg, period_us, quota_us, burst_us);
 }
 
@@ -10492,8 +10505,10 @@ static ssize_t cpu_max_write(struct kernfs_open_file *of,
 
 	tg_bandwidth(tg, &period_us, NULL, &burst_us);
 	ret = cpu_period_quota_parse(buf, &period_us, &quota_us);
-	if (!ret)
+	if (!ret) {
+		burst_us = tg_burst_on_quota_change(quota_us, burst_us);
 		ret = tg_set_bandwidth(tg, period_us, quota_us, burst_us);
+	}
 	return ret ?: nbytes;
 }
 #endif /* CONFIG_CFS_BANDWIDTH */
diff --git a/tools/testing/selftests/cgroup/test_cpu.c b/tools/testing/selftests/cgroup/test_cpu.c
index 7a40d76b9548..2686dd79941b 100644
--- a/tools/testing/selftests/cgroup/test_cpu.c
+++ b/tools/testing/selftests/cgroup/test_cpu.c
@@ -703,6 +703,67 @@ static int test_cpucg_max(const char *root)
 	return ret;
 }
 
+/*
+ * This test verifies that writing a finite cpu.max resets an incompatible
+ * cpu.max.burst, while preserving a compatible burst.
+ */
+static int test_cpucg_max_burst_reset(const char *root)
+{
+	char *cpucg = NULL;
+	int ret = KSFT_FAIL;
+
+	cpucg = cg_name(root, "cpucg_max_burst_reset_test");
+	if (!cpucg)
+		goto cleanup;
+
+	if (cg_create(cpucg))
+		goto cleanup;
+
+	/* An unconstrained group may retain a burst for later use. */
+	if (cg_write(cpucg, "cpu.max.burst", "100000000"))
+		goto cleanup;
+	if (cg_read_long(cpucg, "cpu.max.burst") != 100000000)
+		goto cleanup;
+
+	/* A finite quota must not be blocked by the incompatible burst. */
+	if (cg_write(cpucg, "cpu.max", "50000 100000"))
+		goto cleanup;
+	if (cg_read_long(cpucg, "cpu.max.burst") != 0)
+		goto cleanup;
+	if (cg_read_strcmp(cpucg, "cpu.max", "50000 100000\n"))
+		goto cleanup;
+
+	/* Keep a burst which remains valid across a quota update. */
+	if (cg_write(cpucg, "cpu.max", "100000 100000"))
+		goto cleanup;
+	if (cg_write(cpucg, "cpu.max.burst", "50000"))
+		goto cleanup;
+	if (cg_write(cpucg, "cpu.max", "75000 100000"))
+		goto cleanup;
+	if (cg_read_long(cpucg, "cpu.max.burst") != 50000)
+		goto cleanup;
+
+	/* An unlimited quota preserves burst until it becomes incompatible. */
+	if (cg_write(cpucg, "cpu.max", "max 100000"))
+		goto cleanup;
+	if (cg_read_long(cpucg, "cpu.max.burst") != 50000)
+		goto cleanup;
+
+	/* Reset the same burst when a later finite quota conflicts. */
+	if (cg_write(cpucg, "cpu.max", "25000 100000"))
+		goto cleanup;
+	if (cg_read_long(cpucg, "cpu.max.burst") != 0)
+		goto cleanup;
+
+	ret = KSFT_PASS;
+
+cleanup:
+	cg_destroy(cpucg);
+	free(cpucg);
+
+	return ret;
+}
+
 /*
  * This test verifies that a process inside of a nested cgroup whose parent
  * group has a cpu.max value set, is properly throttled.
@@ -789,6 +850,7 @@ struct cpucg_test {
 	T(test_cpucg_nested_weight_overprovisioned),
 	T(test_cpucg_nested_weight_underprovisioned),
 	T(test_cpucg_max),
+	T(test_cpucg_max_burst_reset),
 	T(test_cpucg_max_nested),
 };
 #undef T
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH 2/2] Documentation: describe burst reset on quota changes
  2026-08-20  3:32 [PATCH 0/2] sched/fair: Reset incompatible burst on quota change Zhe Liu
  2026-08-20  3:32 ` [PATCH 1/2] " Zhe Liu
@ 2026-08-20  3:32 ` Zhe Liu
  1 sibling, 0 replies; 10+ messages in thread
From: Zhe Liu @ 2026-08-20  3:32 UTC (permalink / raw)
  To: tj, hannes, mkoutny, corbet, mingo, peterz, juri.lelli,
	vincent.guittot
  Cc: skhan, dietmar.eggemann, rostedt, bsegall, mgorman, vschneid,
	kprateek.nayak, cgroups, linux-doc, linux-kselftest, linux-kernel,
	Zhe Liu

Document that an incompatible burst is reset when a finite quota is
written through the cgroup v1 or cgroup v2 CPU bandwidth interface, while
compatible bursts and unlimited quota updates preserve the existing value.

Signed-off-by: Zhe Liu <liuzhe1@kylinos.cn>
---
 Documentation/admin-guide/cgroup-v2.rst |  5 ++++-
 Documentation/scheduler/sched-bwc.rst   | 14 ++++++++------
 2 files changed, 12 insertions(+), 7 deletions(-)

diff --git a/Documentation/admin-guide/cgroup-v2.rst b/Documentation/admin-guide/cgroup-v2.rst
index aed195a71cbf..9f5e43d96476 100644
--- a/Documentation/admin-guide/cgroup-v2.rst
+++ b/Documentation/admin-guide/cgroup-v2.rst
@@ -1200,7 +1200,10 @@ will be referred to. All time durations are in microseconds.
 
 	which indicates that the group may consume up to $MAX in each
 	$PERIOD duration.  "max" for $MAX indicates no limit.  If only
-	one number is written, $MAX is updated.
+	one number is written, $MAX is updated.  When a finite $MAX is
+	written, an existing cpu.max.burst value which is incompatible
+	with the new limit is reset to zero.  Writing "max" leaves the
+	burst value unchanged.
 
 	This file affects only processes under the fair-class scheduler.
 
diff --git a/Documentation/scheduler/sched-bwc.rst b/Documentation/scheduler/sched-bwc.rst
index e881a945c188..79bd5f254e50 100644
--- a/Documentation/scheduler/sched-bwc.rst
+++ b/Documentation/scheduler/sched-bwc.rst
@@ -90,14 +90,16 @@ bandwidth restriction in place, such a group is described as an unconstrained
 bandwidth group. This represents the traditional work-conserving behavior for
 CFS.
 
-Writing any (valid) positive value(s) no smaller than cpu.cfs_burst_us will
-enact the specified bandwidth limit. The minimum quota allowed for the quota or
-period is 1ms. There is also an upper bound on the period length of 1s.
-Additional restrictions exist when bandwidth limits are used in a hierarchical
-fashion, these are explained in more detail below.
+Writing any valid positive value will enact the specified bandwidth limit. If
+the existing cpu.cfs_burst_us value is incompatible with the new quota, it is
+reset to zero. The minimum quota allowed for the quota or period is 1ms. There
+is also an upper bound on the period length of 1s. Additional restrictions
+exist when bandwidth limits are used in a hierarchical fashion, these are
+explained in more detail below.
 
 Writing any negative value to cpu.cfs_quota_us will remove the bandwidth limit
-and return the group to an unconstrained state once more.
+and return the group to an unconstrained state once more. The existing
+cpu.cfs_burst_us value remains unchanged.
 
 A value of 0 for cpu.cfs_burst_us indicates that the group can not accumulate
 any unused bandwidth. It makes the traditional bandwidth control behavior for
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 10+ messages in thread

* Re: [PATCH 1/2] sched/fair: Reset incompatible burst on quota change
  2026-08-20  3:32 ` [PATCH 1/2] " Zhe Liu
@ 2026-08-20 11:43   ` Michal Koutný
  2026-08-26  3:00     ` Zhe Liu
  2026-09-04  6:20     ` [PATCH v2 0/3] sched/fair: remove quota/burst write-order dependency Zhe Liu
  0 siblings, 2 replies; 10+ messages in thread
From: Michal Koutný @ 2026-08-20 11:43 UTC (permalink / raw)
  To: Zhe Liu
  Cc: tj, hannes, corbet, mingo, peterz, juri.lelli, vincent.guittot,
	skhan, dietmar.eggemann, rostedt, bsegall, mgorman, vschneid,
	kprateek.nayak, cgroups, linux-doc, linux-kselftest, linux-kernel

[-- Attachment #1: Type: text/plain, Size: 1564 bytes --]

On Thu, Aug 20, 2026 at 11:32:17AM +0800, Zhe Liu <liuzhe1@kylinos.cn> wrote:
> A burst configured while a cgroup has unlimited CPU bandwidth can prevent
> a later finite quota from being installed.  For example, on cgroup v2:
> 
>   # echo 100000000 > cpu.max.burst
>   # echo "50000 100000" > cpu.max
>   sh: write error: Invalid argument
> 
> The quota remains unlimited because tg_set_bandwidth() validates the
> existing burst against the new quota.  Recovering requires userspace to
> know that it must clear the burst before retrying the quota update.  The
> same problem affects cpu.cfs_quota_us on cgroup v1.
> 
> When changing the quota, reset the existing burst to zero if it is
> incompatible with a valid finite quota.  Preserve it when it remains
> compatible or when the new quota is unlimited.  This lets a quota update
> take effect without depending on the order in which userspace writes the
> two files.
> 
> Rejecting the quota would retain this ordering dependency.  Clamping the
> burst would instead silently choose a different nonzero policy on behalf
> of userspace.

Why not clamp the burst_us to quota_us? That's quite natural to me.

> Resetting it to zero provides the existing no-burst default while
> leaving compatible bursts untouched.

Like Sashiko said, the user configured values should not get lost, the
resulting burst value (0 or quota or whatever makes sense) might be
applied effectively (to allow configuration order independence) but not
overwrite what was configured.

Thanks,
Michal

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 265 bytes --]

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [PATCH 1/2] sched/fair: Reset incompatible burst on quota change
  2026-08-20 11:43   ` Michal Koutný
@ 2026-08-26  3:00     ` Zhe Liu
  2026-09-04  6:20     ` [PATCH v2 0/3] sched/fair: remove quota/burst write-order dependency Zhe Liu
  1 sibling, 0 replies; 10+ messages in thread
From: Zhe Liu @ 2026-08-26  3:00 UTC (permalink / raw)
  To: mkoutny
  Cc: bsegall, cgroups, corbet, dietmar.eggemann, hannes, juri.lelli,
	kprateek.nayak, linux-doc, linux-kernel, linux-kselftest, liuzhe1,
	mgorman, mingo, peterz, rostedt, skhan, tj, vincent.guittot,
	vschneid

On Thu, Aug 20, 2026 at 01:43:21PM +0200, Michal Koutný wrote:

> Why not clamp the burst_us to quota_us? That's quite natural to me.
>
> Like Sashiko said, the user configured values should not get lost, the
> resulting burst value (0 or quota or whatever makes sense) might be
> applied effectively (to allow configuration order independence) but not
> overwrite what was configured.

Thanks for the suggestion. I agree that applying the clamp at enforcement
time is a better fit here.

There is also a second ordering case to consider: when both quota and burst
are being increased, writing burst first currently fails with EINVAL because
the burst value is checked against the old quota.

For v2, I plan to remove the validation which couples burst_us to the
current quota_us. The quota upper-bound check will remain unchanged, while
burst_us will be checked independently against max_bw_runtime_us:

@@ tg_set_bandwidth()
 	if (quota_us != RUNTIME_INF &&/path/to/YOUR_REPLY
 	    quota_us > max_bw_runtime_us)
 		return -EINVAL;

-	if (quota_us != RUNTIME_INF && (burst_us > quota_us ||
-					burst_us + quota_us > max_bw_runtime_us))
+	if (burst_us > max_bw_runtime_us)
 		return -EINVAL;

The configured burst value will be retained, and the value used by CFS will
be capped when the runtime is refilled:

@@ __refill_cfs_bandwidth_runtime()
-	cfs_b->runtime = min(cfs_b->runtime,
-			     cfs_b->quota + cfs_b->burst);
+	cfs_b->runtime = min(cfs_b->runtime,
+			     cfs_b->quota +
+			     min(cfs_b->burst, cfs_b->quota));

This preserves the value configured through cpu.max.burst and
cpu.cfs_burst_us while applying the clamp to the value used for enforcement.
It also allows the quota and burst settings to be written in either order.

I have tested both write-order sequences on linux-next next-20260824. A v2
with the corresponding selftest update will follow.

Thanks again for pointing this out.

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH v2 0/3] sched/fair: remove quota/burst write-order dependency
  2026-08-20 11:43   ` Michal Koutný
  2026-08-26  3:00     ` Zhe Liu
@ 2026-09-04  6:20     ` Zhe Liu
  2026-09-04  6:20       ` [PATCH v2 1/3] sched/fair: Remove the write-order dependency between cpu.max and cpu.max.burst Zhe Liu
                         ` (2 more replies)
  1 sibling, 3 replies; 10+ messages in thread
From: Zhe Liu @ 2026-09-04  6:20 UTC (permalink / raw)
  To: mkoutny
  Cc: bsegall, cgroups, corbet, dietmar.eggemann, hannes, juri.lelli,
	kprateek.nayak, linux-doc, linux-kernel, linux-kselftest, liuzhe1,
	mgorman, mingo, peterz, rostedt, skhan, tj, vincent.guittot,
	vschneid

The CPU bandwidth quota and burst controls currently make the order of
userspace writes significant. A burst configured while quota is unlimited can
prevent a later finite quota from being installed, and increasing quota and
burst in the burst-first order can fail with EINVAL.

This series keeps the configured burst value independent of the current quota
and applies the quota-relative clamp when CFS refills runtime. It also adds a
selftest for both write orders and documents the resulting behavior for cgroup
v1 and cgroup v2.

Changes in v2:
  - apply the clamp at refill time instead of changing the configured burst;
  - retain the value reported by cpu.max.burst and cpu.cfs_burst_us;
  - add write-order selftests and update the CPU bandwidth documentation.

Testing:
  make -C tools/testing/selftests TARGETS=cgroup

Zhe Liu (3):
  sched/fair: Remove the write-order dependency between cpu.max and
    cpu.max.burst
  selftests: cgroup: Test CPU quota and burst write order
  Documentation: describe CPU quota and burst ordering

 Documentation/admin-guide/cgroup-v2.rst   |  5 ++-
 Documentation/scheduler/sched-bwc.rst     | 21 ++++++-----
 kernel/sched/core.c                       |  3 +-
 kernel/sched/fair.c                       |  3 +-
 tools/testing/selftests/cgroup/test_cpu.c | 40 +++++++++++++++++++++++
 5 files changed, 59 insertions(+), 13 deletions(-)

-- 
2.25.1

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [PATCH v2 1/3] sched/fair: Remove the write-order dependency between cpu.max and cpu.max.burst
  2026-09-04  6:20     ` [PATCH v2 0/3] sched/fair: remove quota/burst write-order dependency Zhe Liu
@ 2026-09-04  6:20       ` Zhe Liu
  2026-09-04  9:21         ` Tao Cui
  2026-09-04  6:20       ` [PATCH v2 2/3] selftests: cgroup: Test CPU quota and burst write order Zhe Liu
  2026-09-04  6:20       ` [PATCH v2 3/3] Documentation: describe CPU quota and burst ordering Zhe Liu
  2 siblings, 1 reply; 10+ messages in thread
From: Zhe Liu @ 2026-09-04  6:20 UTC (permalink / raw)
  To: mkoutny
  Cc: bsegall, cgroups, corbet, dietmar.eggemann, hannes, juri.lelli,
	kprateek.nayak, linux-doc, linux-kernel, linux-kselftest, liuzhe1,
	mgorman, mingo, peterz, rostedt, skhan, tj, vincent.guittot,
	vschneid, stable

Keep the configured burst independent of the current quota and cap it
when CFS refills runtime. This allows quota and burst updates in either
order.

Fixes: f4183717b370 ("sched/fair: Introduce the burstable CFS controller")

Cc: stable@vger.kernel.org
Signed-off-by: Zhe Liu <liuzhe1@kylinos.cn>
---
 kernel/sched/core.c | 3 +--
 kernel/sched/fair.c | 3 ++-
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/kernel/sched/core.c b/kernel/sched/core.c
index f78275192036..5269b8cfcf7f 100644
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -10159,8 +10159,7 @@ static int tg_set_bandwidth(struct task_group *tg,
 	if (quota_us != RUNTIME_INF && quota_us > max_bw_runtime_us)
 		return -EINVAL;
 
-	if (quota_us != RUNTIME_INF && (burst_us > quota_us ||
-					burst_us + quota_us > max_bw_runtime_us))
+	if (burst_us > max_bw_runtime_us)
 		return -EINVAL;
 
 #ifdef CONFIG_CFS_BANDWIDTH
diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
index 6d881e530f89..488de18d477e 100644
--- a/kernel/sched/fair.c
+++ b/kernel/sched/fair.c
@@ -6627,7 +6627,8 @@ void __refill_cfs_bandwidth_runtime(struct cfs_bandwidth *cfs_b)
 		cfs_b->nr_burst++;
 	}
 
-	cfs_b->runtime = min(cfs_b->runtime, cfs_b->quota + cfs_b->burst);
+	cfs_b->runtime = min(cfs_b->runtime,
+			     cfs_b->quota + min(cfs_b->burst, cfs_b->quota));
 	cfs_b->runtime_snap = cfs_b->runtime;
 }
 
-- 
2.25.1

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH v2 2/3] selftests: cgroup: Test CPU quota and burst write order
  2026-09-04  6:20     ` [PATCH v2 0/3] sched/fair: remove quota/burst write-order dependency Zhe Liu
  2026-09-04  6:20       ` [PATCH v2 1/3] sched/fair: Remove the write-order dependency between cpu.max and cpu.max.burst Zhe Liu
@ 2026-09-04  6:20       ` Zhe Liu
  2026-09-04  6:20       ` [PATCH v2 3/3] Documentation: describe CPU quota and burst ordering Zhe Liu
  2 siblings, 0 replies; 10+ messages in thread
From: Zhe Liu @ 2026-09-04  6:20 UTC (permalink / raw)
  To: mkoutny
  Cc: bsegall, cgroups, corbet, dietmar.eggemann, hannes, juri.lelli,
	kprateek.nayak, linux-doc, linux-kernel, linux-kselftest, liuzhe1,
	mgorman, mingo, peterz, rostedt, skhan, tj, vincent.guittot,
	vschneid

Test that quota and burst can be written in either order without losing
the configured burst value.

Signed-off-by: Zhe Liu <liuzhe1@kylinos.cn>
---
 tools/testing/selftests/cgroup/test_cpu.c | 40 +++++++++++++++++++++++
 1 file changed, 40 insertions(+)

diff --git a/tools/testing/selftests/cgroup/test_cpu.c b/tools/testing/selftests/cgroup/test_cpu.c
index f9f7017d9299..b13c2535afcd 100644
--- a/tools/testing/selftests/cgroup/test_cpu.c
+++ b/tools/testing/selftests/cgroup/test_cpu.c
@@ -733,6 +733,45 @@ static int test_cpucg_max(const char *root)
 	return ret;
 }
 
+static int test_cpucg_max_burst(const char *root)
+{
+	int ret = KSFT_FAIL;
+	char *cpucg;
+
+	cpucg = cg_name(root, "cpucg_max_burst");
+	if (!cpucg)
+		return KSFT_FAIL;
+
+	if (cg_create(cpucg))
+		goto cleanup;
+
+	if (cg_write(cpucg, "cpu.max", "max 100000") ||
+	    cg_write(cpucg, "cpu.max.burst", "100000000") ||
+	    cg_write(cpucg, "cpu.max", "50000 100000") ||
+	    cg_read_strcmp(cpucg, "cpu.max.burst", "100000000\n"))
+		goto cleanup;
+
+	if (cg_write(cpucg, "cpu.max.burst", "80000") ||
+	    cg_write(cpucg, "cpu.max", "100000 100000") ||
+	    cg_read_strcmp(cpucg, "cpu.max.burst", "80000\n"))
+		goto cleanup;
+
+	if (cg_write(cpucg, "cpu.max.burst", "0") ||
+	    cg_write(cpucg, "cpu.max", "50000 100000") ||
+	    cg_write(cpucg, "cpu.max", "100000 100000") ||
+	    cg_write(cpucg, "cpu.max.burst", "80000") ||
+	    cg_read_strcmp(cpucg, "cpu.max.burst", "80000\n"))
+		goto cleanup;
+
+	ret = KSFT_PASS;
+
+cleanup:
+	cg_destroy(cpucg);
+	free(cpucg);
+
+	return ret;
+}
+
 /*
  * This test verifies that a process inside of a nested cgroup whose parent
  * group has a cpu.max value set, is properly throttled.
@@ -822,6 +861,7 @@ struct cpucg_test {
 	T(test_cpucg_nested_weight_overprovisioned),
 	T(test_cpucg_nested_weight_underprovisioned),
 	T(test_cpucg_max),
+	T(test_cpucg_max_burst),
 	T(test_cpucg_max_nested),
 };
 #undef T
-- 
2.25.1

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* [PATCH v2 3/3] Documentation: describe CPU quota and burst ordering
  2026-09-04  6:20     ` [PATCH v2 0/3] sched/fair: remove quota/burst write-order dependency Zhe Liu
  2026-09-04  6:20       ` [PATCH v2 1/3] sched/fair: Remove the write-order dependency between cpu.max and cpu.max.burst Zhe Liu
  2026-09-04  6:20       ` [PATCH v2 2/3] selftests: cgroup: Test CPU quota and burst write order Zhe Liu
@ 2026-09-04  6:20       ` Zhe Liu
  2 siblings, 0 replies; 10+ messages in thread
From: Zhe Liu @ 2026-09-04  6:20 UTC (permalink / raw)
  To: mkoutny
  Cc: bsegall, cgroups, corbet, dietmar.eggemann, hannes, juri.lelli,
	kprateek.nayak, linux-doc, linux-kernel, linux-kselftest, liuzhe1,
	mgorman, mingo, peterz, rostedt, skhan, tj, vincent.guittot,
	vschneid

Document the independent quota and burst configuration and the runtime
burst clamp.

Signed-off-by: Zhe Liu <liuzhe1@kylinos.cn>
---
 Documentation/admin-guide/cgroup-v2.rst |  5 ++++-
 Documentation/scheduler/sched-bwc.rst   | 21 ++++++++++++---------
 2 files changed, 16 insertions(+), 10 deletions(-)

diff --git a/Documentation/admin-guide/cgroup-v2.rst b/Documentation/admin-guide/cgroup-v2.rst
index 7c2a8ed80071..57253c2c1819 100644
--- a/Documentation/admin-guide/cgroup-v2.rst
+++ b/Documentation/admin-guide/cgroup-v2.rst
@@ -1229,7 +1229,10 @@ will be referred to. All time durations are in microseconds.
 	A read-write single value file which exists on non-root
 	cgroups.  The default is "0".
 
-	The burst in the range [0, $MAX].
+	The burst in the range [0, $MAX]. The configured value is retained when
+	the quota changes and may be larger than the current quota. During CFS
+	runtime refill, the effective burst is limited to the current quota.
+	The quota and burst files can therefore be written in either order.
 
 	This file affects only processes under the fair-class scheduler.
 
diff --git a/Documentation/scheduler/sched-bwc.rst b/Documentation/scheduler/sched-bwc.rst
index e881a945c188..08a54ee84da2 100644
--- a/Documentation/scheduler/sched-bwc.rst
+++ b/Documentation/scheduler/sched-bwc.rst
@@ -90,20 +90,22 @@ bandwidth restriction in place, such a group is described as an unconstrained
 bandwidth group. This represents the traditional work-conserving behavior for
 CFS.
 
-Writing any (valid) positive value(s) no smaller than cpu.cfs_burst_us will
-enact the specified bandwidth limit. The minimum quota allowed for the quota or
-period is 1ms. There is also an upper bound on the period length of 1s.
-Additional restrictions exist when bandwidth limits are used in a hierarchical
-fashion, these are explained in more detail below.
+Writing any valid quota value will enact the specified bandwidth limit. The
+minimum quota allowed for the quota or period is 1ms. There is also an upper
+bound on the period length of 1s. Additional restrictions exist when bandwidth
+limits are used in a hierarchical fashion, these are explained in more detail
+below.
 
 Writing any negative value to cpu.cfs_quota_us will remove the bandwidth limit
 and return the group to an unconstrained state once more.
 
 A value of 0 for cpu.cfs_burst_us indicates that the group can not accumulate
 any unused bandwidth. It makes the traditional bandwidth control behavior for
-CFS unchanged. Writing any (valid) positive value(s) no larger than
-cpu.cfs_quota_us into cpu.cfs_burst_us will enact the cap on unused bandwidth
-accumulation.
+CFS unchanged. A valid positive value written to cpu.cfs_burst_us is retained
+when the quota changes. If it is larger than the current quota, CFS limits the
+effective burst during runtime refill to the current quota.
+
+The quota and burst files can be updated in either order.
 
 Any updates to a group's bandwidth specification will result in it becoming
 unthrottled if it is in a constrained state.
@@ -243,4 +245,5 @@ Examples
 	# echo 50000 > cpu.cfs_period_us /* period = 50ms */
 	# echo 10000 > cpu.cfs_burst_us /* burst = 10ms */
 
-   Larger buffer setting (no larger than quota) allows greater burst capacity.
+   A larger buffer setting allows greater burst capacity. If the configured
+   burst is larger than the quota, the effective burst is limited to the quota.
-- 
2.25.1

^ permalink raw reply related	[flat|nested] 10+ messages in thread

* Re: [PATCH v2 1/3] sched/fair: Remove the write-order dependency between cpu.max and cpu.max.burst
  2026-09-04  6:20       ` [PATCH v2 1/3] sched/fair: Remove the write-order dependency between cpu.max and cpu.max.burst Zhe Liu
@ 2026-09-04  9:21         ` Tao Cui
  0 siblings, 0 replies; 10+ messages in thread
From: Tao Cui @ 2026-09-04  9:21 UTC (permalink / raw)
  To: Zhe Liu, mkoutny
  Cc: cui.tao, bsegall, cgroups, corbet, dietmar.eggemann, hannes,
	juri.lelli, kprateek.nayak, linux-doc, linux-kernel,
	linux-kselftest, mgorman, mingo, peterz, rostedt, skhan, tj,
	vincent.guittot, vschneid, stable

Hi, Zhe,

在 2026/9/4 14:20, Zhe Liu 写道:
> Keep the configured burst independent of the current quota and cap it
> when CFS refills runtime. This allows quota and burst updates in either
> order.
> 

Ran the selftests on next-20260903 in a VM: all 10 test_cpu cases pass
with the series applied, and test_cpucg_max_burst fails on the unpatched
kernel, so the test does catch the old behavior.

One problem (spotted by sashiko, an automated overflow checker; I
re-did the arithmetic): dropping the burst_us + quota_us <=
max_bw_runtime_us check is not safe. With quota and burst both near
MAX_BW, the period-scaling path in sched_cfs_period_timer() can double
both up to 512x, and the new clamp quota + min(burst, quota) in
__refill_cfs_bandwidth_runtime() then wraps u64 to 0, leaving the group
with zero runtime on every refill.

I believe you can just drop the burst_us > quota_us comparison and keep
the sum check. Both write-order cases still pass that way: burst=80ms
with quota=50ms gives 130ms, well under the limit.

Tested-by: Tao Cui <cuitao@kylinos.cn>

> Fixes: f4183717b370 ("sched/fair: Introduce the burstable CFS controller")
> 
> Cc: stable@vger.kernel.org
> Signed-off-by: Zhe Liu <liuzhe1@kylinos.cn>
> ---
>  kernel/sched/core.c | 3 +--
>  kernel/sched/fair.c | 3 ++-
>  2 files changed, 3 insertions(+), 3 deletions(-)
> 
> diff --git a/kernel/sched/core.c b/kernel/sched/core.c
> index f78275192036..5269b8cfcf7f 100644
> --- a/kernel/sched/core.c
> +++ b/kernel/sched/core.c
> @@ -10159,8 +10159,7 @@ static int tg_set_bandwidth(struct task_group *tg,
>  	if (quota_us != RUNTIME_INF && quota_us > max_bw_runtime_us)
>  		return -EINVAL;
>  
> -	if (quota_us != RUNTIME_INF && (burst_us > quota_us ||
> -					burst_us + quota_us > max_bw_runtime_us))
> +	if (burst_us > max_bw_runtime_us)
>  		return -EINVAL;
>  
>  #ifdef CONFIG_CFS_BANDWIDTH
> diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
> index 6d881e530f89..488de18d477e 100644
> --- a/kernel/sched/fair.c
> +++ b/kernel/sched/fair.c
> @@ -6627,7 +6627,8 @@ void __refill_cfs_bandwidth_runtime(struct cfs_bandwidth *cfs_b)
>  		cfs_b->nr_burst++;
>  	}
>  
> -	cfs_b->runtime = min(cfs_b->runtime, cfs_b->quota + cfs_b->burst);
> +	cfs_b->runtime = min(cfs_b->runtime,
> +			     cfs_b->quota + min(cfs_b->burst, cfs_b->quota));
>  	cfs_b->runtime_snap = cfs_b->runtime;
>  }
>  


^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2026-09-04  9:21 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-20  3:32 [PATCH 0/2] sched/fair: Reset incompatible burst on quota change Zhe Liu
2026-08-20  3:32 ` [PATCH 1/2] " Zhe Liu
2026-08-20 11:43   ` Michal Koutný
2026-08-26  3:00     ` Zhe Liu
2026-09-04  6:20     ` [PATCH v2 0/3] sched/fair: remove quota/burst write-order dependency Zhe Liu
2026-09-04  6:20       ` [PATCH v2 1/3] sched/fair: Remove the write-order dependency between cpu.max and cpu.max.burst Zhe Liu
2026-09-04  9:21         ` Tao Cui
2026-09-04  6:20       ` [PATCH v2 2/3] selftests: cgroup: Test CPU quota and burst write order Zhe Liu
2026-09-04  6:20       ` [PATCH v2 3/3] Documentation: describe CPU quota and burst ordering Zhe Liu
2026-08-20  3:32 ` [PATCH 2/2] Documentation: describe burst reset on quota changes Zhe Liu

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).