123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131 |
- // +build linux
- /*
- Copyright 2015 The Kubernetes Authors.
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
- http://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- */
- package oom
- import (
- "fmt"
- "io/ioutil"
- "os"
- "path"
- "path/filepath"
- "strconv"
- "time"
- cmutil "k8s.io/kubernetes/pkg/kubelet/cm/util"
- "k8s.io/klog"
- )
- func NewOOMAdjuster() *OOMAdjuster {
- oomAdjuster := &OOMAdjuster{
- pidLister: getPids,
- ApplyOOMScoreAdj: applyOOMScoreAdj,
- }
- oomAdjuster.ApplyOOMScoreAdjContainer = oomAdjuster.applyOOMScoreAdjContainer
- return oomAdjuster
- }
- func getPids(cgroupName string) ([]int, error) {
- return cmutil.GetPids(filepath.Join("/", cgroupName))
- }
- // Writes 'value' to /proc/<pid>/oom_score_adj. PID = 0 means self
- // Returns os.ErrNotExist if the `pid` does not exist.
- func applyOOMScoreAdj(pid int, oomScoreAdj int) error {
- if pid < 0 {
- return fmt.Errorf("invalid PID %d specified for oom_score_adj", pid)
- }
- var pidStr string
- if pid == 0 {
- pidStr = "self"
- } else {
- pidStr = strconv.Itoa(pid)
- }
- maxTries := 2
- oomScoreAdjPath := path.Join("/proc", pidStr, "oom_score_adj")
- value := strconv.Itoa(oomScoreAdj)
- klog.V(4).Infof("attempting to set %q to %q", oomScoreAdjPath, value)
- var err error
- for i := 0; i < maxTries; i++ {
- err = ioutil.WriteFile(oomScoreAdjPath, []byte(value), 0700)
- if err != nil {
- if os.IsNotExist(err) {
- klog.V(2).Infof("%q does not exist", oomScoreAdjPath)
- return os.ErrNotExist
- }
- klog.V(3).Info(err)
- time.Sleep(100 * time.Millisecond)
- continue
- }
- return nil
- }
- if err != nil {
- klog.V(2).Infof("failed to set %q to %q: %v", oomScoreAdjPath, value, err)
- }
- return err
- }
- // Writes 'value' to /proc/<pid>/oom_score_adj for all processes in cgroup cgroupName.
- // Keeps trying to write until the process list of the cgroup stabilizes, or until maxTries tries.
- func (oomAdjuster *OOMAdjuster) applyOOMScoreAdjContainer(cgroupName string, oomScoreAdj, maxTries int) error {
- adjustedProcessSet := make(map[int]bool)
- for i := 0; i < maxTries; i++ {
- continueAdjusting := false
- pidList, err := oomAdjuster.pidLister(cgroupName)
- if err != nil {
- if os.IsNotExist(err) {
- // Nothing to do since the container doesn't exist anymore.
- return os.ErrNotExist
- }
- continueAdjusting = true
- klog.V(10).Infof("Error getting process list for cgroup %s: %+v", cgroupName, err)
- } else if len(pidList) == 0 {
- klog.V(10).Infof("Pid list is empty")
- continueAdjusting = true
- } else {
- for _, pid := range pidList {
- if !adjustedProcessSet[pid] {
- klog.V(10).Infof("pid %d needs to be set", pid)
- if err = oomAdjuster.ApplyOOMScoreAdj(pid, oomScoreAdj); err == nil {
- adjustedProcessSet[pid] = true
- } else if err == os.ErrNotExist {
- continue
- } else {
- klog.V(10).Infof("cannot adjust oom score for pid %d - %v", pid, err)
- continueAdjusting = true
- }
- // Processes can come and go while we try to apply oom score adjust value. So ignore errors here.
- }
- }
- }
- if !continueAdjusting {
- return nil
- }
- // There's a slight race. A process might have forked just before we write its OOM score adjust.
- // The fork might copy the parent process's old OOM score, then this function might execute and
- // update the parent's OOM score, but the forked process id might not be reflected in cgroup.procs
- // for a short amount of time. So this function might return without changing the forked process's
- // OOM score. Very unlikely race, so ignoring this for now.
- }
- return fmt.Errorf("exceeded maxTries, some processes might not have desired OOM score")
- }
|