Tizen_4.0 base
[platform/upstream/docker-engine.git] / vendor / github.com / opencontainers / runc / libcontainer / cgroups / fs / blkio.go
1 // +build linux
2
3 package fs
4
5 import (
6         "bufio"
7         "fmt"
8         "os"
9         "path/filepath"
10         "strconv"
11         "strings"
12
13         "github.com/opencontainers/runc/libcontainer/cgroups"
14         "github.com/opencontainers/runc/libcontainer/configs"
15 )
16
17 type BlkioGroup struct {
18 }
19
20 func (s *BlkioGroup) Name() string {
21         return "blkio"
22 }
23
24 func (s *BlkioGroup) Apply(d *cgroupData) error {
25         _, err := d.join("blkio")
26         if err != nil && !cgroups.IsNotFound(err) {
27                 return err
28         }
29         return nil
30 }
31
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 {
35                         return err
36                 }
37         }
38
39         if cgroup.Resources.BlkioLeafWeight != 0 {
40                 if err := writeFile(path, "blkio.leaf_weight", strconv.FormatUint(uint64(cgroup.Resources.BlkioLeafWeight), 10)); err != nil {
41                         return err
42                 }
43         }
44         for _, wd := range cgroup.Resources.BlkioWeightDevice {
45                 if err := writeFile(path, "blkio.weight_device", wd.WeightString()); err != nil {
46                         return err
47                 }
48                 if err := writeFile(path, "blkio.leaf_weight_device", wd.LeafWeightString()); err != nil {
49                         return err
50                 }
51         }
52         for _, td := range cgroup.Resources.BlkioThrottleReadBpsDevice {
53                 if err := writeFile(path, "blkio.throttle.read_bps_device", td.String()); err != nil {
54                         return err
55                 }
56         }
57         for _, td := range cgroup.Resources.BlkioThrottleWriteBpsDevice {
58                 if err := writeFile(path, "blkio.throttle.write_bps_device", td.String()); err != nil {
59                         return err
60                 }
61         }
62         for _, td := range cgroup.Resources.BlkioThrottleReadIOPSDevice {
63                 if err := writeFile(path, "blkio.throttle.read_iops_device", td.String()); err != nil {
64                         return err
65                 }
66         }
67         for _, td := range cgroup.Resources.BlkioThrottleWriteIOPSDevice {
68                 if err := writeFile(path, "blkio.throttle.write_iops_device", td.String()); err != nil {
69                         return err
70                 }
71         }
72
73         return nil
74 }
75
76 func (s *BlkioGroup) Remove(d *cgroupData) error {
77         return removePath(d.path("blkio"))
78 }
79
80 /*
81 examples:
82
83     blkio.sectors
84     8:0 6792
85
86     blkio.io_service_bytes
87     8:0 Read 1282048
88     8:0 Write 2195456
89     8:0 Sync 2195456
90     8:0 Async 1282048
91     8:0 Total 3477504
92     Total 3477504
93
94     blkio.io_serviced
95     8:0 Read 124
96     8:0 Write 104
97     8:0 Sync 104
98     8:0 Async 124
99     8:0 Total 228
100     Total 228
101
102     blkio.io_queued
103     8:0 Read 0
104     8:0 Write 0
105     8:0 Sync 0
106     8:0 Async 0
107     8:0 Total 0
108     Total 0
109 */
110
111 func splitBlkioStatLine(r rune) bool {
112         return r == ' ' || r == ':'
113 }
114
115 func getBlkioStat(path string) ([]cgroups.BlkioStatEntry, error) {
116         var blkioStats []cgroups.BlkioStatEntry
117         f, err := os.Open(path)
118         if err != nil {
119                 if os.IsNotExist(err) {
120                         return blkioStats, nil
121                 }
122                 return nil, err
123         }
124         defer f.Close()
125
126         sc := bufio.NewScanner(f)
127         for sc.Scan() {
128                 // format: dev type amount
129                 fields := strings.FieldsFunc(sc.Text(), splitBlkioStatLine)
130                 if len(fields) < 3 {
131                         if len(fields) == 2 && fields[0] == "Total" {
132                                 // skip total line
133                                 continue
134                         } else {
135                                 return nil, fmt.Errorf("Invalid line found while parsing %s: %s", path, sc.Text())
136                         }
137                 }
138
139                 v, err := strconv.ParseUint(fields[0], 10, 64)
140                 if err != nil {
141                         return nil, err
142                 }
143                 major := v
144
145                 v, err = strconv.ParseUint(fields[1], 10, 64)
146                 if err != nil {
147                         return nil, err
148                 }
149                 minor := v
150
151                 op := ""
152                 valueField := 2
153                 if len(fields) == 4 {
154                         op = fields[2]
155                         valueField = 3
156                 }
157                 v, err = strconv.ParseUint(fields[valueField], 10, 64)
158                 if err != nil {
159                         return nil, err
160                 }
161                 blkioStats = append(blkioStats, cgroups.BlkioStatEntry{Major: major, Minor: minor, Op: op, Value: v})
162         }
163
164         return blkioStats, nil
165 }
166
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)
171         }
172         return getStats(path, stats) // Use generic stats as fallback
173 }
174
175 func getCFQStats(path string, stats *cgroups.Stats) error {
176         var blkioStats []cgroups.BlkioStatEntry
177         var err error
178
179         if blkioStats, err = getBlkioStat(filepath.Join(path, "blkio.sectors_recursive")); err != nil {
180                 return err
181         }
182         stats.BlkioStats.SectorsRecursive = blkioStats
183
184         if blkioStats, err = getBlkioStat(filepath.Join(path, "blkio.io_service_bytes_recursive")); err != nil {
185                 return err
186         }
187         stats.BlkioStats.IoServiceBytesRecursive = blkioStats
188
189         if blkioStats, err = getBlkioStat(filepath.Join(path, "blkio.io_serviced_recursive")); err != nil {
190                 return err
191         }
192         stats.BlkioStats.IoServicedRecursive = blkioStats
193
194         if blkioStats, err = getBlkioStat(filepath.Join(path, "blkio.io_queued_recursive")); err != nil {
195                 return err
196         }
197         stats.BlkioStats.IoQueuedRecursive = blkioStats
198
199         if blkioStats, err = getBlkioStat(filepath.Join(path, "blkio.io_service_time_recursive")); err != nil {
200                 return err
201         }
202         stats.BlkioStats.IoServiceTimeRecursive = blkioStats
203
204         if blkioStats, err = getBlkioStat(filepath.Join(path, "blkio.io_wait_time_recursive")); err != nil {
205                 return err
206         }
207         stats.BlkioStats.IoWaitTimeRecursive = blkioStats
208
209         if blkioStats, err = getBlkioStat(filepath.Join(path, "blkio.io_merged_recursive")); err != nil {
210                 return err
211         }
212         stats.BlkioStats.IoMergedRecursive = blkioStats
213
214         if blkioStats, err = getBlkioStat(filepath.Join(path, "blkio.time_recursive")); err != nil {
215                 return err
216         }
217         stats.BlkioStats.IoTimeRecursive = blkioStats
218
219         return nil
220 }
221
222 func getStats(path string, stats *cgroups.Stats) error {
223         var blkioStats []cgroups.BlkioStatEntry
224         var err error
225
226         if blkioStats, err = getBlkioStat(filepath.Join(path, "blkio.throttle.io_service_bytes")); err != nil {
227                 return err
228         }
229         stats.BlkioStats.IoServiceBytesRecursive = blkioStats
230
231         if blkioStats, err = getBlkioStat(filepath.Join(path, "blkio.throttle.io_serviced")); err != nil {
232                 return err
233         }
234         stats.BlkioStats.IoServicedRecursive = blkioStats
235
236         return nil
237 }