mirror of
https://github.com/opencontainers/runc.git
synced 2026-07-11 06:03:57 +08:00
c1adc99a20
In manager.Apply() method, a path to each subsystem is obtained by calling d.path(sys.Name()), and the sys.Apply() is called that does the same call to d.path() again. d.path() is an expensive call, so rather than to call it twice, let's reuse the result. This results the number of times we parse mountinfo during container start from 62 to 34 on my setup. Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
94 lines
2.3 KiB
Go
94 lines
2.3 KiB
Go
// +build linux
|
|
|
|
package fs
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"os"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/opencontainers/runc/libcontainer/cgroups"
|
|
"github.com/opencontainers/runc/libcontainer/cgroups/fscommon"
|
|
"github.com/opencontainers/runc/libcontainer/configs"
|
|
"golang.org/x/sys/unix"
|
|
)
|
|
|
|
type FreezerGroup struct {
|
|
}
|
|
|
|
func (s *FreezerGroup) Name() string {
|
|
return "freezer"
|
|
}
|
|
|
|
func (s *FreezerGroup) Apply(path string, d *cgroupData) error {
|
|
return join(path, d.pid)
|
|
}
|
|
|
|
func (s *FreezerGroup) Set(path string, cgroup *configs.Cgroup) error {
|
|
switch cgroup.Resources.Freezer {
|
|
case configs.Frozen, configs.Thawed:
|
|
for {
|
|
// In case this loop does not exit because it doesn't get the expected
|
|
// state, let's write again this state, hoping it's going to be properly
|
|
// set this time. Otherwise, this loop could run infinitely, waiting for
|
|
// a state change that would never happen.
|
|
if err := fscommon.WriteFile(path, "freezer.state", string(cgroup.Resources.Freezer)); err != nil {
|
|
return err
|
|
}
|
|
|
|
state, err := s.GetState(path)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if state == cgroup.Resources.Freezer {
|
|
break
|
|
}
|
|
|
|
time.Sleep(1 * time.Millisecond)
|
|
}
|
|
case configs.Undefined:
|
|
return nil
|
|
default:
|
|
return fmt.Errorf("Invalid argument '%s' to freezer.state", string(cgroup.Resources.Freezer))
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (s *FreezerGroup) Remove(d *cgroupData) error {
|
|
return removePath(d.path("freezer"))
|
|
}
|
|
|
|
func (s *FreezerGroup) GetStats(path string, stats *cgroups.Stats) error {
|
|
return nil
|
|
}
|
|
|
|
func (s *FreezerGroup) GetState(path string) (configs.FreezerState, error) {
|
|
for {
|
|
state, err := fscommon.ReadFile(path, "freezer.state")
|
|
if err != nil {
|
|
// If the kernel is too old, then we just treat the freezer as
|
|
// being in an "undefined" state.
|
|
if os.IsNotExist(err) || errors.Is(err, unix.ENODEV) {
|
|
err = nil
|
|
}
|
|
return configs.Undefined, err
|
|
}
|
|
switch strings.TrimSpace(state) {
|
|
case "THAWED":
|
|
return configs.Thawed, nil
|
|
case "FROZEN":
|
|
return configs.Frozen, nil
|
|
case "FREEZING":
|
|
// Make sure we get a stable freezer state, so retry if the cgroup
|
|
// is still undergoing freezing. This should be a temporary delay.
|
|
time.Sleep(1 * time.Millisecond)
|
|
continue
|
|
default:
|
|
return configs.Undefined, fmt.Errorf("unknown freezer.state %q", state)
|
|
}
|
|
}
|
|
}
|