From 6477190927cec5e20393c303bf7a4049539273bf Mon Sep 17 00:00:00 2001
From: zhongjiawei <zhongjiawei1@huawei.com>
Date: Wed, 26 Jul 2023 15:25:25 +0800
Subject: [PATCH] runc:cgroup apply method modify

---
 libcontainer/cgroups/fs/cpuset.go   | 12 +++-
 libcontainer/cgroups/fs/files.go    | 27 +++-----
 libcontainer/cgroups/fs/utils.go    | 97 +++++++++++++++++++++++++++++
 libcontainer/rootfs_linux.go        |  1 +
 libcontainer/standard_init_linux.go |  6 +-
 5 files changed, 120 insertions(+), 23 deletions(-)
 create mode 100644 libcontainer/cgroups/fs/utils.go

diff --git a/libcontainer/cgroups/fs/cpuset.go b/libcontainer/cgroups/fs/cpuset.go
index ef9164b..01388f7 100644
--- a/libcontainer/cgroups/fs/cpuset.go
+++ b/libcontainer/cgroups/fs/cpuset.go
@@ -1,6 +1,7 @@
 package fs
 
 import (
+	"fmt"
 	"errors"
 	"io/ioutil"
 	"os"
@@ -145,7 +146,7 @@ func (s *CpusetGroup) setCpuset(path, cpuset string) error {
 func (s *CpusetGroup) Set(path string, r *configs.Resources) error {
 	var ret error
 	if r.CpusetCpus != "" {
-		return s.setCpuset(path, cgroup.Resources.CpusetCpus)
+		return s.setCpuset(path, r.CpusetCpus)
 	}
 	if r.CpusetMems != "" {
 		if err := cgroups.WriteFile(path, "cpuset.mems", r.CpusetMems); err != nil {
@@ -352,14 +353,19 @@ func cpusetEnsureParent(current string) error {
 // cpusetCopyIfNeeded copies the cpuset.cpus and cpuset.mems from the parent
 // directory to the current directory if the file's contents are 0
 func cpusetCopyIfNeeded(current, parent string) error {
-	if currentCpus, currentMems, err := getCpusetSubsystemSettings(current); err != nil {
+	var (
+		err                      error
+		currentCpus, currentMems string
+		parentCpus, parentMems   string
+	)
+	if currentCpus, currentMems, err = getCpusetSubsystemSettings(current); err != nil {
 		ret := fmt.Errorf("failed copy current cgroup setting, %v", err)
 		if _, err := os.Stat(current); err != nil {
 			ret = fmt.Errorf("%v, %v", ret, err)
 		}
 		return ret
 	}
-	if parentCpus, parentMems, err := getCpusetSubsystemSettings(parent); err != nil {
+	if parentCpus, parentMems, err = getCpusetSubsystemSettings(parent); err != nil {
 		ret := fmt.Errorf("failed copy parent cgroup setting, %v", err)
 		if _, err := os.Stat(parent); err != nil {
 			ret = fmt.Errorf("%v, %v", ret, err)
diff --git a/libcontainer/cgroups/fs/files.go b/libcontainer/cgroups/fs/files.go
index 3315cda..9dcc54b 100644
--- a/libcontainer/cgroups/fs/files.go
+++ b/libcontainer/cgroups/fs/files.go
@@ -13,34 +13,29 @@ import (
 	"fmt"
 	"strconv"
 
+	"path/filepath"
+
 	"github.com/opencontainers/runc/libcontainer/cgroups"
 	"github.com/opencontainers/runc/libcontainer/configs"
-	"path/filepath"
 )
 
-type FilesGroup struct {
-}
+type FilesGroup struct{}
 
 func (s *FilesGroup) Name() string {
 	return "files"
 }
 
-func (s *FilesGroup) Apply(d *cgroupData) error {
-	_, err := d.join("files")
-	if err != nil && !cgroups.IsNotFound(err) {
-		return err
-	}
-	return nil
+func (s *FilesGroup) Apply(path string, _ *configs.Resources, pid int) error {
+	return apply(path, pid)
 }
 
-func (s *FilesGroup) Set(path string, cgroup *configs.Cgroup) error {
-	if cgroup.Resources.FilesLimit != 0 {
+func (s *FilesGroup) Set(path string, r *configs.Resources) error {
+	if r.FilesLimit != 0 {
 		// "max" is the fallback value.
 		limit := "max"
-		if cgroup.Resources.FilesLimit > 0 {
-			limit = strconv.FormatInt(cgroup.Resources.FilesLimit, 10)
+		if r.FilesLimit > 0 {
+			limit = strconv.FormatInt(r.FilesLimit, 10)
 		}
-
 		if err := writeFile(path, "files.limit", limit); err != nil {
 			return err
 		}
@@ -49,10 +44,6 @@ func (s *FilesGroup) Set(path string, cgroup *configs.Cgroup) error {
 	return nil
 }
 
-func (s *FilesGroup) Remove(d *cgroupData) error {
-	return removePath(d.path("files"))
-}
-
 func (s *FilesGroup) GetStats(path string, stats *cgroups.Stats) error {
 	usage, err := getCgroupParamUint(path, "files.usage")
 	if err != nil {
diff --git a/libcontainer/cgroups/fs/utils.go b/libcontainer/cgroups/fs/utils.go
new file mode 100644
index 0000000..38820a8
--- /dev/null
+++ b/libcontainer/cgroups/fs/utils.go
@@ -0,0 +1,97 @@
+// +build linux
+
+package fs
+
+import (
+	"errors"
+	"os"
+	"fmt"
+	"io/ioutil"
+	"path/filepath"
+	"strconv"
+	"strings"
+)
+
+var (
+	ErrNotValidFormat = errors.New("line is not a valid key value format")
+)
+
+// Saturates negative values at zero and returns a uint64.
+// Due to kernel bugs, some of the memory cgroup stats can be negative.
+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
+}
+
+// Parses a cgroup param and returns as name, value
+//  i.e. "io_service_bytes 1234" will return as io_service_bytes, 1234
+func getCgroupParamKeyValue(t string) (string, uint64, error) {
+	parts := strings.Fields(t)
+	switch len(parts) {
+	case 2:
+		value, err := parseUint(parts[1], 10, 64)
+		if err != nil {
+			return "", 0, fmt.Errorf("unable to convert param value (%q) to uint64: %v", parts[1], err)
+		}
+
+		return parts[0], value, nil
+	default:
+		return "", 0, ErrNotValidFormat
+	}
+}
+
+// Gets a single uint64 value from the specified cgroup file.
+func getCgroupParamUint(cgroupPath, cgroupFile string) (uint64, error) {
+	fileName := filepath.Join(cgroupPath, cgroupFile)
+	contents, err := ioutil.ReadFile(fileName)
+	if err != nil {
+		return 0, err
+	}
+
+	res, err := parseUint(strings.TrimSpace(string(contents)), 10, 64)
+	if err != nil {
+		return res, fmt.Errorf("unable to parse %q as a uint from Cgroup file %q", string(contents), fileName)
+	}
+	return res, nil
+}
+
+// Gets a string value from the specified cgroup file
+func getCgroupParamString(cgroupPath, cgroupFile string) (string, error) {
+	contents, err := ioutil.ReadFile(filepath.Join(cgroupPath, cgroupFile))
+	if err != nil {
+		return "", err
+	}
+
+	return strings.TrimSpace(string(contents)), nil
+}
+
+func writeFile(dir, file, data string) error {
+        // Normally dir should not be empty, one case is that cgroup subsystem
+        // is not mounted, we will get empty dir, and we want it fail here.
+        if dir == "" {
+                return fmt.Errorf("no such directory for %s", file)
+        }
+        if err := ioutil.WriteFile(filepath.Join(dir, file), []byte(data), 0700); err != nil {
+                ret := fmt.Errorf("failed to write %v to %v: %v", data, file, err)
+                if _, err = os.Stat(dir); err != nil {
+                        ret = fmt.Errorf("%v, failed to stat %v, %v", ret, dir, err)
+                }
+
+                return ret
+        }
+        return nil
+}
+
diff --git a/libcontainer/rootfs_linux.go b/libcontainer/rootfs_linux.go
index e7de071..499d753 100644
--- a/libcontainer/rootfs_linux.go
+++ b/libcontainer/rootfs_linux.go
@@ -10,6 +10,7 @@ import (
 	"path/filepath"
 	"strconv"
 	"strings"
+	"syscall"
 	"time"
 
 	securejoin "github.com/cyphar/filepath-securejoin"
diff --git a/libcontainer/standard_init_linux.go b/libcontainer/standard_init_linux.go
index 542edba..cd962c8 100644
--- a/libcontainer/standard_init_linux.go
+++ b/libcontainer/standard_init_linux.go
@@ -6,6 +6,8 @@ import (
 	"os"
 	"os/exec"
 	"strconv"
+	"strings"
+	"syscall"
 	"time"
 
 	"github.com/opencontainers/runtime-spec/specs-go"
@@ -260,11 +262,11 @@ func (l *linuxStandardInit) Init() error {
 	}()
 
 	select {
-	case chErr := <- ch:
+	case chErr := <-ch:
 		if chErr != nil {
 			return chErr
 		}
-	case <- time.After(120 * time.Second):
+	case <-time.After(120 * time.Second):
 		return fmt.Errorf("wait for the fifo to be opened on the other side timeout ")
 	}
 	// Close the O_PATH fifofd fd before exec because the kernel resets
-- 
2.33.0

