exec: add high-level controls for blkio cgroup attributes

This commit is contained in:
Lennart Poettering 2011-08-20 01:38:10 +02:00
parent d8bbda9141
commit 9e37286844
4 changed files with 228 additions and 7 deletions

View file

@ -797,11 +797,13 @@
<term><varname>CPUShares=</varname></term>
<listitem><para>Assign the specified
overall CPU time shares to the processes executed. Takes
an integer value. This controls the
overall CPU time shares to the
processes executed. Takes an integer
value. This controls the
<literal>cpu.shares</literal> control
group attribute. For details about
this control group attribute see <ulink
group attribute, which defaults to
1024. For details about this control
group attribute see <ulink
url="http://www.kernel.org/doc/Documentation/scheduler/sched-design-CFS.txt">sched-design-CFS.txt</ulink>.</para></listitem>
</varlistentry>
@ -814,7 +816,7 @@
size. Takes a memory size in bytes. If
the value is suffixed with K, M, G or
T the specified memory size is parsed
as Kilobytes, Megabytes, Gigabytes
as Kilobytes, Megabytes, Gigabytes,
resp. Terabytes (to the base
1024). This controls the
<literal>memory.limit_in_bytes</literal>
@ -848,6 +850,57 @@
url="http://www.kernel.org/doc/Documentation/cgroups/devices.txt">devices.txt</ulink>.</para></listitem>
</varlistentry>
<varlistentry>
<term><varname>BlockIOWeight=</varname></term>
<listitem><para>Set the default or
per-device overall block IO weight
value for the executed
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
device specific weight value (Example:
"/dev/sda 500"). This controls the
<literal>blkio.weight</literal> and
<literal>blkio.weight_device</literal>
control group attributes, which
default to 1000. Use this option
multiple times to set weights for
multiple devices. For details about
these control group attributes see
<ulink
url="http://www.kernel.org/doc/Documentation/cgroups/blkio-controller.txt">blkio-controller.txt</ulink>.</para></listitem>
</varlistentry>
<varlistentry>
<term><varname>BlockIOReadBandwidth=</varname></term>
<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
<literal>blkio.read_bps_device</literal>
and
<literal>blkio.write_bps_device</literal>
control group attributes. Use this
option multiple times to set bandwith
limits for multiple devices. For
details about these control group
attributes see <ulink
url="http://www.kernel.org/doc/Documentation/cgroups/blkio-controller.txt">blkio-controller.txt</ulink>.</para></listitem>
</varlistentry>
<varlistentry>
<term><varname>ReadWriteDirectories=</varname></term>
<term><varname>ReadOnlyDirectories=</varname></term>

View file

@ -71,6 +71,9 @@ $1.MemoryLimit, config_parse_unit_memory_limit, 0,
$1.MemorySoftLimit, config_parse_unit_memory_limit, 0, 0
$1.DeviceAllow, config_parse_unit_device_allow, 0, 0
$1.DeviceDeny, config_parse_unit_device_allow, 0, 0
$1.BlockIOWeight, config_parse_unit_blkio_weight, 0, 0
$1.BlockIOReadBandwidth, config_parse_unit_blkio_bandwidth, 0, 0
$1.BlockIOWriteBandwidth, config_parse_unit_blkio_bandwidth, 0, 0
$1.ReadWriteDirectories, config_parse_path_strv, 0, offsetof($1, exec_context.read_write_dirs)
$1.ReadOnlyDirectories, config_parse_path_strv, 0, offsetof($1, exec_context.read_only_dirs)
$1.InaccessibleDirectories, config_parse_path_strv, 0, offsetof($1, exec_context.inaccessible_dirs)

View file

@ -1743,9 +1743,13 @@ int config_parse_unit_memory_limit(const char *filename, unsigned line, const ch
}
static int device_map(const char *controller, const char *name, const char *value, char **ret) {
struct stat st;
char **l;
assert(controller);
assert(name);
assert(value);
assert(ret);
l = strv_split_quoted(value);
if (!l)
return -ENOMEM;
@ -1761,7 +1765,9 @@ static int device_map(const char *controller, const char *name, const char *valu
}
} else {
if (lstat(l[0], &st) < 0) {
struct stat st;
if (stat(l[0], &st) < 0) {
log_warning("Couldn't stat device %s", l[0]);
strv_free(l);
return -errno;
@ -1834,6 +1840,163 @@ int config_parse_unit_device_allow(const char *filename, unsigned line, const ch
return 0;
}
static int blkio_map(const char *controller, const char *name, const char *value, char **ret) {
struct stat st;
char **l;
assert(controller);
assert(name);
assert(value);
assert(ret);
l = strv_split_quoted(value);
if (!l)
return -ENOMEM;
assert(strv_length(l) == 2);
if (stat(l[0], &st) < 0) {
log_warning("Couldn't stat device %s", l[0]);
strv_free(l);
return -errno;
}
if (!S_ISBLK(st.st_mode)) {
log_warning("%s is not a block device.", l[0]);
strv_free(l);
return -ENODEV;
}
if (asprintf(ret, "%u:%u %s", major(st.st_rdev), minor(st.st_rdev), l[1]) < 0) {
strv_free(l);
return -ENOMEM;
}
strv_free(l);
return 0;
}
int config_parse_unit_blkio_weight(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata) {
Unit *u = data;
int r;
unsigned long ul;
const char *device = NULL, *weight;
unsigned k;
char *t, **l;
assert(filename);
assert(lvalue);
assert(rvalue);
assert(data);
l = strv_split_quoted(rvalue);
if (!l)
return -ENOMEM;
k = strv_length(l);
if (k < 1 || k > 2) {
log_error("[%s:%u] Failed to parse weight value, ignoring: %s", filename, line, rvalue);
strv_free(l);
return 0;
}
if (k == 1)
weight = l[0];
else {
device = l[0];
weight = l[1];
}
if (device && !path_startswith(device, "/dev/")) {
log_error("[%s:%u] Failed to parse block device node value, ignoring: %s", filename, line, rvalue);
strv_free(l);
return 0;
}
if (safe_atolu(weight, &ul) < 0 || ul < 10 || ul > 1000) {
log_error("[%s:%u] Failed to parse block IO weight value, ignoring: %s", filename, line, rvalue);
strv_free(l);
return 0;
}
if (device)
r = asprintf(&t, "%s %lu", device, ul);
else
r = asprintf(&t, "%lu", ul);
strv_free(l);
if (r < 0)
return -ENOMEM;
if (device)
r = unit_add_cgroup_attribute(u, "blkio", "blkio.weight_device", t, blkio_map);
else
r = unit_add_cgroup_attribute(u, "blkio", "blkio.weight", t, NULL);
free(t);
if (r < 0) {
log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue);
return 0;
}
return 0;
}
int config_parse_unit_blkio_bandwidth(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata) {
Unit *u = data;
int r;
off_t bytes;
unsigned k;
char *t, **l;
assert(filename);
assert(lvalue);
assert(rvalue);
assert(data);
l = strv_split_quoted(rvalue);
if (!l)
return -ENOMEM;
k = strv_length(l);
if (k != 2) {
log_error("[%s:%u] Failed to parse bandwidth value, ignoring: %s", filename, line, rvalue);
strv_free(l);
return 0;
}
if (!path_startswith(l[0], "/dev/")) {
log_error("[%s:%u] Failed to parse block device node value, ignoring: %s", filename, line, rvalue);
strv_free(l);
return 0;
}
if (parse_bytes(l[1], &bytes) < 0 || bytes <= 0) {
log_error("[%s:%u] Failed to parse block IO bandwith value, ignoring: %s", filename, line, rvalue);
strv_free(l);
return 0;
}
r = asprintf(&t, "%s %llu", l[0], (unsigned long long) bytes);
strv_free(l);
if (r < 0)
return -ENOMEM;
r = unit_add_cgroup_attribute(u, "blkio",
streq(lvalue, "BlockIOReadBandwidth") ? "blkio.read_bps_device" : "blkio.write_bps_device",
t, blkio_map);
free(t);
if (r < 0) {
log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue);
return 0;
}
return 0;
}
#define FOLLOW_MAX 8
static int open_follow(char **filename, FILE **_f, Set *names, char **_final) {

View file

@ -80,6 +80,8 @@ int config_parse_unit_cgroup_attr(const char *filename, unsigned line, const cha
int config_parse_unit_cpu_shares(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_unit_memory_limit(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_unit_device_allow(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_unit_blkio_weight(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_unit_blkio_bandwidth(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
/* gperf prototypes */
const struct ConfigPerfItem* load_fragment_gperf_lookup(const char *key, unsigned length);