core: introduce CGroupIOLimitType enums

Currently, there are two cgroup IO limits, bandwidth max for read and write,
and they are hard-coded in various places.  This is fine for two limits but IO
is expected to grow more limits - low, high and max limits for bandwidth and
IOPS - and hard-coding each limit won't make sense.

This patch replaces hard-coded limits with an array indexed by
CGroupIOLimitType and accompanying string and default value tables so that new
limits can be added trivially.
This commit is contained in:
Tejun Heo 2016-05-18 13:50:56 -07:00 committed by Tejun Heo
parent 4e080f502a
commit 9be572497d
8 changed files with 76 additions and 75 deletions

View File

@ -2269,6 +2269,18 @@ int cg_weight_parse(const char *s, uint64_t *ret) {
return 0;
}
const uint64_t cgroup_io_limit_defaults[_CGROUP_IO_LIMIT_TYPE_MAX] = {
[CGROUP_IO_RBPS_MAX] = CGROUP_LIMIT_MAX,
[CGROUP_IO_WBPS_MAX] = CGROUP_LIMIT_MAX,
};
static const char* const cgroup_io_limit_type_table[_CGROUP_IO_LIMIT_TYPE_MAX] = {
[CGROUP_IO_RBPS_MAX] = "IOReadBandwidthMax",
[CGROUP_IO_WBPS_MAX] = "IOWriteBandwidthMax",
};
DEFINE_STRING_TABLE_LOOKUP(cgroup_io_limit_type, CGroupIOLimitType);
int cg_cpu_shares_parse(const char *s, uint64_t *ret) {
uint64_t u;
int r;

View File

@ -72,6 +72,20 @@ static inline bool CGROUP_WEIGHT_IS_OK(uint64_t x) {
(x >= CGROUP_WEIGHT_MIN && x <= CGROUP_WEIGHT_MAX);
}
/* IO limits on unified hierarchy */
typedef enum CGroupIOLimitType {
CGROUP_IO_RBPS_MAX,
CGROUP_IO_WBPS_MAX,
_CGROUP_IO_LIMIT_TYPE_MAX,
_CGROUP_IO_LIMIT_TYPE_INVALID = -1
} CGroupIOLimitType;
extern const uint64_t cgroup_io_limit_defaults[_CGROUP_IO_LIMIT_TYPE_MAX];
const char* cgroup_io_limit_type_to_string(CGroupIOLimitType t) _const_;
CGroupIOLimitType cgroup_io_limit_type_from_string(const char *s) _pure_;
/* Special values for the cpu.shares attribute */
#define CGROUP_CPU_SHARES_INVALID ((uint64_t) -1)
#define CGROUP_CPU_SHARES_MIN UINT64_C(2)

View File

@ -184,20 +184,16 @@ void cgroup_context_dump(CGroupContext *c, FILE* f, const char *prefix) {
LIST_FOREACH(device_limits, il, c->io_device_limits) {
char buf[FORMAT_BYTES_MAX];
CGroupIOLimitType type;
if (il->rbps_max != CGROUP_LIMIT_MAX)
fprintf(f,
"%sIOReadBandwidthMax=%s %s\n",
prefix,
il->path,
format_bytes(buf, sizeof(buf), il->rbps_max));
if (il->wbps_max != CGROUP_LIMIT_MAX)
fprintf(f,
"%sIOWriteBandwidthMax=%s %s\n",
prefix,
il->path,
format_bytes(buf, sizeof(buf), il->wbps_max));
for (type = 0; type < _CGROUP_IO_LIMIT_TYPE_MAX; type++)
if (il->limits[type] != cgroup_io_limit_defaults[type])
fprintf(f,
"%s%s=%s %s\n",
prefix,
cgroup_io_limit_type_to_string(type),
il->path,
format_bytes(buf, sizeof(buf), il->limits[type]));
}
LIST_FOREACH(device_weights, w, c->blockio_device_weights)
@ -442,9 +438,9 @@ void cgroup_context_apply(CGroupContext *c, CGroupMask mask, const char *path, M
}
LIST_FOREACH_SAFE(device_limits, l, next, c->io_device_limits) {
char rbps_buf[DECIMAL_STR_MAX(uint64_t)] = "max";
char wbps_buf[DECIMAL_STR_MAX(uint64_t)] = "max";
char limit_bufs[_CGROUP_IO_LIMIT_TYPE_MAX][DECIMAL_STR_MAX(uint64_t)];
char buf[DECIMAL_STR_MAX(dev_t)*2+2+(5+DECIMAL_STR_MAX(uint64_t)+1)*2];
CGroupIOLimitType type;
dev_t dev;
unsigned n = 0;
@ -452,17 +448,18 @@ void cgroup_context_apply(CGroupContext *c, CGroupMask mask, const char *path, M
if (r < 0)
continue;
if (l->rbps_max != CGROUP_LIMIT_MAX) {
xsprintf(rbps_buf, "%" PRIu64, l->rbps_max);
n++;
for (type = 0; type < _CGROUP_IO_LIMIT_TYPE_MAX; type++) {
if (l->limits[type] != cgroup_io_limit_defaults[type]) {
xsprintf(limit_bufs[type], "%" PRIu64, l->limits[type]);
n++;
} else {
xsprintf(limit_bufs[type], "%s",
l->limits[type] == CGROUP_LIMIT_MAX ? "max" : "0");
}
}
if (l->wbps_max != CGROUP_LIMIT_MAX) {
xsprintf(wbps_buf, "%" PRIu64, l->wbps_max);
n++;
}
xsprintf(buf, "%u:%u rbps=%s wbps=%s\n", major(dev), minor(dev), rbps_buf, wbps_buf);
xsprintf(buf, "%u:%u rbps=%s wbps=%s\n", major(dev), minor(dev),
limit_bufs[CGROUP_IO_RBPS_MAX], limit_bufs[CGROUP_IO_WBPS_MAX]);
r = cg_set_attribute("io", path, "io.max", buf);
if (r < 0)
log_full_errno(IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r,

View File

@ -23,6 +23,7 @@
#include "list.h"
#include "time-util.h"
#include "cgroup-util.h"
typedef struct CGroupContext CGroupContext;
typedef struct CGroupDeviceAllow CGroupDeviceAllow;
@ -64,8 +65,7 @@ struct CGroupIODeviceWeight {
struct CGroupIODeviceLimit {
LIST_FIELDS(CGroupIODeviceLimit, device_limits);
char *path;
uint64_t rbps_max;
uint64_t wbps_max;
uint64_t limits[_CGROUP_IO_LIMIT_TYPE_MAX];
};
struct CGroupBlockIODeviceWeight {

View File

@ -80,17 +80,13 @@ static int property_get_io_device_limits(
return r;
LIST_FOREACH(device_limits, l, c->io_device_limits) {
uint64_t v;
CGroupIOLimitType type;
if (streq(property, "IOReadBandwidthMax"))
v = l->rbps_max;
else
v = l->wbps_max;
if (v == CGROUP_LIMIT_MAX)
type = cgroup_io_limit_type_from_string(property);
if (type < 0 || l->limits[type] == cgroup_io_limit_defaults[type])
continue;
r = sd_bus_message_append(reply, "(st)", l->path, v);
r = sd_bus_message_append(reply, "(st)", l->path, l->limits[type]);
if (r < 0)
return r;
}
@ -273,6 +269,7 @@ int bus_cgroup_set_property(
UnitSetPropertiesMode mode,
sd_bus_error *error) {
CGroupIOLimitType iol_type;
int r;
assert(u);
@ -416,15 +413,11 @@ int bus_cgroup_set_property(
return 1;
} else if (streq(name, "IOReadBandwidthMax") || streq(name, "IOWriteBandwidthMax")) {
} else if ((iol_type = cgroup_io_limit_type_from_string(name)) >= 0) {
const char *path;
bool read = true;
unsigned n = 0;
uint64_t u64;
if (streq(name, "IOWriteBandwidthMax"))
read = false;
r = sd_bus_message_enter_container(message, 'a', "(st)");
if (r < 0)
return r;
@ -442,6 +435,8 @@ int bus_cgroup_set_property(
}
if (!a) {
CGroupIOLimitType type;
a = new0(CGroupIODeviceLimit, 1);
if (!a)
return -ENOMEM;
@ -452,16 +447,13 @@ int bus_cgroup_set_property(
return -ENOMEM;
}
a->rbps_max = CGROUP_LIMIT_MAX;
a->wbps_max = CGROUP_LIMIT_MAX;
for (type = 0; type < _CGROUP_IO_LIMIT_TYPE_MAX; type++)
a->limits[type] = cgroup_io_limit_defaults[type];
LIST_PREPEND(device_limits, c->io_device_limits, a);
}
if (read)
a->rbps_max = u64;
else
a->wbps_max = u64;
a->limits[iol_type] = u64;
}
n++;
@ -481,10 +473,7 @@ int bus_cgroup_set_property(
if (n == 0) {
LIST_FOREACH(device_limits, a, c->io_device_limits)
if (read)
a->rbps_max = CGROUP_LIMIT_MAX;
else
a->wbps_max = CGROUP_LIMIT_MAX;
a->limits[iol_type] = cgroup_io_limit_defaults[iol_type];
}
unit_invalidate_cgroup(u, CGROUP_MASK_IO);
@ -493,17 +482,10 @@ int bus_cgroup_set_property(
if (!f)
return -ENOMEM;
if (read) {
fputs("IOReadBandwidthMax=\n", f);
LIST_FOREACH(device_limits, a, c->io_device_limits)
if (a->rbps_max != CGROUP_LIMIT_MAX)
fprintf(f, "IOReadBandwidthMax=%s %" PRIu64 "\n", a->path, a->rbps_max);
} else {
fputs("IOWriteBandwidthMax=\n", f);
LIST_FOREACH(device_limits, a, c->io_device_limits)
if (a->wbps_max != CGROUP_LIMIT_MAX)
fprintf(f, "IOWriteBandwidthMax=%s %" PRIu64 "\n", a->path, a->wbps_max);
}
fprintf(f, "%s=\n", name);
LIST_FOREACH(device_limits, a, c->io_device_limits)
if (a->limits[iol_type] != cgroup_io_limit_defaults[iol_type])
fprintf(f, "%s=%s %" PRIu64 "\n", name, a->path, a->limits[iol_type]);
r = fflush_and_check(f);
if (r < 0)

View File

@ -3023,9 +3023,9 @@ int config_parse_io_limit(
_cleanup_free_ char *path = NULL;
CGroupIODeviceLimit *l = NULL, *t;
CGroupContext *c = data;
CGroupIOLimitType type;
const char *limit;
uint64_t num;
bool read;
size_t n;
int r;
@ -3033,14 +3033,12 @@ int config_parse_io_limit(
assert(lvalue);
assert(rvalue);
read = streq("IOReadBandwidthMax", lvalue);
type = cgroup_io_limit_type_from_string(lvalue);
assert(type >= 0);
if (isempty(rvalue)) {
LIST_FOREACH(device_limits, l, c->io_device_limits)
if (read)
l->rbps_max = CGROUP_LIMIT_MAX;
else
l->wbps_max = CGROUP_LIMIT_MAX;
l->limits[type] = cgroup_io_limit_defaults[type];
return 0;
}
@ -3080,22 +3078,21 @@ int config_parse_io_limit(
}
if (!l) {
CGroupIOLimitType ttype;
l = new0(CGroupIODeviceLimit, 1);
if (!l)
return log_oom();
l->path = path;
path = NULL;
l->rbps_max = CGROUP_LIMIT_MAX;
l->wbps_max = CGROUP_LIMIT_MAX;
for (ttype = 0; ttype < _CGROUP_IO_LIMIT_TYPE_MAX; ttype++)
l->limits[ttype] = cgroup_io_limit_defaults[ttype];
LIST_PREPEND(device_limits, c->io_device_limits, l);
}
if (read)
l->rbps_max = num;
else
l->wbps_max = num;
l->limits[type] = num;
return 0;
}

View File

@ -284,8 +284,7 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen
r = sd_bus_message_append(m, "v", "a(ss)", 1, path, rwm);
}
} else if (STR_IN_SET(field, "IOReadBandwidthMax", "IOWriteBandwidthMax",
"BlockIOReadBandwidth", "BlockIOWriteBandwidth")) {
} else if (cgroup_io_limit_type_from_string(field) >= 0 || STR_IN_SET(field, "BlockIOReadBandwidth", "BlockIOWriteBandwidth")) {
if (isempty(eq))
r = sd_bus_message_append(m, "v", "a(st)", 0);

View File

@ -4447,7 +4447,7 @@ static int print_property(const char *name, sd_bus_message *m, const char *conte
return 0;
} else if (contents[1] == SD_BUS_TYPE_STRUCT_BEGIN && (streq(name, "IOReadBandwidthMax") || streq(name, "IOWriteBandwidthMax") ||
} else if (contents[1] == SD_BUS_TYPE_STRUCT_BEGIN && (cgroup_io_limit_type_from_string(name) >= 0 ||
streq(name, "BlockIOReadBandwidth") || streq(name, "BlockIOWriteBandwidth"))) {
const char *path;
uint64_t bandwidth;