systemctl: allow percent-based MemoryLimit= settings via systemctl set-property
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.
This commit is contained in:
@@ -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;
|
||||
|
||||
+28
-15
@@ -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;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user