From 9be572497df8dd0a076c3a2c9142e25b1106aa60 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Wed, 18 May 2016 13:50:56 -0700 Subject: 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. --- src/basic/cgroup-util.c | 12 +++++++++++ src/basic/cgroup-util.h | 14 +++++++++++++ src/core/cgroup.c | 47 ++++++++++++++++++++----------------------- src/core/cgroup.h | 4 ++-- src/core/dbus-cgroup.c | 50 +++++++++++++++------------------------------- src/core/load-fragment.c | 21 +++++++++---------- src/shared/bus-unit-util.c | 3 +-- src/systemctl/systemctl.c | 2 +- 8 files changed, 77 insertions(+), 76 deletions(-) diff --git a/src/basic/cgroup-util.c b/src/basic/cgroup-util.c index ff57cf30b7..8eab100748 100644 --- a/src/basic/cgroup-util.c +++ b/src/basic/cgroup-util.c @@ -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; diff --git a/src/basic/cgroup-util.h b/src/basic/cgroup-util.h index a696c1fa60..0d96fb6b76 100644 --- a/src/basic/cgroup-util.h +++ b/src/basic/cgroup-util.h @@ -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) diff --git a/src/core/cgroup.c b/src/core/cgroup.c index 4f1637ffe9..0b902fa6f7 100644 --- a/src/core/cgroup.c +++ b/src/core/cgroup.c @@ -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]; - - 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)); + CGroupIOLimitType type; + + 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++; - } - - if (l->wbps_max != CGROUP_LIMIT_MAX) { - xsprintf(wbps_buf, "%" PRIu64, l->wbps_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"); + } } - 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, diff --git a/src/core/cgroup.h b/src/core/cgroup.h index a533923072..1907461f7e 100644 --- a/src/core/cgroup.h +++ b/src/core/cgroup.h @@ -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 { diff --git a/src/core/dbus-cgroup.c b/src/core/dbus-cgroup.c index a2a4a6249c..4372828e30 100644 --- a/src/core/dbus-cgroup.c +++ b/src/core/dbus-cgroup.c @@ -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) diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c index cea615132a..9626d861c5 100644 --- a/src/core/load-fragment.c +++ b/src/core/load-fragment.c @@ -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; } diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c index 8f0df84793..03ae67ae7b 100644 --- a/src/shared/bus-unit-util.c +++ b/src/shared/bus-unit-util.c @@ -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); diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index 0faf37d320..2097c5a660 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -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; -- cgit v1.2.3-54-g00ecf