Merge pull request #2412 from lifubang/removecgpath
remove cgroup path recursively in cgroup v2
diff --git a/libcontainer/cgroups/fs2/fs2.go b/libcontainer/cgroups/fs2/fs2.go
index b7fe442..5566847 100644
--- a/libcontainer/cgroups/fs2/fs2.go
+++ b/libcontainer/cgroups/fs2/fs2.go
@@ -156,11 +156,35 @@
return nil
}
-func (m *manager) Destroy() error {
- if err := os.Remove(m.dirPath); err != nil && !os.IsNotExist(err) {
+// removeCgroupPath aims to remove cgroup path recursively
+// Because there may be subcgroups in it.
+func removeCgroupPath(path string) error {
+ infos, err := ioutil.ReadDir(path)
+ if err != nil {
+ if os.IsNotExist(err) {
+ err = nil
+ }
return err
}
- return nil
+ for _, info := range infos {
+ if info.IsDir() {
+ // We should remove subcgroups dir first
+ if err = removeCgroupPath(filepath.Join(path, info.Name())); err != nil {
+ break
+ }
+ }
+ }
+ if err == nil {
+ err = os.Remove(path)
+ if os.IsNotExist(err) {
+ err = nil
+ }
+ }
+ return err
+}
+
+func (m *manager) Destroy() error {
+ return removeCgroupPath(m.dirPath)
}
func (m *manager) Path(_ string) string {
diff --git a/tests/integration/delete.bats b/tests/integration/delete.bats
index c5ed215..44a76fc 100644
--- a/tests/integration/delete.bats
+++ b/tests/integration/delete.bats
@@ -51,3 +51,58 @@
runc delete --force notexists
[ "$status" -eq 0 ]
}
+
+@test "runc delete --force in cgroupv2 with subcgroups" {
+ requires cgroups_v2 root
+ set_cgroups_path "$BUSYBOX_BUNDLE"
+
+ # grant `rw` priviledge to `/sys/fs/cgroup`
+ cat "${BUSYBOX_BUNDLE}/config.json"\
+ | jq '.mounts |= map((select(.type=="cgroup") | .options -= ["ro"]) // .)'\
+ > "${BUSYBOX_BUNDLE}/config.json.tmp"
+ mv "${BUSYBOX_BUNDLE}/config.json"{.tmp,}
+
+ # run busybox detached
+ runc run -d --console-socket $CONSOLE_SOCKET test_busybox
+ [ "$status" -eq 0 ]
+
+ # check state
+ testcontainer test_busybox running
+
+ # create a sub process
+ __runc exec -d test_busybox sleep 1d
+ [ "$status" -eq 0 ]
+
+ # find the pid of sleep
+ pid=$(__runc exec test_busybox ps -a | grep 1d | awk '{print $1}')
+ [[ ${pid} =~ [0-9]+ ]]
+
+ # create subcgroups
+ cat <<EOF > nest.sh
+ cd /sys/fs/cgroup
+ for f in \$(cat cgroup.controllers); do echo +\$f > cgroup.subtree_control; done
+ mkdir foo
+ cd foo
+ echo threaded > cgroup.type
+ echo ${pid} > cgroup.threads
+ cat cgroup.threads
+EOF
+ cat nest.sh | runc exec test_busybox sh
+ [[ ${output} =~ [0-9]+ ]]
+
+ # check create subcgroups success
+ [ -d $CGROUP_PATH/foo ]
+
+ # check cgroup.threads' value
+ runc exec test_busybox cat /sys/fs/cgroup/foo/cgroup.threads
+ [[ ${output} =~ [0-9]+ ]]
+
+ # force delete test_busybox
+ runc delete --force test_busybox
+
+ runc state test_busybox
+ [ "$status" -ne 0 ]
+
+ # check delete subcgroups success
+ [ ! -d $CGROUP_PATH/foo ]
+}