]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
systemctl: allow percent-based MemoryLimit= settings via systemctl set-property
authorLennart Poettering <lennart@poettering.net>
Wed, 8 Jun 2016 18:52:06 +0000 (20:52 +0200)
committerLennart Poettering <lennart@poettering.net>
Tue, 14 Jun 2016 18:01:45 +0000 (20:01 +0200)
The unit files already accept relative, percent-based memory limit
specification, let's make sure "systemctl set-property" support this too.

Since we want the physical memory size of the destination machine to apply we
pass the percentage in a new set of properties that only exist for this
purpose, and can only be set.

src/core/dbus-cgroup.c
src/shared/bus-unit-util.c

index fe035109e39f478203836d7c883da4ce99f76d02..27bbe2d26d46a8b8d524dd538c375564696d1df9 100644 (file)
@@ -856,6 +856,38 @@ int bus_cgroup_set_property(
 
                 return 1;
 
+        } else if (STR_IN_SET(name, "MemoryLowByPhysicalMemory", "MemoryHighByPhysicalMemory", "MemoryMaxByPhysicalMemory")) {
+                uint32_t raw;
+                uint64_t v;
+
+                r = sd_bus_message_read(message, "u", &raw);
+                if (r < 0)
+                        return r;
+
+                v = physical_memory_scale(raw, UINT32_MAX);
+                if (v <= 0 || v == UINT64_MAX)
+                        return sd_bus_error_set_errnof(error, EINVAL, "%s= is out of range", name);
+
+                if (mode != UNIT_CHECK) {
+                        const char *e;
+
+                        /* Chop off suffix */
+                        assert_se(e = endswith(name, "ByPhysicalMemory"));
+                        name = strndupa(name, e - name);
+
+                        if (streq(name, "MemoryLow"))
+                                c->memory_low = v;
+                        else if (streq(name, "MemoryHigh"))
+                                c->memory_high = v;
+                        else
+                                c->memory_max = v;
+
+                        unit_invalidate_cgroup(u, CGROUP_MASK_MEMORY);
+                        unit_write_drop_in_private_format(u, mode, name, "%s=%" PRIu32 "%%", name, (uint32_t) (DIV_ROUND_UP((uint64_t) raw * 100, (uint64_t) UINT32_MAX)));
+                }
+
+                return 1;
+
         } else if (streq(name, "MemoryLimit")) {
                 uint64_t limit;
 
@@ -877,6 +909,26 @@ int bus_cgroup_set_property(
 
                 return 1;
 
+        } else if (streq(name, "MemoryLimitByPhysicalMemory")) {
+                uint64_t limit;
+                uint32_t raw;
+
+                r = sd_bus_message_read(message, "u", &raw);
+                if (r < 0)
+                        return r;
+
+                limit = physical_memory_scale(raw, UINT32_MAX);
+                if (limit <= 0 || limit == UINT64_MAX)
+                        return sd_bus_error_set_errnof(error, EINVAL, "%s= is out of range", name);
+
+                if (mode != UNIT_CHECK) {
+                        c->memory_limit = limit;
+                        unit_invalidate_cgroup(u, CGROUP_MASK_MEMORY);
+                        unit_write_drop_in_private_format(u, mode, "MemoryLimit", "MemoryLimit=%" PRIu32 "%%", (uint32_t) (DIV_ROUND_UP((uint64_t) raw * 100, (uint64_t) UINT32_MAX)));
+                }
+
+                return 1;
+
         } else if (streq(name, "DevicePolicy")) {
                 const char *policy;
                 CGroupDevicePolicy p;
index 778c79b3cffd72f2d9c58099c75591b28c86b7a8..6fc201b88575fdc7350c783469c9dca71b6cd25b 100644 (file)
@@ -120,6 +120,34 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen
                 strcpy(mempcpy(n, field, l - 3), "USec");
                 r = sd_bus_message_append(m, "sv", n, "t", t);
                 goto finish;
+
+        } else if (STR_IN_SET(field, "MemoryLow", "MemoryHigh", "MemoryMax", "MemoryLimit")) {
+                uint64_t bytes;
+
+                if (isempty(eq) || streq(eq, "infinity"))
+                        bytes = CGROUP_LIMIT_MAX;
+                else {
+                        r = parse_percent(eq);
+                        if (r >= 0) {
+                                char *n;
+
+                                /* When this is a percentage we'll convert this into a relative value in the range
+                                 * 0…UINT32_MAX and pass it in the MemoryLowByPhysicalMemory property (and related
+                                 * ones). This way the physical memory size can be determined server-side */
+
+                                n = strjoina(field, "ByPhysicalMemory");
+                                r = sd_bus_message_append(m, "sv", n, "u", (uint32_t) (((uint64_t) UINT32_MAX * r) / 100U));
+                                goto finish;
+
+                        } else {
+                                r = parse_size(eq, 1024, &bytes);
+                                if (r < 0)
+                                        return log_error_errno(r, "Failed to parse bytes specification %s", assignment);
+                        }
+                }
+
+                r = sd_bus_message_append(m, "sv", field, "t", bytes);
+                goto finish;
         }
 
         r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
@@ -163,21 +191,6 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen
 
                 r = sd_bus_message_append(m, "v", "b", r);
 
-        } else if (STR_IN_SET(field, "MemoryLow", "MemoryHigh", "MemoryMax", "MemoryLimit")) {
-                uint64_t bytes;
-
-                if (isempty(eq) || streq(eq, "infinity"))
-                        bytes = CGROUP_LIMIT_MAX;
-                else {
-                        r = parse_size(eq, 1024, &bytes);
-                        if (r < 0) {
-                                log_error("Failed to parse bytes specification %s", assignment);
-                                return -EINVAL;
-                        }
-                }
-
-                r = sd_bus_message_append(m, "v", "t", bytes);
-
         } else if (streq(field, "TasksMax")) {
                 uint64_t n;