Support process.scheduler

Spec: https://github.com/opencontainers/runtime-spec/pull/1188
Fix: https://github.com/opencontainers/runc/issues/3895

Co-authored-by: lifubang <lifubang@acmcoder.com>
Signed-off-by: utam0k <k0ma@utam0k.jp>
Signed-off-by: lifubang <lifubang@acmcoder.com>
This commit is contained in:
utam0k
2023-08-04 02:04:56 +00:00
committed by lifubang
parent 634280f5ab
commit 770728e16e
11 changed files with 208 additions and 1 deletions
@@ -11,6 +11,7 @@ import (
"github.com/opencontainers/runc/libcontainer/cgroups"
"github.com/opencontainers/runc/libcontainer/configs"
"github.com/opencontainers/runc/libcontainer/intelrdt"
"github.com/opencontainers/runtime-spec/specs-go"
selinux "github.com/opencontainers/selinux/go-selinux"
"github.com/sirupsen/logrus"
"golang.org/x/sys/unix"
@@ -30,6 +31,7 @@ func Validate(config *configs.Config) error {
intelrdtCheck,
rootlessEUIDCheck,
mountsStrict,
scheduler,
}
for _, c := range checks {
if err := c(config); err != nil {
@@ -353,3 +355,24 @@ func isHostNetNS(path string) (bool, error) {
return (st1.Dev == st2.Dev) && (st1.Ino == st2.Ino), nil
}
// scheduler is to validate scheduler configs according to https://man7.org/linux/man-pages/man2/sched_setattr.2.html
func scheduler(config *configs.Config) error {
s := config.Scheduler
if s == nil {
return nil
}
if s.Policy == "" {
return errors.New("scheduler policy is required")
}
if s.Nice < -20 || s.Nice > 19 {
return fmt.Errorf("invalid scheduler.nice: %d", s.Nice)
}
if s.Priority != 0 && (s.Policy != specs.SchedFIFO && s.Policy != specs.SchedRR) {
return errors.New("scheduler.priority can only be specified for SchedFIFO or SchedRR policy")
}
if s.Policy != specs.SchedDeadline && (s.Runtime != 0 || s.Deadline != 0 || s.Period != 0) {
return errors.New("scheduler runtime/deadline/period can only be specified for SchedDeadline policy")
}
return nil
}
@@ -616,3 +616,53 @@ func TestValidateIDMapMounts(t *testing.T) {
})
}
}
func TestValidateScheduler(t *testing.T) {
testCases := []struct {
isErr bool
policy string
niceValue int32
priority int32
runtime uint64
deadline uint64
period uint64
}{
{isErr: true, niceValue: 0},
{isErr: false, policy: "SCHED_OTHER", niceValue: 19},
{isErr: false, policy: "SCHED_OTHER", niceValue: -20},
{isErr: true, policy: "SCHED_OTHER", niceValue: 20},
{isErr: true, policy: "SCHED_OTHER", niceValue: -21},
{isErr: true, policy: "SCHED_OTHER", priority: 100},
{isErr: false, policy: "SCHED_FIFO", priority: 100},
{isErr: true, policy: "SCHED_FIFO", runtime: 20},
{isErr: true, policy: "SCHED_BATCH", deadline: 30},
{isErr: true, policy: "SCHED_IDLE", period: 40},
{isErr: true, policy: "SCHED_DEADLINE", priority: 100},
{isErr: false, policy: "SCHED_DEADLINE", runtime: 200},
{isErr: false, policy: "SCHED_DEADLINE", deadline: 300},
{isErr: false, policy: "SCHED_DEADLINE", period: 400},
}
for _, tc := range testCases {
scheduler := configs.Scheduler{
Policy: specs.LinuxSchedulerPolicy(tc.policy),
Nice: tc.niceValue,
Priority: tc.priority,
Runtime: tc.runtime,
Deadline: tc.deadline,
Period: tc.period,
}
config := &configs.Config{
Rootfs: "/var",
Scheduler: &scheduler,
}
err := Validate(config)
if tc.isErr && err == nil {
t.Errorf("scheduler: %d, expected error, got nil", tc.niceValue)
}
if !tc.isErr && err != nil {
t.Errorf("scheduler: %d, expected nil, got error %v", tc.niceValue, err)
}
}
}