mirror of
https://github.com/opencontainers/runc.git
synced 2025-09-27 03:46:19 +08:00
runc exec: fix setting process.Scheduler
Commit 770728e1
added Scheduler field into both Config and Process,
but forgot to add a mechanism to actually use Process.Scheduler.
As a result, runc exec does not set Process.Scheduler ever.
Fix it, and a test case (which fails before the fix).
Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
This commit is contained in:
@@ -18,9 +18,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
github.com/moby/sys/user for that. (#3999)
|
github.com/moby/sys/user for that. (#3999)
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
* `runc exec -p` no longer ignores specified `ioPriority` setting.
|
* `runc exec -p` no longer ignores specified `ioPriority` and `scheduler`
|
||||||
Similarly, libcontainer's `Container.Start` and `Container.Run`
|
settings. Similarly, libcontainer's `Container.Start` and `Container.Run`
|
||||||
methods no longer ignore `Process.IOPriority` setting. (#4585)
|
methods no longer ignore `Process.IOPriority` and `Process.Scheduler`
|
||||||
|
settings. (#4585)
|
||||||
|
|
||||||
## [1.2.0] - 2024-10-22
|
## [1.2.0] - 2024-10-22
|
||||||
|
|
||||||
|
@@ -708,6 +708,7 @@ func (c *Container) newInitConfig(process *Process) *initConfig {
|
|||||||
ProcessLabel: c.config.ProcessLabel,
|
ProcessLabel: c.config.ProcessLabel,
|
||||||
Rlimits: c.config.Rlimits,
|
Rlimits: c.config.Rlimits,
|
||||||
IOPriority: c.config.IOPriority,
|
IOPriority: c.config.IOPriority,
|
||||||
|
Scheduler: c.config.Scheduler,
|
||||||
CreateConsole: process.ConsoleSocket != nil,
|
CreateConsole: process.ConsoleSocket != nil,
|
||||||
ConsoleWidth: process.ConsoleWidth,
|
ConsoleWidth: process.ConsoleWidth,
|
||||||
ConsoleHeight: process.ConsoleHeight,
|
ConsoleHeight: process.ConsoleHeight,
|
||||||
@@ -733,6 +734,9 @@ func (c *Container) newInitConfig(process *Process) *initConfig {
|
|||||||
if process.IOPriority != nil {
|
if process.IOPriority != nil {
|
||||||
cfg.IOPriority = process.IOPriority
|
cfg.IOPriority = process.IOPriority
|
||||||
}
|
}
|
||||||
|
if process.Scheduler != nil {
|
||||||
|
cfg.Scheduler = process.Scheduler
|
||||||
|
}
|
||||||
|
|
||||||
// Set misc properties.
|
// Set misc properties.
|
||||||
|
|
||||||
|
@@ -82,6 +82,7 @@ type initConfig struct {
|
|||||||
ProcessLabel string `json:"process_label"`
|
ProcessLabel string `json:"process_label"`
|
||||||
Rlimits []configs.Rlimit `json:"rlimits"`
|
Rlimits []configs.Rlimit `json:"rlimits"`
|
||||||
IOPriority *configs.IOPriority `json:"io_priority,omitempty"`
|
IOPriority *configs.IOPriority `json:"io_priority,omitempty"`
|
||||||
|
Scheduler *configs.Scheduler `json:"scheduler,omitempty"`
|
||||||
|
|
||||||
// Miscellaneous properties, filled in by [Container.newInitConfig]
|
// Miscellaneous properties, filled in by [Container.newInitConfig]
|
||||||
// unless documented otherwise.
|
// unless documented otherwise.
|
||||||
@@ -607,7 +608,7 @@ func setupRlimits(limits []configs.Rlimit, pid int) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func setupScheduler(config *configs.Config) error {
|
func setupScheduler(config *initConfig) error {
|
||||||
if config.Scheduler == nil {
|
if config.Scheduler == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -616,7 +617,7 @@ func setupScheduler(config *configs.Config) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := unix.SchedSetAttr(0, attr, 0); err != nil {
|
if err := unix.SchedSetAttr(0, attr, 0); err != nil {
|
||||||
if errors.Is(err, unix.EPERM) && config.Cgroups.CpusetCpus != "" {
|
if errors.Is(err, unix.EPERM) && config.Config.Cgroups.CpusetCpus != "" {
|
||||||
return errors.New("process scheduler can't be used together with AllowedCPUs")
|
return errors.New("process scheduler can't be used together with AllowedCPUs")
|
||||||
}
|
}
|
||||||
return fmt.Errorf("error setting scheduler: %w", err)
|
return fmt.Errorf("error setting scheduler: %w", err)
|
||||||
|
@@ -112,6 +112,9 @@ type Process struct {
|
|||||||
// For cgroup v2, the only key allowed is "".
|
// For cgroup v2, the only key allowed is "".
|
||||||
SubCgroupPaths map[string]string
|
SubCgroupPaths map[string]string
|
||||||
|
|
||||||
|
// Scheduler represents the scheduling attributes for a process.
|
||||||
|
//
|
||||||
|
// If not empty, takes precedence over container's [configs.Config.Scheduler].
|
||||||
Scheduler *configs.Scheduler
|
Scheduler *configs.Scheduler
|
||||||
|
|
||||||
// IOPriority is a process I/O priority.
|
// IOPriority is a process I/O priority.
|
||||||
|
@@ -71,7 +71,7 @@ func (l *linuxSetnsInit) Init() error {
|
|||||||
unix.Umask(int(*l.config.Config.Umask))
|
unix.Umask(int(*l.config.Config.Umask))
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := setupScheduler(l.config.Config); err != nil {
|
if err := setupScheduler(l.config); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -155,7 +155,7 @@ func (l *linuxStandardInit) Init() error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := setupScheduler(l.config.Config); err != nil {
|
if err := setupScheduler(l.config); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -12,17 +12,49 @@ function teardown() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@test "scheduler is applied" {
|
@test "scheduler is applied" {
|
||||||
update_config ' .process.scheduler = {"policy": "SCHED_DEADLINE", "nice": 19, "priority": 0, "runtime": 42000, "deadline": 1000000, "period": 1000000, }'
|
update_config ' .process.scheduler = {
|
||||||
|
"policy": "SCHED_BATCH",
|
||||||
|
"priority": 0,
|
||||||
|
"nice": 19
|
||||||
|
}'
|
||||||
|
|
||||||
runc run -d --console-socket "$CONSOLE_SOCKET" test_scheduler
|
runc run -d --console-socket "$CONSOLE_SOCKET" test_scheduler
|
||||||
[ "$status" -eq 0 ]
|
[ "$status" -eq 0 ]
|
||||||
|
|
||||||
|
# Check init settings.
|
||||||
runc exec test_scheduler chrt -p 1
|
runc exec test_scheduler chrt -p 1
|
||||||
[ "$status" -eq 0 ]
|
[ "$status" -eq 0 ]
|
||||||
|
[[ "${lines[0]}" == *"scheduling policy: SCHED_BATCH" ]]
|
||||||
[[ "${lines[0]}" == *"scheduling policy: SCHED_DEADLINE" ]]
|
|
||||||
[[ "${lines[1]}" == *"priority: 0" ]]
|
[[ "${lines[1]}" == *"priority: 0" ]]
|
||||||
[[ "${lines[2]}" == *"runtime/deadline/period parameters: 42000/1000000/1000000" ]]
|
|
||||||
|
# Check exec settings derived from config.json.
|
||||||
|
runc exec test_scheduler sh -c 'chrt -p $$'
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
[[ "${lines[0]}" == *"scheduling policy: SCHED_BATCH" ]]
|
||||||
|
[[ "${lines[1]}" == *"priority: 0" ]]
|
||||||
|
|
||||||
|
# Another exec, with different scheduler settings.
|
||||||
|
proc='
|
||||||
|
{
|
||||||
|
"terminal": false,
|
||||||
|
"args": [ "/bin/sleep", "600" ],
|
||||||
|
"cwd": "/",
|
||||||
|
"scheduler": {
|
||||||
|
"policy": "SCHED_DEADLINE",
|
||||||
|
"flags": [ "SCHED_FLAG_RESET_ON_FORK" ],
|
||||||
|
"nice": 19,
|
||||||
|
"priority": 0,
|
||||||
|
"runtime": 42000,
|
||||||
|
"deadline": 100000,
|
||||||
|
"period": 1000000
|
||||||
|
}
|
||||||
|
}'
|
||||||
|
__runc exec -d --pid-file pid.txt --process <(echo "$proc") test_scheduler
|
||||||
|
|
||||||
|
run chrt -p "$(cat pid.txt)"
|
||||||
|
[[ "${lines[0]}" == *"scheduling policy: SCHED_DEADLINE|SCHED_RESET_ON_FORK" ]]
|
||||||
|
[[ "${lines[1]}" == *"priority: 0" ]]
|
||||||
|
[[ "${lines[2]}" == *"runtime/deadline/period parameters: 42000/100000/1000000" ]]
|
||||||
}
|
}
|
||||||
|
|
||||||
# Checks that runc emits a specific error when scheduling policy is used
|
# Checks that runc emits a specific error when scheduling policy is used
|
||||||
|
Reference in New Issue
Block a user