Skip to content

Commit

Permalink
Add I/O priority
Browse files Browse the repository at this point in the history
Signed-off-by: utam0k <k0ma@utam0k.jp>
  • Loading branch information
utam0k committed Mar 24, 2023
1 parent efad7a3 commit c3bcfb1
Show file tree
Hide file tree
Showing 13 changed files with 137 additions and 9 deletions.
2 changes: 2 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,5 @@ require (
github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df // indirect
)

replace github.com/opencontainers/runtime-spec => github.com/utam0k/runtime-spec v1.0.3-0.20230323080204-aa2eddcaeb98
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,6 @@ github.com/moby/sys/mountinfo v0.6.2 h1:BzJjoreD5BMFNmD9Rus6gdd1pLuecOFPt8wC+Vyg
github.com/moby/sys/mountinfo v0.6.2/go.mod h1:IJb6JQeOklcdMU9F5xQ8ZALD+CUr5VlGpwtX+VE0rpI=
github.com/mrunalp/fileutils v0.5.0 h1:NKzVxiH7eSk+OQ4M+ZYW1K6h27RUV3MI6NUTsHhU6Z4=
github.com/mrunalp/fileutils v0.5.0/go.mod h1:M1WthSahJixYnrXQl/DFQuteStB1weuxD2QJNHXfbSQ=
github.com/opencontainers/runtime-spec v1.1.0-rc.1 h1:wHa9jroFfKGQqFHj0I1fMRKLl0pfj+ynAqBxo3v6u9w=
github.com/opencontainers/runtime-spec v1.1.0-rc.1/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
github.com/opencontainers/selinux v1.11.0 h1:+5Zbo97w3Lbmb3PeqQtpmTkMwsW5nRI3YaLpt7tQ7oU=
github.com/opencontainers/selinux v1.11.0/go.mod h1:E5dMC3VPuVvVHDYmi78qvhJp8+M586T4DlDRYpFkyec=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
Expand All @@ -55,6 +53,8 @@ github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635 h1:kdXcSzyDtse
github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
github.com/urfave/cli v1.22.9 h1:cv3/KhXGBGjEXLC4bH0sLuJ9BewaAbpk5oyMOveu4pw=
github.com/urfave/cli v1.22.9/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
github.com/utam0k/runtime-spec v1.0.3-0.20230323080204-aa2eddcaeb98 h1:l8lMbcNzKnGchkl2dadkvnRYS2LlgDxEa4HQChXGvCc=
github.com/utam0k/runtime-spec v1.0.3-0.20230323080204-aa2eddcaeb98/go.mod h1:oOfhCQaKpd/ZkHR2gIO1W4WNJbZIQLksMlkXBytRkQ8=
github.com/vishvananda/netlink v1.1.0 h1:1iyaYNBLmP6L0220aDnYQpo1QEV4t4hJ+xEEhhJH8j0=
github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE=
github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df h1:OviZH7qLw/7ZovXvuNyL3XQl8UFofeikI1NW1Gypu7k=
Expand Down
14 changes: 14 additions & 0 deletions libcontainer/configs/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,20 @@ type Config struct {
// RootlessCgroups is set when unlikely to have the full access to cgroups.
// When RootlessCgroups is set, cgroups errors are ignored.
RootlessCgroups bool `json:"rootless_cgroups,omitempty"`

// IOPriority is the container's I/O priority.
IOPriority *IOPriority `json:"io_priority,omitempty"`
}

var IOPrioClassMapping = map[specs.IOPriorityClass]int{
specs.IOPRIO_CLASS_RT: 1,
specs.IOPRIO_CLASS_BE: 2,
specs.IOPRIO_CLASS_IDLE: 3,
}

type IOPriority struct {
Class specs.IOPriorityClass `json:"class"`
Priority int `json:"priority"`
}

type (
Expand Down
2 changes: 2 additions & 0 deletions libcontainer/process.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,8 @@ type Process struct {
//
// For cgroup v2, the only key allowed is "".
SubCgroupPaths map[string]string

IOPriority *configs.IOPriority
}

// Wait waits for the process to exit.
Expand Down
6 changes: 6 additions & 0 deletions libcontainer/process_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,12 @@ func (p *setnsProcess) signal(sig os.Signal) error {

func (p *setnsProcess) start() (retErr error) {
defer p.messageSockPair.parent.Close()
if p.process.IOPriority != nil {
if err := utils.SetIOPriority(p.process.IOPriority); err != nil {
return fmt.Errorf("unable to apply iopriority: %w", err)
}
}

// get the "before" value of oom kill count
oom, _ := p.manager.OOMKillCount()
err := p.cmd.Start()
Expand Down
6 changes: 6 additions & 0 deletions libcontainer/specconv/spec_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -490,6 +490,12 @@ func CreateLibcontainerConfig(opts *CreateOpts) (*configs.Config, error) {
Ambient: spec.Process.Capabilities.Ambient,
}
}
if spec.Process.IOPriority != nil {
config.IOPriority = &configs.IOPriority{
Class: spec.Process.IOPriority.Class,
Priority: spec.Process.IOPriority.Priority,
}
}
}
createHooks(spec, config)
config.Version = specs.Version
Expand Down
8 changes: 8 additions & 0 deletions libcontainer/standard_init_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import (
"github.com/opencontainers/runc/libcontainer/keys"
"github.com/opencontainers/runc/libcontainer/seccomp"
"github.com/opencontainers/runc/libcontainer/system"
"github.com/opencontainers/runc/libcontainer/utils"
)

type linuxStandardInit struct {
Expand Down Expand Up @@ -154,6 +155,13 @@ func (l *linuxStandardInit) Init() error {
return &os.SyscallError{Syscall: "prctl(SET_NO_NEW_PRIVS)", Err: err}
}
}

if l.config.Config.IOPriority != nil {
if err := utils.SetIOPriority(l.config.Config.IOPriority); err != nil {
return fmt.Errorf("unable to apply iopriority: %w", err)
}
}

// Tell our parent that we're ready to Execv. This must be done before the
// Seccomp rules have been applied, because we need to be able to read and
// write to a socket.
Expand Down
22 changes: 22 additions & 0 deletions libcontainer/utils/utils_unix.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ import (
"fmt"
"os"
"strconv"
"syscall"

"github.com/opencontainers/runc/libcontainer/configs"

"golang.org/x/sys/unix"
)
Expand Down Expand Up @@ -67,3 +70,22 @@ func NewSockPair(name string) (parent *os.File, child *os.File, err error) {
}
return os.NewFile(uintptr(fds[1]), name+"-p"), os.NewFile(uintptr(fds[0]), name+"-c"), nil
}

const (
IOPRIO_WHO_PGRP = 1
)

func SetIOPriority(ioprio *configs.IOPriority) error {
class, ok := configs.IOPrioClassMapping[ioprio.Class]
if !ok {
return fmt.Errorf("invalid io priority class: %s", ioprio.Class)
}

// Combine class and priority into a single value
iop := (class << 13) | ioprio.Priority
_, _, errno := syscall.RawSyscall(syscall.SYS_IOPRIO_SET, IOPRIO_WHO_PGRP, 0, uintptr(iop))
if errno != 0 {
return fmt.Errorf("failed to set io priority: %w", errno)
}
return nil
}
30 changes: 30 additions & 0 deletions tests/integration/ioprio.bats
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#!/usr/bin/env bats

load helpers

function setup() {
setup_debian
}

function teardown() {
teardown_bundle
}

@test "ioprio_set is applied to process group" {
# Create a container with a specific I/O priority
update_config '.process.ioPriority = {"class": "IOPRIO_CLASS_BE", "priority": 4}'

runc run -d --console-socket "$CONSOLE_SOCKET" test_ioprio
[ "$status" -eq 0 ]

# Check the init process
runc exec test_ioprio ionice -p 1
[ "$status" -eq 0 ]
echo "${output}" | grep -q "best-effort: prio 4"

# Check the process made from the exec command
runc exec test_ioprio ionice
[ "$status" -eq 0 ]
echo "${output}" | grep -q "best-effort: prio 4"
}

6 changes: 6 additions & 0 deletions utils_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,12 @@ func newProcess(p specs.Process) (*libcontainer.Process, error) {
lp.ConsoleHeight = uint16(p.ConsoleSize.Height)
}

if p.IOPriority != nil {
lp.IOPriority = &configs.IOPriority{}
lp.IOPriority.Class = p.IOPriority.Class
lp.IOPriority.Priority = p.IOPriority.Priority
}

if p.Capabilities != nil {
lp.Capabilities = &configs.Capabilities{}
lp.Capabilities.Bounding = p.Capabilities.Bounding
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion vendor/modules.txt
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ github.com/moby/sys/mountinfo
# github.com/mrunalp/fileutils v0.5.0
## explicit; go 1.13
github.com/mrunalp/fileutils
# github.com/opencontainers/runtime-spec v1.1.0-rc.1
# github.com/opencontainers/runtime-spec v1.1.0-rc.1 => github.com/utam0k/runtime-spec v1.0.3-0.20230323080204-aa2eddcaeb98
## explicit
github.com/opencontainers/runtime-spec/specs-go
# github.com/opencontainers/selinux v1.11.0
Expand Down Expand Up @@ -103,3 +103,4 @@ google.golang.org/protobuf/reflect/protoreflect
google.golang.org/protobuf/reflect/protoregistry
google.golang.org/protobuf/runtime/protoiface
google.golang.org/protobuf/runtime/protoimpl
# github.com/opencontainers/runtime-spec => github.com/utam0k/runtime-spec v1.0.3-0.20230323080204-aa2eddcaeb98

0 comments on commit c3bcfb1

Please sign in to comment.