try to fix root ownership
Some checks failed
memory-limit / Build judge (push) Successful in 13s
memory-limit / Linux / clang (push) Failing after 10s
memory-limit / Linux / gcc (push) Failing after 10s
memory-limit / Windows / clang (push) Failing after 13s
memory-limit / Windows / msvc (push) Failing after 13s
Some checks failed
memory-limit / Build judge (push) Successful in 13s
memory-limit / Linux / clang (push) Failing after 10s
memory-limit / Linux / gcc (push) Failing after 10s
memory-limit / Windows / clang (push) Failing after 13s
memory-limit / Windows / msvc (push) Failing after 13s
This commit is contained in:
@@ -17,6 +17,7 @@ import (
|
|||||||
var (
|
var (
|
||||||
cgroupRootOnce sync.Once
|
cgroupRootOnce sync.Once
|
||||||
cgroupRoot string
|
cgroupRoot string
|
||||||
|
cgroupRootOwned bool
|
||||||
cgroupInitErr error
|
cgroupInitErr error
|
||||||
cgroupCounter int64
|
cgroupCounter int64
|
||||||
)
|
)
|
||||||
@@ -25,10 +26,80 @@ const cgroupFSRoot = "/sys/fs/cgroup"
|
|||||||
|
|
||||||
func ensureCgroupRoot() (string, error) {
|
func ensureCgroupRoot() (string, error) {
|
||||||
cgroupRootOnce.Do(func() {
|
cgroupRootOnce.Do(func() {
|
||||||
|
if root, err := createOwnedCgroup(); err == nil {
|
||||||
|
cgroupRoot = root
|
||||||
|
cgroupRootOwned = true
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
root, err := createScopeCgroup()
|
||||||
|
if err != nil {
|
||||||
|
cgroupInitErr = err
|
||||||
|
return
|
||||||
|
}
|
||||||
|
cgroupRoot = root
|
||||||
|
})
|
||||||
|
return cgroupRoot, cgroupInitErr
|
||||||
|
}
|
||||||
|
|
||||||
|
func hasController(path, name string) (bool, error) {
|
||||||
|
data, err := os.ReadFile(path)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
needle := " " + name + " "
|
||||||
|
return strings.Contains(" "+strings.TrimSpace(string(data))+" ", needle), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func createOwnedCgroup() (string, error) {
|
||||||
|
ok, err := hasController(filepath.Join(cgroupFSRoot, "cgroup.controllers"), "memory")
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
if !ok {
|
||||||
|
return "", fmt.Errorf("memory controller not available in root cgroup")
|
||||||
|
}
|
||||||
|
|
||||||
|
enabled, err := hasController(filepath.Join(cgroupFSRoot, "cgroup.subtree_control"), "memory")
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
if !enabled {
|
||||||
|
if err := os.WriteFile(filepath.Join(cgroupFSRoot, "cgroup.subtree_control"), []byte("+memory"), 0644); err != nil {
|
||||||
|
return "", fmt.Errorf("enable +memory in root subtree_control: %w", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
name := fmt.Sprintf("judge.%d", os.Getpid())
|
||||||
|
root := filepath.Join(cgroupFSRoot, name)
|
||||||
|
if err := os.Mkdir(root, 0755); err != nil {
|
||||||
|
if os.IsExist(err) {
|
||||||
|
} else {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ok, err = hasController(filepath.Join(root, "cgroup.controllers"), "memory")
|
||||||
|
if err != nil {
|
||||||
|
_ = os.Remove(root)
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
if !ok {
|
||||||
|
_ = os.Remove(root)
|
||||||
|
return "", fmt.Errorf("memory controller not inherited into %s", root)
|
||||||
|
}
|
||||||
|
if err := os.WriteFile(filepath.Join(root, "cgroup.subtree_control"), []byte("+memory"), 0644); err != nil {
|
||||||
|
_ = os.Remove(root)
|
||||||
|
return "", fmt.Errorf("enable +memory in %s: %w", root, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return root, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func createScopeCgroup() (string, error) {
|
||||||
data, err := os.ReadFile("/proc/self/cgroup")
|
data, err := os.ReadFile("/proc/self/cgroup")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
cgroupInitErr = fmt.Errorf("read /proc/self/cgroup: %w", err)
|
return "", fmt.Errorf("read /proc/self/cgroup: %w", err)
|
||||||
return
|
|
||||||
}
|
}
|
||||||
var rel string
|
var rel string
|
||||||
for _, line := range strings.Split(strings.TrimSpace(string(data)), "\n") {
|
for _, line := range strings.Split(strings.TrimSpace(string(data)), "\n") {
|
||||||
@@ -38,42 +109,42 @@ func ensureCgroupRoot() (string, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if rel == "" {
|
if rel == "" {
|
||||||
cgroupInitErr = fmt.Errorf("cgroup v2 not found in /proc/self/cgroup (unified hierarchy required)")
|
return "", fmt.Errorf("cgroup v2 not found in /proc/self/cgroup (unified hierarchy required)")
|
||||||
return
|
|
||||||
}
|
}
|
||||||
ownCg := filepath.Join(cgroupFSRoot, rel)
|
ownCg := filepath.Join(cgroupFSRoot, rel)
|
||||||
|
|
||||||
controllers, err := os.ReadFile(filepath.Join(ownCg, "cgroup.controllers"))
|
ok, err := hasController(filepath.Join(ownCg, "cgroup.controllers"), "memory")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
cgroupInitErr = fmt.Errorf("cgroup %s not accessible: %w", ownCg, err)
|
return "", fmt.Errorf("cgroup %s not accessible: %w", ownCg, err)
|
||||||
return
|
|
||||||
}
|
}
|
||||||
if !strings.Contains(" "+string(controllers)+" ", " memory ") {
|
if !ok {
|
||||||
cgroupInitErr = fmt.Errorf("memory controller not delegated to %s (controllers: %s)", ownCg, strings.TrimSpace(string(controllers)))
|
return "", fmt.Errorf("memory controller not delegated to %s", ownCg)
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
initCg := filepath.Join(ownCg, "judge.init")
|
initCg := filepath.Join(ownCg, "judge.init")
|
||||||
if err := os.MkdirAll(initCg, 0755); err != nil {
|
if err := os.MkdirAll(initCg, 0755); err != nil {
|
||||||
cgroupInitErr = fmt.Errorf("mkdir %s: %w", initCg, err)
|
return "", fmt.Errorf("mkdir %s: %w", initCg, err)
|
||||||
return
|
|
||||||
}
|
}
|
||||||
if err := os.WriteFile(filepath.Join(initCg, "cgroup.procs"), []byte(strconv.Itoa(os.Getpid())), 0644); err != nil {
|
if err := os.WriteFile(filepath.Join(initCg, "cgroup.procs"), []byte(strconv.Itoa(os.Getpid())), 0644); err != nil {
|
||||||
cgroupInitErr = fmt.Errorf("move judge into %s: %w", initCg, err)
|
return "", fmt.Errorf("move judge into %s: %w", initCg, err)
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := os.WriteFile(filepath.Join(ownCg, "cgroup.subtree_control"), []byte("+memory"), 0644); err != nil {
|
if err := os.WriteFile(filepath.Join(ownCg, "cgroup.subtree_control"), []byte("+memory"), 0644); err != nil {
|
||||||
current, _ := os.ReadFile(filepath.Join(ownCg, "cgroup.subtree_control"))
|
enabled, _ := hasController(filepath.Join(ownCg, "cgroup.subtree_control"), "memory")
|
||||||
if !strings.Contains(" "+string(current)+" ", " memory ") {
|
if !enabled {
|
||||||
cgroupInitErr = fmt.Errorf("enable +memory in %s/cgroup.subtree_control: %w", ownCg, err)
|
return "", fmt.Errorf("enable +memory in %s/cgroup.subtree_control: %w", ownCg, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ownCg, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func cleanupCgroupRoot() {
|
||||||
|
if cgroupRoot == "" || !cgroupRootOwned {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
_ = os.Remove(cgroupRoot)
|
||||||
|
cgroupRoot = ""
|
||||||
cgroupRoot = ownCg
|
cgroupRootOwned = false
|
||||||
})
|
|
||||||
return cgroupRoot, cgroupInitErr
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type linuxLimiter struct {
|
type linuxLimiter struct {
|
||||||
|
|||||||
@@ -25,3 +25,5 @@ func (l *noopLimiter) prepare(cmd *exec.Cmd) error {
|
|||||||
func (l *noopLimiter) afterStart(cmd *exec.Cmd) error { return nil }
|
func (l *noopLimiter) afterStart(cmd *exec.Cmd) error { return nil }
|
||||||
func (l *noopLimiter) collect() limitStats { return limitStats{} }
|
func (l *noopLimiter) collect() limitStats { return limitStats{} }
|
||||||
func (l *noopLimiter) cleanup() {}
|
func (l *noopLimiter) cleanup() {}
|
||||||
|
|
||||||
|
func cleanupCgroupRoot() {}
|
||||||
|
|||||||
@@ -132,3 +132,5 @@ func (l *windowsLimiter) cleanup() {
|
|||||||
l.job = 0
|
l.job = 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func cleanupCgroupRoot() {}
|
||||||
|
|||||||
@@ -59,6 +59,8 @@ func resolveBinary(workDir, name string) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (r *Runner) Run() *SuiteResult {
|
func (r *Runner) Run() *SuiteResult {
|
||||||
|
defer cleanupCgroupRoot()
|
||||||
|
|
||||||
result := &SuiteResult{}
|
result := &SuiteResult{}
|
||||||
|
|
||||||
buildLog, err := r.build()
|
buildLog, err := r.build()
|
||||||
|
|||||||
Reference in New Issue
Block a user