Browse code

Add support for blkio read/write iops device

Signed-off-by: Ma Shimiao <mashimiao.fnst@cn.fujitsu.com>

Ma Shimiao authored on 2015/07/08 20:06:48
Showing 19 changed files
... ...
@@ -1389,7 +1389,9 @@ _docker_run() {
1389 1389
 		--cpu-shares
1390 1390
 		--device
1391 1391
 		--device-read-bps
1392
+		--device-read-iops
1392 1393
 		--device-write-bps
1394
+		--device-write-iops
1393 1395
 		--dns
1394 1396
 		--dns-opt
1395 1397
 		--dns-search
... ...
@@ -469,7 +469,9 @@ __docker_subcommand() {
469 469
         "($help)--cidfile=[Write the container ID to the file]:CID file:_files"
470 470
         "($help)*--device=[Add a host device to the container]:device:_files"
471 471
         "($help)*--device-read-bps=[Limit the read rate (bytes per second) from a device]:device:IO rate: "
472
+        "($help)*--device-read-iops=[Limit the read rate (IO per second) from a device]:device:IO rate: "
472 473
         "($help)*--device-write-bps=[Limit the write rate (bytes per second) to a device]:device:IO rate: "
474
+        "($help)*--device-write-iops=[Limit the write rate (IO per second) to a device]:device:IO rate: "
473 475
         "($help)*--dns=[Set custom DNS servers]:DNS server: "
474 476
         "($help)*--dns-opt=[Set custom DNS options]:DNS option: "
475 477
         "($help)*--dns-search=[Set custom DNS search domains]:DNS domains: "
... ...
@@ -174,6 +174,16 @@ func (daemon *Daemon) populateCommand(c *container.Container, env []string) erro
174 174
 		return err
175 175
 	}
176 176
 
177
+	readIOpsDevice, err := getBlkioReadIOpsDevices(c.HostConfig)
178
+	if err != nil {
179
+		return err
180
+	}
181
+
182
+	writeIOpsDevice, err := getBlkioWriteIOpsDevices(c.HostConfig)
183
+	if err != nil {
184
+		return err
185
+	}
186
+
177 187
 	for _, limit := range ulimits {
178 188
 		rl, err := limit.GetRlimit()
179 189
 		if err != nil {
... ...
@@ -189,18 +199,20 @@ func (daemon *Daemon) populateCommand(c *container.Container, env []string) erro
189 189
 			CPUShares:         c.HostConfig.CPUShares,
190 190
 			BlkioWeight:       c.HostConfig.BlkioWeight,
191 191
 		},
192
-		MemorySwap:                  c.HostConfig.MemorySwap,
193
-		KernelMemory:                c.HostConfig.KernelMemory,
194
-		CpusetCpus:                  c.HostConfig.CpusetCpus,
195
-		CpusetMems:                  c.HostConfig.CpusetMems,
196
-		CPUPeriod:                   c.HostConfig.CPUPeriod,
197
-		CPUQuota:                    c.HostConfig.CPUQuota,
198
-		Rlimits:                     rlimits,
199
-		BlkioWeightDevice:           weightDevices,
200
-		BlkioThrottleReadBpsDevice:  readBpsDevice,
201
-		BlkioThrottleWriteBpsDevice: writeBpsDevice,
202
-		OomKillDisable:              c.HostConfig.OomKillDisable,
203
-		MemorySwappiness:            -1,
192
+		MemorySwap:                   c.HostConfig.MemorySwap,
193
+		KernelMemory:                 c.HostConfig.KernelMemory,
194
+		CpusetCpus:                   c.HostConfig.CpusetCpus,
195
+		CpusetMems:                   c.HostConfig.CpusetMems,
196
+		CPUPeriod:                    c.HostConfig.CPUPeriod,
197
+		CPUQuota:                     c.HostConfig.CPUQuota,
198
+		Rlimits:                      rlimits,
199
+		BlkioWeightDevice:            weightDevices,
200
+		BlkioThrottleReadBpsDevice:   readBpsDevice,
201
+		BlkioThrottleWriteBpsDevice:  writeBpsDevice,
202
+		BlkioThrottleReadIOpsDevice:  readIOpsDevice,
203
+		BlkioThrottleWriteIOpsDevice: writeIOpsDevice,
204
+		OomKillDisable:               c.HostConfig.OomKillDisable,
205
+		MemorySwappiness:             -1,
204 206
 	}
205 207
 
206 208
 	if c.HostConfig.MemorySwappiness != nil {
... ...
@@ -85,6 +85,36 @@ func parseSecurityOpt(container *container.Container, config *runconfig.HostConf
85 85
 	return err
86 86
 }
87 87
 
88
+func getBlkioReadIOpsDevices(config *runconfig.HostConfig) ([]*blkiodev.ThrottleDevice, error) {
89
+	var blkioReadIOpsDevice []*blkiodev.ThrottleDevice
90
+	var stat syscall.Stat_t
91
+
92
+	for _, iopsDevice := range config.BlkioDeviceReadIOps {
93
+		if err := syscall.Stat(iopsDevice.Path, &stat); err != nil {
94
+			return nil, err
95
+		}
96
+		readIOpsDevice := blkiodev.NewThrottleDevice(int64(stat.Rdev/256), int64(stat.Rdev%256), iopsDevice.Rate)
97
+		blkioReadIOpsDevice = append(blkioReadIOpsDevice, readIOpsDevice)
98
+	}
99
+
100
+	return blkioReadIOpsDevice, nil
101
+}
102
+
103
+func getBlkioWriteIOpsDevices(config *runconfig.HostConfig) ([]*blkiodev.ThrottleDevice, error) {
104
+	var blkioWriteIOpsDevice []*blkiodev.ThrottleDevice
105
+	var stat syscall.Stat_t
106
+
107
+	for _, iopsDevice := range config.BlkioDeviceWriteIOps {
108
+		if err := syscall.Stat(iopsDevice.Path, &stat); err != nil {
109
+			return nil, err
110
+		}
111
+		writeIOpsDevice := blkiodev.NewThrottleDevice(int64(stat.Rdev/256), int64(stat.Rdev%256), iopsDevice.Rate)
112
+		blkioWriteIOpsDevice = append(blkioWriteIOpsDevice, writeIOpsDevice)
113
+	}
114
+
115
+	return blkioWriteIOpsDevice, nil
116
+}
117
+
88 118
 func getBlkioReadBpsDevices(config *runconfig.HostConfig) ([]*blkiodev.ThrottleDevice, error) {
89 119
 	var blkioReadBpsDevice []*blkiodev.ThrottleDevice
90 120
 	var stat syscall.Stat_t
... ...
@@ -299,6 +329,16 @@ func verifyContainerResources(resources *runconfig.Resources) ([]string, error)
299 299
 		logrus.Warnf("Your kernel does not support Block I/O write limit in bytes per second. --device-write-bps discarded.")
300 300
 		resources.BlkioDeviceWriteBps = []*pblkiodev.ThrottleDevice{}
301 301
 	}
302
+	if len(resources.BlkioDeviceReadIOps) > 0 && !sysInfo.BlkioReadIOpsDevice {
303
+		warnings = append(warnings, "Your kernel does not support Block read limit in IO per second.")
304
+		logrus.Warnf("Your kernel does not support Block I/O read limit in IO per second. -device-read-iops discarded.")
305
+		resources.BlkioDeviceReadIOps = []*pblkiodev.ThrottleDevice{}
306
+	}
307
+	if len(resources.BlkioDeviceWriteIOps) > 0 && !sysInfo.BlkioWriteIOpsDevice {
308
+		warnings = append(warnings, "Your kernel does not support Block write limit in IO per second.")
309
+		logrus.Warnf("Your kernel does not support Block I/O write limit in IO per second. --device-write-iops discarded.")
310
+		resources.BlkioDeviceWriteIOps = []*pblkiodev.ThrottleDevice{}
311
+	}
302 312
 
303 313
 	return warnings, nil
304 314
 }
... ...
@@ -328,7 +368,6 @@ func verifyPlatformContainerSettings(daemon *Daemon, hostConfig *runconfig.HostC
328 328
 		hostConfig.OomKillDisable = false
329 329
 		return warnings, fmt.Errorf("Your kernel does not support oom kill disable.")
330 330
 	}
331
-
332 331
 	if hostConfig.OomScoreAdj < -1000 || hostConfig.OomScoreAdj > 1000 {
333 332
 		return warnings, fmt.Errorf("Invalid value %d, range for oom score adj is [-1000, 1000].", hostConfig.OomScoreAdj)
334 333
 	}
... ...
@@ -38,6 +38,14 @@ func parseSecurityOpt(container *container.Container, config *runconfig.HostConf
38 38
 	return nil
39 39
 }
40 40
 
41
+func getBlkioReadIOpsDevices(config *runconfig.HostConfig) ([]*blkiodev.ThrottleDevice, error) {
42
+	return nil, nil
43
+}
44
+
45
+func getBlkioWriteIOpsDevices(config *runconfig.HostConfig) ([]*blkiodev.ThrottleDevice, error) {
46
+	return nil, nil
47
+}
48
+
41 49
 func getBlkioReadBpsDevices(config *runconfig.HostConfig) ([]*blkiodev.ThrottleDevice, error) {
42 50
 	return nil, nil
43 51
 }
... ...
@@ -37,18 +37,20 @@ type Resources struct {
37 37
 
38 38
 	// Fields below here are platform specific
39 39
 
40
-	BlkioWeightDevice           []*blkiodev.WeightDevice   `json:"blkio_weight_device"`
41
-	BlkioThrottleReadBpsDevice  []*blkiodev.ThrottleDevice `json:"blkio_throttle_read_bps_device"`
42
-	BlkioThrottleWriteBpsDevice []*blkiodev.ThrottleDevice `json:"blkio_throttle_write_bps_device"`
43
-	MemorySwap                  int64                      `json:"memory_swap"`
44
-	KernelMemory                int64                      `json:"kernel_memory"`
45
-	CPUQuota                    int64                      `json:"cpu_quota"`
46
-	CpusetCpus                  string                     `json:"cpuset_cpus"`
47
-	CpusetMems                  string                     `json:"cpuset_mems"`
48
-	CPUPeriod                   int64                      `json:"cpu_period"`
49
-	Rlimits                     []*ulimit.Rlimit           `json:"rlimits"`
50
-	OomKillDisable              bool                       `json:"oom_kill_disable"`
51
-	MemorySwappiness            int64                      `json:"memory_swappiness"`
40
+	BlkioWeightDevice            []*blkiodev.WeightDevice   `json:"blkio_weight_device"`
41
+	BlkioThrottleReadBpsDevice   []*blkiodev.ThrottleDevice `json:"blkio_throttle_read_bps_device"`
42
+	BlkioThrottleWriteBpsDevice  []*blkiodev.ThrottleDevice `json:"blkio_throttle_write_bps_device"`
43
+	BlkioThrottleReadIOpsDevice  []*blkiodev.ThrottleDevice `json:"blkio_throttle_read_iops_device"`
44
+	BlkioThrottleWriteIOpsDevice []*blkiodev.ThrottleDevice `json:"blkio_throttle_write_iops_device"`
45
+	MemorySwap                   int64                      `json:"memory_swap"`
46
+	KernelMemory                 int64                      `json:"kernel_memory"`
47
+	CPUQuota                     int64                      `json:"cpu_quota"`
48
+	CpusetCpus                   string                     `json:"cpuset_cpus"`
49
+	CpusetMems                   string                     `json:"cpuset_mems"`
50
+	CPUPeriod                    int64                      `json:"cpu_period"`
51
+	Rlimits                      []*ulimit.Rlimit           `json:"rlimits"`
52
+	OomKillDisable               bool                       `json:"oom_kill_disable"`
53
+	MemorySwappiness             int64                      `json:"memory_swappiness"`
52 54
 }
53 55
 
54 56
 // ProcessConfig is the platform specific structure that describes a process
... ...
@@ -181,6 +183,8 @@ func SetupCgroups(container *configs.Config, c *Command) error {
181 181
 		container.Cgroups.BlkioWeightDevice = c.Resources.BlkioWeightDevice
182 182
 		container.Cgroups.BlkioThrottleReadBpsDevice = c.Resources.BlkioThrottleReadBpsDevice
183 183
 		container.Cgroups.BlkioThrottleWriteBpsDevice = c.Resources.BlkioThrottleWriteBpsDevice
184
+		container.Cgroups.BlkioThrottleReadIOPSDevice = c.Resources.BlkioThrottleReadIOpsDevice
185
+		container.Cgroups.BlkioThrottleWriteIOPSDevice = c.Resources.BlkioThrottleWriteIOpsDevice
184 186
 		container.Cgroups.OomKillDisable = c.Resources.OomKillDisable
185 187
 		container.Cgroups.MemorySwappiness = c.Resources.MemorySwappiness
186 188
 	}
... ...
@@ -107,6 +107,8 @@ This section lists each version from latest to oldest.  Each listing includes a
107 107
 * Pushes initiated with `POST /images/(name)/push` and pulls initiated with `POST /images/create`
108 108
   will be cancelled if the HTTP connection making the API request is closed before
109 109
   the push or pull completes.
110
+* `POST /containers/create` now allows you to set a read/write rate limit for a 
111
+  device (in bytes per second or IO per second).
110 112
 
111 113
 ### v1.21 API changes
112 114
 
... ...
@@ -248,7 +248,9 @@ Create a container
248 248
              "BlkioWeight": 300,
249 249
              "BlkioWeightDevice": [{}],
250 250
              "BlkioDeviceReadBps": [{}],
251
+             "BlkioDeviceReadIOps": [{}],
251 252
              "BlkioDeviceWriteBps": [{}],
253
+             "BlkioDeviceWriteIOps": [{}],
252 254
              "MemorySwappiness": 60,
253 255
              "OomKillDisable": false,
254 256
              "OomScoreAdj": 500,
... ...
@@ -306,10 +308,14 @@ Json Parameters:
306 306
 -   **CpusetMems** - Memory nodes (MEMs) in which to allow execution (0-3, 0,1). Only effective on NUMA systems.
307 307
 -   **BlkioWeight** - Block IO weight (relative weight) accepts a weight value between 10 and 1000.
308 308
 -   **BlkioWeightDevice** - Block IO weight (relative device weight) in the form of:        `"BlkioWeightDevice": [{"Path": "device_path", "Weight": weight}]`
309
--   **BlkioDeviceReadBps** - Limit read rate from a device in form of:	`"BlkioDeviceReadBps": [{"Path": "device_path", "Rate": rate}]`, for example:
309
+-   **BlkioDeviceReadBps** - Limit read rate (bytes per second) from a device in the form of:	`"BlkioDeviceReadBps": [{"Path": "device_path", "Rate": rate}]`, for example:
310 310
 	`"BlkioDeviceReadBps": [{"Path": "/dev/sda", "Rate": "1024"}]"`
311
--   **BlkioDeviceWriteBps** - Limit write rate to a device in the form of:	`"BlkioDeviceWriteBps": [{"Path": "device_path", "Rate": rate}]`, for example:
311
+-   **BlkioDeviceWriteBps** - Limit write rate (bytes per second) to a device in the form of:	`"BlkioDeviceWriteBps": [{"Path": "device_path", "Rate": rate}]`, for example:
312 312
 	`"BlkioDeviceWriteBps": [{"Path": "/dev/sda", "Rate": "1024"}]"`
313
+-   **BlkioDeviceReadIOps** - Limit read rate (IO per second) from a device in the form of:	`"BlkioDeviceReadIOps": [{"Path": "device_path", "Rate": rate}]`, for example:
314
+	`"BlkioDeviceReadIOps": [{"Path": "/dev/sda", "Rate": "1000"}]`
315
+-   **BlkioDeviceWiiteIOps** - Limit write rate (IO per second) to a device in the form of:	`"BlkioDeviceWriteIOps": [{"Path": "device_path", "Rate": rate}]`, for example:
316
+	`"BlkioDeviceWriteIOps": [{"Path": "/dev/sda", "Rate": "1000"}]`
313 317
 -   **MemorySwappiness** - Tune a container's memory swappiness behavior. Accepts an integer between 0 and 100.
314 318
 -   **OomKillDisable** - Boolean value, whether to disable OOM Killer for the container or not.
315 319
 -   **OomScoreAdj** - An integer value containing the score given to the container in order to tune OOM killer preferences.
... ...
@@ -465,6 +471,8 @@ Return low-level information on the container `id`
465 465
 			"BlkioWeightDevice": [{}],
466 466
 			"BlkioDeviceReadBps": [{}],
467 467
 			"BlkioDeviceWriteBps": [{}],
468
+			"BlkioDeviceReadIOps": [{}],
469
+			"BlkioDeviceWriteIOps": [{}],
468 470
 			"CapAdd": null,
469 471
 			"CapDrop": null,
470 472
 			"ContainerIDFile": "",
... ...
@@ -31,7 +31,9 @@ Creates a new container.
31 31
       --cpuset-mems=""              Memory nodes (MEMs) in which to allow execution (0-3, 0,1)
32 32
       --device=[]                   Add a host device to the container
33 33
       --device-read-bps=[]          Limit read rate (bytes per second) from a device (e.g., --device-read-bps=/dev/sda:1mb)
34
+      --device-read-iops=[]         Limit read rate (IO per second) from a device (e.g., --device-read-iops=/dev/sda:1000)
34 35
       --device-write-bps=[]         Limit write rate (bytes per second) to a device (e.g., --device-write-bps=/dev/sda:1mb)
36
+      --device-write-iops=[]        Limit write rate (IO per second) to a device (e.g., --device-write-iops=/dev/sda:1000)
35 37
       --disable-content-trust=true  Skip image verification
36 38
       --dns=[]                      Set custom DNS servers
37 39
       --dns-opt=[]                  Set custom DNS options
... ...
@@ -30,7 +30,9 @@ parent = "smn_cli"
30 30
       -d, --detach=false            Run container in background and print container ID
31 31
       --device=[]                   Add a host device to the container
32 32
       --device-read-bps=[]          Limit read rate (bytes per second) from a device (e.g., --device-read-bps=/dev/sda:1mb)
33
+      --device-read-iops=[]         Limit read rate (IO per second) from a device (e.g., --device-read-iops=/dev/sda:1000)
33 34
       --device-write-bps=[]         Limit write rate (bytes per second) to a device (e.g., --device-write-bps=/dev/sda:1mb)
35
+      --device-write-iops=[]        Limit write rate (IO per second) to a device (e.g., --device-write-bps=/dev/sda:1000)
34 36
       --disable-content-trust=true  Skip image verification
35 37
       --dns=[]                      Set custom DNS servers
36 38
       --dns-opt=[]                  Set custom DNS options
... ...
@@ -632,6 +632,8 @@ container:
632 632
 | `--blkio-weight-device=""` | Block IO weight (relative device weight, format: `DEVICE_NAME:WEIGHT`)                                                                          |
633 633
 | `--device-read-bps=""`     | Limit read rate from a device (format: `<device-path>:<number>[<unit>]`). Number is a positive integer. Unit can be one of `kb`, `mb`, or `gb`. |
634 634
 | `--device-write-bps=""`    | Limit write rate to a device (format: `<device-path>:<number>[<unit>]`). Number is a positive integer. Unit can be one of `kb`, `mb`, or `gb`.  |
635
+| `--device-read-iops="" `   | Limit read rate (IO per second) from a device (format: `<device-path>:<number>`). Number is a positive integer.                                 |
636
+| `--device-write-iops="" `  | Limit write rate (IO per second) to a device (format: `<device-path>:<number>`). Number is a positive integer.                                  |
635 637
 | `--oom-kill-disable=false` | Whether to disable OOM Killer for the container or not.                                                                                         |
636 638
 | `--memory-swappiness=""`   | Tune a container's memory swappiness behavior. Accepts an integer between 0 and 100.                                                            |
637 639
 | `--shm-size=""`            | Size of `/dev/shm`. The format is `<number><unit>`. `number` must be greater than `0`. Unit is optional and can be `b` (bytes), `k` (kilobytes), `m` (megabytes), or `g` (gigabytes). If you omit the unit, the system uses bytes. If you omit the size entirely, the system uses `64m`. |
... ...
@@ -983,15 +985,15 @@ on `/dev/sda` setting that weight to `200`:
983 983
         --blkio-weight-device "/dev/sda:200" \
984 984
         ubuntu
985 985
 
986
-The `--device-read-bps` flag limits the read rate from a device. For example,
987
-this command creates a container and limits the read rate to `1mb` per second
988
-from `/dev/sda`:
986
+The `--device-read-bps` flag limits the read rate (bytes per second) from a device.
987
+For example, this command creates a container and limits the read rate to `1mb`
988
+per second from `/dev/sda`:
989 989
 
990 990
     $ docker run -it --device-read-bps /dev/sda:1mb ubuntu
991 991
 
992
-The `--device-write-bps` flag limits the write rate to a device. For example,
993
-this command creates a container and limits the write rate to `1mb` per second
994
-for `/dev/sda`: 
992
+The `--device-write-bps` flag limits the write rate (bytes per second)to a device.
993
+For example, this command creates a container and limits the write rate to `1mb`
994
+per second for `/dev/sda`: 
995 995
 
996 996
     $ docker run -it --device-write-bps /dev/sda:1mb ubuntu
997 997
 
... ...
@@ -999,6 +1001,21 @@ Both flags take limits in the `<device-path>:<limit>[unit]` format. Both read
999 999
 and write rates must be a positive integer. You can specify the rate in `kb`
1000 1000
 (kilobytes), `mb` (megabytes), or `gb` (gigabytes).
1001 1001
 
1002
+The `--device-read-iops` flag limits read rate (IO per second) from a device.
1003
+For example, this command creates a container and limits the read rate to
1004
+`1000` IO per second from `/dev/sda`:
1005
+
1006
+    $ docker run -ti --device-read-iops /dev/sda:1000 ubuntu
1007
+
1008
+The `--device-write-iops` flag limits write rate (IO per second) to a device.
1009
+For example, this command creates a container and limits the write rate to
1010
+`1000` IO per second to `/dev/sda`:
1011
+
1012
+    $ docker run -ti --device-write-iops /dev/sda:1000 ubuntu
1013
+
1014
+Both flags take limits in the `<device-path>:<limit>` format. Both read and
1015
+write rates must be a positive integer.
1016
+
1002 1017
 ## Additional groups
1003 1018
     --group-add: Add Linux capabilities
1004 1019
 
... ...
@@ -267,6 +267,18 @@ func (s *DockerSuite) TestRunWithBlkioInvalidDeviceWriteBps(c *check.C) {
267 267
 	c.Assert(err, check.NotNil, check.Commentf(out))
268 268
 }
269 269
 
270
+func (s *DockerSuite) TestRunWithBlkioInvalidReadiopsDevice(c *check.C) {
271
+	testRequires(c, blkioWeight)
272
+	out, _, err := dockerCmdWithError("run", "--device-read-iops", "/dev/sdX:500", "busybox", "true")
273
+	c.Assert(err, check.NotNil, check.Commentf(out))
274
+}
275
+
276
+func (s *DockerSuite) TestRunWithBlkioInvalidWriteiopsDevice(c *check.C) {
277
+	testRequires(c, blkioWeight)
278
+	out, _, err := dockerCmdWithError("run", "--device-write-iops", "/dev/sdX:500", "busybox", "true")
279
+	c.Assert(err, check.NotNil, check.Commentf(out))
280
+}
281
+
270 282
 func (s *DockerSuite) TestRunOOMExitCode(c *check.C) {
271 283
 	testRequires(c, oomControl)
272 284
 	errChan := make(chan error)
... ...
@@ -21,7 +21,9 @@ docker-create - Create a new container
21 21
 [**--cpuset-mems**[=*CPUSET-MEMS*]]
22 22
 [**--device**[=*[]*]]
23 23
 [**--device-read-bps**[=*[]*]]
24
+[**--device-read-iops**[=*[]*]]
24 25
 [**--device-write-bps**[=*[]*]]
26
+[**--device-write-iops**[=*[]*]]
25 27
 [**--dns**[=*[]*]]
26 28
 [**--dns-search**[=*[]*]]
27 29
 [**--dns-opt**[=*[]*]]
... ...
@@ -130,9 +132,15 @@ two memory nodes.
130 130
 **--device-read-bps**=[]
131 131
     Limit read rate (bytes per second) from a device (e.g. --device-read-bps=/dev/sda:1mb)
132 132
 
133
+**--device-read-iops**=[]
134
+    Limit read rate (IO per second) from a device (e.g. --device-read-iops=/dev/sda:1000)
135
+
133 136
 **--device-write-bps**=[]
134 137
     Limit write rate (bytes per second) to a device (e.g. --device-write-bps=/dev/sda:1mb)
135 138
 
139
+**--device-write-iops**=[]
140
+    Limit write rate (IO per second) to a device (e.g. --device-write-iops=/dev/sda:1000)
141
+
136 142
 **--dns**=[]
137 143
    Set custom DNS servers
138 144
 
... ...
@@ -22,7 +22,9 @@ docker-run - Run a command in a new container
22 22
 [**-d**|**--detach**[=*false*]]
23 23
 [**--device**[=*[]*]]
24 24
 [**--device-read-bps**[=*[]*]]
25
+[**--device-read-iops**[=*[]*]]
25 26
 [**--device-write-bps**[=*[]*]]
27
+[**--device-write-iops**[=*[]*]]
26 28
 [**--dns**[=*[]*]]
27 29
 [**--dns-opt**[=*[]*]]
28 30
 [**--dns-search**[=*[]*]]
... ...
@@ -197,9 +199,15 @@ stopping the process by pressing the keys CTRL-P CTRL-Q.
197 197
 **--device-read-bps**=[]
198 198
    Limit read rate from a device (e.g. --device-read-bps=/dev/sda:1mb)
199 199
 
200
+**--device-read-iops**=[]
201
+   Limit read rate from a device (e.g. --device-read-iops=/dev/sda:1000)
202
+
200 203
 **--device-write-bps**=[]
201 204
    Limit write rate to a device (e.g. --device-write-bps=/dev/sda:1mb)
202 205
 
206
+**--device-write-iops**=[]
207
+   Limit write rate a a device (e.g. --device-write-iops=/dev/sda:1000)
208
+
203 209
 **--dns-search**=[]
204 210
    Set custom DNS search domains (Use --dns-search=. if you don't wish to set the search domain)
205 211
 
... ...
@@ -219,6 +219,29 @@ func ValidateThrottleBpsDevice(val string) (*blkiodev.ThrottleDevice, error) {
219 219
 	}, nil
220 220
 }
221 221
 
222
+// ValidateThrottleIOpsDevice validates that the specified string has a valid device-rate format.
223
+func ValidateThrottleIOpsDevice(val string) (*blkiodev.ThrottleDevice, error) {
224
+	split := strings.SplitN(val, ":", 2)
225
+	if len(split) != 2 {
226
+		return nil, fmt.Errorf("bad format: %s", val)
227
+	}
228
+	if !strings.HasPrefix(split[0], "/dev/") {
229
+		return nil, fmt.Errorf("bad format for device path: %s", val)
230
+	}
231
+	rate, err := strconv.ParseUint(split[1], 10, 64)
232
+	if err != nil {
233
+		return nil, fmt.Errorf("invalid rate for device: %s. The correct format is <device-path>:<number>. Number must be a positive integer", val)
234
+	}
235
+	if rate < 0 {
236
+		return nil, fmt.Errorf("invalid rate for device: %s. The correct format is <device-path>:<number>. Number must be a positive integer", val)
237
+	}
238
+
239
+	return &blkiodev.ThrottleDevice{
240
+		Path: split[0],
241
+		Rate: uint64(rate),
242
+	}, nil
243
+}
244
+
222 245
 // ValidateEnv validates an environment variable and returns it.
223 246
 // If no value is specified, it returns the current value using os.Getenv.
224 247
 //
... ...
@@ -69,6 +69,12 @@ type cgroupBlkioInfo struct {
69 69
 
70 70
 	// Whether Block IO write limit in bytes per second is supported or not
71 71
 	BlkioWriteBpsDevice bool
72
+
73
+	// Whether Block IO read limit in IO per second is supported or not
74
+	BlkioReadIOpsDevice bool
75
+
76
+	// Whether Block IO write limit in IO per second is supported or not
77
+	BlkioWriteIOpsDevice bool
72 78
 }
73 79
 
74 80
 type cgroupCpusetInfo struct {
... ...
@@ -136,11 +136,22 @@ func checkCgroupBlkioInfo(quiet bool) cgroupBlkioInfo {
136 136
 	if !quiet && !writeBpsDevice {
137 137
 		logrus.Warn("Your kernel does not support cgroup blkio throttle.write_bps_device")
138 138
 	}
139
+	readIOpsDevice := cgroupEnabled(mountPoint, "blkio.throttle.read_iops_device")
140
+	if !quiet && !readIOpsDevice {
141
+		logrus.Warn("Your kernel does not support cgroup blkio throttle.read_iops_device")
142
+	}
143
+
144
+	writeIOpsDevice := cgroupEnabled(mountPoint, "blkio.throttle.write_iops_device")
145
+	if !quiet && !writeIOpsDevice {
146
+		logrus.Warn("Your kernel does not support cgroup blkio throttle.write_iops_device")
147
+	}
139 148
 	return cgroupBlkioInfo{
140
-		BlkioWeight:         weight,
141
-		BlkioWeightDevice:   weightDevice,
142
-		BlkioReadBpsDevice:  readBpsDevice,
143
-		BlkioWriteBpsDevice: writeBpsDevice,
149
+		BlkioWeight:          weight,
150
+		BlkioWeightDevice:    weightDevice,
151
+		BlkioReadBpsDevice:   readBpsDevice,
152
+		BlkioWriteBpsDevice:  writeBpsDevice,
153
+		BlkioReadIOpsDevice:  readIOpsDevice,
154
+		BlkioWriteIOpsDevice: writeIOpsDevice,
144 155
 	}
145 156
 }
146 157
 
... ...
@@ -171,22 +171,24 @@ type Resources struct {
171 171
 	CPUShares int64 `json:"CpuShares"` // CPU shares (relative weight vs. other containers)
172 172
 
173 173
 	// Applicable to UNIX platforms
174
-	CgroupParent        string // Parent cgroup.
175
-	BlkioWeight         uint16 // Block IO weight (relative weight vs. other containers)
176
-	BlkioWeightDevice   []*blkiodev.WeightDevice
177
-	BlkioDeviceReadBps  []*blkiodev.ThrottleDevice
178
-	BlkioDeviceWriteBps []*blkiodev.ThrottleDevice
179
-	CPUPeriod           int64            `json:"CpuPeriod"` // CPU CFS (Completely Fair Scheduler) period
180
-	CPUQuota            int64            `json:"CpuQuota"`  // CPU CFS (Completely Fair Scheduler) quota
181
-	CpusetCpus          string           // CpusetCpus 0-2, 0,1
182
-	CpusetMems          string           // CpusetMems 0-2, 0,1
183
-	Devices             []DeviceMapping  // List of devices to map inside the container
184
-	KernelMemory        int64            // Kernel memory limit (in bytes)
185
-	Memory              int64            // Memory limit (in bytes)
186
-	MemoryReservation   int64            // Memory soft limit (in bytes)
187
-	MemorySwap          int64            // Total memory usage (memory + swap); set `-1` to disable swap
188
-	MemorySwappiness    *int64           // Tuning container memory swappiness behaviour
189
-	Ulimits             []*ulimit.Ulimit // List of ulimits to be set in the container
174
+	CgroupParent         string // Parent cgroup.
175
+	BlkioWeight          uint16 // Block IO weight (relative weight vs. other containers)
176
+	BlkioWeightDevice    []*blkiodev.WeightDevice
177
+	BlkioDeviceReadBps   []*blkiodev.ThrottleDevice
178
+	BlkioDeviceWriteBps  []*blkiodev.ThrottleDevice
179
+	BlkioDeviceReadIOps  []*blkiodev.ThrottleDevice
180
+	BlkioDeviceWriteIOps []*blkiodev.ThrottleDevice
181
+	CPUPeriod            int64            `json:"CpuPeriod"` // CPU CFS (Completely Fair Scheduler) period
182
+	CPUQuota             int64            `json:"CpuQuota"`  // CPU CFS (Completely Fair Scheduler) quota
183
+	CpusetCpus           string           // CpusetCpus 0-2, 0,1
184
+	CpusetMems           string           // CpusetMems 0-2, 0,1
185
+	Devices              []DeviceMapping  // List of devices to map inside the container
186
+	KernelMemory         int64            // Kernel memory limit (in bytes)
187
+	Memory               int64            // Memory limit (in bytes)
188
+	MemoryReservation    int64            // Memory soft limit (in bytes)
189
+	MemorySwap           int64            // Total memory usage (memory + swap); set `-1` to disable swap
190
+	MemorySwappiness     *int64           // Tuning container memory swappiness behaviour
191
+	Ulimits              []*ulimit.Ulimit // List of ulimits to be set in the container
190 192
 }
191 193
 
192 194
 // HostConfig the non-portable Config structure of a container.
... ...
@@ -57,6 +57,8 @@ func Parse(cmd *flag.FlagSet, args []string) (*Config, *HostConfig, *flag.FlagSe
57 57
 		flDeviceReadBps     = opts.NewThrottledeviceOpt(opts.ValidateThrottleBpsDevice)
58 58
 		flDeviceWriteBps    = opts.NewThrottledeviceOpt(opts.ValidateThrottleBpsDevice)
59 59
 		flLinks             = opts.NewListOpts(ValidateLink)
60
+		flDeviceReadIOps    = opts.NewThrottledeviceOpt(opts.ValidateThrottleIOpsDevice)
61
+		flDeviceWriteIOps   = opts.NewThrottledeviceOpt(opts.ValidateThrottleIOpsDevice)
60 62
 		flEnv               = opts.NewListOpts(opts.ValidateEnv)
61 63
 		flLabels            = opts.NewListOpts(opts.ValidateEnv)
62 64
 		flDevices           = opts.NewListOpts(ValidateDevice)
... ...
@@ -118,6 +120,8 @@ func Parse(cmd *flag.FlagSet, args []string) (*Config, *HostConfig, *flag.FlagSe
118 118
 	cmd.Var(&flBlkioWeightDevice, []string{"-blkio-weight-device"}, "Block IO weight (relative device weight)")
119 119
 	cmd.Var(&flDeviceReadBps, []string{"-device-read-bps"}, "Limit read rate (bytes per second) from a device")
120 120
 	cmd.Var(&flDeviceWriteBps, []string{"-device-write-bps"}, "Limit write rate (bytes per second) to a device")
121
+	cmd.Var(&flDeviceReadIOps, []string{"-device-read-iops"}, "Limit read rate (IO per second) from a device")
122
+	cmd.Var(&flDeviceWriteIOps, []string{"-device-write-iops"}, "Limit write rate (IO per second) to a device")
121 123
 	cmd.Var(&flVolumes, []string{"v", "-volume"}, "Bind mount a volume")
122 124
 	cmd.Var(&flTmpfs, []string{"-tmpfs"}, "Mount a tmpfs directory")
123 125
 	cmd.Var(&flLinks, []string{"-link"}, "Add link to another container")
... ...
@@ -343,23 +347,25 @@ func Parse(cmd *flag.FlagSet, args []string) (*Config, *HostConfig, *flag.FlagSe
343 343
 	}
344 344
 
345 345
 	resources := Resources{
346
-		CgroupParent:        *flCgroupParent,
347
-		Memory:              flMemory,
348
-		MemoryReservation:   MemoryReservation,
349
-		MemorySwap:          memorySwap,
350
-		MemorySwappiness:    flSwappiness,
351
-		KernelMemory:        KernelMemory,
352
-		CPUShares:           *flCPUShares,
353
-		CPUPeriod:           *flCPUPeriod,
354
-		CpusetCpus:          *flCpusetCpus,
355
-		CpusetMems:          *flCpusetMems,
356
-		CPUQuota:            *flCPUQuota,
357
-		BlkioWeight:         *flBlkioWeight,
358
-		BlkioWeightDevice:   flBlkioWeightDevice.GetList(),
359
-		BlkioDeviceReadBps:  flDeviceReadBps.GetList(),
360
-		BlkioDeviceWriteBps: flDeviceWriteBps.GetList(),
361
-		Ulimits:             flUlimits.GetList(),
362
-		Devices:             deviceMappings,
346
+		CgroupParent:         *flCgroupParent,
347
+		Memory:               flMemory,
348
+		MemoryReservation:    MemoryReservation,
349
+		MemorySwap:           memorySwap,
350
+		MemorySwappiness:     flSwappiness,
351
+		KernelMemory:         KernelMemory,
352
+		CPUShares:            *flCPUShares,
353
+		CPUPeriod:            *flCPUPeriod,
354
+		CpusetCpus:           *flCpusetCpus,
355
+		CpusetMems:           *flCpusetMems,
356
+		CPUQuota:             *flCPUQuota,
357
+		BlkioWeight:          *flBlkioWeight,
358
+		BlkioWeightDevice:    flBlkioWeightDevice.GetList(),
359
+		BlkioDeviceReadBps:   flDeviceReadBps.GetList(),
360
+		BlkioDeviceWriteBps:  flDeviceWriteBps.GetList(),
361
+		BlkioDeviceReadIOps:  flDeviceReadIOps.GetList(),
362
+		BlkioDeviceWriteIOps: flDeviceWriteIOps.GetList(),
363
+		Ulimits:              flUlimits.GetList(),
364
+		Devices:              deviceMappings,
363 365
 	}
364 366
 
365 367
 	config := &Config{