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; 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) { int cg_cpu_shares_parse(const char *s, uint64_t *ret) {
uint64_t u; uint64_t u;
int r; 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); (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 */ /* Special values for the cpu.shares attribute */
#define CGROUP_CPU_SHARES_INVALID ((uint64_t) -1) #define CGROUP_CPU_SHARES_INVALID ((uint64_t) -1)
#define CGROUP_CPU_SHARES_MIN UINT64_C(2) #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) { LIST_FOREACH(device_limits, il, c->io_device_limits) {
char buf[FORMAT_BYTES_MAX]; char buf[FORMAT_BYTES_MAX];
CGroupIOLimitType type;
if (il->rbps_max != CGROUP_LIMIT_MAX) for (type = 0; type < _CGROUP_IO_LIMIT_TYPE_MAX; type++)
fprintf(f, if (il->limits[type] != cgroup_io_limit_defaults[type])
"%sIOReadBandwidthMax=%s %s\n", fprintf(f,
prefix, "%s%s=%s %s\n",
il->path, prefix,
format_bytes(buf, sizeof(buf), il->rbps_max)); cgroup_io_limit_type_to_string(type),
il->path,
if (il->wbps_max != CGROUP_LIMIT_MAX) format_bytes(buf, sizeof(buf), il->limits[type]));
fprintf(f,
"%sIOWriteBandwidthMax=%s %s\n",
prefix,
il->path,
format_bytes(buf, sizeof(buf), il->wbps_max));
} }
LIST_FOREACH(device_weights, w, c->blockio_device_weights) 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) { LIST_FOREACH_SAFE(device_limits, l, next, c->io_device_limits) {
char rbps_buf[DECIMAL_STR_MAX(uint64_t)] = "max"; char limit_bufs[_CGROUP_IO_LIMIT_TYPE_MAX][DECIMAL_STR_MAX(uint64_t)];
char wbps_buf[DECIMAL_STR_MAX(uint64_t)] = "max";
char buf[DECIMAL_STR_MAX(dev_t)*2+2+(5+DECIMAL_STR_MAX(uint64_t)+1)*2]; char buf[DECIMAL_STR_MAX(dev_t)*2+2+(5+DECIMAL_STR_MAX(uint64_t)+1)*2];
CGroupIOLimitType type;
dev_t dev; dev_t dev;
unsigned n = 0; unsigned n = 0;
@ -452,17 +448,18 @@ void cgroup_context_apply(CGroupContext *c, CGroupMask mask, const char *path, M
if (r < 0) if (r < 0)
continue; continue;
if (l->rbps_max != CGROUP_LIMIT_MAX) { for (type = 0; type < _CGROUP_IO_LIMIT_TYPE_MAX; type++) {
xsprintf(rbps_buf, "%" PRIu64, l->rbps_max); if (l->limits[type] != cgroup_io_limit_defaults[type]) {
n++; 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(buf, "%u:%u rbps=%s wbps=%s\n", major(dev), minor(dev),
xsprintf(wbps_buf, "%" PRIu64, l->wbps_max); limit_bufs[CGROUP_IO_RBPS_MAX], limit_bufs[CGROUP_IO_WBPS_MAX]);
n++;
}
xsprintf(buf, "%u:%u rbps=%s wbps=%s\n", major(dev), minor(dev), rbps_buf, wbps_buf);
r = cg_set_attribute("io", path, "io.max", buf); r = cg_set_attribute("io", path, "io.max", buf);
if (r < 0) if (r < 0)
log_full_errno(IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r, log_full_errno(IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r,

View file

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

View file

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

View file

@ -3023,9 +3023,9 @@ int config_parse_io_limit(
_cleanup_free_ char *path = NULL; _cleanup_free_ char *path = NULL;
CGroupIODeviceLimit *l = NULL, *t; CGroupIODeviceLimit *l = NULL, *t;
CGroupContext *c = data; CGroupContext *c = data;
CGroupIOLimitType type;
const char *limit; const char *limit;
uint64_t num; uint64_t num;
bool read;
size_t n; size_t n;
int r; int r;
@ -3033,14 +3033,12 @@ int config_parse_io_limit(
assert(lvalue); assert(lvalue);
assert(rvalue); assert(rvalue);
read = streq("IOReadBandwidthMax", lvalue); type = cgroup_io_limit_type_from_string(lvalue);
assert(type >= 0);
if (isempty(rvalue)) { if (isempty(rvalue)) {
LIST_FOREACH(device_limits, l, c->io_device_limits) LIST_FOREACH(device_limits, l, c->io_device_limits)
if (read) l->limits[type] = cgroup_io_limit_defaults[type];
l->rbps_max = CGROUP_LIMIT_MAX;
else
l->wbps_max = CGROUP_LIMIT_MAX;
return 0; return 0;
} }
@ -3080,22 +3078,21 @@ int config_parse_io_limit(
} }
if (!l) { if (!l) {
CGroupIOLimitType ttype;
l = new0(CGroupIODeviceLimit, 1); l = new0(CGroupIODeviceLimit, 1);
if (!l) if (!l)
return log_oom(); return log_oom();
l->path = path; l->path = path;
path = NULL; path = NULL;
l->rbps_max = CGROUP_LIMIT_MAX; for (ttype = 0; ttype < _CGROUP_IO_LIMIT_TYPE_MAX; ttype++)
l->wbps_max = CGROUP_LIMIT_MAX; l->limits[ttype] = cgroup_io_limit_defaults[ttype];
LIST_PREPEND(device_limits, c->io_device_limits, l); LIST_PREPEND(device_limits, c->io_device_limits, l);
} }
if (read) l->limits[type] = num;
l->rbps_max = num;
else
l->wbps_max = num;
return 0; 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); r = sd_bus_message_append(m, "v", "a(ss)", 1, path, rwm);
} }
} else if (STR_IN_SET(field, "IOReadBandwidthMax", "IOWriteBandwidthMax", } else if (cgroup_io_limit_type_from_string(field) >= 0 || STR_IN_SET(field, "BlockIOReadBandwidth", "BlockIOWriteBandwidth")) {
"BlockIOReadBandwidth", "BlockIOWriteBandwidth")) {
if (isempty(eq)) if (isempty(eq))
r = sd_bus_message_append(m, "v", "a(st)", 0); 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; 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"))) { streq(name, "BlockIOReadBandwidth") || streq(name, "BlockIOWriteBandwidth"))) {
const char *path; const char *path;
uint64_t bandwidth; uint64_t bandwidth;