...

Source file src/github.com/containerd/cgroups/cpuset.go

Documentation: github.com/containerd/cgroups

     1  /*
     2     Copyright The containerd Authors.
     3  
     4     Licensed under the Apache License, Version 2.0 (the "License");
     5     you may not use this file except in compliance with the License.
     6     You may obtain a copy of the License at
     7  
     8         http://www.apache.org/licenses/LICENSE-2.0
     9  
    10     Unless required by applicable law or agreed to in writing, software
    11     distributed under the License is distributed on an "AS IS" BASIS,
    12     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13     See the License for the specific language governing permissions and
    14     limitations under the License.
    15  */
    16  
    17  package cgroups
    18  
    19  import (
    20  	"bytes"
    21  	"fmt"
    22  	"os"
    23  	"path/filepath"
    24  
    25  	specs "github.com/opencontainers/runtime-spec/specs-go"
    26  )
    27  
    28  func NewCpuset(root string) *cpusetController {
    29  	return &cpusetController{
    30  		root: filepath.Join(root, string(Cpuset)),
    31  	}
    32  }
    33  
    34  type cpusetController struct {
    35  	root string
    36  }
    37  
    38  func (c *cpusetController) Name() Name {
    39  	return Cpuset
    40  }
    41  
    42  func (c *cpusetController) Path(path string) string {
    43  	return filepath.Join(c.root, path)
    44  }
    45  
    46  func (c *cpusetController) Create(path string, resources *specs.LinuxResources) error {
    47  	if err := c.ensureParent(c.Path(path), c.root); err != nil {
    48  		return err
    49  	}
    50  	if err := os.MkdirAll(c.Path(path), defaultDirPerm); err != nil {
    51  		return err
    52  	}
    53  	if err := c.copyIfNeeded(c.Path(path), filepath.Dir(c.Path(path))); err != nil {
    54  		return err
    55  	}
    56  	if resources.CPU != nil {
    57  		for _, t := range []struct {
    58  			name  string
    59  			value string
    60  		}{
    61  			{
    62  				name:  "cpus",
    63  				value: resources.CPU.Cpus,
    64  			},
    65  			{
    66  				name:  "mems",
    67  				value: resources.CPU.Mems,
    68  			},
    69  		} {
    70  			if t.value != "" {
    71  				if err := retryingWriteFile(
    72  					filepath.Join(c.Path(path), "cpuset."+t.name),
    73  					[]byte(t.value),
    74  					defaultFilePerm,
    75  				); err != nil {
    76  					return err
    77  				}
    78  			}
    79  		}
    80  	}
    81  	return nil
    82  }
    83  
    84  func (c *cpusetController) Update(path string, resources *specs.LinuxResources) error {
    85  	return c.Create(path, resources)
    86  }
    87  
    88  func (c *cpusetController) getValues(path string) (cpus []byte, mems []byte, err error) {
    89  	if cpus, err = os.ReadFile(filepath.Join(path, "cpuset.cpus")); err != nil && !os.IsNotExist(err) {
    90  		return
    91  	}
    92  	if mems, err = os.ReadFile(filepath.Join(path, "cpuset.mems")); err != nil && !os.IsNotExist(err) {
    93  		return
    94  	}
    95  	return cpus, mems, nil
    96  }
    97  
    98  // ensureParent makes sure that the parent directory of current is created
    99  // and populated with the proper cpus and mems files copied from
   100  // it's parent.
   101  func (c *cpusetController) ensureParent(current, root string) error {
   102  	parent := filepath.Dir(current)
   103  	if _, err := filepath.Rel(root, parent); err != nil {
   104  		return nil
   105  	}
   106  	// Avoid infinite recursion.
   107  	if parent == current {
   108  		return fmt.Errorf("cpuset: cgroup parent path outside cgroup root")
   109  	}
   110  	if cleanPath(parent) != root {
   111  		if err := c.ensureParent(parent, root); err != nil {
   112  			return err
   113  		}
   114  	}
   115  	if err := os.MkdirAll(current, defaultDirPerm); err != nil {
   116  		return err
   117  	}
   118  	return c.copyIfNeeded(current, parent)
   119  }
   120  
   121  // copyIfNeeded copies the cpuset.cpus and cpuset.mems from the parent
   122  // directory to the current directory if the file's contents are 0
   123  func (c *cpusetController) copyIfNeeded(current, parent string) error {
   124  	var (
   125  		err                      error
   126  		currentCpus, currentMems []byte
   127  		parentCpus, parentMems   []byte
   128  	)
   129  	if currentCpus, currentMems, err = c.getValues(current); err != nil {
   130  		return err
   131  	}
   132  	if parentCpus, parentMems, err = c.getValues(parent); err != nil {
   133  		return err
   134  	}
   135  	if isEmpty(currentCpus) {
   136  		if err := retryingWriteFile(
   137  			filepath.Join(current, "cpuset.cpus"),
   138  			parentCpus,
   139  			defaultFilePerm,
   140  		); err != nil {
   141  			return err
   142  		}
   143  	}
   144  	if isEmpty(currentMems) {
   145  		if err := retryingWriteFile(
   146  			filepath.Join(current, "cpuset.mems"),
   147  			parentMems,
   148  			defaultFilePerm,
   149  		); err != nil {
   150  			return err
   151  		}
   152  	}
   153  	return nil
   154  }
   155  
   156  func isEmpty(b []byte) bool {
   157  	return len(bytes.Trim(b, "\n")) == 0
   158  }
   159  

View as plain text