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:
parent
4e080f502a
commit
9be572497d
|
@ -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;
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
|
|
Loading…
Reference in a new issue