core: introduce CGroupIOLimitType enums
authorTejun Heo <htejun@fb.com>
Wed, 18 May 2016 20:50:56 +0000 (13:50 -0700)
committerTejun Heo <tj@kernel.org>
Wed, 18 May 2016 20:50:56 +0000 (13:50 -0700)
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
src/basic/cgroup-util.h
src/core/cgroup.c
src/core/cgroup.h
src/core/dbus-cgroup.c
src/core/load-fragment.c
src/shared/bus-unit-util.c
src/systemctl/systemctl.c

index ff57cf3..8eab100 100644 (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;
index a696c1f..0d96fb6 100644 (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)
index 4f1637f..0b902fa 100644 (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];
-
-                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,
index a533923..1907461 100644 (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 {
index a2a4a62..4372828 100644 (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)
index cea6151..9626d86 100644 (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;
 }
index 8f0df84..03ae67a 100644 (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);
index 0faf37d..2097c5a 100644 (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;