Skip to content

Commit

Permalink
runc exec: fix setting process.Scheduler
Browse files Browse the repository at this point in the history
Commit 770728e 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>
  • Loading branch information
kolyshkin committed Jan 16, 2025
1 parent 92ae668 commit fa41079
Show file tree
Hide file tree
Showing 5 changed files with 46 additions and 7 deletions.
4 changes: 4 additions & 0 deletions libcontainer/container_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -699,6 +699,7 @@ func (c *Container) newInitConfig(process *Process) *initConfig {
ProcessLabel: c.config.ProcessLabel,
Rlimits: c.config.Rlimits,
IOPriority: c.config.IOPriority,
Scheduler: c.config.Scheduler,
CreateConsole: process.ConsoleSocket != nil,
ConsoleWidth: process.ConsoleWidth,
ConsoleHeight: process.ConsoleHeight,
Expand All @@ -724,6 +725,9 @@ func (c *Container) newInitConfig(process *Process) *initConfig {
if process.IOPriority != nil {
cfg.IOPriority = process.IOPriority
}
if process.Scheduler != nil {
cfg.Scheduler = process.Scheduler
}

// Set misc properties.

Expand Down
5 changes: 3 additions & 2 deletions libcontainer/init_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ type initConfig struct {
ProcessLabel string `json:"process_label"`
Rlimits []configs.Rlimit `json:"rlimits"`
IOPriority *configs.IOPriority `json:"io_priority,omitempty"`
Scheduler *configs.Scheduler `json:"scheduler,omitempty"`

// Miscellaneous properties, filled in by [Container.newInitConfig]
// unless documented otherwise.
Expand Down Expand Up @@ -656,7 +657,7 @@ func setupRlimits(limits []configs.Rlimit, pid int) error {
return nil
}

func setupScheduler(config *configs.Config) error {
func setupScheduler(config *initConfig) error {
if config.Scheduler == nil {
return nil
}
Expand All @@ -665,7 +666,7 @@ func setupScheduler(config *configs.Config) error {
return err
}
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 fmt.Errorf("error setting scheduler: %w", err)
Expand Down
2 changes: 1 addition & 1 deletion libcontainer/setns_init_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ func (l *linuxSetnsInit) Init() error {
unix.Umask(int(*l.config.Config.Umask))
}

if err := setupScheduler(l.config.Config); err != nil {
if err := setupScheduler(l.config); err != nil {
return err
}

Expand Down
2 changes: 1 addition & 1 deletion libcontainer/standard_init_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ func (l *linuxStandardInit) Init() error {
}
}

if err := setupScheduler(l.config.Config); err != nil {
if err := setupScheduler(l.config); err != nil {
return err
}

Expand Down
40 changes: 37 additions & 3 deletions tests/integration/scheduler.bats
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,51 @@ function teardown() {
}

@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
[ "$status" -eq 0 ]

# Check init settings.
runc exec test_scheduler chrt -p 1
[ "$status" -eq 0 ]
[[ "${lines[0]}" == *"scheduling policy: SCHED_BATCH" ]]
[[ "${lines[1]}" == *"priority: 0" ]]

# 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", "1h" ],
"cwd": "/",
"scheduler": {
"policy": "SCHED_DEADLINE",
"flags": [ "SCHED_FLAG_RESET_ON_FORK" ],
"nice": 19,
"priority": 0,
"runtime": 42000,
"deadline": 100000,
"period": 1000000
}
}'
__runc exec -d --process <(echo "$proc") test_scheduler
[ "$status" -eq 0 ]

[[ "${lines[0]}" == *"scheduling policy: SCHED_DEADLINE" ]]
# shellcheck disable=SC2016
runc exec test_scheduler sh -c 'chrt -p $(pidof sleep)'
[[ "${lines[0]}" == *"scheduling policy: SCHED_DEADLINE|SCHED_RESET_ON_FORK" ]]
[[ "${lines[1]}" == *"priority: 0" ]]
[[ "${lines[2]}" == *"runtime/deadline/period parameters: 42000/1000000/1000000" ]]
[[ "${lines[2]}" == *"runtime/deadline/period parameters: 42000/100000/1000000" ]]
}

# Checks that runc emits a specific error when scheduling policy is used
Expand Down

0 comments on commit fa41079

Please sign in to comment.