core: update CGroupBlockIODeviceBandwidth to record both rbps and wbps

CGroupBlockIODeviceBandwith is used to keep track of IO bandwidth limits for
legacy cgroup hierarchies.  Unlike the unified hierarchy counterpart
CGroupIODeviceLimit, a CGroupBlockIODeviceBandwiddth records either a read or
write limit and has a couple issues.

* There's no way to clear specific config entry.

* When configs are cleared for an IO direction of a unit, the kernel settings
  aren't cleared accordingly creating discrepancies.

This patch updates CGroupBlockIODeviceBandwidth so that it behaves similarly to
CGroupIODeviceLimit - each entry records both rbps and wbps limits and is
cleared if both are at default values after kernel settings are updated.
This commit is contained in:
Tejun Heo
2016-05-18 13:51:46 -07:00
committed by Tejun Heo
parent ac06a0cf8a
commit 979d03117f
4 changed files with 88 additions and 45 deletions
+33 -15
View File
@@ -206,12 +206,18 @@ void cgroup_context_dump(CGroupContext *c, FILE* f, const char *prefix) {
LIST_FOREACH(device_bandwidths, b, c->blockio_device_bandwidths) {
char buf[FORMAT_BYTES_MAX];
fprintf(f,
"%s%s=%s %s\n",
prefix,
b->read ? "BlockIOReadBandwidth" : "BlockIOWriteBandwidth",
b->path,
format_bytes(buf, sizeof(buf), b->bandwidth));
if (b->rbps != CGROUP_LIMIT_MAX)
fprintf(f,
"%sBlockIOReadBandwidth=%s %s\n",
prefix,
b->path,
format_bytes(buf, sizeof(buf), b->rbps));
if (b->wbps != CGROUP_LIMIT_MAX)
fprintf(f,
"%sBlockIOWriteBandwidth=%s %s\n",
prefix,
b->path,
format_bytes(buf, sizeof(buf), b->wbps));
}
}
@@ -477,7 +483,7 @@ void cgroup_context_apply(CGroupContext *c, CGroupMask mask, const char *path, M
char buf[MAX(DECIMAL_STR_MAX(uint64_t)+1,
DECIMAL_STR_MAX(dev_t)*2+2+DECIMAL_STR_MAX(uint64_t)+1)];
CGroupBlockIODeviceWeight *w;
CGroupBlockIODeviceBandwidth *b;
CGroupBlockIODeviceBandwidth *b, *next;
if (!is_root) {
sprintf(buf, "%" PRIu64 "\n",
@@ -504,22 +510,34 @@ void cgroup_context_apply(CGroupContext *c, CGroupMask mask, const char *path, M
}
}
/* FIXME: no way to reset this list */
LIST_FOREACH(device_bandwidths, b, c->blockio_device_bandwidths) {
const char *a;
LIST_FOREACH_SAFE(device_bandwidths, b, next, c->blockio_device_bandwidths) {
dev_t dev;
unsigned n = 0;
r = lookup_block_device(b->path, &dev);
if (r < 0)
continue;
a = b->read ? "blkio.throttle.read_bps_device" : "blkio.throttle.write_bps_device";
sprintf(buf, "%u:%u %" PRIu64 "\n", major(dev), minor(dev), b->bandwidth);
r = cg_set_attribute("blkio", path, a, buf);
if (b->rbps != CGROUP_LIMIT_MAX)
n++;
sprintf(buf, "%u:%u %" PRIu64 "\n", major(dev), minor(dev), b->rbps);
r = cg_set_attribute("blkio", path, "blkio.throttle.read_bps_device", buf);
if (r < 0)
log_full_errno(IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r,
"Failed to set %s on %s: %m", a, path);
"Failed to set blkio.throttle.read_bps_device on %s: %m", path);
if (b->wbps != CGROUP_LIMIT_MAX)
n++;
sprintf(buf, "%u:%u %" PRIu64 "\n", major(dev), minor(dev), b->wbps);
r = cg_set_attribute("blkio", path, "blkio.throttle.write_bps_device", buf);
if (r < 0)
log_full_errno(IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r,
"Failed to set blkio.throttle.write_bps_device on %s: %m", path);
/* If @b contained no config, we just cleared the kernel
* counterpart too. No reason to keep @l around. */
if (!n)
cgroup_context_free_blockio_device_bandwidth(c, b);
}
}
+2 -2
View File
@@ -77,8 +77,8 @@ struct CGroupBlockIODeviceWeight {
struct CGroupBlockIODeviceBandwidth {
LIST_FIELDS(CGroupBlockIODeviceBandwidth, device_bandwidths);
char *path;
uint64_t bandwidth;
bool read;
uint64_t rbps;
uint64_t wbps;
};
struct CGroupContext {
+26 -13
View File
@@ -146,11 +146,17 @@ static int property_get_blockio_device_bandwidths(
return r;
LIST_FOREACH(device_bandwidths, b, c->blockio_device_bandwidths) {
uint64_t v;
if (streq(property, "BlockIOReadBandwidth") != b->read)
if (streq(property, "BlockIOReadBandwidth"))
v = b->rbps;
else
v = b->wbps;
if (v == CGROUP_LIMIT_MAX)
continue;
r = sd_bus_message_append(reply, "(st)", b->path, b->bandwidth);
r = sd_bus_message_append(reply, "(st)", b->path, v);
if (r < 0)
return r;
}
@@ -651,7 +657,7 @@ int bus_cgroup_set_property(
CGroupBlockIODeviceBandwidth *a = NULL, *b;
LIST_FOREACH(device_bandwidths, b, c->blockio_device_bandwidths) {
if (path_equal(path, b->path) && read == b->read) {
if (path_equal(path, b->path)) {
a = b;
break;
}
@@ -662,7 +668,8 @@ int bus_cgroup_set_property(
if (!a)
return -ENOMEM;
a->read = read;
a->rbps = CGROUP_LIMIT_MAX;
a->wbps = CGROUP_LIMIT_MAX;
a->path = strdup(path);
if (!a->path) {
free(a);
@@ -672,7 +679,10 @@ int bus_cgroup_set_property(
LIST_PREPEND(device_bandwidths, c->blockio_device_bandwidths, a);
}
a->bandwidth = u64;
if (read)
a->rbps = u64;
else
a->wbps = u64;
}
n++;
@@ -685,15 +695,18 @@ int bus_cgroup_set_property(
return r;
if (mode != UNIT_CHECK) {
CGroupBlockIODeviceBandwidth *a, *next;
CGroupBlockIODeviceBandwidth *a;
_cleanup_free_ char *buf = NULL;
_cleanup_fclose_ FILE *f = NULL;
size_t size = 0;
if (n == 0) {
LIST_FOREACH_SAFE(device_bandwidths, a, next, c->blockio_device_bandwidths)
if (a->read == read)
cgroup_context_free_blockio_device_bandwidth(c, a);
LIST_FOREACH(device_bandwidths, a, c->blockio_device_bandwidths) {
if (read)
a->rbps = CGROUP_LIMIT_MAX;
else
a->wbps = CGROUP_LIMIT_MAX;
}
}
unit_invalidate_cgroup(u, CGROUP_MASK_BLKIO);
@@ -705,13 +718,13 @@ int bus_cgroup_set_property(
if (read) {
fputs("BlockIOReadBandwidth=\n", f);
LIST_FOREACH(device_bandwidths, a, c->blockio_device_bandwidths)
if (a->read)
fprintf(f, "BlockIOReadBandwidth=%s %" PRIu64 "\n", a->path, a->bandwidth);
if (a->rbps != CGROUP_LIMIT_MAX)
fprintf(f, "BlockIOReadBandwidth=%s %" PRIu64 "\n", a->path, a->rbps);
} else {
fputs("BlockIOWriteBandwidth=\n", f);
LIST_FOREACH(device_bandwidths, a, c->blockio_device_bandwidths)
if (!a->read)
fprintf(f, "BlockIOWriteBandwidth=%s %" PRIu64 "\n", a->path, a->bandwidth);
if (a->wbps != CGROUP_LIMIT_MAX)
fprintf(f, "BlockIOWriteBandwidth=%s %" PRIu64 "\n", a->path, a->wbps);
}
r = fflush_and_check(f);
+27 -15
View File
@@ -3208,7 +3208,7 @@ int config_parse_blockio_bandwidth(
void *userdata) {
_cleanup_free_ char *path = NULL;
CGroupBlockIODeviceBandwidth *b;
CGroupBlockIODeviceBandwidth *b = NULL, *t;
CGroupContext *c = data;
const char *bandwidth;
uint64_t bytes;
@@ -3223,12 +3223,10 @@ int config_parse_blockio_bandwidth(
read = streq("BlockIOReadBandwidth", lvalue);
if (isempty(rvalue)) {
CGroupBlockIODeviceBandwidth *next;
LIST_FOREACH_SAFE (device_bandwidths, b, next, c->blockio_device_bandwidths)
if (b->read == read)
cgroup_context_free_blockio_device_bandwidth(c, b);
LIST_FOREACH(device_bandwidths, b, c->blockio_device_bandwidths) {
b->rbps = CGROUP_LIMIT_MAX;
b->wbps = CGROUP_LIMIT_MAX;
}
return 0;
}
@@ -3256,16 +3254,30 @@ int config_parse_blockio_bandwidth(
return 0;
}
b = new0(CGroupBlockIODeviceBandwidth, 1);
if (!b)
return log_oom();
LIST_FOREACH(device_bandwidths, t, c->blockio_device_bandwidths) {
if (path_equal(path, t->path)) {
b = t;
break;
}
}
b->path = path;
path = NULL;
b->bandwidth = bytes;
b->read = read;
if (!t) {
b = new0(CGroupBlockIODeviceBandwidth, 1);
if (!b)
return log_oom();
LIST_PREPEND(device_bandwidths, c->blockio_device_bandwidths, b);
b->path = path;
path = NULL;
b->rbps = CGROUP_LIMIT_MAX;
b->wbps = CGROUP_LIMIT_MAX;
LIST_PREPEND(device_bandwidths, c->blockio_device_bandwidths, b);
}
if (read)
b->rbps = bytes;
else
b->wbps = bytes;
return 0;
}