summaryrefslogtreecommitdiff
path: root/vendor/github.com/opencontainers/runc/libcontainer/intelrdt/intelrdt.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/opencontainers/runc/libcontainer/intelrdt/intelrdt.go')
-rw-r--r--vendor/github.com/opencontainers/runc/libcontainer/intelrdt/intelrdt.go241
1 files changed, 93 insertions, 148 deletions
diff --git a/vendor/github.com/opencontainers/runc/libcontainer/intelrdt/intelrdt.go b/vendor/github.com/opencontainers/runc/libcontainer/intelrdt/intelrdt.go
index 3fa11b800..8b6bf3ef0 100644
--- a/vendor/github.com/opencontainers/runc/libcontainer/intelrdt/intelrdt.go
+++ b/vendor/github.com/opencontainers/runc/libcontainer/intelrdt/intelrdt.go
@@ -1,13 +1,11 @@
-// +build linux
-
package intelrdt
import (
"bufio"
"bytes"
+ "errors"
"fmt"
"io"
- "io/ioutil"
"os"
"path/filepath"
"strconv"
@@ -15,6 +13,7 @@ import (
"sync"
"github.com/moby/sys/mountinfo"
+ "github.com/opencontainers/runc/libcontainer/cgroups/fscommon"
"github.com/opencontainers/runc/libcontainer/configs"
)
@@ -70,7 +69,7 @@ import (
* |-- ...
* |-- schemata
* |-- tasks
- * |-- <container_id>
+ * |-- <clos>
* |-- ...
* |-- schemata
* |-- tasks
@@ -153,7 +152,7 @@ type Manager interface {
// Returns statistics for Intel RDT
GetStats() (*Stats, error)
- // Destroys the Intel RDT 'container_id' group
+ // Destroys the Intel RDT container-specific 'container_id' group
Destroy() error
// Returns Intel RDT path to save in a state file and to be able to
@@ -181,14 +180,10 @@ func NewManager(config *configs.Config, id string, path string) Manager {
}
const (
- IntelRdtTasks = "tasks"
+ intelRdtTasks = "tasks"
)
var (
- // The absolute root path of the Intel RDT "resource control" filesystem
- intelRdtRoot string
- intelRdtRootLock sync.Mutex
-
// The flag to indicate if Intel RDT/CAT is enabled
catEnabled bool
// The flag to indicate if Intel RDT/MBA is enabled
@@ -198,13 +193,9 @@ var (
// For Intel RDT initialization
initOnce sync.Once
-)
-type intelRdtData struct {
- root string
- config *configs.Config
- pid int
-}
+ errNotFound = errors.New("Intel RDT resctrl mount point not found")
+)
// Check if Intel RDT sub-features are enabled in featuresInit()
func featuresInit() {
@@ -215,9 +206,10 @@ func featuresInit() {
return
}
- // 2. Check if Intel RDT "resource control" filesystem is mounted
- // The user guarantees to mount the filesystem
- if !isIntelRdtMounted() {
+ // 2. Check if Intel RDT "resource control" filesystem is available.
+ // The user guarantees to mount the filesystem.
+ root, err := Root()
+ if err != nil {
return
}
@@ -226,7 +218,7 @@ func featuresInit() {
// selectively disabled or enabled by kernel command line
// (e.g., rdt=!l3cat,mba) in 4.14 and newer kernel
if flagsSet.CAT {
- if _, err := os.Stat(filepath.Join(intelRdtRoot, "info", "L3")); err == nil {
+ if _, err := os.Stat(filepath.Join(root, "info", "L3")); err == nil {
catEnabled = true
}
}
@@ -236,15 +228,15 @@ func featuresInit() {
// depends on MBA
mbaEnabled = true
} else if flagsSet.MBA {
- if _, err := os.Stat(filepath.Join(intelRdtRoot, "info", "MB")); err == nil {
+ if _, err := os.Stat(filepath.Join(root, "info", "MB")); err == nil {
mbaEnabled = true
}
}
if flagsSet.MBMTotal || flagsSet.MBMLocal || flagsSet.CMT {
- if _, err := os.Stat(filepath.Join(intelRdtRoot, "info", "L3_MON")); err != nil {
+ if _, err := os.Stat(filepath.Join(root, "info", "L3_MON")); err != nil {
return
}
- enabledMonFeatures, err = getMonFeatures(intelRdtRoot)
+ enabledMonFeatures, err = getMonFeatures(root)
if err != nil {
return
}
@@ -271,7 +263,7 @@ func findIntelRdtMountpointDir(f io.Reader) (string, error) {
return "", err
}
if len(mi) < 1 {
- return "", NewNotFoundError("Intel RDT")
+ return "", errNotFound
}
// Check if MBA Software Controller is enabled through mount option "-o mba_MBps"
@@ -282,10 +274,16 @@ func findIntelRdtMountpointDir(f io.Reader) (string, error) {
return mi[0].Mountpoint, nil
}
-// Gets the root path of Intel RDT "resource control" filesystem
-func getIntelRdtRoot() (string, error) {
- intelRdtRootLock.Lock()
- defer intelRdtRootLock.Unlock()
+// For Root() use only.
+var (
+ intelRdtRoot string
+ rootMu sync.Mutex
+)
+
+// Root returns the Intel RDT "resource control" filesystem mount point.
+func Root() (string, error) {
+ rootMu.Lock()
+ defer rootMu.Unlock()
if intelRdtRoot != "" {
return intelRdtRoot, nil
@@ -309,11 +307,6 @@ func getIntelRdtRoot() (string, error) {
return intelRdtRoot, nil
}
-func isIntelRdtMounted() bool {
- _, err := getIntelRdtRoot()
- return err == nil
-}
-
type cpuInfoFlags struct {
CAT bool // Cache Allocation Technology
MBA bool // Memory Bandwidth Allocation
@@ -366,33 +359,15 @@ func parseCpuInfoFile(path string) (cpuInfoFlags, error) {
return infoFlags, nil
}
-func parseUint(s string, base, bitSize int) (uint64, error) {
- value, err := strconv.ParseUint(s, base, bitSize)
- if err != nil {
- intValue, intErr := strconv.ParseInt(s, base, bitSize)
- // 1. Handle negative values greater than MinInt64 (and)
- // 2. Handle negative values lesser than MinInt64
- if intErr == nil && intValue < 0 {
- return 0, nil
- } else if intErr != nil && intErr.(*strconv.NumError).Err == strconv.ErrRange && intValue < 0 {
- return 0, nil
- }
-
- return value, err
- }
-
- return value, nil
-}
-
// Gets a single uint64 value from the specified file.
func getIntelRdtParamUint(path, file string) (uint64, error) {
fileName := filepath.Join(path, file)
- contents, err := ioutil.ReadFile(fileName)
+ contents, err := os.ReadFile(fileName)
if err != nil {
return 0, err
}
- res, err := parseUint(string(bytes.TrimSpace(contents)), 10, 64)
+ res, err := fscommon.ParseUint(string(bytes.TrimSpace(contents)), 10, 64)
if err != nil {
return res, fmt.Errorf("unable to parse %q as a uint from file %q", string(contents), fileName)
}
@@ -401,7 +376,7 @@ func getIntelRdtParamUint(path, file string) (uint64, error) {
// Gets a string value from the specified file
func getIntelRdtParamString(path, file string) (string, error) {
- contents, err := ioutil.ReadFile(filepath.Join(path, file))
+ contents, err := os.ReadFile(filepath.Join(path, file))
if err != nil {
return "", err
}
@@ -413,29 +388,17 @@ func writeFile(dir, file, data string) error {
if dir == "" {
return fmt.Errorf("no such directory for %s", file)
}
- if err := ioutil.WriteFile(filepath.Join(dir, file), []byte(data+"\n"), 0o600); err != nil {
- return fmt.Errorf("failed to write %v to %v: %v", data, file, err)
+ if err := os.WriteFile(filepath.Join(dir, file), []byte(data+"\n"), 0o600); err != nil {
+ return newLastCmdError(fmt.Errorf("intelrdt: unable to write %v: %w", data, err))
}
return nil
}
-func getIntelRdtData(c *configs.Config, pid int) (*intelRdtData, error) {
- rootPath, err := getIntelRdtRoot()
- if err != nil {
- return nil, err
- }
- return &intelRdtData{
- root: rootPath,
- config: c,
- pid: pid,
- }, nil
-}
-
// Get the read-only L3 cache information
func getL3CacheInfo() (*L3CacheInfo, error) {
l3CacheInfo := &L3CacheInfo{}
- rootPath, err := getIntelRdtRoot()
+ rootPath, err := Root()
if err != nil {
return l3CacheInfo, err
}
@@ -465,7 +428,7 @@ func getL3CacheInfo() (*L3CacheInfo, error) {
func getMemBwInfo() (*MemBwInfo, error) {
memBwInfo := &MemBwInfo{}
- rootPath, err := getIntelRdtRoot()
+ rootPath, err := Root()
if err != nil {
return memBwInfo, err
}
@@ -498,7 +461,7 @@ func getMemBwInfo() (*MemBwInfo, error) {
// Get diagnostics for last filesystem operation error from file info/last_cmd_status
func getLastCmdStatus() (string, error) {
- rootPath, err := getIntelRdtRoot()
+ rootPath, err := Root()
if err != nil {
return "", err
}
@@ -515,13 +478,13 @@ func getLastCmdStatus() (string, error) {
// WriteIntelRdtTasks writes the specified pid into the "tasks" file
func WriteIntelRdtTasks(dir string, pid int) error {
if dir == "" {
- return fmt.Errorf("no such directory for %s", IntelRdtTasks)
+ return fmt.Errorf("no such directory for %s", intelRdtTasks)
}
// Don't attach any pid if -1 is specified as a pid
if pid != -1 {
- if err := ioutil.WriteFile(filepath.Join(dir, IntelRdtTasks), []byte(strconv.Itoa(pid)), 0o600); err != nil {
- return fmt.Errorf("failed to write %v to %v: %v", pid, IntelRdtTasks, err)
+ if err := os.WriteFile(filepath.Join(dir, intelRdtTasks), []byte(strconv.Itoa(pid)), 0o600); err != nil {
+ return newLastCmdError(fmt.Errorf("intelrdt: unable to add pid %d: %w", pid, err))
}
}
return nil
@@ -545,15 +508,19 @@ func IsMBAScEnabled() bool {
return mbaScEnabled
}
-// Get the 'container_id' path in Intel RDT "resource control" filesystem
-func GetIntelRdtPath(id string) (string, error) {
- rootPath, err := getIntelRdtRoot()
+// Get the path of the clos group in "resource control" filesystem that the container belongs to
+func (m *intelRdtManager) getIntelRdtPath() (string, error) {
+ rootPath, err := Root()
if err != nil {
return "", err
}
- path := filepath.Join(rootPath, id)
- return path, nil
+ clos := m.id
+ if m.config.IntelRdt != nil && m.config.IntelRdt.ClosID != "" {
+ clos = m.config.IntelRdt.ClosID
+ }
+
+ return filepath.Join(rootPath, clos), nil
}
// Applies Intel RDT configuration to the process with the specified pid
@@ -562,30 +529,48 @@ func (m *intelRdtManager) Apply(pid int) (err error) {
if m.config.IntelRdt == nil {
return nil
}
- d, err := getIntelRdtData(m.config, pid)
- if err != nil && !IsNotFound(err) {
+
+ path, err := m.getIntelRdtPath()
+ if err != nil {
return err
}
m.mu.Lock()
defer m.mu.Unlock()
- path, err := d.join(m.id)
- if err != nil {
- return err
+
+ if m.config.IntelRdt.ClosID != "" && m.config.IntelRdt.L3CacheSchema == "" && m.config.IntelRdt.MemBwSchema == "" {
+ // Check that the CLOS exists, i.e. it has been pre-configured to
+ // conform with the runtime spec
+ if _, err := os.Stat(path); err != nil {
+ return fmt.Errorf("clos dir not accessible (must be pre-created when l3CacheSchema and memBwSchema are empty): %w", err)
+ }
+ }
+
+ if err := os.MkdirAll(path, 0o755); err != nil {
+ return newLastCmdError(err)
+ }
+
+ if err := WriteIntelRdtTasks(path, pid); err != nil {
+ return newLastCmdError(err)
}
m.path = path
return nil
}
-// Destroys the Intel RDT 'container_id' group
+// Destroys the Intel RDT container-specific 'container_id' group
func (m *intelRdtManager) Destroy() error {
- m.mu.Lock()
- defer m.mu.Unlock()
- if err := os.RemoveAll(m.GetPath()); err != nil {
- return err
+ // Don't remove resctrl group if closid has been explicitly specified. The
+ // group is likely externally managed, i.e. by some other entity than us.
+ // There are probably other containers/tasks sharing the same group.
+ if m.config.IntelRdt == nil || m.config.IntelRdt.ClosID == "" {
+ m.mu.Lock()
+ defer m.mu.Unlock()
+ if err := os.RemoveAll(m.GetPath()); err != nil {
+ return err
+ }
+ m.path = ""
}
- m.path = ""
return nil
}
@@ -593,7 +578,7 @@ func (m *intelRdtManager) Destroy() error {
// restore the object later
func (m *intelRdtManager) GetPath() string {
if m.path == "" {
- m.path, _ = GetIntelRdtPath(m.id)
+ m.path, _ = m.getIntelRdtPath()
}
return m.path
}
@@ -607,9 +592,9 @@ func (m *intelRdtManager) GetStats() (*Stats, error) {
m.mu.Lock()
defer m.mu.Unlock()
- stats := NewStats()
+ stats := newStats()
- rootPath, err := getIntelRdtRoot()
+ rootPath, err := Root()
if err != nil {
return nil, err
}
@@ -620,7 +605,7 @@ func (m *intelRdtManager) GetStats() (*Stats, error) {
}
schemaRootStrings := strings.Split(tmpRootStrings, "\n")
- // The L3 cache and memory bandwidth schemata in 'container_id' group
+ // The L3 cache and memory bandwidth schemata in container's clos group
containerPath := m.GetPath()
tmpStrings, err := getIntelRdtParamString(containerPath, "schemata")
if err != nil {
@@ -643,7 +628,7 @@ func (m *intelRdtManager) GetStats() (*Stats, error) {
}
}
- // The L3 cache schema in 'container_id' group
+ // The L3 cache schema in container's clos group
for _, schema := range schemaStrings {
if strings.Contains(schema, "L3") {
stats.L3CacheSchema = strings.TrimSpace(schema)
@@ -666,7 +651,7 @@ func (m *intelRdtManager) GetStats() (*Stats, error) {
}
}
- // The memory bandwidth schema in 'container_id' group
+ // The memory bandwidth schema in container's clos group
for _, schema := range schemaStrings {
if strings.Contains(schema, "MB") {
stats.MemBwSchema = strings.TrimSpace(schema)
@@ -736,24 +721,30 @@ func (m *intelRdtManager) Set(container *configs.Config) error {
l3CacheSchema := container.IntelRdt.L3CacheSchema
memBwSchema := container.IntelRdt.MemBwSchema
+ // TODO: verify that l3CacheSchema and/or memBwSchema match the
+ // existing schemata if ClosID has been specified. This is a more
+ // involved than reading the file and doing plain string comparison as
+ // the value written in does not necessarily match what gets read out
+ // (leading zeros, cache id ordering etc).
+
// Write a single joint schema string to schemata file
if l3CacheSchema != "" && memBwSchema != "" {
if err := writeFile(path, "schemata", l3CacheSchema+"\n"+memBwSchema); err != nil {
- return NewLastCmdError(err)
+ return err
}
}
// Write only L3 cache schema string to schemata file
if l3CacheSchema != "" && memBwSchema == "" {
if err := writeFile(path, "schemata", l3CacheSchema); err != nil {
- return NewLastCmdError(err)
+ return err
}
}
// Write only memory bandwidth schema string to schemata file
if l3CacheSchema == "" && memBwSchema != "" {
if err := writeFile(path, "schemata", memBwSchema); err != nil {
- return NewLastCmdError(err)
+ return err
}
}
}
@@ -761,56 +752,10 @@ func (m *intelRdtManager) Set(container *configs.Config) error {
return nil
}
-func (raw *intelRdtData) join(id string) (string, error) {
- path := filepath.Join(raw.root, id)
- if err := os.MkdirAll(path, 0o755); err != nil {
- return "", NewLastCmdError(err)
- }
-
- if err := WriteIntelRdtTasks(path, raw.pid); err != nil {
- return "", NewLastCmdError(err)
- }
- return path, nil
-}
-
-type NotFoundError struct {
- ResourceControl string
-}
-
-func (e *NotFoundError) Error() string {
- return fmt.Sprintf("mountpoint for %s not found", e.ResourceControl)
-}
-
-func NewNotFoundError(res string) error {
- return &NotFoundError{
- ResourceControl: res,
- }
-}
-
-func IsNotFound(err error) bool {
- if err == nil {
- return false
- }
- _, ok := err.(*NotFoundError)
- return ok
-}
-
-type LastCmdError struct {
- LastCmdStatus string
- Err error
-}
-
-func (e *LastCmdError) Error() string {
- return e.Err.Error() + ", last_cmd_status: " + e.LastCmdStatus
-}
-
-func NewLastCmdError(err error) error {
- lastCmdStatus, err1 := getLastCmdStatus()
+func newLastCmdError(err error) error {
+ status, err1 := getLastCmdStatus()
if err1 == nil {
- return &LastCmdError{
- LastCmdStatus: lastCmdStatus,
- Err: err,
- }
+ return fmt.Errorf("%w, last_cmd_status: %s", err, status)
}
return err
}