io.go 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  1. // +build linux
  2. package fs2
  3. import (
  4. "bufio"
  5. "os"
  6. "path/filepath"
  7. "strconv"
  8. "strings"
  9. "github.com/opencontainers/runc/libcontainer/cgroups"
  10. "github.com/opencontainers/runc/libcontainer/cgroups/fscommon"
  11. "github.com/opencontainers/runc/libcontainer/configs"
  12. )
  13. func setIo(dirPath string, cgroup *configs.Cgroup) error {
  14. if cgroup.Resources.BlkioWeight != 0 {
  15. filename := "io.bfq.weight"
  16. if err := fscommon.WriteFile(dirPath, filename, strconv.FormatUint(uint64(cgroup.Resources.BlkioWeight), 10)); err != nil {
  17. return err
  18. }
  19. }
  20. for _, td := range cgroup.Resources.BlkioThrottleReadBpsDevice {
  21. if err := fscommon.WriteFile(dirPath, "io.max", td.StringName("rbps")); err != nil {
  22. return err
  23. }
  24. }
  25. for _, td := range cgroup.Resources.BlkioThrottleWriteBpsDevice {
  26. if err := fscommon.WriteFile(dirPath, "io.max", td.StringName("wbps")); err != nil {
  27. return err
  28. }
  29. }
  30. for _, td := range cgroup.Resources.BlkioThrottleReadIOPSDevice {
  31. if err := fscommon.WriteFile(dirPath, "io.max", td.StringName("riops")); err != nil {
  32. return err
  33. }
  34. }
  35. for _, td := range cgroup.Resources.BlkioThrottleWriteIOPSDevice {
  36. if err := fscommon.WriteFile(dirPath, "io.max", td.StringName("wiops")); err != nil {
  37. return err
  38. }
  39. }
  40. return nil
  41. }
  42. func readCgroup2MapFile(dirPath string, name string) (map[string][]string, error) {
  43. ret := map[string][]string{}
  44. p := filepath.Join(dirPath, name)
  45. f, err := os.Open(p)
  46. if err != nil {
  47. return nil, err
  48. }
  49. defer f.Close()
  50. scanner := bufio.NewScanner(f)
  51. for scanner.Scan() {
  52. line := scanner.Text()
  53. parts := strings.Fields(line)
  54. if len(parts) < 2 {
  55. continue
  56. }
  57. ret[parts[0]] = parts[1:]
  58. }
  59. if err := scanner.Err(); err != nil {
  60. return nil, err
  61. }
  62. return ret, nil
  63. }
  64. func statIo(dirPath string, stats *cgroups.Stats) error {
  65. // more details on the io.stat file format: https://www.kernel.org/doc/Documentation/cgroup-v2.txt
  66. var ioServiceBytesRecursive []cgroups.BlkioStatEntry
  67. values, err := readCgroup2MapFile(dirPath, "io.stat")
  68. if err != nil {
  69. return err
  70. }
  71. for k, v := range values {
  72. d := strings.Split(k, ":")
  73. if len(d) != 2 {
  74. continue
  75. }
  76. minor, err := strconv.ParseUint(d[0], 10, 0)
  77. if err != nil {
  78. return err
  79. }
  80. major, err := strconv.ParseUint(d[1], 10, 0)
  81. if err != nil {
  82. return err
  83. }
  84. for _, item := range v {
  85. d := strings.Split(item, "=")
  86. if len(d) != 2 {
  87. continue
  88. }
  89. op := d[0]
  90. // Accommodate the cgroup v1 naming
  91. switch op {
  92. case "rbytes":
  93. op = "read"
  94. case "wbytes":
  95. op = "write"
  96. }
  97. value, err := strconv.ParseUint(d[1], 10, 0)
  98. if err != nil {
  99. return err
  100. }
  101. entry := cgroups.BlkioStatEntry{
  102. Op: op,
  103. Major: major,
  104. Minor: minor,
  105. Value: value,
  106. }
  107. ioServiceBytesRecursive = append(ioServiceBytesRecursive, entry)
  108. }
  109. }
  110. stats.BlkioStats = cgroups.BlkioStats{IoServiceBytesRecursive: ioServiceBytesRecursive}
  111. return nil
  112. }