Skip to content

Commit 1641f82

Browse files
committed
Intel RDT: updates according to proposed spec changes.
There are two proposed clarifications to the OCI spec. The first item specifies that the L3CacheSchema line filtering needs to happen only when both MemBw and L3Cache schemas are specified. The second item specifies that the subdirectory needs to be deleted. Runc already does that, but the clarification adds for directory removal only if the directory was created by us. Signed-off-by: Ismo Puustinen <[email protected]>
1 parent 8eb801d commit 1641f82

File tree

2 files changed

+84
-10
lines changed

2 files changed

+84
-10
lines changed

libcontainer/intelrdt/intelrdt.go

Lines changed: 44 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -146,10 +146,11 @@ import (
146146
*/
147147

148148
type Manager struct {
149-
mu sync.Mutex
150-
config *configs.Config
151-
id string
152-
path string
149+
mu sync.Mutex
150+
config *configs.Config
151+
id string
152+
path string
153+
directoryCreated bool
153154
}
154155

155156
// NewManager returns a new instance of Manager, or nil if the Intel RDT
@@ -170,9 +171,10 @@ func NewManager(config *configs.Config, id string, path string) *Manager {
170171
// is actually available. Used by unit tests that mock intelrdt paths.
171172
func newManager(config *configs.Config, id string, path string) *Manager {
172173
return &Manager{
173-
config: config,
174-
id: id,
175-
path: path,
174+
config: config,
175+
id: id,
176+
path: path,
177+
directoryCreated: false,
176178
}
177179
}
178180

@@ -466,6 +468,14 @@ func (m *Manager) Apply(pid int) (err error) {
466468
}
467469
}
468470

471+
// If the directory doesn't exist we need to create it -> it means we also need
472+
// to clean it up afterwards. Make a note to the manager.
473+
if _, err := os.Stat(path); err != nil {
474+
if os.IsNotExist(err) {
475+
m.directoryCreated = true
476+
}
477+
}
478+
469479
if err := os.MkdirAll(path, 0o755); err != nil {
470480
return newLastCmdError(err)
471481
}
@@ -482,8 +492,9 @@ func (m *Manager) Apply(pid int) (err error) {
482492
func (m *Manager) Destroy() error {
483493
// Don't remove resctrl group if closid has been explicitly specified. The
484494
// group is likely externally managed, i.e. by some other entity than us.
485-
// There are probably other containers/tasks sharing the same group.
486-
if m.config.IntelRdt != nil && m.config.IntelRdt.ClosID == "" {
495+
// There are probably other containers/tasks sharing the same group. Also
496+
// only remove the directory if it was created by us.
497+
if m.config.IntelRdt != nil && m.config.IntelRdt.ClosID == "" && m.directoryCreated {
487498
m.mu.Lock()
488499
defer m.mu.Unlock()
489500
if err := os.RemoveAll(m.GetPath()); err != nil {
@@ -589,6 +600,28 @@ func (m *Manager) GetStats() (*Stats, error) {
589600
return stats, nil
590601
}
591602

603+
func combineSchemas(l3CacheSchema, memBwSchema string) string {
604+
// If both l3CacheSchema and memBwSchema are set and
605+
// l3CacheSchema contains a line beginning with "MB:", the
606+
// value written to schemata file MUST be the non-"MB:"
607+
// line(s) from l3CacheSchema and the line from memBWSchema.
608+
609+
validLines := make([]string, 0)
610+
611+
// Split the l3CacheSchema to lines.
612+
lines := strings.Split(l3CacheSchema, "\n")
613+
614+
// Remove the "MB:" lines.
615+
for _, line := range lines {
616+
if strings.HasPrefix(line, "MB:") {
617+
continue
618+
}
619+
validLines = append(validLines, line)
620+
}
621+
622+
return strings.Join(validLines, "\n") + "\n" + memBwSchema
623+
}
624+
592625
// Set Intel RDT "resource control" filesystem as configured.
593626
func (m *Manager) Set(container *configs.Config) error {
594627
// About L3 cache schema:
@@ -649,7 +682,8 @@ func (m *Manager) Set(container *configs.Config) error {
649682

650683
// Write a single joint schema string to schemata file
651684
if l3CacheSchema != "" && memBwSchema != "" {
652-
if err := writeFile(path, "schemata", l3CacheSchema+"\n"+memBwSchema); err != nil {
685+
schemata := combineSchemas(l3CacheSchema, memBwSchema)
686+
if err := writeFile(path, "schemata", schemata); err != nil {
653687
return err
654688
}
655689
}

libcontainer/intelrdt/intelrdt_test.go

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,46 @@ func TestIntelRdtSetMemBwSchema(t *testing.T) {
6767
}
6868
}
6969

70+
func TestIntelRdtSetCombinedSchema(t *testing.T) {
71+
helper := NewIntelRdtTestUtil(t)
72+
73+
// Test filtering out the "MB:"" line in l3CacheSchema.
74+
75+
const (
76+
schemaBefore = "MB:0=20;1=70"
77+
memBwSchema = "MB:0=70;1=20"
78+
l3CacheSchema = "MB:0=80;1=10\nL3:0=f0;1=f"
79+
combinedSchemaAfter = "L3:0=f0;1=f\nMB:0=70;1=20"
80+
)
81+
82+
helper.writeFileContents(map[string]string{
83+
"schemata": schemaBefore + "\n",
84+
})
85+
86+
helper.config.IntelRdt.MemBwSchema = memBwSchema
87+
helper.config.IntelRdt.L3CacheSchema = l3CacheSchema
88+
intelrdt := newManager(helper.config, "", helper.IntelRdtPath)
89+
if err := intelrdt.Set(helper.config); err != nil {
90+
t.Fatal(err)
91+
}
92+
93+
tmpStrings, err := getIntelRdtParamString(helper.IntelRdtPath, "schemata")
94+
if err != nil {
95+
t.Fatalf("Failed to parse file 'schemata' - %s", err)
96+
}
97+
98+
readValues := strings.Split(tmpStrings, "\n")
99+
expectedValues := strings.Split(combinedSchemaAfter, "\n")
100+
101+
if readValues[0] != expectedValues[0] {
102+
t.Fatal("Got the wrong value for L3 cache, set 'schemata' failed.")
103+
}
104+
105+
if readValues[1] != expectedValues[1] {
106+
t.Fatal("Got the wrong value for MemBW, set 'schemata' failed.")
107+
}
108+
}
109+
70110
func TestIntelRdtSetMemBwScSchema(t *testing.T) {
71111
helper := NewIntelRdtTestUtil(t)
72112

0 commit comments

Comments
 (0)