From b9114d91e2ee50fd610b9fa201375763b64df121 Mon Sep 17 00:00:00 2001 From: Kir Kolyshkin Date: Tue, 7 Jan 2025 19:48:58 -0800 Subject: [PATCH] runc exec: fix setting process.ioPriority Commit bfbd0305b added IOPriority field into both Config and Process, but forgot to add a mechanism to actually use Process.IOPriority. As a result, runc exec does not set Process.IOPriority ever. Fix it, and a test case (which fails before the fix). Signed-off-by: Kir Kolyshkin --- CHANGELOG.md | 5 +++++ libcontainer/container_linux.go | 4 ++++ libcontainer/init_linux.go | 3 ++- libcontainer/process.go | 3 +++ libcontainer/setns_init_linux.go | 2 +- libcontainer/standard_init_linux.go | 2 +- tests/integration/ioprio.bats | 20 +++++++++++++++++--- 7 files changed, 33 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2ebb60722..a810474ce 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 IDs before calling libcontainer; it is recommended to use Go package github.com/moby/sys/user for that. (#3999) +### Fixed + * `runc exec -p` no longer ignores specified `ioPriority` setting. + Similarly, libcontainer's `Container.Start` and `Container.Run` + methods no longer ignore `Process.IOPriority` setting. (#4585) + ## [1.2.0] - 2024-10-22 > できるときにできることをやるんだ。それが今だ。 diff --git a/libcontainer/container_linux.go b/libcontainer/container_linux.go index a0d2ec260..8a9cf0786 100644 --- a/libcontainer/container_linux.go +++ b/libcontainer/container_linux.go @@ -707,6 +707,7 @@ func (c *Container) newInitConfig(process *Process) *initConfig { AppArmorProfile: c.config.AppArmorProfile, ProcessLabel: c.config.ProcessLabel, Rlimits: c.config.Rlimits, + IOPriority: c.config.IOPriority, CreateConsole: process.ConsoleSocket != nil, ConsoleWidth: process.ConsoleWidth, ConsoleHeight: process.ConsoleHeight, @@ -729,6 +730,9 @@ func (c *Container) newInitConfig(process *Process) *initConfig { if len(process.Rlimits) > 0 { cfg.Rlimits = process.Rlimits } + if process.IOPriority != nil { + cfg.IOPriority = process.IOPriority + } // Set misc properties. diff --git a/libcontainer/init_linux.go b/libcontainer/init_linux.go index 11a9069d8..5976b2933 100644 --- a/libcontainer/init_linux.go +++ b/libcontainer/init_linux.go @@ -81,6 +81,7 @@ type initConfig struct { NoNewPrivileges bool `json:"no_new_privileges"` ProcessLabel string `json:"process_label"` Rlimits []configs.Rlimit `json:"rlimits"` + IOPriority *configs.IOPriority `json:"io_priority,omitempty"` // Miscellaneous properties, filled in by [Container.newInitConfig] // unless documented otherwise. @@ -623,7 +624,7 @@ func setupScheduler(config *configs.Config) error { return nil } -func setupIOPriority(config *configs.Config) error { +func setupIOPriority(config *initConfig) error { const ioprioWhoPgrp = 1 ioprio := config.IOPriority diff --git a/libcontainer/process.go b/libcontainer/process.go index 5b2928be4..09e57ae46 100644 --- a/libcontainer/process.go +++ b/libcontainer/process.go @@ -114,6 +114,9 @@ type Process struct { Scheduler *configs.Scheduler + // IOPriority is a process I/O priority. + // + // If not empty, takes precedence over container's [configs.Config.IOPriority]. IOPriority *configs.IOPriority } diff --git a/libcontainer/setns_init_linux.go b/libcontainer/setns_init_linux.go index d1885b3fd..505af1d08 100644 --- a/libcontainer/setns_init_linux.go +++ b/libcontainer/setns_init_linux.go @@ -75,7 +75,7 @@ func (l *linuxSetnsInit) Init() error { return err } - if err := setupIOPriority(l.config.Config); err != nil { + if err := setupIOPriority(l.config); err != nil { return err } // Tell our parent that we're ready to exec. This must be done before the diff --git a/libcontainer/standard_init_linux.go b/libcontainer/standard_init_linux.go index 9517820bc..0c83db30f 100644 --- a/libcontainer/standard_init_linux.go +++ b/libcontainer/standard_init_linux.go @@ -159,7 +159,7 @@ func (l *linuxStandardInit) Init() error { return err } - if err := setupIOPriority(l.config.Config); err != nil { + if err := setupIOPriority(l.config); err != nil { return err } diff --git a/tests/integration/ioprio.bats b/tests/integration/ioprio.bats index a907d782f..9faa72d61 100644 --- a/tests/integration/ioprio.bats +++ b/tests/integration/ioprio.bats @@ -20,11 +20,25 @@ function teardown() { # Check the init process. runc exec test_ioprio ionice -p 1 [ "$status" -eq 0 ] - [[ "$output" = *'best-effort: prio 4'* ]] + [ "${lines[0]}" = 'best-effort: prio 4' ] - # Check the process made from the exec command. + # Check an exec process, which should derive ioprio from config.json. runc exec test_ioprio ionice [ "$status" -eq 0 ] + [ "${lines[0]}" = 'best-effort: prio 4' ] - [[ "$output" = *'best-effort: prio 4'* ]] + # Check an exec with a priority taken from process.json, + # which should override the ioprio in config.json. + proc=' +{ + "terminal": false, + "ioPriority": { + "class": "IOPRIO_CLASS_IDLE" + }, + "args": [ "/usr/bin/ionice" ], + "cwd": "/" +}' + runc exec --process <(echo "$proc") test_ioprio + [ "$status" -eq 0 ] + [ "${lines[0]}" = 'idle' ] }