core: adding CGroup runtime for io.systemd.Unit.List

This commit is contained in:
Ivan Kruglov
2025-06-05 04:05:05 -07:00
parent dffde7708a
commit 8006ab9047
4 changed files with 328 additions and 2 deletions
+259
View File
@@ -8,6 +8,7 @@
#include "json-util.h"
#include "in-addr-prefix-util.h"
#include "ip-protocol-list.h"
#include "path-util.h"
#include "set.h"
#include "unit.h"
#include "varlink-cgroup.h"
@@ -351,3 +352,261 @@ int unit_cgroup_context_build_json(sd_json_variant **ret, const char *name, void
/* Others */
SD_JSON_BUILD_PAIR_BOOLEAN("CoredumpReceive", c->coredump_receive));
}
static int memory_accounting_metric_build_json(sd_json_variant **ret, const char *name, void *userdata) {
Unit *u = ASSERT_PTR(userdata);
CGroupMemoryAccountingMetric metric;
uint64_t value;
int r;
assert(ret);
assert(name);
metric = cgroup_memory_accounting_metric_from_string(name);
assert(metric >= 0);
r = unit_get_memory_accounting(u, metric, &value);
if (r == -ENODATA)
goto empty;
if (r < 0)
return log_debug_errno(r, "Failed to get value for '%s': %m", name);
if (value == UINT64_MAX)
goto empty;
return sd_json_variant_new_unsigned(ret, value);
empty:
*ret = NULL;
return 0;
}
static int memory_available_build_json(sd_json_variant **ret, const char *name, void *userdata) {
Unit *u = ASSERT_PTR(userdata);
uint64_t value;
int r;
assert(ret);
assert(name);
r = unit_get_memory_available(u, &value);
if (r == -ENODATA)
goto empty;
if (r < 0)
return log_debug_errno(r, "Failed to get value of available memory: %m");
if (value == UINT64_MAX)
goto empty;
return sd_json_variant_new_unsigned(ret, value);
empty:
*ret = NULL;
return 0;
}
static int effective_limit_build_json(sd_json_variant **ret, const char *name, void *userdata) {
Unit *u = ASSERT_PTR(userdata);
CGroupLimitType type;
uint64_t value;
int r;
assert(ret);
assert(name);
type = cgroup_effective_limit_type_from_string(name);
assert(type >= 0);
r = unit_get_effective_limit(u, type, &value);
if (r < 0)
return log_debug_errno(r, "Failed to get value for '%s': %m", name);
if (value == UINT64_MAX) {
*ret = NULL;
return 0;
}
return sd_json_variant_new_unsigned(ret, value);
}
static int cpu_usage_build_json(sd_json_variant **ret, const char *name, void *userdata) {
Unit *u = ASSERT_PTR(userdata);
nsec_t ns;
int r;
assert(ret);
assert(name);
r = unit_get_cpu_usage(u, &ns);
if (r == -ENODATA)
goto empty;
if (r < 0)
return log_debug_errno(r, "Failed to get cpu usage: %m");
if (ns == NSEC_INFINITY)
goto empty;
return sd_json_variant_new_unsigned(ret, ns);
empty:
*ret = NULL;
return 0;
}
static int effective_cpuset_build_json(sd_json_variant **ret, const char *name, void *userdata, const char *cpuset_name) {
Unit *u = ASSERT_PTR(userdata);
_cleanup_(cpu_set_reset) CPUSet cpus = {};
int r;
assert(ret);
assert(name);
assert(cpuset_name);
r = unit_get_cpuset(u, &cpus, cpuset_name);
if (r == -ENODATA) {
*ret = NULL;
return 0;
}
if (r < 0)
return log_debug_errno(r, "Failed to get cpu set '%s': %m", cpuset_name);
return cpu_set_build_json(ret, name, &cpus);
}
static inline int effective_cpus_build_json(sd_json_variant **ret, const char *name, void *userdata) {
return effective_cpuset_build_json(ret, name, userdata, "cpuset.cpus.effective");
}
static inline int effective_mems_build_json(sd_json_variant **ret, const char *name, void *userdata) {
return effective_cpuset_build_json(ret, name, userdata, "cpuset.mems.effective");
}
static int tasks_current_build_json(sd_json_variant **ret, const char *name, void *userdata) {
Unit *u = ASSERT_PTR(userdata);
uint64_t cn;
int r;
assert(ret);
assert(name);
r = unit_get_tasks_current(u, &cn);
if (r == -ENODATA)
goto empty;
if (r < 0)
return log_debug_errno(r, "Failed to get count of current tasks: %m");
if (cn == UINT64_MAX)
goto empty;
return sd_json_variant_new_unsigned(ret, cn);
empty:
*ret = NULL;
return 0;
}
static int get_ip_counter_build_json(sd_json_variant **ret, const char *name, void *userdata) {
Unit *u = ASSERT_PTR(userdata);
CGroupIPAccountingMetric metric;
uint64_t value;
int r;
assert(ret);
assert(name);
metric = cgroup_ip_accounting_metric_from_string(name);
assert(metric >= 0);
r = unit_get_ip_accounting(u, metric, &value);
if (r == -ENODATA)
goto empty;
if (r < 0)
return log_debug_errno(r, "Failed to get value for '%s': %m", name);
if (value == UINT64_MAX)
goto empty;
return sd_json_variant_new_unsigned(ret, value);
empty:
*ret = NULL;
return 0;
}
static int get_io_counter_build_json(sd_json_variant **ret, const char *name, void *userdata) {
Unit *u = ASSERT_PTR(userdata);
CGroupIOAccountingMetric metric;
uint64_t value;
int r;
assert(ret);
assert(name);
metric = cgroup_io_accounting_metric_from_string(name);
assert(metric >= 0);
r = unit_get_io_accounting(u, metric, &value);
if (r == -ENODATA)
goto empty;
if (r < 0)
return log_debug_errno(r, "Failed to get value for '%s': %m", name);
if (value == UINT64_MAX)
goto empty;
return sd_json_variant_new_unsigned(ret, value);
empty:
*ret = NULL;
return 0;
}
int unit_cgroup_runtime_build_json(sd_json_variant **ret, const char *name, void *userdata) {
Unit *u = ASSERT_PTR(userdata);
assert(ret);
assert(name);
CGroupRuntime *crt = unit_get_cgroup_runtime(u);
if (!crt) {
*ret = NULL;
return 0;
}
return sd_json_buildo(
ret,
/* ID */
JSON_BUILD_PAIR_UNSIGNED_NON_ZERO("ID", crt->cgroup_id),
JSON_BUILD_PAIR_STRING_NON_EMPTY("Path", crt->cgroup_path ? empty_to_root(crt->cgroup_path) : NULL),
JSON_BUILD_PAIR_STRING_NON_EMPTY("Slice", unit_slice_name(u)),
/* Memory */
JSON_BUILD_PAIR_CALLBACK_NON_NULL("MemoryCurrent", memory_accounting_metric_build_json, u),
JSON_BUILD_PAIR_CALLBACK_NON_NULL("MemoryPeak", memory_accounting_metric_build_json, u),
JSON_BUILD_PAIR_CALLBACK_NON_NULL("MemorySwapCurrent", memory_accounting_metric_build_json, u),
JSON_BUILD_PAIR_CALLBACK_NON_NULL("MemorySwapPeak", memory_accounting_metric_build_json, u),
JSON_BUILD_PAIR_CALLBACK_NON_NULL("MemoryZSwapCurrent", memory_accounting_metric_build_json, u),
JSON_BUILD_PAIR_CALLBACK_NON_NULL("MemoryAvailable", memory_available_build_json, u),
JSON_BUILD_PAIR_CALLBACK_NON_NULL("EffectiveMemoryMax", effective_limit_build_json, u),
JSON_BUILD_PAIR_CALLBACK_NON_NULL("EffectiveMemoryHigh", effective_limit_build_json, u),
JSON_BUILD_PAIR_CALLBACK_NON_NULL("EffectiveMemoryNodes", effective_mems_build_json, u),
/* CPU */
JSON_BUILD_PAIR_CALLBACK_NON_NULL("CPUUsageNSec", cpu_usage_build_json, u),
JSON_BUILD_PAIR_CALLBACK_NON_NULL("EffectiveCPUs", effective_cpus_build_json, u),
JSON_BUILD_PAIR_CALLBACK_NON_NULL("TasksCurrent", tasks_current_build_json, u),
JSON_BUILD_PAIR_CALLBACK_NON_NULL("EffectiveTasksMax", effective_limit_build_json, u),
/* IP */
JSON_BUILD_PAIR_CALLBACK_NON_NULL("IPIngressBytes", get_ip_counter_build_json, u),
JSON_BUILD_PAIR_CALLBACK_NON_NULL("IPIngressPackets", get_ip_counter_build_json, u),
JSON_BUILD_PAIR_CALLBACK_NON_NULL("IPEgressBytes", get_ip_counter_build_json, u),
JSON_BUILD_PAIR_CALLBACK_NON_NULL("IPEgressPackets", get_ip_counter_build_json, u),
/* IO */
JSON_BUILD_PAIR_CALLBACK_NON_NULL("IOReadBytes", get_io_counter_build_json, u),
JSON_BUILD_PAIR_CALLBACK_NON_NULL("IOReadOperations", get_io_counter_build_json, u),
JSON_BUILD_PAIR_CALLBACK_NON_NULL("IOWriteBytes", get_io_counter_build_json, u),
JSON_BUILD_PAIR_CALLBACK_NON_NULL("IOWriteOperations", get_io_counter_build_json, u));
}
+1
View File
@@ -4,3 +4,4 @@
#include "forward.h"
int unit_cgroup_context_build_json(sd_json_variant **ret, const char *name, void *userdata);
int unit_cgroup_runtime_build_json(sd_json_variant **ret, const char *name, void *userdata);
+2 -1
View File
@@ -300,7 +300,8 @@ static int unit_runtime_build_json(sd_json_variant **ret, const char *name, void
SD_JSON_BUILD_PAIR_CONDITION(!sd_id128_is_null(u->invocation_id), "InvocationID", SD_JSON_BUILD_UUID(u->invocation_id)),
JSON_BUILD_PAIR_CALLBACK_NON_NULL("Markers", markers_build_json, &u->markers),
JSON_BUILD_PAIR_CALLBACK_NON_NULL("ActivationDetails", activation_details_build_json, u->activation_details),
SD_JSON_BUILD_PAIR_BOOLEAN("DebugInvocation", u->debug_invocation));
SD_JSON_BUILD_PAIR_BOOLEAN("DebugInvocation", u->debug_invocation),
JSON_BUILD_PAIR_CALLBACK_NON_NULL("CGroup", unit_cgroup_runtime_build_json, u));
}
static int list_unit_one(sd_varlink *link, Unit *unit, bool more) {
+66 -1
View File
@@ -393,6 +393,67 @@ static SD_VARLINK_DEFINE_STRUCT_TYPE(
SD_VARLINK_FIELD_COMMENT("Trigger unit name"),
SD_VARLINK_DEFINE_FIELD(name, SD_VARLINK_STRING, 0));
static SD_VARLINK_DEFINE_STRUCT_TYPE(
CGroupRuntime,
/* ID */
SD_VARLINK_FIELD_COMMENT("ID of the CGroup"),
SD_VARLINK_DEFINE_FIELD(ID, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Path of the CGroup"),
SD_VARLINK_DEFINE_FIELD(Path, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Slice of the CGroup"),
SD_VARLINK_DEFINE_FIELD(Slice, SD_VARLINK_STRING, SD_VARLINK_NULLABLE),
/* Memory */
SD_VARLINK_FIELD_COMMENT("The current amount of memory used by the cgroup, in bytes"),
SD_VARLINK_DEFINE_FIELD(MemoryCurrent, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("The peak amount of memory used by the cgroup since its creation, in bytes"),
SD_VARLINK_DEFINE_FIELD(MemoryPeak, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("The current amount of swap space used by the cgroup, in bytes"),
SD_VARLINK_DEFINE_FIELD(MemorySwapCurrent, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("The peak amount of swap space used by the cgroup since its creation, in bytes"),
SD_VARLINK_DEFINE_FIELD(MemorySwapPeak, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("The current amount of zswap space used by the cgroup, in bytes"),
SD_VARLINK_DEFINE_FIELD(MemoryZSwapCurrent, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("The available memory for the cgroup, in bytes."),
SD_VARLINK_DEFINE_FIELD(MemoryAvailable, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("The effective maximum amount of memory allowed for the cgroup, in bytes"),
SD_VARLINK_DEFINE_FIELD(EffectiveMemoryMax, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("The effective high watermark for memory usage by the cgroup, in bytes"),
SD_VARLINK_DEFINE_FIELD(EffectiveMemoryHigh, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("Memory NUMA nodes that the cgroup is allowed to use"),
SD_VARLINK_DEFINE_FIELD(EffectiveMemoryNodes, SD_VARLINK_INT, SD_VARLINK_ARRAY|SD_VARLINK_NULLABLE),
/* CPU */
SD_VARLINK_FIELD_COMMENT("The total CPU usage time in nanoseconds (ns) for the cgroup"),
SD_VARLINK_DEFINE_FIELD(CPUUsageNSec, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("NUMA nodes that the cgroup is allowed to use"),
SD_VARLINK_DEFINE_FIELD(EffectiveCPUs, SD_VARLINK_INT, SD_VARLINK_ARRAY|SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("The current number of tasks (i.e., processes or threads) running within the cgroup"),
SD_VARLINK_DEFINE_FIELD(TasksCurrent, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("The maximum number of tasks that the cgroup is allowed to run concurrently"),
SD_VARLINK_DEFINE_FIELD(EffectiveTasksMax, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
/* IP */
SD_VARLINK_FIELD_COMMENT("The total number of bytes received by the cgroup's IP stack"),
SD_VARLINK_DEFINE_FIELD(IPIngressBytes, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("The total number of incoming packets received by the cgroup's IP stack"),
SD_VARLINK_DEFINE_FIELD(IPIngressPackets, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("iThe total number of bytes sent by the cgroup's IP stack"),
SD_VARLINK_DEFINE_FIELD(IPEgressBytes, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("The total number of outgoing packets sent by the cgroup's IP stack"),
SD_VARLINK_DEFINE_FIELD(IPEgressPackets, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
/* IO */
SD_VARLINK_FIELD_COMMENT("The total number of bytes read from block devices by the cgroup"),
SD_VARLINK_DEFINE_FIELD(IOReadBytes, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("The total number of read operations performed on block devices by the cgroup"),
SD_VARLINK_DEFINE_FIELD(IOReadOperations, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("The total number of bytes written to block devices by the cgroup"),
SD_VARLINK_DEFINE_FIELD(IOWriteBytes, SD_VARLINK_INT, SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("The total number of write operations performed on block devices by the cgroup"),
SD_VARLINK_DEFINE_FIELD(IOWriteOperations, SD_VARLINK_INT, SD_VARLINK_NULLABLE));
static SD_VARLINK_DEFINE_STRUCT_TYPE(
UnitRuntime,
SD_VARLINK_FIELD_COMMENT("If not empty, the field contains the name of another unit that this unit follows in state"),
@@ -450,7 +511,9 @@ static SD_VARLINK_DEFINE_STRUCT_TYPE(
SD_VARLINK_FIELD_COMMENT("Provides details about why a unit was activated"),
SD_VARLINK_DEFINE_FIELD_BY_TYPE(ActivationDetails, ActivationDetails, SD_VARLINK_ARRAY|SD_VARLINK_NULLABLE),
SD_VARLINK_FIELD_COMMENT("When true, logs about this unit will be at debug level regardless of other log level settings"),
SD_VARLINK_DEFINE_FIELD(DebugInvocation, SD_VARLINK_BOOL, 0));
SD_VARLINK_DEFINE_FIELD(DebugInvocation, SD_VARLINK_BOOL, 0),
SD_VARLINK_FIELD_COMMENT("The cgroup runtime of the unit"),
SD_VARLINK_DEFINE_FIELD_BY_TYPE(CGroup, CGroupRuntime, SD_VARLINK_NULLABLE));
static SD_VARLINK_DEFINE_ERROR(NoSuchUnit);
@@ -496,5 +559,7 @@ SD_VARLINK_DEFINE_INTERFACE(
&vl_type_CGroupDeviceAllow,
SD_VARLINK_SYMBOL_COMMENT("CGroup context of a unit"),
&vl_type_CGroupContext,
SD_VARLINK_SYMBOL_COMMENT("CGroup runtime of a unit"),
&vl_type_CGroupRuntime,
SD_VARLINK_SYMBOL_COMMENT("No matching unit found"),
&vl_error_NoSuchUnit);