| package fs2 |
| |
| import ( |
| "errors" |
| "math" |
| "os" |
| "strings" |
| |
| "golang.org/x/sys/unix" |
| |
| "github.com/opencontainers/runc/libcontainer/cgroups" |
| "github.com/opencontainers/runc/libcontainer/cgroups/fscommon" |
| "github.com/opencontainers/runc/libcontainer/configs" |
| ) |
| |
| func isPidsSet(r *configs.Resources) bool { |
| return r.PidsLimit != 0 |
| } |
| |
| func setPids(dirPath string, r *configs.Resources) error { |
| if !isPidsSet(r) { |
| return nil |
| } |
| if val := numToStr(r.PidsLimit); val != "" { |
| if err := cgroups.WriteFile(dirPath, "pids.max", val); err != nil { |
| return err |
| } |
| } |
| |
| return nil |
| } |
| |
| func statPidsFromCgroupProcs(dirPath string, stats *cgroups.Stats) error { |
| // if the controller is not enabled, let's read PIDS from cgroups.procs |
| // (or threads if cgroup.threads is enabled) |
| contents, err := cgroups.ReadFile(dirPath, "cgroup.procs") |
| if errors.Is(err, unix.ENOTSUP) { |
| contents, err = cgroups.ReadFile(dirPath, "cgroup.threads") |
| } |
| if err != nil { |
| return err |
| } |
| pids := strings.Count(contents, "\n") |
| stats.PidsStats.Current = uint64(pids) |
| stats.PidsStats.Limit = 0 |
| return nil |
| } |
| |
| func statPids(dirPath string, stats *cgroups.Stats) error { |
| current, err := fscommon.GetCgroupParamUint(dirPath, "pids.current") |
| if err != nil { |
| if os.IsNotExist(err) { |
| return statPidsFromCgroupProcs(dirPath, stats) |
| } |
| return err |
| } |
| |
| max, err := fscommon.GetCgroupParamUint(dirPath, "pids.max") |
| if err != nil { |
| return err |
| } |
| // If no limit is set, read from pids.max returns "max", which is |
| // converted to MaxUint64 by GetCgroupParamUint. Historically, we |
| // represent "no limit" for pids as 0, thus this conversion. |
| if max == math.MaxUint64 { |
| max = 0 |
| } |
| |
| stats.PidsStats.Current = current |
| stats.PidsStats.Limit = max |
| return nil |
| } |