Skip to content

Commit 9087f2e

Browse files
committed
fix path error in systemd when stopped
When we use cgroup with systemd driver, the cgroup path will be auto removed by systemd when all processes exited. So we should check cgroup path exists when we access the cgroup path, for example in `kill/ps`, or else we will got an error. Signed-off-by: lifubang <[email protected]>
1 parent dbe5aca commit 9087f2e

8 files changed

Lines changed: 69 additions & 7 deletions

File tree

libcontainer/cgroups/cgroups.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,9 @@ type Manager interface {
4747

4848
// GetFreezerState retrieves the current FreezerState of the cgroup.
4949
GetFreezerState() (configs.FreezerState, error)
50+
51+
// Whether the cgroup path exists or not
52+
Exists() bool
5053
}
5154

5255
type NotFoundError struct {

libcontainer/cgroups/fs/apply_raw.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -392,3 +392,7 @@ func (m *manager) GetFreezerState() (configs.FreezerState, error) {
392392
}
393393
return freezer.(*FreezerGroup).GetState(dir)
394394
}
395+
396+
func (m *manager) Exists() bool {
397+
return cgroups.PathExists(m.paths["devices"])
398+
}

libcontainer/cgroups/fs2/fs2.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -262,3 +262,7 @@ func (m *manager) GetCgroups() (*configs.Cgroup, error) {
262262
func (m *manager) GetFreezerState() (configs.FreezerState, error) {
263263
return getFreezer(m.dirPath)
264264
}
265+
266+
func (m *manager) Exists() bool {
267+
return cgroups.PathExists(m.dirPath)
268+
}

libcontainer/cgroups/systemd/unsupported.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,3 +65,7 @@ func Freeze(c *configs.Cgroup, state configs.FreezerState) error {
6565
func (m *Manager) GetCgroups() (*configs.Cgroup, error) {
6666
return nil, errors.New("Systemd not supported")
6767
}
68+
69+
func (m *Manager) Exists() bool {
70+
return false
71+
}

libcontainer/cgroups/systemd/v1.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -481,3 +481,7 @@ func (m *legacyManager) GetFreezerState() (configs.FreezerState, error) {
481481
}
482482
return freezer.(*fs.FreezerGroup).GetState(path)
483483
}
484+
485+
func (m *legacyManager) Exists() bool {
486+
return cgroups.PathExists(m.paths["devices"])
487+
}

libcontainer/cgroups/systemd/v2.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -370,3 +370,7 @@ func (m *unifiedManager) GetFreezerState() (configs.FreezerState, error) {
370370
}
371371
return fsMgr.GetFreezerState()
372372
}
373+
374+
func (m *unifiedManager) Exists() bool {
375+
return cgroups.PathExists(m.path)
376+
}

libcontainer/container_linux.go

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,17 @@ func (c *linuxContainer) OCIState() (*specs.State, error) {
169169
}
170170

171171
func (c *linuxContainer) Processes() ([]int, error) {
172-
pids, err := c.cgroupManager.GetAllPids()
172+
var pids []int
173+
status, err := c.currentStatus()
174+
if err != nil {
175+
return pids, err
176+
}
177+
// for systemd cgroup, the unit's cgroup path will be auto removed if container's all processes exited
178+
if status == Stopped && !c.cgroupManager.Exists() {
179+
return pids, nil
180+
}
181+
182+
pids, err = c.cgroupManager.GetAllPids()
173183
if err != nil {
174184
return nil, newSystemErrorWithCause(err, "getting all container pids from cgroups")
175185
}
@@ -385,13 +395,17 @@ func (c *linuxContainer) start(process *Process) error {
385395
func (c *linuxContainer) Signal(s os.Signal, all bool) error {
386396
c.m.Lock()
387397
defer c.m.Unlock()
388-
if all {
389-
return signalAllProcesses(c.cgroupManager, s)
390-
}
391398
status, err := c.currentStatus()
392399
if err != nil {
393400
return err
394401
}
402+
if all {
403+
// for systemd cgroup, the unit's cgroup path will be auto removed if container's all processes exited
404+
if status == Stopped && !c.cgroupManager.Exists() {
405+
return nil
406+
}
407+
return signalAllProcesses(c.cgroupManager, s)
408+
}
395409
// to avoid a PID reuse attack
396410
if status == Running || status == Created || status == Paused {
397411
if err := c.initProcess.signal(s); err != nil {

libcontainer/container_linux_test.go

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,15 @@ func (m *mockCgroupManager) Destroy() error {
5050
return nil
5151
}
5252

53+
func (m *mockCgroupManager) Exists() bool {
54+
paths := m.GetPaths()
55+
if paths != nil {
56+
_, err := os.Lstat(paths["devices"])
57+
return err == nil
58+
}
59+
return false
60+
}
61+
5362
func (m *mockCgroupManager) GetPaths() map[string]string {
5463
return m.paths
5564
}
@@ -134,11 +143,27 @@ func (m *mockProcess) forwardChildLogs() {
134143
}
135144

136145
func TestGetContainerPids(t *testing.T) {
146+
pid := 1
147+
stat, err := system.Stat(pid)
148+
if err != nil {
149+
t.Fatalf("can't stat pid %d, got %v", pid, err)
150+
}
137151
container := &linuxContainer{
138-
id: "myid",
139-
config: &configs.Config{},
140-
cgroupManager: &mockCgroupManager{allPids: []int{1, 2, 3}},
152+
id: "myid",
153+
config: &configs.Config{},
154+
cgroupManager: &mockCgroupManager{
155+
allPids: []int{1, 2, 3},
156+
paths: map[string]string{
157+
"device": "/proc/self/cgroups",
158+
},
159+
},
160+
initProcess: &mockProcess{
161+
_pid: 1,
162+
started: 10,
163+
},
164+
initProcessStartTime: stat.StartTime,
141165
}
166+
container.state = &runningState{c: container}
142167
pids, err := container.Processes()
143168
if err != nil {
144169
t.Fatal(err)

0 commit comments

Comments
 (0)