kmem.go 1.8 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556
  1. // +build linux,!nokmem
  2. package fs
  3. import (
  4. "fmt"
  5. "io/ioutil"
  6. "os"
  7. "path/filepath"
  8. "strconv"
  9. "syscall" // for Errno type only
  10. "github.com/opencontainers/runc/libcontainer/cgroups"
  11. "golang.org/x/sys/unix"
  12. )
  13. const cgroupKernelMemoryLimit = "memory.kmem.limit_in_bytes"
  14. func EnableKernelMemoryAccounting(path string) error {
  15. // Check if kernel memory is enabled
  16. // We have to limit the kernel memory here as it won't be accounted at all
  17. // until a limit is set on the cgroup and limit cannot be set once the
  18. // cgroup has children, or if there are already tasks in the cgroup.
  19. for _, i := range []int64{1, -1} {
  20. if err := setKernelMemory(path, i); err != nil {
  21. return err
  22. }
  23. }
  24. return nil
  25. }
  26. func setKernelMemory(path string, kernelMemoryLimit int64) error {
  27. if path == "" {
  28. return fmt.Errorf("no such directory for %s", cgroupKernelMemoryLimit)
  29. }
  30. if !cgroups.PathExists(filepath.Join(path, cgroupKernelMemoryLimit)) {
  31. // kernel memory is not enabled on the system so we should do nothing
  32. return nil
  33. }
  34. if err := ioutil.WriteFile(filepath.Join(path, cgroupKernelMemoryLimit), []byte(strconv.FormatInt(kernelMemoryLimit, 10)), 0700); err != nil {
  35. // Check if the error number returned by the syscall is "EBUSY"
  36. // The EBUSY signal is returned on attempts to write to the
  37. // memory.kmem.limit_in_bytes file if the cgroup has children or
  38. // once tasks have been attached to the cgroup
  39. if pathErr, ok := err.(*os.PathError); ok {
  40. if errNo, ok := pathErr.Err.(syscall.Errno); ok {
  41. if errNo == unix.EBUSY {
  42. return fmt.Errorf("failed to set %s, because either tasks have already joined this cgroup or it has children", cgroupKernelMemoryLimit)
  43. }
  44. }
  45. }
  46. return fmt.Errorf("failed to write %v to %v: %v", kernelMemoryLimit, cgroupKernelMemoryLimit, err)
  47. }
  48. return nil
  49. }