core/cgroup: fix TasksMaxScale percentage serialization (#41011)
bus_cgroup_set_tasks_max_scale() used a hand-rolled percentage format that produced values ~10x too small (e.g., "TasksMax=4.0%" instead of "TasksMax=40.00%"). On daemon-reload, the incorrect value was re-read, silently reducing the effective TasksMax by ~10x and causing fork rejections on systems with high thread counts. Fix by using the existing PERMYRIAD macros, consistent with memory property handlers (MemoryMax, MemoryHigh, MemoryLow, etc.). Fixes: #41009
This commit is contained in:
@@ -1010,9 +1010,9 @@ static int bus_cgroup_set_tasks_max_scale(
|
||||
*p = (CGroupTasksMax) { v, UINT32_MAX }; /* .scale is not 0, so this is interpreted as v/UINT32_MAX. */
|
||||
unit_invalidate_cgroup(u, CGROUP_MASK_PIDS);
|
||||
|
||||
uint32_t scaled = DIV_ROUND_UP((uint64_t) v * 100U, (uint64_t) UINT32_MAX);
|
||||
unit_write_settingf(u, flags, name, "%s=%" PRIu32 ".%" PRIu32 "%%", "TasksMax",
|
||||
scaled / 10, scaled % 10);
|
||||
int scaled = UINT32_SCALE_TO_PERMYRIAD(v);
|
||||
unit_write_settingf(u, flags, name, "TasksMax=" PERMYRIAD_AS_PERCENT_FORMAT_STR,
|
||||
PERMYRIAD_AS_PERCENT_FORMAT_VAL(scaled));
|
||||
}
|
||||
|
||||
return 1;
|
||||
|
||||
Executable
+50
@@ -0,0 +1,50 @@
|
||||
#!/usr/bin/env bash
|
||||
# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
set -ex
|
||||
set -o pipefail
|
||||
|
||||
# shellcheck source=test/units/test-control.sh
|
||||
. "$(dirname "$0")"/test-control.sh
|
||||
# shellcheck source=test/units/util.sh
|
||||
. "$(dirname "$0")"/util.sh
|
||||
|
||||
testcase_tasks_max_scale_serialize() {
|
||||
# Regression test for https://github.com/systemd/systemd/issues/41009
|
||||
# TasksMaxScale was serialized as 4.0% instead of 40.00%, causing 10x reduction on daemon-reload
|
||||
|
||||
local unit="test-tasks-max.slice"
|
||||
local unit_file="/run/systemd/system/${unit}"
|
||||
local dropin_dir="/run/systemd/system.control/${unit}.d"
|
||||
|
||||
# shellcheck disable=SC2329
|
||||
cleanup() (
|
||||
set +e
|
||||
rm -rf "${dropin_dir}"
|
||||
rm -f "${unit_file}"
|
||||
systemctl daemon-reload
|
||||
)
|
||||
trap cleanup RETURN
|
||||
|
||||
printf '[Slice]\n' >"${unit_file}"
|
||||
|
||||
systemctl daemon-reload
|
||||
|
||||
# Set TasksMax=40% via D-Bus — exercises bus_cgroup_set_tasks_max_scale()
|
||||
systemctl set-property --runtime "${unit}" TasksMax=40%
|
||||
|
||||
# Verify drop-in file contains correct percentage (40.00%, not 4.0%)
|
||||
grep -q '^TasksMax=40\.00%$' "${dropin_dir}/50-TasksMaxScale.conf"
|
||||
|
||||
# Capture value before daemon-reload
|
||||
local tasks_max_before
|
||||
tasks_max_before=$(systemctl show -P TasksMax "${unit}")
|
||||
|
||||
# Reload and verify value is preserved (the actual bug: value dropped 10x here)
|
||||
systemctl daemon-reload
|
||||
|
||||
local tasks_max_after
|
||||
tasks_max_after=$(systemctl show -P TasksMax "${unit}")
|
||||
assert_eq "${tasks_max_before}" "${tasks_max_after}"
|
||||
}
|
||||
|
||||
run_testcases
|
||||
Reference in New Issue
Block a user