13 "github.com/opencontainers/runc/libcontainer/cgroups"
14 "github.com/opencontainers/runc/libcontainer/configs"
17 type BlkioGroup struct {
20 func (s *BlkioGroup) Name() string {
24 func (s *BlkioGroup) Apply(d *cgroupData) error {
25 _, err := d.join("blkio")
26 if err != nil && !cgroups.IsNotFound(err) {
32 func (s *BlkioGroup) Set(path string, cgroup *configs.Cgroup) error {
33 if cgroup.Resources.BlkioWeight != 0 {
34 if err := writeFile(path, "blkio.weight", strconv.FormatUint(uint64(cgroup.Resources.BlkioWeight), 10)); err != nil {
39 if cgroup.Resources.BlkioLeafWeight != 0 {
40 if err := writeFile(path, "blkio.leaf_weight", strconv.FormatUint(uint64(cgroup.Resources.BlkioLeafWeight), 10)); err != nil {
44 for _, wd := range cgroup.Resources.BlkioWeightDevice {
45 if err := writeFile(path, "blkio.weight_device", wd.WeightString()); err != nil {
48 if err := writeFile(path, "blkio.leaf_weight_device", wd.LeafWeightString()); err != nil {
52 for _, td := range cgroup.Resources.BlkioThrottleReadBpsDevice {
53 if err := writeFile(path, "blkio.throttle.read_bps_device", td.String()); err != nil {
57 for _, td := range cgroup.Resources.BlkioThrottleWriteBpsDevice {
58 if err := writeFile(path, "blkio.throttle.write_bps_device", td.String()); err != nil {
62 for _, td := range cgroup.Resources.BlkioThrottleReadIOPSDevice {
63 if err := writeFile(path, "blkio.throttle.read_iops_device", td.String()); err != nil {
67 for _, td := range cgroup.Resources.BlkioThrottleWriteIOPSDevice {
68 if err := writeFile(path, "blkio.throttle.write_iops_device", td.String()); err != nil {
76 func (s *BlkioGroup) Remove(d *cgroupData) error {
77 return removePath(d.path("blkio"))
86 blkio.io_service_bytes
111 func splitBlkioStatLine(r rune) bool {
112 return r == ' ' || r == ':'
115 func getBlkioStat(path string) ([]cgroups.BlkioStatEntry, error) {
116 var blkioStats []cgroups.BlkioStatEntry
117 f, err := os.Open(path)
119 if os.IsNotExist(err) {
120 return blkioStats, nil
126 sc := bufio.NewScanner(f)
128 // format: dev type amount
129 fields := strings.FieldsFunc(sc.Text(), splitBlkioStatLine)
131 if len(fields) == 2 && fields[0] == "Total" {
135 return nil, fmt.Errorf("Invalid line found while parsing %s: %s", path, sc.Text())
139 v, err := strconv.ParseUint(fields[0], 10, 64)
145 v, err = strconv.ParseUint(fields[1], 10, 64)
153 if len(fields) == 4 {
157 v, err = strconv.ParseUint(fields[valueField], 10, 64)
161 blkioStats = append(blkioStats, cgroups.BlkioStatEntry{Major: major, Minor: minor, Op: op, Value: v})
164 return blkioStats, nil
167 func (s *BlkioGroup) GetStats(path string, stats *cgroups.Stats) error {
168 // Try to read CFQ stats available on all CFQ enabled kernels first
169 if blkioStats, err := getBlkioStat(filepath.Join(path, "blkio.io_serviced_recursive")); err == nil && blkioStats != nil {
170 return getCFQStats(path, stats)
172 return getStats(path, stats) // Use generic stats as fallback
175 func getCFQStats(path string, stats *cgroups.Stats) error {
176 var blkioStats []cgroups.BlkioStatEntry
179 if blkioStats, err = getBlkioStat(filepath.Join(path, "blkio.sectors_recursive")); err != nil {
182 stats.BlkioStats.SectorsRecursive = blkioStats
184 if blkioStats, err = getBlkioStat(filepath.Join(path, "blkio.io_service_bytes_recursive")); err != nil {
187 stats.BlkioStats.IoServiceBytesRecursive = blkioStats
189 if blkioStats, err = getBlkioStat(filepath.Join(path, "blkio.io_serviced_recursive")); err != nil {
192 stats.BlkioStats.IoServicedRecursive = blkioStats
194 if blkioStats, err = getBlkioStat(filepath.Join(path, "blkio.io_queued_recursive")); err != nil {
197 stats.BlkioStats.IoQueuedRecursive = blkioStats
199 if blkioStats, err = getBlkioStat(filepath.Join(path, "blkio.io_service_time_recursive")); err != nil {
202 stats.BlkioStats.IoServiceTimeRecursive = blkioStats
204 if blkioStats, err = getBlkioStat(filepath.Join(path, "blkio.io_wait_time_recursive")); err != nil {
207 stats.BlkioStats.IoWaitTimeRecursive = blkioStats
209 if blkioStats, err = getBlkioStat(filepath.Join(path, "blkio.io_merged_recursive")); err != nil {
212 stats.BlkioStats.IoMergedRecursive = blkioStats
214 if blkioStats, err = getBlkioStat(filepath.Join(path, "blkio.time_recursive")); err != nil {
217 stats.BlkioStats.IoTimeRecursive = blkioStats
222 func getStats(path string, stats *cgroups.Stats) error {
223 var blkioStats []cgroups.BlkioStatEntry
226 if blkioStats, err = getBlkioStat(filepath.Join(path, "blkio.throttle.io_service_bytes")); err != nil {
229 stats.BlkioStats.IoServiceBytesRecursive = blkioStats
231 if blkioStats, err = getBlkioStat(filepath.Join(path, "blkio.throttle.io_serviced")); err != nil {
234 stats.BlkioStats.IoServicedRecursive = blkioStats