exec: allow passing arbitrary path names to blkio cgroup attributes

If a device node is specified, then adjust the bandwidth/weight of it,
otherwise find the backing block device of the file system the path
refers to and adjust its bandwidth/weight.
This commit is contained in:
Lennart Poettering 2011-08-21 00:28:30 +02:00
parent 9e37286844
commit 94959f0fa0
4 changed files with 103 additions and 19 deletions

View File

@ -859,10 +859,15 @@
processes. Takes either a single
weight value (between 10 and 1000) to
set the default block IO weight, or a
space separated pair of a device node
path and a weight value to specify the
space separated pair of a file path
and a weight value to specify the
device specific weight value (Example:
"/dev/sda 500"). This controls the
"/dev/sda 500"). The file path may be
specified as path to a block device
node or as any other file in which
case the backing block device of the
file system of the file is
determined. This controls the
<literal>blkio.weight</literal> and
<literal>blkio.weight_device</literal>
control group attributes, which
@ -879,17 +884,22 @@
<term><varname>BlockIOWriteBandwidth=</varname></term>
<listitem><para>Set the per-device
overall block IO bandwith limit for the
executed processes. Takes a space
separated pair of a device node path
and a bandwith value (in bytes per
second) to specify the device specific
bandwidth. If the bandwith is suffixed
with K, M, G, or T the specified
bandwith is parsed as Kilobytes,
Megabytes, Gigabytes, resp. Terabytes
(Example: "/dev/disk/by-path/pci-0000:00:1f.2-scsi-0:0:0:0 5M"). This
controls the
overall block IO bandwith limit for
the executed processes. Takes a space
separated pair of a file path and a
bandwith value (in bytes per second)
to specify the device specific
bandwidth. The file path may be
specified as path to a block device
node or as any other file in which
case the backing block device of the
file system of the file is determined.
If the bandwith is suffixed with K, M,
G, or T the specified bandwith is
parsed as Kilobytes, Megabytes,
Gigabytes, resp. Terabytes (Example:
"/dev/disk/by-path/pci-0000:00:1f.2-scsi-0:0:0:0
5M"). This controls the
<literal>blkio.read_bps_device</literal>
and
<literal>blkio.write_bps_device</literal>

View File

@ -1843,6 +1843,7 @@ int config_parse_unit_device_allow(const char *filename, unsigned line, const ch
static int blkio_map(const char *controller, const char *name, const char *value, char **ret) {
struct stat st;
char **l;
dev_t d;
assert(controller);
assert(name);
@ -1861,13 +1862,23 @@ static int blkio_map(const char *controller, const char *name, const char *value
return -errno;
}
if (!S_ISBLK(st.st_mode)) {
log_warning("%s is not a block device.", l[0]);
if (S_ISBLK(st.st_mode))
d = st.st_rdev;
else if (major(st.st_dev) != 0) {
/* If this is not a device node then find the block
* device this file is stored on */
d = st.st_dev;
/* If this is a partition, try to get the originating
* block device */
block_get_whole_disk(d, &d);
} else {
log_warning("%s is not a block device and file system block device cannot be determined or is not local.", l[0]);
strv_free(l);
return -ENODEV;
}
if (asprintf(ret, "%u:%u %s", major(st.st_rdev), minor(st.st_rdev), l[1]) < 0) {
if (asprintf(ret, "%u:%u %s", major(d), minor(d), l[1]) < 0) {
strv_free(l);
return -ENOMEM;
}
@ -1907,7 +1918,7 @@ int config_parse_unit_blkio_weight(const char *filename, unsigned line, const ch
weight = l[1];
}
if (device && !path_startswith(device, "/dev/")) {
if (device && !path_is_absolute(device)) {
log_error("[%s:%u] Failed to parse block device node value, ignoring: %s", filename, line, rvalue);
strv_free(l);
return 0;
@ -1965,7 +1976,7 @@ int config_parse_unit_blkio_bandwidth(const char *filename, unsigned line, const
return 0;
}
if (!path_startswith(l[0], "/dev/")) {
if (!path_is_absolute(l[0])) {
log_error("[%s:%u] Failed to parse block device node value, ignoring: %s", filename, line, rvalue);
strv_free(l);
return 0;

View File

@ -5614,6 +5614,67 @@ bool is_main_thread(void) {
return cached > 0;
}
int block_get_whole_disk(dev_t d, dev_t *ret) {
char *p, *s;
int r;
unsigned n, m;
assert(ret);
/* If it has a queue this is good enough for us */
if (asprintf(&p, "/sys/dev/block/%u:%u/queue", major(d), minor(d)) < 0)
return -ENOMEM;
r = access(p, F_OK);
free(p);
if (r >= 0) {
*ret = d;
return 0;
}
/* If it is a partition find the originating device */
if (asprintf(&p, "/sys/dev/block/%u:%u/partition", major(d), minor(d)) < 0)
return -ENOMEM;
r = access(p, F_OK);
free(p);
if (r < 0)
return -ENOENT;
/* Get parent dev_t */
if (asprintf(&p, "/sys/dev/block/%u:%u/../dev", major(d), minor(d)) < 0)
return -ENOMEM;
r = read_one_line_file(p, &s);
free(p);
if (r < 0)
return r;
r = sscanf(s, "%u:%u", &m, &n);
free(s);
if (r != 2)
return -EINVAL;
/* Only return this if it is really good enough for us. */
if (asprintf(&p, "/sys/dev/block/%u:%u/queue", m, n) < 0)
return -ENOMEM;
r = access(p, F_OK);
free(p);
if (r >= 0) {
*ret = makedev(m, n);
return 0;
}
return -ENOENT;
}
static const char *const ioprio_class_table[] = {
[IOPRIO_CLASS_NONE] = "none",
[IOPRIO_CLASS_RT] = "realtime",

View File

@ -465,6 +465,8 @@ bool is_main_thread(void);
bool in_charset(const char *s, const char* charset);
int block_get_whole_disk(dev_t d, dev_t *ret);
#define NULSTR_FOREACH(i, l) \
for ((i) = (l); (i) && *(i); (i) = strchr((i), 0)+1)