Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixups to scheduler/priority settings #4459

Merged
merged 5 commits into from
Dec 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 0 additions & 6 deletions libcontainer/configs/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -286,12 +286,6 @@ func ToSchedAttr(scheduler *Scheduler) (*unix.SchedAttr, error) {
}, nil
}

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

type IOPriority = specs.LinuxIOPriority

type (
Expand Down
8 changes: 8 additions & 0 deletions libcontainer/configs/validate/validator.go
Original file line number Diff line number Diff line change
Expand Up @@ -406,5 +406,13 @@ func ioPriority(config *configs.Config) error {
if priority < 0 || priority > 7 {
return fmt.Errorf("invalid ioPriority.Priority: %d", priority)
}

switch class := config.IOPriority.Class; class {
case specs.IOPRIO_CLASS_RT, specs.IOPRIO_CLASS_BE, specs.IOPRIO_CLASS_IDLE:
// Valid class, do nothing.
default:
return fmt.Errorf("invalid ioPriority.Class: %q", class)
}

return nil
}
12 changes: 9 additions & 3 deletions libcontainer/configs/validate/validator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -847,15 +847,21 @@ func TestValidateIOPriority(t *testing.T) {
testCases := []struct {
isErr bool
priority int
class specs.IOPriorityClass
}{
{isErr: false, priority: 0},
{isErr: false, priority: 7},
{isErr: true, priority: -1},
{isErr: false, priority: 0, class: specs.IOPRIO_CLASS_IDLE},
{isErr: false, priority: 7, class: specs.IOPRIO_CLASS_RT},
{isErr: false, priority: 3, class: specs.IOPRIO_CLASS_BE},
// Invalid priority.
{isErr: true, priority: -1, class: specs.IOPRIO_CLASS_BE},
// Invalid class.
{isErr: true, priority: 3, class: specs.IOPriorityClass("IOPRIO_CLASS_WOW")},
}

for _, tc := range testCases {
ioPriroty := configs.IOPriority{
Priority: tc.priority,
Class: tc.class,
}
config := &configs.Config{
Rootfs: "/var",
Expand Down
32 changes: 32 additions & 0 deletions libcontainer/init_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -662,6 +662,9 @@ func setupRlimits(limits []configs.Rlimit, pid int) error {
}

func setupScheduler(config *configs.Config) error {
if config.Scheduler == nil {
return nil
}
attr, err := configs.ToSchedAttr(config.Scheduler)
if err != nil {
return err
Expand All @@ -675,6 +678,35 @@ func setupScheduler(config *configs.Config) error {
return nil
}

func setupIOPriority(config *configs.Config) error {
const ioprioWhoPgrp = 1

ioprio := config.IOPriority
if ioprio == nil {
return nil
}
class := 0
switch ioprio.Class {
case specs.IOPRIO_CLASS_RT:
class = 1
case specs.IOPRIO_CLASS_BE:
class = 2
case specs.IOPRIO_CLASS_IDLE:
class = 3
default:
return fmt.Errorf("invalid io priority class: %s", ioprio.Class)
}

// Combine class and priority into a single value
// https://github.com/torvalds/linux/blob/v5.18/include/uapi/linux/ioprio.h#L5-L17
iop := (class << 13) | ioprio.Priority
_, _, errno := unix.RawSyscall(unix.SYS_IOPRIO_SET, ioprioWhoPgrp, 0, uintptr(iop))
if errno != 0 {
return fmt.Errorf("failed to set io priority: %w", errno)
}
return nil
}

func setupPersonality(config *configs.Config) error {
return system.SetLinuxPersonality(config.Personality.Domain)
}
Expand Down
24 changes: 0 additions & 24 deletions libcontainer/process_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -166,12 +166,6 @@ type setnsProcess struct {
func (p *setnsProcess) start() (retErr error) {
defer p.comm.closeParent()

if p.process.IOPriority != nil {
if err := setIOPriority(p.process.IOPriority); err != nil {
return err
}
}

// get the "before" value of oom kill count
oom, _ := p.manager.OOMKillCount()
err := p.cmd.Start()
Expand Down Expand Up @@ -908,21 +902,3 @@ func (p *Process) InitializeIO(rootuid, rootgid int) (i *IO, err error) {
}
return i, nil
}

func setIOPriority(ioprio *configs.IOPriority) error {
const ioprioWhoPgrp = 1

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
// https://github.com/torvalds/linux/blob/v5.18/include/uapi/linux/ioprio.h#L5-L17
iop := (class << 13) | ioprio.Priority
_, _, errno := unix.RawSyscall(unix.SYS_IOPRIO_SET, ioprioWhoPgrp, 0, uintptr(iop))
if errno != 0 {
return fmt.Errorf("failed to set io priority: %w", errno)
}
return nil
}
9 changes: 5 additions & 4 deletions libcontainer/setns_init_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,12 +71,13 @@ func (l *linuxSetnsInit) Init() error {
unix.Umask(int(*l.config.Config.Umask))
}

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

if err := setupIOPriority(l.config.Config); err != nil {
return err
}
// Tell our parent that we're ready to exec. 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
13 changes: 5 additions & 8 deletions libcontainer/standard_init_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -155,15 +155,12 @@ func (l *linuxStandardInit) Init() error {
}
}

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

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

// Tell our parent that we're ready to exec. This must be done before the
Expand Down
12 changes: 2 additions & 10 deletions utils_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,23 +55,15 @@ func newProcess(p specs.Process) (*libcontainer.Process, error) {
Label: p.SelinuxLabel,
NoNewPrivileges: &p.NoNewPrivileges,
AppArmorProfile: p.ApparmorProfile,
Scheduler: p.Scheduler,
IOPriority: p.IOPriority,
}

if p.ConsoleSize != nil {
lp.ConsoleWidth = uint16(p.ConsoleSize.Width)
lp.ConsoleHeight = uint16(p.ConsoleSize.Height)
}

if p.Scheduler != nil {
s := *p.Scheduler
lp.Scheduler = &s
}

if p.IOPriority != nil {
ioPriority := *p.IOPriority
lp.IOPriority = &ioPriority
}

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