1 Star 0 Fork 98

Mingtai/systemd

forked from src-openEuler/systemd 
加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
该仓库未声明开源许可证文件(LICENSE),使用请关注具体项目描述及其代码上游依赖。
克隆/下载
core-cgroup-support-cpuset.patch 40.26 KB
一键复制 编辑 原始数据 按行查看 历史
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872
From 2ea8175b3d8ec118fa0f42392485ce0f4308456a Mon Sep 17 00:00:00 2001
From: licunlong <licunlong1@huawei.com>
Date: Thu, 6 May 2021 09:38:54 +0800
Subject: [PATCH] core-cgroup: support cpuset
This patch add support for cpuset subsystem.
---
src/basic/cgroup-util.c | 3 +-
src/basic/cgroup-util.h | 10 ++-
src/basic/string-util.c | 42 +++++++++
src/basic/string-util.h | 2 +
src/core/cgroup.c | 86 ++++++++++++++++---
src/core/cgroup.h | 10 ++-
src/core/dbus-cgroup.c | 52 +++++++++--
src/core/dbus-manager.c | 1 +
src/core/load-fragment-gperf.gperf.in | 5 ++
src/core/load-fragment.c | 73 +++++++++++++++-
src/core/load-fragment.h | 1 +
src/core/main.c | 4 +
src/core/manager.c | 1 +
src/core/manager.h | 1 +
src/core/system.conf.in | 1 +
src/core/unit.c | 1 +
src/shared/bus-unit-util.c | 15 +++-
src/shared/cpu-set-util.c | 1 +
src/test/test-cgroup-mask.c | 5 +-
.../fuzz-unit-file/directives-all.service | 5 ++
test/fuzz/fuzz-unit-file/directives.mount | 5 ++
test/fuzz/fuzz-unit-file/directives.scope | 5 ++
test/fuzz/fuzz-unit-file/directives.service | 5 ++
test/fuzz/fuzz-unit-file/directives.slice | 5 ++
test/fuzz/fuzz-unit-file/directives.socket | 5 ++
test/fuzz/fuzz-unit-file/directives.swap | 5 ++
26 files changed, 319 insertions(+), 30 deletions(-)
diff --git a/src/basic/cgroup-util.c b/src/basic/cgroup-util.c
index 1ff6160..01a4181 100644
--- a/src/basic/cgroup-util.c
+++ b/src/basic/cgroup-util.c
@@ -2155,12 +2155,13 @@ bool fd_is_cgroup_fs(int fd) {
static const char *const cgroup_controller_table[_CGROUP_CONTROLLER_MAX] = {
[CGROUP_CONTROLLER_CPU] = "cpu",
[CGROUP_CONTROLLER_CPUACCT] = "cpuacct",
- [CGROUP_CONTROLLER_CPUSET] = "cpuset",
+ [CGROUP_CONTROLLER_CPUSET2] = "cpuset2",
[CGROUP_CONTROLLER_IO] = "io",
[CGROUP_CONTROLLER_BLKIO] = "blkio",
[CGROUP_CONTROLLER_MEMORY] = "memory",
[CGROUP_CONTROLLER_DEVICES] = "devices",
[CGROUP_CONTROLLER_PIDS] = "pids",
+ [CGROUP_CONTROLLER_CPUSET] = "cpuset",
[CGROUP_CONTROLLER_BPF_FIREWALL] = "bpf-firewall",
[CGROUP_CONTROLLER_BPF_DEVICES] = "bpf-devices",
[CGROUP_CONTROLLER_BPF_FOREIGN] = "bpf-foreign",
diff --git a/src/basic/cgroup-util.h b/src/basic/cgroup-util.h
index ce2f4c6..06a23ff 100644
--- a/src/basic/cgroup-util.h
+++ b/src/basic/cgroup-util.h
@@ -20,12 +20,13 @@ typedef enum CGroupController {
/* Original cgroup controllers */
CGROUP_CONTROLLER_CPU,
CGROUP_CONTROLLER_CPUACCT, /* v1 only */
- CGROUP_CONTROLLER_CPUSET, /* v2 only */
+ CGROUP_CONTROLLER_CPUSET2, /* v2 only */
CGROUP_CONTROLLER_IO, /* v2 only */
CGROUP_CONTROLLER_BLKIO, /* v1 only */
CGROUP_CONTROLLER_MEMORY,
CGROUP_CONTROLLER_DEVICES, /* v1 only */
CGROUP_CONTROLLER_PIDS,
+ CGROUP_CONTROLLER_CPUSET,
/* BPF-based pseudo-controllers, v2 only */
CGROUP_CONTROLLER_BPF_FIREWALL,
@@ -43,22 +44,23 @@ typedef enum CGroupController {
typedef enum CGroupMask {
CGROUP_MASK_CPU = CGROUP_CONTROLLER_TO_MASK(CGROUP_CONTROLLER_CPU),
CGROUP_MASK_CPUACCT = CGROUP_CONTROLLER_TO_MASK(CGROUP_CONTROLLER_CPUACCT),
- CGROUP_MASK_CPUSET = CGROUP_CONTROLLER_TO_MASK(CGROUP_CONTROLLER_CPUSET),
+ CGROUP_MASK_CPUSET2 = CGROUP_CONTROLLER_TO_MASK(CGROUP_CONTROLLER_CPUSET2),
CGROUP_MASK_IO = CGROUP_CONTROLLER_TO_MASK(CGROUP_CONTROLLER_IO),
CGROUP_MASK_BLKIO = CGROUP_CONTROLLER_TO_MASK(CGROUP_CONTROLLER_BLKIO),
CGROUP_MASK_MEMORY = CGROUP_CONTROLLER_TO_MASK(CGROUP_CONTROLLER_MEMORY),
CGROUP_MASK_DEVICES = CGROUP_CONTROLLER_TO_MASK(CGROUP_CONTROLLER_DEVICES),
CGROUP_MASK_PIDS = CGROUP_CONTROLLER_TO_MASK(CGROUP_CONTROLLER_PIDS),
+ CGROUP_MASK_CPUSET = CGROUP_CONTROLLER_TO_MASK(CGROUP_CONTROLLER_CPUSET),
CGROUP_MASK_BPF_FIREWALL = CGROUP_CONTROLLER_TO_MASK(CGROUP_CONTROLLER_BPF_FIREWALL),
CGROUP_MASK_BPF_DEVICES = CGROUP_CONTROLLER_TO_MASK(CGROUP_CONTROLLER_BPF_DEVICES),
CGROUP_MASK_BPF_FOREIGN = CGROUP_CONTROLLER_TO_MASK(CGROUP_CONTROLLER_BPF_FOREIGN),
CGROUP_MASK_BPF_SOCKET_BIND = CGROUP_CONTROLLER_TO_MASK(CGROUP_CONTROLLER_BPF_SOCKET_BIND),
/* All real cgroup v1 controllers */
- CGROUP_MASK_V1 = CGROUP_MASK_CPU|CGROUP_MASK_CPUACCT|CGROUP_MASK_BLKIO|CGROUP_MASK_MEMORY|CGROUP_MASK_DEVICES|CGROUP_MASK_PIDS,
+ CGROUP_MASK_V1 = CGROUP_MASK_CPU|CGROUP_MASK_CPUACCT|CGROUP_MASK_BLKIO|CGROUP_MASK_MEMORY|CGROUP_MASK_CPUSET|CGROUP_MASK_DEVICES|CGROUP_MASK_PIDS,
/* All real cgroup v2 controllers */
- CGROUP_MASK_V2 = CGROUP_MASK_CPU|CGROUP_MASK_CPUSET|CGROUP_MASK_IO|CGROUP_MASK_MEMORY|CGROUP_MASK_PIDS,
+ CGROUP_MASK_V2 = CGROUP_MASK_CPU|CGROUP_MASK_CPUSET2|CGROUP_MASK_IO|CGROUP_MASK_MEMORY|CGROUP_MASK_PIDS,
/* All cgroup v2 BPF pseudo-controllers */
CGROUP_MASK_BPF = CGROUP_MASK_BPF_FIREWALL|CGROUP_MASK_BPF_DEVICES|CGROUP_MASK_BPF_FOREIGN|CGROUP_MASK_BPF_SOCKET_BIND,
diff --git a/src/basic/string-util.c b/src/basic/string-util.c
index a645958..45f358b 100644
--- a/src/basic/string-util.c
+++ b/src/basic/string-util.c
@@ -1146,3 +1146,45 @@ int string_contains_word_strv(const char *string, const char *separators, char *
*ret_word = found;
return !!found;
}
+
+int string_isvalid_interval(const char *instr)
+{
+ const char *pstr = instr; /* tmp */
+ const char *pstr_front = instr; /* front char */
+ const char *pstr_behind = instr; /* behind char */
+
+ if (isempty(instr))
+ {
+ return 1;
+ }
+
+ while (*pstr != '\0')
+ {
+ /* behind */
+ pstr_behind = pstr + 1;
+
+ /* 0-3,4,6,7-10 */
+ if (((*pstr < '0') || (*pstr > '9')) &&
+ (*pstr != '-') &&
+ (*pstr != ','))
+ {
+ return 2;
+ }
+
+ /* - , must is a num */
+ if (('-' == *pstr) || (',' == *pstr))
+ {
+ if ((*pstr_front < '0') || (*pstr_front > '9') ||
+ (*pstr_behind < '0') || (*pstr_behind > '9'))
+ {
+ return 3;
+ }
+ }
+
+ /* front */
+ pstr_front = pstr;
+ pstr++;
+ }
+
+ return 0;
+}
diff --git a/src/basic/string-util.h b/src/basic/string-util.h
index 9155e50..338dcd5 100644
--- a/src/basic/string-util.h
+++ b/src/basic/string-util.h
@@ -242,3 +242,5 @@ int string_contains_word_strv(const char *string, const char *separators, char *
static inline int string_contains_word(const char *string, const char *separators, const char *word) {
return string_contains_word_strv(string, separators, STRV_MAKE(word), NULL);
}
+
+int string_isvalid_interval(const char *instr);
diff --git a/src/core/cgroup.c b/src/core/cgroup.c
index de1d5f4..2c2d1b0 100644
--- a/src/core/cgroup.c
+++ b/src/core/cgroup.c
@@ -246,8 +246,14 @@ void cgroup_context_done(CGroupContext *c) {
while (c->bpf_foreign_programs)
cgroup_context_remove_bpf_foreign_program(c, c->bpf_foreign_programs);
- cpu_set_reset(&c->cpuset_cpus);
- cpu_set_reset(&c->cpuset_mems);
+ if (c->cpuset_cpus)
+ c->cpuset_cpus = mfree(c->cpuset_cpus);
+
+ if (c->cpuset_mems)
+ c->cpuset_mems = mfree(c->cpuset_mems);
+
+ cpu_set_reset(&c->cpuset_cpus2);
+ cpu_set_reset(&c->cpuset_mems2);
}
static int unit_get_kernel_memory_limit(Unit *u, const char *file, uint64_t *ret) {
@@ -382,7 +388,7 @@ static char *format_cgroup_memory_limit_comparison(char *buf, size_t l, Unit *u,
}
void cgroup_context_dump(Unit *u, FILE* f, const char *prefix) {
- _cleanup_free_ char *disable_controllers_str = NULL, *cpuset_cpus = NULL, *cpuset_mems = NULL;
+ _cleanup_free_ char *disable_controllers_str = NULL, *cpuset_cpus2 = NULL, *cpuset_mems2 = NULL;
CGroupIODeviceLimit *il;
CGroupIODeviceWeight *iw;
CGroupIODeviceLatency *l;
@@ -412,14 +418,15 @@ void cgroup_context_dump(Unit *u, FILE* f, const char *prefix) {
(void) cg_mask_to_string(c->disable_controllers, &disable_controllers_str);
- cpuset_cpus = cpu_set_to_range_string(&c->cpuset_cpus);
- cpuset_mems = cpu_set_to_range_string(&c->cpuset_mems);
+ cpuset_cpus2 = cpu_set_to_range_string(&c->cpuset_cpus2);
+ cpuset_mems2 = cpu_set_to_range_string(&c->cpuset_mems2);
fprintf(f,
"%sCPUAccounting: %s\n"
"%sIOAccounting: %s\n"
"%sBlockIOAccounting: %s\n"
"%sMemoryAccounting: %s\n"
+ "%sCPUSetAccounting: %s\n"
"%sTasksAccounting: %s\n"
"%sIPAccounting: %s\n"
"%sCPUWeight: %" PRIu64 "\n"
@@ -442,6 +449,10 @@ void cgroup_context_dump(Unit *u, FILE* f, const char *prefix) {
"%sMemoryMax: %" PRIu64 "%s\n"
"%sMemorySwapMax: %" PRIu64 "%s\n"
"%sMemoryLimit: %" PRIu64 "\n"
+ "%sCPUSetCpus=%s\n"
+ "%sCPUSetMems=%s\n"
+ "%sCPUSetCloneChildren=%s\n"
+ "%sCPUSetMemMigrate=%s\n"
"%sTasksMax: %" PRIu64 "\n"
"%sDevicePolicy: %s\n"
"%sDisableControllers: %s\n"
@@ -454,6 +465,7 @@ void cgroup_context_dump(Unit *u, FILE* f, const char *prefix) {
prefix, yes_no(c->io_accounting),
prefix, yes_no(c->blockio_accounting),
prefix, yes_no(c->memory_accounting),
+ prefix, yes_no(c->cpuset_accounting),
prefix, yes_no(c->tasks_accounting),
prefix, yes_no(c->ip_accounting),
prefix, c->cpu_weight,
@@ -462,8 +474,8 @@ void cgroup_context_dump(Unit *u, FILE* f, const char *prefix) {
prefix, c->startup_cpu_shares,
prefix, format_timespan(q, sizeof(q), c->cpu_quota_per_sec_usec, 1),
prefix, format_timespan(v, sizeof(v), c->cpu_quota_period_usec, 1),
- prefix, strempty(cpuset_cpus),
- prefix, strempty(cpuset_mems),
+ prefix, strempty(cpuset_cpus2),
+ prefix, strempty(cpuset_mems2),
prefix, c->io_weight,
prefix, c->startup_io_weight,
prefix, c->blockio_weight,
@@ -476,6 +488,10 @@ void cgroup_context_dump(Unit *u, FILE* f, const char *prefix) {
prefix, c->memory_max, format_cgroup_memory_limit_comparison(cdd, sizeof(cdd), u, "MemoryMax"),
prefix, c->memory_swap_max, format_cgroup_memory_limit_comparison(cde, sizeof(cde), u, "MemorySwapMax"),
prefix, c->memory_limit,
+ prefix, c->cpuset_cpus,
+ prefix, c->cpuset_mems,
+ prefix, yes_no(c->cpuset_clone_children),
+ prefix, yes_no(c->cpuset_memory_migrate),
prefix, tasks_max_resolve(&c->tasks_max),
prefix, cgroup_device_policy_to_string(c->device_policy),
prefix, strempty(disable_controllers_str),
@@ -1277,9 +1293,9 @@ static void cgroup_context_apply(
}
}
- if ((apply_mask & CGROUP_MASK_CPUSET) && !is_local_root) {
- cgroup_apply_unified_cpuset(u, &c->cpuset_cpus, "cpuset.cpus");
- cgroup_apply_unified_cpuset(u, &c->cpuset_mems, "cpuset.mems");
+ if ((apply_mask & CGROUP_MASK_CPUSET2) && !is_local_root) {
+ cgroup_apply_unified_cpuset(u, &c->cpuset_cpus2, "cpuset.cpus");
+ cgroup_apply_unified_cpuset(u, &c->cpuset_mems2, "cpuset.mems");
}
/* The 'io' controller attributes are not exported on the host's root cgroup (being a pure cgroup v2
@@ -1477,6 +1493,45 @@ static void cgroup_context_apply(
}
}
+ if ((apply_mask & CGROUP_MASK_CPUSET) && !is_local_root) {
+ (void) set_attribute_and_warn(u, "cpuset", "cgroup.clone_children", one_zero(c->cpuset_clone_children));
+ (void) set_attribute_and_warn(u, "cpuset", "cpuset.memory_migrate", one_zero(c->cpuset_memory_migrate));
+ if (c->cpuset_cpus) {
+ if (streq(c->cpuset_cpus, "all")) {
+ _cleanup_free_ char *str_cpuset_cpus = NULL;
+ _cleanup_free_ char *cg_root_path_cpus = NULL;
+ r = cg_get_root_path(&cg_root_path_cpus);
+ if (r < 0)
+ log_info_errno(r, "Failed to determine root cgroup, ignoring cgroup cpuset cpus: %m");
+ if (cg_root_path_cpus) {
+ r = cg_get_attribute("cpuset", cg_root_path_cpus, "cpuset.cpus", &str_cpuset_cpus);
+ if (r < 0)
+ log_error("cgroup context apply: cg get attribute is error(%d), path=%s.", r, cg_root_path_cpus);
+ if (str_cpuset_cpus)
+ (void) set_attribute_and_warn(u, "cpuset", "cpuset.cpus", str_cpuset_cpus);
+ }
+ } else
+ (void) set_attribute_and_warn(u, "cpuset", "cpuset.cpus", c->cpuset_cpus);
+ }
+ if (c->cpuset_mems) {
+ if (streq(c->cpuset_mems, "all")) {
+ _cleanup_free_ char *str_cpuset_mems = NULL;
+ _cleanup_free_ char *cg_root_path_mems = NULL;
+ r = cg_get_root_path(&cg_root_path_mems);
+ if (r < 0)
+ log_info_errno(r, "Failed to determine root cgroup, ignoring cgroup cpuset mems: %m");
+ if (cg_root_path_mems) {
+ r = cg_get_attribute("cpuset", cg_root_path_mems, "cpuset.mems", &str_cpuset_mems);
+ if (r < 0)
+ log_error("cgroup context apply: cg get attribute is error(%d), path=%s.", r, cg_root_path_mems);
+ if (str_cpuset_mems)
+ (void) set_attribute_and_warn(u, "cpuset", "cpuset.mems", str_cpuset_mems);
+ }
+ } else
+ (void) set_attribute_and_warn(u, "cpuset", "cpuset.mems", c->cpuset_mems);
+ }
+ }
+
/* On cgroup v2 we can apply BPF everywhere. On cgroup v1 we apply it everywhere except for the root of
* containers, where we leave this to the manager */
if ((apply_mask & (CGROUP_MASK_DEVICES | CGROUP_MASK_BPF_DEVICES)) &&
@@ -1603,8 +1658,8 @@ static CGroupMask unit_get_cgroup_mask(Unit *u) {
c->cpu_quota_per_sec_usec != USEC_INFINITY)
mask |= CGROUP_MASK_CPU;
- if (c->cpuset_cpus.set || c->cpuset_mems.set)
- mask |= CGROUP_MASK_CPUSET;
+ if (c->cpuset_cpus2.set || c->cpuset_mems2.set)
+ mask |= CGROUP_MASK_CPUSET2;
if (cgroup_context_has_io_config(c) || cgroup_context_has_blockio_config(c))
mask |= CGROUP_MASK_IO | CGROUP_MASK_BLKIO;
@@ -1614,6 +1669,11 @@ static CGroupMask unit_get_cgroup_mask(Unit *u) {
unit_has_unified_memory_config(u))
mask |= CGROUP_MASK_MEMORY;
+ if (c->cpuset_accounting ||
+ c->cpuset_cpus ||
+ c->cpuset_mems)
+ mask |= CGROUP_MASK_CPUSET;
+
if (c->device_allow ||
c->device_policy != CGROUP_DEVICE_POLICY_AUTO)
mask |= CGROUP_MASK_DEVICES | CGROUP_MASK_BPF_DEVICES;
@@ -3984,7 +4044,7 @@ int unit_get_cpuset(Unit *u, CPUSet *cpus, const char *name) {
if (!u->cgroup_path)
return -ENODATA;
- if ((u->cgroup_realized_mask & CGROUP_MASK_CPUSET) == 0)
+ if ((u->cgroup_realized_mask & CGROUP_MASK_CPUSET2) == 0)
return -ENODATA;
r = cg_all_unified();
diff --git a/src/core/cgroup.h b/src/core/cgroup.h
index ea92936..a8a4726 100644
--- a/src/core/cgroup.h
+++ b/src/core/cgroup.h
@@ -115,6 +115,7 @@ struct CGroupContext {
bool io_accounting;
bool blockio_accounting;
bool memory_accounting;
+ bool cpuset_accounting;
bool tasks_accounting;
bool ip_accounting;
@@ -131,8 +132,8 @@ struct CGroupContext {
usec_t cpu_quota_per_sec_usec;
usec_t cpu_quota_period_usec;
- CPUSet cpuset_cpus;
- CPUSet cpuset_mems;
+ CPUSet cpuset_cpus2;
+ CPUSet cpuset_mems2;
uint64_t io_weight;
uint64_t startup_io_weight;
@@ -148,6 +149,11 @@ struct CGroupContext {
uint64_t memory_max;
uint64_t memory_swap_max;
+ char *cpuset_cpus;
+ char *cpuset_mems;
+ bool cpuset_clone_children;
+ bool cpuset_memory_migrate;
+
bool default_memory_min_set;
bool default_memory_low_set;
bool memory_min_set;
diff --git a/src/core/dbus-cgroup.c b/src/core/dbus-cgroup.c
index 84c3caf..0cdc98c 100644
--- a/src/core/dbus-cgroup.c
+++ b/src/core/dbus-cgroup.c
@@ -414,8 +414,8 @@ const sd_bus_vtable bus_cgroup_vtable[] = {
SD_BUS_PROPERTY("StartupCPUShares", "t", NULL, offsetof(CGroupContext, startup_cpu_shares), 0),
SD_BUS_PROPERTY("CPUQuotaPerSecUSec", "t", bus_property_get_usec, offsetof(CGroupContext, cpu_quota_per_sec_usec), 0),
SD_BUS_PROPERTY("CPUQuotaPeriodUSec", "t", bus_property_get_usec, offsetof(CGroupContext, cpu_quota_period_usec), 0),
- SD_BUS_PROPERTY("AllowedCPUs", "ay", property_get_cpuset, offsetof(CGroupContext, cpuset_cpus), 0),
- SD_BUS_PROPERTY("AllowedMemoryNodes", "ay", property_get_cpuset, offsetof(CGroupContext, cpuset_mems), 0),
+ SD_BUS_PROPERTY("AllowedCPUs", "ay", property_get_cpuset, offsetof(CGroupContext, cpuset_cpus2), 0),
+ SD_BUS_PROPERTY("AllowedMemoryNodes", "ay", property_get_cpuset, offsetof(CGroupContext, cpuset_mems2), 0),
SD_BUS_PROPERTY("IOAccounting", "b", bus_property_get_bool, offsetof(CGroupContext, io_accounting), 0),
SD_BUS_PROPERTY("IOWeight", "t", NULL, offsetof(CGroupContext, io_weight), 0),
SD_BUS_PROPERTY("StartupIOWeight", "t", NULL, offsetof(CGroupContext, startup_io_weight), 0),
@@ -440,6 +440,11 @@ const sd_bus_vtable bus_cgroup_vtable[] = {
SD_BUS_PROPERTY("MemoryMax", "t", NULL, offsetof(CGroupContext, memory_max), 0),
SD_BUS_PROPERTY("MemorySwapMax", "t", NULL, offsetof(CGroupContext, memory_swap_max), 0),
SD_BUS_PROPERTY("MemoryLimit", "t", NULL, offsetof(CGroupContext, memory_limit), 0),
+ SD_BUS_PROPERTY("CPUSetAccounting", "b", bus_property_get_bool, offsetof(CGroupContext, cpuset_accounting), 0),
+ SD_BUS_PROPERTY("CPUSetCpus", "s", NULL, offsetof(CGroupContext, cpuset_cpus), 0),
+ SD_BUS_PROPERTY("CPUSetMems", "s", NULL, offsetof(CGroupContext, cpuset_mems), 0),
+ SD_BUS_PROPERTY("CPUSetCloneChildren", "b", bus_property_get_bool, offsetof(CGroupContext, cpuset_clone_children), 0),
+ SD_BUS_PROPERTY("CPUSetMemMigrate", "b", bus_property_get_bool, offsetof(CGroupContext, cpuset_memory_migrate), 0),
SD_BUS_PROPERTY("DevicePolicy", "s", property_get_cgroup_device_policy, offsetof(CGroupContext, device_policy), 0),
SD_BUS_PROPERTY("DeviceAllow", "a(ss)", property_get_device_allow, 0, 0),
SD_BUS_PROPERTY("TasksAccounting", "b", bus_property_get_bool, offsetof(CGroupContext, tasks_accounting), 0),
@@ -1065,6 +1070,43 @@ int bus_cgroup_set_property(
if (streq(name, "MemoryLimitScale"))
return bus_cgroup_set_memory_scale(u, name, &c->memory_limit, message, flags, error);
+ if (streq(name, "CPUSetAccounting"))
+ return bus_cgroup_set_boolean(u, name, &c->cpuset_accounting, CGROUP_MASK_CPUSET, message, flags, error);
+
+ if (STR_IN_SET(name, "CPUSetCpus", "CPUSetMems")) {
+ const char *cpuset_str = NULL;
+
+ r = sd_bus_message_read(message, "s", &cpuset_str);
+ if (r < 0)
+ return r;
+
+ if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
+ unit_invalidate_cgroup(u, CGROUP_MASK_CPUSET);
+ if (streq(name, "CPUSetCpus")) {
+ if (c->cpuset_cpus)
+ c->cpuset_cpus = mfree(c->cpuset_cpus);
+ c->cpuset_cpus = strdup(cpuset_str);
+ if (!c->cpuset_cpus)
+ return -ENOMEM;
+ unit_write_settingf(u, flags, name, "CPUSetCpus=%s", cpuset_str);
+ } else {
+ if (c->cpuset_mems)
+ c->cpuset_mems = mfree(c->cpuset_mems);
+ c->cpuset_mems = strdup(cpuset_str);
+ if (!c->cpuset_mems)
+ return -ENOMEM;
+ unit_write_settingf(u, flags, name, "CPUSetMems=%s", cpuset_str);
+ }
+ }
+ return 1;
+ }
+
+ if (streq(name, "CPUSetCloneChildren"))
+ return bus_cgroup_set_boolean(u, name, &c->cpuset_clone_children, CGROUP_MASK_CPUSET, message, flags, error);
+
+ if (streq(name, "CPUSetMemMigrate"))
+ return bus_cgroup_set_boolean(u, name, &c->cpuset_memory_migrate, CGROUP_MASK_CPUSET, message, flags, error);
+
if (streq(name, "TasksAccounting"))
return bus_cgroup_set_boolean(u, name, &c->tasks_accounting, CGROUP_MASK_PIDS, message, flags, error);
@@ -1146,15 +1188,15 @@ int bus_cgroup_set_property(
return -ENOMEM;
if (streq(name, "AllowedCPUs"))
- set = &c->cpuset_cpus;
+ set = &c->cpuset_cpus2;
else
- set = &c->cpuset_mems;
+ set = &c->cpuset_mems2;
cpu_set_reset(set);
*set = new_set;
new_set = (CPUSet) {};
- unit_invalidate_cgroup(u, CGROUP_MASK_CPUSET);
+ unit_invalidate_cgroup(u, CGROUP_MASK_CPUSET2);
unit_write_settingf(u, flags, name, "%s=%s", name, setstr);
}
diff --git a/src/core/dbus-manager.c b/src/core/dbus-manager.c
index de057a0..82896af 100644
--- a/src/core/dbus-manager.c
+++ b/src/core/dbus-manager.c
@@ -2690,6 +2690,7 @@ const sd_bus_vtable bus_manager_vtable[] = {
SD_BUS_PROPERTY("DefaultCPUAccounting", "b", bus_property_get_bool, offsetof(Manager, default_cpu_accounting), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("DefaultBlockIOAccounting", "b", bus_property_get_bool, offsetof(Manager, default_blockio_accounting), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("DefaultMemoryAccounting", "b", bus_property_get_bool, offsetof(Manager, default_memory_accounting), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("DefaultCpusetAccounting", "b", bus_property_get_bool, offsetof(Manager, default_cpuset_accounting), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("DefaultTasksAccounting", "b", bus_property_get_bool, offsetof(Manager, default_tasks_accounting), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("DefaultLimitCPU", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_CPU]), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("DefaultLimitCPUSoft", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_CPU]), SD_BUS_VTABLE_PROPERTY_CONST),
diff --git a/src/core/load-fragment-gperf.gperf.in b/src/core/load-fragment-gperf.gperf.in
index 42441ea..60c9dbc 100644
--- a/src/core/load-fragment-gperf.gperf.in
+++ b/src/core/load-fragment-gperf.gperf.in
@@ -197,6 +197,11 @@
{{type}}.MemoryMax, config_parse_memory_limit, 0, offsetof({{type}}, cgroup_context)
{{type}}.MemorySwapMax, config_parse_memory_limit, 0, offsetof({{type}}, cgroup_context)
{{type}}.MemoryLimit, config_parse_memory_limit, 0, offsetof({{type}}, cgroup_context)
+{{type}}.CPUSetAccounting, config_parse_bool, 0, offsetof({{type}}, cgroup_context.cpuset_accounting)
+{{type}}.CPUSetCpus, config_parse_cpuset_cpumems, 0, offsetof({{type}}, cgroup_context.cpuset_cpus)
+{{type}}.CPUSetMems, config_parse_cpuset_cpumems, 0, offsetof({{type}}, cgroup_context.cpuset_mems)
+{{type}}.CPUSetCloneChildren, config_parse_bool, 0, offsetof({{type}}, cgroup_context.cpuset_clone_children)
+{{type}}.CPUSetMemMigrate, config_parse_bool, 0, offsetof({{type}}, cgroup_context.cpuset_memory_migrate)
{{type}}.DeviceAllow, config_parse_device_allow, 0, offsetof({{type}}, cgroup_context)
{{type}}.DevicePolicy, config_parse_device_policy, 0, offsetof({{type}}, cgroup_context.device_policy)
{{type}}.IOAccounting, config_parse_bool, 0, offsetof({{type}}, cgroup_context.io_accounting)
diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c
index 399a759..ad80a64 100644
--- a/src/core/load-fragment.c
+++ b/src/core/load-fragment.c
@@ -3632,7 +3632,7 @@ int config_parse_allowed_cpus(
CGroupContext *c = data;
- (void) parse_cpu_set_extend(rvalue, &c->cpuset_cpus, true, unit, filename, line, lvalue);
+ (void) parse_cpu_set_extend(rvalue, &c->cpuset_cpus2, true, unit, filename, line, lvalue);
return 0;
}
@@ -3651,7 +3651,7 @@ int config_parse_allowed_mems(
CGroupContext *c = data;
- (void) parse_cpu_set_extend(rvalue, &c->cpuset_mems, true, unit, filename, line, lvalue);
+ (void) parse_cpu_set_extend(rvalue, &c->cpuset_mems2, true, unit, filename, line, lvalue);
return 0;
}
@@ -3722,6 +3722,75 @@ int config_parse_memory_limit(
return 0;
}
+int config_parse_cpuset_cpumems(
+ const char *unit,
+ const char *filename,
+ unsigned line,
+ const char *section,
+ unsigned section_line,
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data,
+ void *userdata)
+{
+ char **pcpumems = data;
+ char *pinstr = NULL;
+ int iret = 0;
+
+ assert(filename);
+ assert(lvalue);
+ assert(rvalue);
+ assert(data);
+ (void)section;
+ (void)section_line;
+ (void)ltype;
+ (void)userdata;
+
+ if (!utf8_is_valid(rvalue))
+ {
+ log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, rvalue);
+ return 0;
+ }
+
+ if (0 == strcmp(rvalue, "all"))
+ {
+ pinstr = strdup(rvalue);
+ if (!pinstr)
+ {
+ return log_oom();
+ }
+
+ free(*pcpumems);
+ *pcpumems = pinstr;
+
+ return 0;
+ }
+
+ /* 0-2,4 */
+ iret = string_isvalid_interval(rvalue);
+ if (0 != iret)
+ {
+ pinstr = NULL;
+ log_syntax(unit, LOG_ERR, filename, line, EINVAL,
+ "cpuset cpumems '%s' is invalid, Ignoring(%d).",
+ rvalue, iret);
+ }
+ else
+ {
+ pinstr = strdup(rvalue);
+ if (!pinstr)
+ {
+ return log_oom();
+ }
+ }
+
+ free(*pcpumems);
+ *pcpumems = pinstr;
+
+ return 0;
+}
+
int config_parse_tasks_max(
const char *unit,
const char *filename,
diff --git a/src/core/load-fragment.h b/src/core/load-fragment.h
index 45e9c39..1ecad67 100644
--- a/src/core/load-fragment.h
+++ b/src/core/load-fragment.h
@@ -74,6 +74,7 @@ CONFIG_PARSER_PROTOTYPE(config_parse_unit_slice);
CONFIG_PARSER_PROTOTYPE(config_parse_cg_weight);
CONFIG_PARSER_PROTOTYPE(config_parse_cpu_shares);
CONFIG_PARSER_PROTOTYPE(config_parse_memory_limit);
+CONFIG_PARSER_PROTOTYPE(config_parse_cpuset_cpumems);
CONFIG_PARSER_PROTOTYPE(config_parse_tasks_max);
CONFIG_PARSER_PROTOTYPE(config_parse_delegate);
CONFIG_PARSER_PROTOTYPE(config_parse_managed_oom_mode);
diff --git a/src/core/main.c b/src/core/main.c
index 9282b09..c4564e8 100644
--- a/src/core/main.c
+++ b/src/core/main.c
@@ -148,6 +148,7 @@ static bool arg_default_io_accounting;
static bool arg_default_ip_accounting;
static bool arg_default_blockio_accounting;
static bool arg_default_memory_accounting;
+static bool arg_default_cpuset_accounting;
static bool arg_default_tasks_accounting;
static TasksMax arg_default_tasks_max;
static sd_id128_t arg_machine_id;
@@ -693,6 +694,7 @@ static int parse_config_file(void) {
{ "Manager", "DefaultIPAccounting", config_parse_bool, 0, &arg_default_ip_accounting },
{ "Manager", "DefaultBlockIOAccounting", config_parse_bool, 0, &arg_default_blockio_accounting },
{ "Manager", "DefaultMemoryAccounting", config_parse_bool, 0, &arg_default_memory_accounting },
+ { "Manager", "DefaultCpusetAccounting", config_parse_bool, 0, &arg_default_cpuset_accounting },
{ "Manager", "DefaultTasksAccounting", config_parse_bool, 0, &arg_default_tasks_accounting },
{ "Manager", "DefaultTasksMax", config_parse_tasks_max, 0, &arg_default_tasks_max },
{ "Manager", "CtrlAltDelBurstAction", config_parse_emergency_action, 0, &arg_cad_burst_action },
@@ -764,6 +766,7 @@ static void set_manager_defaults(Manager *m) {
m->default_ip_accounting = arg_default_ip_accounting;
m->default_blockio_accounting = arg_default_blockio_accounting;
m->default_memory_accounting = arg_default_memory_accounting;
+ m->default_cpuset_accounting = arg_default_cpuset_accounting;
m->default_tasks_accounting = arg_default_tasks_accounting;
m->default_tasks_max = arg_default_tasks_max;
m->default_oom_policy = arg_default_oom_policy;
@@ -2358,6 +2361,7 @@ static void reset_arguments(void) {
arg_default_ip_accounting = false;
arg_default_blockio_accounting = false;
arg_default_memory_accounting = MEMORY_ACCOUNTING_DEFAULT;
+ arg_default_cpuset_accounting = false;
arg_default_tasks_accounting = true;
arg_default_tasks_max = DEFAULT_TASKS_MAX;
arg_machine_id = (sd_id128_t) {};
diff --git a/src/core/manager.c b/src/core/manager.c
index 38482c0..3a12d6d 100644
--- a/src/core/manager.c
+++ b/src/core/manager.c
@@ -776,6 +776,7 @@ int manager_new(UnitFileScope scope, ManagerTestRunFlags test_run_flags, Manager
.default_timer_accuracy_usec = USEC_PER_MINUTE,
.default_memory_accounting = MEMORY_ACCOUNTING_DEFAULT,
+ .default_cpuset_accounting = false,
.default_tasks_accounting = true,
.default_tasks_max = TASKS_MAX_UNSET,
.default_timeout_start_usec = DEFAULT_TIMEOUT_USEC,
diff --git a/src/core/manager.h b/src/core/manager.h
index 0c39626..f658caa 100644
--- a/src/core/manager.h
+++ b/src/core/manager.h
@@ -360,6 +360,7 @@ struct Manager {
bool default_cpu_accounting;
bool default_memory_accounting;
+ bool default_cpuset_accounting;
bool default_io_accounting;
bool default_blockio_accounting;
bool default_tasks_accounting;
diff --git a/src/core/system.conf.in b/src/core/system.conf.in
index f2c75fc..fcc20d0 100644
--- a/src/core/system.conf.in
+++ b/src/core/system.conf.in
@@ -53,6 +53,7 @@
#DefaultIPAccounting=no
#DefaultBlockIOAccounting=no
#DefaultMemoryAccounting={{ 'yes' if MEMORY_ACCOUNTING_DEFAULT else 'no' }}
+#DefaultCpusetAccounting=
#DefaultTasksAccounting=yes
#DefaultTasksMax=80%
#DefaultLimitCPU=
diff --git a/src/core/unit.c b/src/core/unit.c
index e30c14b..bfd47cf 100644
--- a/src/core/unit.c
+++ b/src/core/unit.c
@@ -176,6 +176,7 @@ static void unit_init(Unit *u) {
cc->io_accounting = u->manager->default_io_accounting;
cc->blockio_accounting = u->manager->default_blockio_accounting;
cc->memory_accounting = u->manager->default_memory_accounting;
+ cc->cpuset_accounting = u->manager->default_cpuset_accounting;
cc->tasks_accounting = u->manager->default_tasks_accounting;
cc->ip_accounting = u->manager->default_ip_accounting;
diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c
index d3a5b25..caad3ab 100644
--- a/src/shared/bus-unit-util.c
+++ b/src/shared/bus-unit-util.c
@@ -460,7 +460,10 @@ static int bus_append_cgroup_property(sd_bus_message *m, const char *field, cons
"IOAccounting",
"BlockIOAccounting",
"TasksAccounting",
- "IPAccounting"))
+ "IPAccounting",
+ "CPUSetAccounting",
+ "CPUSetCloneChildren",
+ "CPUSetMemMigrate"))
return bus_append_parse_boolean(m, field, eq);
if (STR_IN_SET(field, "CPUWeight",
@@ -561,6 +564,16 @@ static int bus_append_cgroup_property(sd_bus_message *m, const char *field, cons
return bus_append_parse_size(m, field, eq, 1024);
}
+ if (STR_IN_SET(field, "CPUSetCpus", "CPUSetMems")) {
+ if (string_isvalid_interval(eq) == 0 || streq(eq, "all"))
+ r = sd_bus_message_append(m, "(sv)", field, "s", eq);
+ else
+ r = -EINVAL;
+ if (r < 0)
+ return bus_log_create_error(r);
+ return 1;
+ }
+
if (streq(field, "CPUQuota")) {
if (isempty(eq))
r = sd_bus_message_append(m, "(sv)", "CPUQuotaPerSecUSec", "t", USEC_INFINITY);
diff --git a/src/shared/cpu-set-util.c b/src/shared/cpu-set-util.c
index e3e6963..2cb4a36 100644
--- a/src/shared/cpu-set-util.c
+++ b/src/shared/cpu-set-util.c
@@ -7,6 +7,7 @@
#include "alloc-util.h"
#include "cpu-set-util.h"
+#include "cgroup-util.h"
#include "dirent-util.h"
#include "errno-util.h"
#include "extract-word.h"
diff --git a/src/test/test-cgroup-mask.c b/src/test/test-cgroup-mask.c
index 19e159b..425fe19 100644
--- a/src/test/test-cgroup-mask.c
+++ b/src/test/test-cgroup-mask.c
@@ -55,6 +55,7 @@ static int test_cgroup_mask(void) {
* else. */
m->default_cpu_accounting =
m->default_memory_accounting =
+ m->default_cpuset_accounting =
m->default_blockio_accounting =
m->default_io_accounting =
m->default_tasks_accounting = false;
@@ -140,10 +141,10 @@ static void test_cg_mask_to_string_one(CGroupMask mask, const char *t) {
static void test_cg_mask_to_string(void) {
test_cg_mask_to_string_one(0, NULL);
- test_cg_mask_to_string_one(_CGROUP_MASK_ALL, "cpu cpuacct cpuset io blkio memory devices pids bpf-firewall bpf-devices bpf-foreign bpf-socket-bind");
+ test_cg_mask_to_string_one(_CGROUP_MASK_ALL, "cpu cpuacct cpuset2 io blkio memory devices pids cpuset bpf-firewall bpf-devices bpf-foreign bpf-socket-bind");
test_cg_mask_to_string_one(CGROUP_MASK_CPU, "cpu");
test_cg_mask_to_string_one(CGROUP_MASK_CPUACCT, "cpuacct");
- test_cg_mask_to_string_one(CGROUP_MASK_CPUSET, "cpuset");
+ test_cg_mask_to_string_one(CGROUP_MASK_CPUSET2, "cpuset2");
test_cg_mask_to_string_one(CGROUP_MASK_IO, "io");
test_cg_mask_to_string_one(CGROUP_MASK_BLKIO, "blkio");
test_cg_mask_to_string_one(CGROUP_MASK_MEMORY, "memory");
diff --git a/test/fuzz/fuzz-unit-file/directives-all.service b/test/fuzz/fuzz-unit-file/directives-all.service
index 3039d1c..5f8cdd8 100644
--- a/test/fuzz/fuzz-unit-file/directives-all.service
+++ b/test/fuzz/fuzz-unit-file/directives-all.service
@@ -48,6 +48,11 @@ BusName=
CoredumpFilter=
CPUAccounting=
CPUQuota=
+CPUSetAccounting=
+CPUSetCloneChildren=
+CPUSetCpus=
+CPUSetMemMigrate=
+CPUSetMems=
CPUShares=
CPUWeight=
CapabilityBoundingSet=
diff --git a/test/fuzz/fuzz-unit-file/directives.mount b/test/fuzz/fuzz-unit-file/directives.mount
index 451f291..3adfd5b 100644
--- a/test/fuzz/fuzz-unit-file/directives.mount
+++ b/test/fuzz/fuzz-unit-file/directives.mount
@@ -19,6 +19,11 @@ CPUQuotaPeriodSec=
CPUSchedulingPolicy=
CPUSchedulingPriority=
CPUSchedulingResetOnFork=
+CPUSetAccounting=
+CPUSetCloneChildren=
+CPUSetCpus=
+CPUSetMemMigrate=
+CPUSetMems=
CPUShares=
CPUWeight=
CacheDirectory=
diff --git a/test/fuzz/fuzz-unit-file/directives.scope b/test/fuzz/fuzz-unit-file/directives.scope
index 7e69cf8..c953f9c 100644
--- a/test/fuzz/fuzz-unit-file/directives.scope
+++ b/test/fuzz/fuzz-unit-file/directives.scope
@@ -11,6 +11,11 @@ BlockIOWriteBandwidth=
CPUAccounting=
CPUQuota=
CPUQuotaPeriodSec=
+CPUSetAccounting=
+CPUSetCloneChildren=
+CPUSetCpus=
+CPUSetMemMigrate=
+CPUSetMems=
CPUShares=
CPUWeight=
DefaultMemoryLow=
diff --git a/test/fuzz/fuzz-unit-file/directives.service b/test/fuzz/fuzz-unit-file/directives.service
index de7d2c7..aa5ad32 100644
--- a/test/fuzz/fuzz-unit-file/directives.service
+++ b/test/fuzz/fuzz-unit-file/directives.service
@@ -63,6 +63,11 @@ ConditionSecurity=
ConditionUser=
ConditionVirtualization=
Conflicts=
+CPUSetAccounting=
+CPUSetCloneChildren=
+CPUSetCpus=
+CPUSetMemMigrate=
+CPUSetMems=
DefaultDependencies=
Description=
Documentation=
diff --git a/test/fuzz/fuzz-unit-file/directives.slice b/test/fuzz/fuzz-unit-file/directives.slice
index 789ac8f..54cb55d 100644
--- a/test/fuzz/fuzz-unit-file/directives.slice
+++ b/test/fuzz/fuzz-unit-file/directives.slice
@@ -11,6 +11,11 @@ BlockIOWriteBandwidth=
CPUAccounting=
CPUQuota=
CPUQuotaPeriodSec=
+CPUSetAccounting=
+CPUSetCloneChildren=
+CPUSetCpus=
+CPUSetMemMigrate=
+CPUSetMems=
CPUShares=
CPUWeight=
DefaultMemoryLow=
diff --git a/test/fuzz/fuzz-unit-file/directives.socket b/test/fuzz/fuzz-unit-file/directives.socket
index 11f589e..aa9e758 100644
--- a/test/fuzz/fuzz-unit-file/directives.socket
+++ b/test/fuzz/fuzz-unit-file/directives.socket
@@ -24,6 +24,11 @@ CPUQuotaPeriodSec=
CPUSchedulingPolicy=
CPUSchedulingPriority=
CPUSchedulingResetOnFork=
+CPUSetAccounting=
+CPUSetCloneChildren=
+CPUSetCpus=
+CPUSetMemMigrate=
+CPUSetMems=
CPUShares=
CPUWeight=
CacheDirectory=
diff --git a/test/fuzz/fuzz-unit-file/directives.swap b/test/fuzz/fuzz-unit-file/directives.swap
index 582a136..bc07775 100644
--- a/test/fuzz/fuzz-unit-file/directives.swap
+++ b/test/fuzz/fuzz-unit-file/directives.swap
@@ -19,6 +19,11 @@ CPUQuotaPeriodSec=
CPUSchedulingPolicy=
CPUSchedulingPriority=
CPUSchedulingResetOnFork=
+CPUSetAccounting=
+CPUSetCloneChildren=
+CPUSetCpus=
+CPUSetMemMigrate=
+CPUSetMems=
CPUShares=
CPUWeight=
CacheDirectory=
--
2.23.0
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
1
https://gitee.com/yangmingtaip/systemd.git
git@gitee.com:yangmingtaip/systemd.git
yangmingtaip
systemd
systemd
master

搜索帮助