|
|
a19bc6 |
From 7d44d0d43465892d4753ff50592588f49d56cf95 Mon Sep 17 00:00:00 2001
|
|
|
a19bc6 |
From: Lennart Poettering <lennart@poettering.net>
|
|
|
a19bc6 |
Date: Thu, 10 Sep 2015 12:32:16 +0200
|
|
|
a19bc6 |
Subject: [PATCH] core: add support for the "pids" cgroup controller
|
|
|
a19bc6 |
|
|
|
a19bc6 |
This adds support for the new "pids" cgroup controller of 4.3 kernels.
|
|
|
a19bc6 |
It allows accounting the number of tasks in a cgroup and enforcing
|
|
|
a19bc6 |
limits on it.
|
|
|
a19bc6 |
|
|
|
a19bc6 |
This adds two new setting TasksAccounting= and TasksMax= to each unit,
|
|
|
a19bc6 |
as well as a gloabl option DefaultTasksAccounting=.
|
|
|
a19bc6 |
|
|
|
a19bc6 |
This also updated "cgtop" to optionally make use of the new
|
|
|
a19bc6 |
kernel-provided accounting.
|
|
|
a19bc6 |
|
|
|
a19bc6 |
systemctl has been updated to show the number of tasks for each service
|
|
|
a19bc6 |
if it is available.
|
|
|
a19bc6 |
|
|
|
a19bc6 |
This patch also adds correct support for undoing memory limits for units
|
|
|
a19bc6 |
using a MemoryLimit=infinity syntax. We do the same for TasksMax= now
|
|
|
a19bc6 |
and hence keep things in sync here.
|
|
|
a19bc6 |
|
|
|
a19bc6 |
Cherry-picked from: 03a7b521e3ffb7f5d153d90480ba5d4bc29d1e8f
|
|
|
a19bc6 |
Resolves: #1337244
|
|
|
a19bc6 |
---
|
|
|
23b3cf |
man/systemd-system.conf.xml | 22 +++++-----
|
|
|
23b3cf |
man/systemd.resource-control.xml | 63 ++++++++++++++++++++++-----
|
|
|
23b3cf |
src/core/cgroup.c | 44 +++++++++++++++++++
|
|
|
a19bc6 |
src/core/cgroup.h | 5 +++
|
|
|
23b3cf |
src/core/dbus-cgroup.c | 41 ++++++++++++++++-
|
|
|
23b3cf |
src/core/dbus-unit.c | 25 +++++++++++
|
|
|
23b3cf |
src/core/load-fragment-gperf.gperf.m4 | 2 +
|
|
|
23b3cf |
src/core/load-fragment.c | 37 ++++++++++++++--
|
|
|
a19bc6 |
src/core/load-fragment.h | 1 +
|
|
|
a19bc6 |
src/core/main.c | 3 ++
|
|
|
a19bc6 |
src/core/manager.h | 1 +
|
|
|
a19bc6 |
src/core/unit.c | 1 +
|
|
|
a19bc6 |
src/shared/cgroup-util.h | 1 +
|
|
|
23b3cf |
src/systemctl/systemctl.c | 17 ++++++++
|
|
|
a19bc6 |
14 files changed, 236 insertions(+), 27 deletions(-)
|
|
|
a19bc6 |
|
|
|
a19bc6 |
diff --git a/man/systemd-system.conf.xml b/man/systemd-system.conf.xml
|
|
|
181b3f |
index 57b3b90be..d367ccd13 100644
|
|
|
a19bc6 |
--- a/man/systemd-system.conf.xml
|
|
|
a19bc6 |
+++ b/man/systemd-system.conf.xml
|
|
|
a19bc6 |
@@ -51,14 +51,14 @@
|
|
|
a19bc6 |
</refnamediv>
|
|
|
a19bc6 |
|
|
|
a19bc6 |
<refsynopsisdiv>
|
|
|
a19bc6 |
- <para><filename>/etc/systemd/system.conf</filename></para>
|
|
|
a19bc6 |
- <para><filename>/etc/systemd/system.conf.d/*.conf</filename></para>
|
|
|
a19bc6 |
- <para><filename>/run/systemd/system.conf.d/*.conf</filename></para>
|
|
|
a19bc6 |
- <para><filename>/usr/lib/systemd/system.conf.d/*.conf</filename></para>
|
|
|
a19bc6 |
- <para><filename>/etc/systemd/user.conf</filename></para>
|
|
|
a19bc6 |
- <para><filename>/etc/systemd/user.conf.d/*.conf</filename></para>
|
|
|
a19bc6 |
- <para><filename>/run/systemd/user.conf.d/*.conf</filename></para>
|
|
|
a19bc6 |
- <para><filename>/usr/lib/systemd/user.conf.d/*.conf</filename></para>
|
|
|
a19bc6 |
+ <para><filename>/etc/systemd/system.conf</filename>,
|
|
|
a19bc6 |
+ <filename>/etc/systemd/system.conf.d/*.conf</filename>,
|
|
|
a19bc6 |
+ <filename>/run/systemd/system.conf.d/*.conf</filename>,
|
|
|
a19bc6 |
+ <filename>/usr/lib/systemd/system.conf.d/*.conf</filename></para>
|
|
|
a19bc6 |
+ <para><filename>/etc/systemd/user.conf</filename>,
|
|
|
a19bc6 |
+ <filename>/etc/systemd/user.conf.d/*.conf</filename>,
|
|
|
a19bc6 |
+ <filename>/run/systemd/user.conf.d/*.conf</filename>,
|
|
|
a19bc6 |
+ <filename>/usr/lib/systemd/user.conf.d/*.conf</filename></para>
|
|
|
a19bc6 |
</refsynopsisdiv>
|
|
|
a19bc6 |
|
|
|
a19bc6 |
<refsect1>
|
|
|
a19bc6 |
@@ -307,12 +307,14 @@
|
|
|
a19bc6 |
<term><varname>DefaultCPUAccounting=</varname></term>
|
|
|
a19bc6 |
<term><varname>DefaultBlockIOAccounting=</varname></term>
|
|
|
a19bc6 |
<term><varname>DefaultMemoryAccounting=</varname></term>
|
|
|
a19bc6 |
+ <term><varname>DefaultTasksAccounting=</varname></term>
|
|
|
a19bc6 |
|
|
|
a19bc6 |
<listitem><para>Configure the default resource accounting
|
|
|
a19bc6 |
settings, as configured per-unit by
|
|
|
a19bc6 |
<varname>CPUAccounting=</varname>,
|
|
|
a19bc6 |
- <varname>BlockIOAccounting=</varname> and
|
|
|
a19bc6 |
- <varname>MemoryAccounting=</varname>. See
|
|
|
a19bc6 |
+ <varname>BlockIOAccounting=</varname>,
|
|
|
a19bc6 |
+ <varname>MemoryAccounting=</varname> and
|
|
|
a19bc6 |
+ <varname>TasksAccounting=</varname>. See
|
|
|
a19bc6 |
<citerefentry><refentrytitle>systemd.resource-control</refentrytitle><manvolnum>5</manvolnum></citerefentry>
|
|
|
a19bc6 |
for details on the per-unit settings.</para></listitem>
|
|
|
a19bc6 |
</varlistentry>
|
|
|
a19bc6 |
diff --git a/man/systemd.resource-control.xml b/man/systemd.resource-control.xml
|
|
|
181b3f |
index 8f4e7a3f1..6b9329bbe 100644
|
|
|
a19bc6 |
--- a/man/systemd.resource-control.xml
|
|
|
a19bc6 |
+++ b/man/systemd.resource-control.xml
|
|
|
a19bc6 |
@@ -103,10 +103,10 @@
|
|
|
a19bc6 |
<listitem>
|
|
|
a19bc6 |
<para>Turn on CPU usage accounting for this unit. Takes a
|
|
|
a19bc6 |
boolean argument. Note that turning on CPU accounting for
|
|
|
a19bc6 |
- one unit might also implicitly turn it on for all units
|
|
|
a19bc6 |
+ one unit will also implicitly turn it on for all units
|
|
|
a19bc6 |
contained in the same slice and for all its parent slices
|
|
|
a19bc6 |
and the units contained therein. The system default for this
|
|
|
a19bc6 |
- setting maybe controlled with
|
|
|
a19bc6 |
+ setting may be controlled with
|
|
|
a19bc6 |
<varname>DefaultCPUAccounting=</varname> in
|
|
|
a19bc6 |
<citerefentry><refentrytitle>systemd-system.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>.</para>
|
|
|
a19bc6 |
</listitem>
|
|
|
a19bc6 |
@@ -134,7 +134,7 @@
|
|
|
a19bc6 |
prioritizing specific services at boot-up differently than
|
|
|
a19bc6 |
during normal runtime.</para>
|
|
|
a19bc6 |
|
|
|
a19bc6 |
- <para>Those options imply
|
|
|
a19bc6 |
+ <para>These options imply
|
|
|
a19bc6 |
<literal>CPUAccounting=true</literal>.</para>
|
|
|
a19bc6 |
</listitem>
|
|
|
a19bc6 |
</varlistentry>
|
|
|
a19bc6 |
@@ -168,9 +168,10 @@
|
|
|
a19bc6 |
<listitem>
|
|
|
a19bc6 |
<para>Turn on process and kernel memory accounting for this
|
|
|
a19bc6 |
unit. Takes a boolean argument. Note that turning on memory
|
|
|
a19bc6 |
- accounting for one unit might also implicitly turn it on for
|
|
|
a19bc6 |
- all its parent slices. The system default for this setting
|
|
|
a19bc6 |
- maybe controlled with
|
|
|
a19bc6 |
+ accounting for one unit will also implicitly turn it on for
|
|
|
a19bc6 |
+ all units contained in the same slice and for all its parent
|
|
|
a19bc6 |
+ slices and the units contained therein. The system default
|
|
|
a19bc6 |
+ for this setting may be controlled with
|
|
|
a19bc6 |
<varname>DefaultMemoryAccounting=</varname> in
|
|
|
a19bc6 |
<citerefentry><refentrytitle>systemd-system.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>.</para>
|
|
|
a19bc6 |
</listitem>
|
|
|
181b3f |
@@ -186,26 +187,64 @@
|
|
|
a19bc6 |
memory size in bytes. If the value is suffixed with K, M, G
|
|
|
a19bc6 |
or T, the specified memory size is parsed as Kilobytes,
|
|
|
a19bc6 |
Megabytes, Gigabytes, or Terabytes (with the base 1024),
|
|
|
a19bc6 |
- respectively. This controls the
|
|
|
a19bc6 |
- <literal>memory.limit_in_bytes</literal> control group
|
|
|
a19bc6 |
- attribute. For details about this control group attribute,
|
|
|
a19bc6 |
- see
|
|
|
a19bc6 |
+ respectively. If assigned the special value
|
|
|
a19bc6 |
+ <literal>infinity</literal> no memory limit is applied. This
|
|
|
a19bc6 |
+ controls the <literal>memory.limit_in_bytes</literal>
|
|
|
a19bc6 |
+ control group attribute. For details about this control
|
|
|
a19bc6 |
+ group attribute, see
|
|
|
a19bc6 |
url="https://www.kernel.org/doc/Documentation/cgroups/memory.txt">memory.txt</ulink>.</para>
|
|
|
a19bc6 |
|
|
|
a19bc6 |
<para>Implies <literal>MemoryAccounting=true</literal>.</para>
|
|
|
181b3f |
</listitem>
|
|
|
a19bc6 |
</varlistentry>
|
|
|
a19bc6 |
|
|
|
181b3f |
+ <varlistentry>
|
|
|
a19bc6 |
+ <term><varname>TasksAccounting=</varname></term>
|
|
|
a19bc6 |
+
|
|
|
a19bc6 |
+ <listitem>
|
|
|
a19bc6 |
+ <para>Turn on task accounting for this unit. Takes a
|
|
|
a19bc6 |
+ boolean argument. If enabled, the system manager will keep
|
|
|
a19bc6 |
+ track of the number of tasks in the unit. The number of
|
|
|
a19bc6 |
+ tasks accounted this way includes both kernel threads and
|
|
|
a19bc6 |
+ userspace processes, with each thread counting
|
|
|
a19bc6 |
+ individually. Note that turning on tasks accounting for one
|
|
|
a19bc6 |
+ unit will also implicitly turn it on for all units contained
|
|
|
a19bc6 |
+ in the same slice and for all its parent slices and the
|
|
|
a19bc6 |
+ units contained therein. The system default for this setting
|
|
|
a19bc6 |
+ may be controlled with
|
|
|
a19bc6 |
+ <varname>DefaultTasksAccounting=</varname> in
|
|
|
a19bc6 |
+ <citerefentry><refentrytitle>systemd-system.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>.</para>
|
|
|
a19bc6 |
+ </listitem>
|
|
|
a19bc6 |
+ </varlistentry>
|
|
|
a19bc6 |
+
|
|
|
a19bc6 |
+ <varlistentry>
|
|
|
a19bc6 |
+ <term><varname>TasksMax=<replaceable>N</replaceable></varname></term>
|
|
|
a19bc6 |
+
|
|
|
a19bc6 |
+ <listitem>
|
|
|
a19bc6 |
+ <para>Specify the maximum number of tasks that may be
|
|
|
a19bc6 |
+ created in the unit. This ensures that the number of tasks
|
|
|
a19bc6 |
+ accounted for the unit (see above) stays below a specific
|
|
|
a19bc6 |
+ limit. If assigned the special value
|
|
|
a19bc6 |
+ <literal>infinity</literal> no tasks limit is applied. This
|
|
|
a19bc6 |
+ controls the <literal>pids.max</literal> control group
|
|
|
a19bc6 |
+ attribute. For details about this control group attribute,
|
|
|
a19bc6 |
+ see
|
|
|
a19bc6 |
+ url="https://www.kernel.org/doc/Documentation/cgroups/pids.txt">pids.txt</ulink>.</para>
|
|
|
a19bc6 |
+
|
|
|
a19bc6 |
+ <para>Implies <literal>TasksAccounting=true</literal>.</para>
|
|
|
a19bc6 |
+ </listitem>
|
|
|
a19bc6 |
+ </varlistentry>
|
|
|
a19bc6 |
+
|
|
|
181b3f |
<varlistentry>
|
|
|
a19bc6 |
<term><varname>BlockIOAccounting=</varname></term>
|
|
|
a19bc6 |
|
|
|
a19bc6 |
<listitem>
|
|
|
a19bc6 |
<para>Turn on Block IO accounting for this unit. Takes a
|
|
|
a19bc6 |
boolean argument. Note that turning on block IO accounting
|
|
|
a19bc6 |
- for one unit might also implicitly turn it on for all units
|
|
|
a19bc6 |
+ for one unit will also implicitly turn it on for all units
|
|
|
a19bc6 |
contained in the same slice and all for its parent slices
|
|
|
a19bc6 |
and the units contained therein. The system default for this
|
|
|
a19bc6 |
- setting maybe controlled with
|
|
|
a19bc6 |
+ setting may be controlled with
|
|
|
a19bc6 |
<varname>DefaultBlockIOAccounting=</varname> in
|
|
|
a19bc6 |
<citerefentry><refentrytitle>systemd-system.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>.</para>
|
|
|
a19bc6 |
</listitem>
|
|
|
a19bc6 |
diff --git a/src/core/cgroup.c b/src/core/cgroup.c
|
|
|
181b3f |
index b7f08fb42..d4a8f9cbe 100644
|
|
|
a19bc6 |
--- a/src/core/cgroup.c
|
|
|
a19bc6 |
+++ b/src/core/cgroup.c
|
|
|
a19bc6 |
@@ -40,6 +40,7 @@ void cgroup_context_init(CGroupContext *c) {
|
|
|
a19bc6 |
c->memory_limit = (uint64_t) -1;
|
|
|
a19bc6 |
c->blockio_weight = (unsigned long) -1;
|
|
|
a19bc6 |
c->startup_blockio_weight = (unsigned long) -1;
|
|
|
a19bc6 |
+ c->tasks_max = (uint64_t) -1;
|
|
|
a19bc6 |
|
|
|
a19bc6 |
c->cpu_quota_per_sec_usec = USEC_INFINITY;
|
|
|
a19bc6 |
}
|
|
|
a19bc6 |
@@ -105,6 +106,7 @@ void cgroup_context_dump(CGroupContext *c, FILE* f, const char *prefix) {
|
|
|
a19bc6 |
"%sBlockIOWeight=%lu\n"
|
|
|
a19bc6 |
"%sStartupBlockIOWeight=%lu\n"
|
|
|
a19bc6 |
"%sMemoryLimit=%" PRIu64 "\n"
|
|
|
a19bc6 |
+ "%sTasksMax=%" PRIu64 "\n"
|
|
|
a19bc6 |
"%sDevicePolicy=%s\n"
|
|
|
a19bc6 |
"%sDelegate=%s\n",
|
|
|
a19bc6 |
prefix, yes_no(c->cpu_accounting),
|
|
|
a19bc6 |
@@ -116,6 +118,7 @@ void cgroup_context_dump(CGroupContext *c, FILE* f, const char *prefix) {
|
|
|
a19bc6 |
prefix, c->blockio_weight,
|
|
|
a19bc6 |
prefix, c->startup_blockio_weight,
|
|
|
a19bc6 |
prefix, c->memory_limit,
|
|
|
a19bc6 |
+ prefix, c->tasks_max,
|
|
|
a19bc6 |
prefix, cgroup_device_policy_to_string(c->device_policy),
|
|
|
a19bc6 |
prefix, yes_no(c->delegate));
|
|
|
a19bc6 |
|
|
|
a19bc6 |
@@ -456,6 +459,21 @@ void cgroup_context_apply(CGroupContext *c, CGroupControllerMask mask, const cha
|
|
|
a19bc6 |
log_debug("Ignoring device %s while writing cgroup attribute.", a->path);
|
|
|
a19bc6 |
}
|
|
|
a19bc6 |
}
|
|
|
a19bc6 |
+
|
|
|
a19bc6 |
+ if ((mask & CGROUP_PIDS) && !is_root) {
|
|
|
a19bc6 |
+
|
|
|
a19bc6 |
+ if (c->tasks_max != (uint64_t) -1) {
|
|
|
a19bc6 |
+ char buf[DECIMAL_STR_MAX(uint64_t) + 2];
|
|
|
a19bc6 |
+
|
|
|
a19bc6 |
+ sprintf(buf, "%" PRIu64 "\n", c->tasks_max);
|
|
|
a19bc6 |
+ r = cg_set_attribute("pids", path, "pids.max", buf);
|
|
|
a19bc6 |
+ } else
|
|
|
a19bc6 |
+ r = cg_set_attribute("pids", path, "pids.max", "max");
|
|
|
a19bc6 |
+
|
|
|
a19bc6 |
+ if (r < 0)
|
|
|
a19bc6 |
+ log_full_errno(IN_SET(r, -ENOENT, -EROFS) ? LOG_DEBUG : LOG_WARNING, r,
|
|
|
a19bc6 |
+ "Failed to set pids.max on %s: %m", path);
|
|
|
a19bc6 |
+ }
|
|
|
a19bc6 |
}
|
|
|
a19bc6 |
|
|
|
a19bc6 |
CGroupControllerMask cgroup_context_get_mask(CGroupContext *c) {
|
|
|
a19bc6 |
@@ -484,6 +502,10 @@ CGroupControllerMask cgroup_context_get_mask(CGroupContext *c) {
|
|
|
a19bc6 |
c->device_policy != CGROUP_AUTO)
|
|
|
a19bc6 |
mask |= CGROUP_DEVICE;
|
|
|
a19bc6 |
|
|
|
a19bc6 |
+ if (c->tasks_accounting ||
|
|
|
a19bc6 |
+ c->tasks_max != (uint64_t) -1)
|
|
|
a19bc6 |
+ mask |= CGROUP_PIDS;
|
|
|
a19bc6 |
+
|
|
|
a19bc6 |
return mask;
|
|
|
a19bc6 |
}
|
|
|
a19bc6 |
|
|
|
a19bc6 |
@@ -1044,6 +1066,28 @@ int manager_notify_cgroup_empty(Manager *m, const char *cgroup) {
|
|
|
a19bc6 |
return 0;
|
|
|
a19bc6 |
}
|
|
|
a19bc6 |
|
|
|
a19bc6 |
+int unit_get_tasks_current(Unit *u, uint64_t *ret) {
|
|
|
a19bc6 |
+ _cleanup_free_ char *v = NULL;
|
|
|
a19bc6 |
+ int r;
|
|
|
a19bc6 |
+
|
|
|
a19bc6 |
+ assert(u);
|
|
|
a19bc6 |
+ assert(ret);
|
|
|
a19bc6 |
+
|
|
|
a19bc6 |
+ if (!u->cgroup_path)
|
|
|
a19bc6 |
+ return -ENODATA;
|
|
|
a19bc6 |
+
|
|
|
a19bc6 |
+ if ((u->cgroup_realized_mask & CGROUP_PIDS) == 0)
|
|
|
a19bc6 |
+ return -ENODATA;
|
|
|
a19bc6 |
+
|
|
|
a19bc6 |
+ r = cg_get_attribute("pids", u->cgroup_path, "pids.current", &v);
|
|
|
a19bc6 |
+ if (r == -ENOENT)
|
|
|
a19bc6 |
+ return -ENODATA;
|
|
|
a19bc6 |
+ if (r < 0)
|
|
|
a19bc6 |
+ return r;
|
|
|
a19bc6 |
+
|
|
|
a19bc6 |
+ return safe_atou64(v, ret);
|
|
|
a19bc6 |
+}
|
|
|
a19bc6 |
+
|
|
|
a19bc6 |
static const char* const cgroup_device_policy_table[_CGROUP_DEVICE_POLICY_MAX] = {
|
|
|
a19bc6 |
[CGROUP_AUTO] = "auto",
|
|
|
a19bc6 |
[CGROUP_CLOSED] = "closed",
|
|
|
a19bc6 |
diff --git a/src/core/cgroup.h b/src/core/cgroup.h
|
|
|
181b3f |
index 8fa851de3..8af3eaa3a 100644
|
|
|
a19bc6 |
--- a/src/core/cgroup.h
|
|
|
a19bc6 |
+++ b/src/core/cgroup.h
|
|
|
a19bc6 |
@@ -72,6 +72,7 @@ struct CGroupContext {
|
|
|
a19bc6 |
bool cpu_accounting;
|
|
|
a19bc6 |
bool blockio_accounting;
|
|
|
a19bc6 |
bool memory_accounting;
|
|
|
a19bc6 |
+ bool tasks_accounting;
|
|
|
a19bc6 |
|
|
|
a19bc6 |
unsigned long cpu_shares;
|
|
|
a19bc6 |
unsigned long startup_cpu_shares;
|
|
|
a19bc6 |
@@ -88,6 +89,8 @@ struct CGroupContext {
|
|
|
a19bc6 |
LIST_HEAD(CGroupDeviceAllow, device_allow);
|
|
|
a19bc6 |
|
|
|
a19bc6 |
bool delegate;
|
|
|
a19bc6 |
+
|
|
|
a19bc6 |
+ uint64_t tasks_max;
|
|
|
a19bc6 |
};
|
|
|
a19bc6 |
|
|
|
a19bc6 |
#include "unit.h"
|
|
|
a19bc6 |
@@ -127,5 +130,7 @@ pid_t unit_search_main_pid(Unit *u);
|
|
|
a19bc6 |
|
|
|
a19bc6 |
int manager_notify_cgroup_empty(Manager *m, const char *group);
|
|
|
a19bc6 |
|
|
|
a19bc6 |
+int unit_get_tasks_current(Unit *u, uint64_t *ret);
|
|
|
a19bc6 |
+
|
|
|
a19bc6 |
const char* cgroup_device_policy_to_string(CGroupDevicePolicy i) _const_;
|
|
|
a19bc6 |
CGroupDevicePolicy cgroup_device_policy_from_string(const char *s) _pure_;
|
|
|
a19bc6 |
diff --git a/src/core/dbus-cgroup.c b/src/core/dbus-cgroup.c
|
|
|
181b3f |
index 4a9df0601..a4465dc7a 100644
|
|
|
a19bc6 |
--- a/src/core/dbus-cgroup.c
|
|
|
a19bc6 |
+++ b/src/core/dbus-cgroup.c
|
|
|
a19bc6 |
@@ -168,6 +168,8 @@ const sd_bus_vtable bus_cgroup_vtable[] = {
|
|
|
a19bc6 |
SD_BUS_PROPERTY("MemoryLimit", "t", NULL, offsetof(CGroupContext, memory_limit), 0),
|
|
|
a19bc6 |
SD_BUS_PROPERTY("DevicePolicy", "s", property_get_cgroup_device_policy, offsetof(CGroupContext, device_policy), 0),
|
|
|
a19bc6 |
SD_BUS_PROPERTY("DeviceAllow", "a(ss)", property_get_device_allow, 0, 0),
|
|
|
a19bc6 |
+ SD_BUS_PROPERTY("TasksAccounting", "b", bus_property_get_bool, offsetof(CGroupContext, tasks_accounting), 0),
|
|
|
a19bc6 |
+ SD_BUS_PROPERTY("TasksMax", "t", NULL, offsetof(CGroupContext, tasks_max), 0),
|
|
|
a19bc6 |
SD_BUS_VTABLE_END
|
|
|
a19bc6 |
};
|
|
|
a19bc6 |
|
|
|
a19bc6 |
@@ -551,7 +553,11 @@ int bus_cgroup_set_property(
|
|
|
a19bc6 |
if (mode != UNIT_CHECK) {
|
|
|
a19bc6 |
c->memory_limit = limit;
|
|
|
a19bc6 |
u->cgroup_realized_mask &= ~CGROUP_MEMORY;
|
|
|
a19bc6 |
- unit_write_drop_in_private_format(u, mode, name, "%s=%" PRIu64, name, limit);
|
|
|
a19bc6 |
+
|
|
|
a19bc6 |
+ if (limit == (uint64_t) -1)
|
|
|
a19bc6 |
+ unit_write_drop_in_private(u, mode, name, "MemoryLimit=infinity");
|
|
|
a19bc6 |
+ else
|
|
|
a19bc6 |
+ unit_write_drop_in_private_format(u, mode, name, "MemoryLimit=%" PRIu64, limit);
|
|
|
a19bc6 |
}
|
|
|
a19bc6 |
|
|
|
a19bc6 |
return 1;
|
|
|
a19bc6 |
@@ -667,6 +673,39 @@ int bus_cgroup_set_property(
|
|
|
a19bc6 |
|
|
|
a19bc6 |
return 1;
|
|
|
a19bc6 |
|
|
|
a19bc6 |
+ } else if (streq(name, "TasksAccounting")) {
|
|
|
a19bc6 |
+ int b;
|
|
|
a19bc6 |
+
|
|
|
a19bc6 |
+ r = sd_bus_message_read(message, "b", &b);
|
|
|
a19bc6 |
+ if (r < 0)
|
|
|
a19bc6 |
+ return r;
|
|
|
a19bc6 |
+
|
|
|
a19bc6 |
+ if (mode != UNIT_CHECK) {
|
|
|
a19bc6 |
+ c->tasks_accounting = b;
|
|
|
a19bc6 |
+ u->cgroup_realized_mask &= ~CGROUP_PIDS;
|
|
|
a19bc6 |
+ unit_write_drop_in_private(u, mode, name, b ? "TasksAccounting=yes" : "TasksAccounting=no");
|
|
|
a19bc6 |
+ }
|
|
|
a19bc6 |
+
|
|
|
a19bc6 |
+ return 1;
|
|
|
a19bc6 |
+
|
|
|
a19bc6 |
+ } else if (streq(name, "TasksMax")) {
|
|
|
a19bc6 |
+ uint64_t limit;
|
|
|
a19bc6 |
+
|
|
|
a19bc6 |
+ r = sd_bus_message_read(message, "t", &limit);
|
|
|
a19bc6 |
+ if (r < 0)
|
|
|
a19bc6 |
+ return r;
|
|
|
a19bc6 |
+
|
|
|
a19bc6 |
+ if (mode != UNIT_CHECK) {
|
|
|
a19bc6 |
+ c->tasks_max = limit;
|
|
|
a19bc6 |
+ u->cgroup_realized_mask &= ~CGROUP_PIDS;
|
|
|
a19bc6 |
+
|
|
|
a19bc6 |
+ if (limit == (uint64_t) -1)
|
|
|
a19bc6 |
+ unit_write_drop_in_private(u, mode, name, "TasksMax=infinity");
|
|
|
a19bc6 |
+ else
|
|
|
a19bc6 |
+ unit_write_drop_in_private_format(u, mode, name, "TasksMax=%" PRIu64, limit);
|
|
|
a19bc6 |
+ }
|
|
|
a19bc6 |
+
|
|
|
a19bc6 |
+ return 1;
|
|
|
a19bc6 |
}
|
|
|
a19bc6 |
|
|
|
a19bc6 |
if (u->transient && u->load_state == UNIT_STUB) {
|
|
|
a19bc6 |
diff --git a/src/core/dbus-unit.c b/src/core/dbus-unit.c
|
|
|
181b3f |
index 056a17ac1..1d0d6f67c 100644
|
|
|
a19bc6 |
--- a/src/core/dbus-unit.c
|
|
|
a19bc6 |
+++ b/src/core/dbus-unit.c
|
|
|
a19bc6 |
@@ -673,11 +673,36 @@ static int property_get_current_memory(
|
|
|
a19bc6 |
return sd_bus_message_append(reply, "t", sz);
|
|
|
a19bc6 |
}
|
|
|
a19bc6 |
|
|
|
a19bc6 |
+static int property_get_current_tasks(
|
|
|
a19bc6 |
+ sd_bus *bus,
|
|
|
a19bc6 |
+ const char *path,
|
|
|
a19bc6 |
+ const char *interface,
|
|
|
a19bc6 |
+ const char *property,
|
|
|
a19bc6 |
+ sd_bus_message *reply,
|
|
|
a19bc6 |
+ void *userdata,
|
|
|
a19bc6 |
+ sd_bus_error *error) {
|
|
|
a19bc6 |
+
|
|
|
a19bc6 |
+ uint64_t cn = (uint64_t) -1;
|
|
|
a19bc6 |
+ Unit *u = userdata;
|
|
|
a19bc6 |
+ int r;
|
|
|
a19bc6 |
+
|
|
|
a19bc6 |
+ assert(bus);
|
|
|
a19bc6 |
+ assert(reply);
|
|
|
a19bc6 |
+ assert(u);
|
|
|
a19bc6 |
+
|
|
|
a19bc6 |
+ r = unit_get_tasks_current(u, &cn;;
|
|
|
a19bc6 |
+ if (r < 0 && r != -ENODATA)
|
|
|
a19bc6 |
+ log_unit_warning_errno(u->id, r, "Failed to get pids.current attribute: %m");
|
|
|
a19bc6 |
+
|
|
|
a19bc6 |
+ return sd_bus_message_append(reply, "t", cn);
|
|
|
a19bc6 |
+}
|
|
|
a19bc6 |
+
|
|
|
a19bc6 |
const sd_bus_vtable bus_unit_cgroup_vtable[] = {
|
|
|
a19bc6 |
SD_BUS_VTABLE_START(0),
|
|
|
a19bc6 |
SD_BUS_PROPERTY("Slice", "s", property_get_slice, 0, 0),
|
|
|
a19bc6 |
SD_BUS_PROPERTY("ControlGroup", "s", NULL, offsetof(Unit, cgroup_path), 0),
|
|
|
a19bc6 |
SD_BUS_PROPERTY("MemoryCurrent", "t", property_get_current_memory, 0, 0),
|
|
|
a19bc6 |
+ SD_BUS_PROPERTY("TasksCurrent", "t", property_get_current_tasks, 0, 0),
|
|
|
a19bc6 |
SD_BUS_VTABLE_END
|
|
|
a19bc6 |
};
|
|
|
a19bc6 |
|
|
|
a19bc6 |
diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4
|
|
|
181b3f |
index f996032cf..26e4c618e 100644
|
|
|
a19bc6 |
--- a/src/core/load-fragment-gperf.gperf.m4
|
|
|
a19bc6 |
+++ b/src/core/load-fragment-gperf.gperf.m4
|
|
|
a19bc6 |
@@ -125,6 +125,8 @@ $1.StartupBlockIOWeight, config_parse_blockio_weight, 0,
|
|
|
a19bc6 |
$1.BlockIODeviceWeight, config_parse_blockio_device_weight, 0, offsetof($1, cgroup_context)
|
|
|
a19bc6 |
$1.BlockIOReadBandwidth, config_parse_blockio_bandwidth, 0, offsetof($1, cgroup_context)
|
|
|
a19bc6 |
$1.BlockIOWriteBandwidth, config_parse_blockio_bandwidth, 0, offsetof($1, cgroup_context)
|
|
|
a19bc6 |
+$1.TasksAccounting, config_parse_bool, 0, offsetof($1, cgroup_context.tasks_accounting)
|
|
|
a19bc6 |
+$1.TasksMax, config_parse_tasks_max, 0, offsetof($1, cgroup_context)
|
|
|
a19bc6 |
$1.Delegate, config_parse_bool, 0, offsetof($1, cgroup_context.delegate)'
|
|
|
a19bc6 |
)m4_dnl
|
|
|
a19bc6 |
Unit.Description, config_parse_unit_string_printf, 0, offsetof(Unit, description)
|
|
|
a19bc6 |
diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c
|
|
|
181b3f |
index 7d1ac6c25..7d2e737d0 100644
|
|
|
a19bc6 |
--- a/src/core/load-fragment.c
|
|
|
a19bc6 |
+++ b/src/core/load-fragment.c
|
|
|
a19bc6 |
@@ -3052,7 +3052,7 @@ int config_parse_memory_limit(
|
|
|
a19bc6 |
off_t bytes;
|
|
|
a19bc6 |
int r;
|
|
|
a19bc6 |
|
|
|
a19bc6 |
- if (isempty(rvalue)) {
|
|
|
a19bc6 |
+ if (isempty(rvalue) || streq(rvalue, "infinity")) {
|
|
|
a19bc6 |
c->memory_limit = (uint64_t) -1;
|
|
|
a19bc6 |
return 0;
|
|
|
a19bc6 |
}
|
|
|
a19bc6 |
@@ -3060,9 +3060,8 @@ int config_parse_memory_limit(
|
|
|
a19bc6 |
assert_cc(sizeof(uint64_t) == sizeof(off_t));
|
|
|
a19bc6 |
|
|
|
a19bc6 |
r = parse_size(rvalue, 1024, &bytes);
|
|
|
a19bc6 |
- if (r < 0) {
|
|
|
a19bc6 |
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
|
|
|
a19bc6 |
- "Memory limit '%s' invalid. Ignoring.", rvalue);
|
|
|
a19bc6 |
+ if (r < 0 || bytes < 1) {
|
|
|
a19bc6 |
+ log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Memory limit '%s' invalid. Ignoring.", rvalue);
|
|
|
a19bc6 |
return 0;
|
|
|
a19bc6 |
}
|
|
|
a19bc6 |
|
|
|
a19bc6 |
@@ -3070,6 +3069,36 @@ int config_parse_memory_limit(
|
|
|
a19bc6 |
return 0;
|
|
|
a19bc6 |
}
|
|
|
a19bc6 |
|
|
|
a19bc6 |
+int config_parse_tasks_max(
|
|
|
a19bc6 |
+ const char *unit,
|
|
|
a19bc6 |
+ const char *filename,
|
|
|
a19bc6 |
+ unsigned line,
|
|
|
a19bc6 |
+ const char *section,
|
|
|
a19bc6 |
+ unsigned section_line,
|
|
|
a19bc6 |
+ const char *lvalue,
|
|
|
a19bc6 |
+ int ltype,
|
|
|
a19bc6 |
+ const char *rvalue,
|
|
|
a19bc6 |
+ void *data,
|
|
|
a19bc6 |
+ void *userdata) {
|
|
|
a19bc6 |
+
|
|
|
a19bc6 |
+ CGroupContext *c = data;
|
|
|
a19bc6 |
+ uint64_t u;
|
|
|
a19bc6 |
+ int r;
|
|
|
a19bc6 |
+
|
|
|
a19bc6 |
+ if (isempty(rvalue) || streq(rvalue, "infinity")) {
|
|
|
a19bc6 |
+ c->tasks_max = (uint64_t) -1;
|
|
|
a19bc6 |
+ return 0;
|
|
|
a19bc6 |
+ }
|
|
|
a19bc6 |
+
|
|
|
a19bc6 |
+ r = safe_atou64(rvalue, &u);
|
|
|
a19bc6 |
+ if (r < 0 || u < 1) {
|
|
|
a19bc6 |
+ log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Maximum tasks value '%s' invalid. Ignoring.", rvalue);
|
|
|
a19bc6 |
+ return 0;
|
|
|
a19bc6 |
+ }
|
|
|
a19bc6 |
+
|
|
|
a19bc6 |
+ return 0;
|
|
|
a19bc6 |
+}
|
|
|
a19bc6 |
+
|
|
|
a19bc6 |
int config_parse_device_allow(
|
|
|
a19bc6 |
const char *unit,
|
|
|
a19bc6 |
const char *filename,
|
|
|
a19bc6 |
diff --git a/src/core/load-fragment.h b/src/core/load-fragment.h
|
|
|
181b3f |
index 2059353d3..8d334f2c8 100644
|
|
|
a19bc6 |
--- a/src/core/load-fragment.h
|
|
|
a19bc6 |
+++ b/src/core/load-fragment.h
|
|
|
a19bc6 |
@@ -89,6 +89,7 @@ int config_parse_pass_environ(const char *unit, const char *filename, unsigned l
|
|
|
a19bc6 |
int config_parse_unit_slice(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);
|
|
|
a19bc6 |
int config_parse_cpu_shares(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);
|
|
|
a19bc6 |
int config_parse_memory_limit(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);
|
|
|
a19bc6 |
+int config_parse_tasks_max(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);
|
|
|
a19bc6 |
int config_parse_device_policy(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);
|
|
|
a19bc6 |
int config_parse_device_allow(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);
|
|
|
a19bc6 |
int config_parse_blockio_weight(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);
|
|
|
a19bc6 |
diff --git a/src/core/main.c b/src/core/main.c
|
|
|
181b3f |
index cba992cea..aca05a535 100644
|
|
|
a19bc6 |
--- a/src/core/main.c
|
|
|
a19bc6 |
+++ b/src/core/main.c
|
|
|
a19bc6 |
@@ -117,6 +117,7 @@ static bool arg_default_cpu_accounting = false;
|
|
|
a19bc6 |
static bool arg_default_blockio_accounting = false;
|
|
|
a19bc6 |
static bool arg_default_memory_accounting = false;
|
|
|
a19bc6 |
static EmergencyAction arg_cad_burst_action = EMERGENCY_ACTION_REBOOT_FORCE;
|
|
|
a19bc6 |
+static bool arg_default_tasks_accounting = false;
|
|
|
a19bc6 |
|
|
|
a19bc6 |
static void nop_handler(int sig) {}
|
|
|
a19bc6 |
|
|
|
a19bc6 |
@@ -676,6 +677,7 @@ static int parse_config_file(void) {
|
|
|
a19bc6 |
{ "Manager", "DefaultBlockIOAccounting", config_parse_bool, 0, &arg_default_blockio_accounting },
|
|
|
a19bc6 |
{ "Manager", "DefaultMemoryAccounting", config_parse_bool, 0, &arg_default_memory_accounting },
|
|
|
a19bc6 |
{ "Manager", "CtrlAltDelBurstAction", config_parse_emergency_action, 0, &arg_cad_burst_action },
|
|
|
a19bc6 |
+ { "Manager", "DefaultTasksAccounting", config_parse_bool, 0, &arg_default_tasks_accounting },
|
|
|
a19bc6 |
{}
|
|
|
a19bc6 |
};
|
|
|
a19bc6 |
|
|
|
a19bc6 |
@@ -1685,6 +1687,7 @@ int main(int argc, char *argv[]) {
|
|
|
a19bc6 |
m->default_cpu_accounting = arg_default_cpu_accounting;
|
|
|
a19bc6 |
m->default_blockio_accounting = arg_default_blockio_accounting;
|
|
|
a19bc6 |
m->default_memory_accounting = arg_default_memory_accounting;
|
|
|
a19bc6 |
+ m->default_tasks_accounting = arg_default_tasks_accounting;
|
|
|
a19bc6 |
m->runtime_watchdog = arg_runtime_watchdog;
|
|
|
a19bc6 |
m->shutdown_watchdog = arg_shutdown_watchdog;
|
|
|
a19bc6 |
|
|
|
a19bc6 |
diff --git a/src/core/manager.h b/src/core/manager.h
|
|
|
181b3f |
index 231c076b1..96dcd83dc 100644
|
|
|
a19bc6 |
--- a/src/core/manager.h
|
|
|
a19bc6 |
+++ b/src/core/manager.h
|
|
|
a19bc6 |
@@ -261,6 +261,7 @@ struct Manager {
|
|
|
a19bc6 |
bool default_cpu_accounting;
|
|
|
a19bc6 |
bool default_memory_accounting;
|
|
|
a19bc6 |
bool default_blockio_accounting;
|
|
|
a19bc6 |
+ bool default_tasks_accounting;
|
|
|
a19bc6 |
|
|
|
a19bc6 |
usec_t default_timer_accuracy_usec;
|
|
|
a19bc6 |
|
|
|
a19bc6 |
diff --git a/src/core/unit.c b/src/core/unit.c
|
|
|
181b3f |
index 103f92084..2fcb4fbf0 100644
|
|
|
a19bc6 |
--- a/src/core/unit.c
|
|
|
a19bc6 |
+++ b/src/core/unit.c
|
|
|
a19bc6 |
@@ -126,6 +126,7 @@ static void unit_init(Unit *u) {
|
|
|
a19bc6 |
cc->cpu_accounting = u->manager->default_cpu_accounting;
|
|
|
a19bc6 |
cc->blockio_accounting = u->manager->default_blockio_accounting;
|
|
|
a19bc6 |
cc->memory_accounting = u->manager->default_memory_accounting;
|
|
|
a19bc6 |
+ cc->tasks_accounting = u->manager->default_tasks_accounting;
|
|
|
a19bc6 |
}
|
|
|
a19bc6 |
|
|
|
a19bc6 |
ec = unit_get_exec_context(u);
|
|
|
a19bc6 |
diff --git a/src/shared/cgroup-util.h b/src/shared/cgroup-util.h
|
|
|
181b3f |
index 96a3d3baf..31bd8d311 100644
|
|
|
a19bc6 |
--- a/src/shared/cgroup-util.h
|
|
|
a19bc6 |
+++ b/src/shared/cgroup-util.h
|
|
|
a19bc6 |
@@ -35,6 +35,7 @@ typedef enum CGroupControllerMask {
|
|
|
a19bc6 |
CGROUP_BLKIO = 4,
|
|
|
a19bc6 |
CGROUP_MEMORY = 8,
|
|
|
a19bc6 |
CGROUP_DEVICE = 16,
|
|
|
a19bc6 |
+ CGROUP_PIDS = 32,
|
|
|
a19bc6 |
_CGROUP_CONTROLLER_MASK_ALL = 31
|
|
|
a19bc6 |
} CGroupControllerMask;
|
|
|
a19bc6 |
|
|
|
a19bc6 |
diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c
|
|
|
181b3f |
index 0333599c8..b1862b567 100644
|
|
|
a19bc6 |
--- a/src/systemctl/systemctl.c
|
|
|
a19bc6 |
+++ b/src/systemctl/systemctl.c
|
|
|
a19bc6 |
@@ -3280,6 +3280,8 @@ typedef struct UnitStatusInfo {
|
|
|
a19bc6 |
/* CGroup */
|
|
|
a19bc6 |
uint64_t memory_current;
|
|
|
a19bc6 |
uint64_t memory_limit;
|
|
|
a19bc6 |
+ uint64_t tasks_current;
|
|
|
a19bc6 |
+ uint64_t tasks_max;
|
|
|
a19bc6 |
|
|
|
a19bc6 |
LIST_HEAD(ExecStatusInfo, exec);
|
|
|
a19bc6 |
} UnitStatusInfo;
|
|
|
a19bc6 |
@@ -3539,6 +3541,15 @@ static void print_status_info(
|
|
|
a19bc6 |
if (i->status_errno > 0)
|
|
|
a19bc6 |
printf(" Error: %i (%s)\n", i->status_errno, strerror(i->status_errno));
|
|
|
a19bc6 |
|
|
|
a19bc6 |
+ if (i->tasks_current != (uint64_t) -1) {
|
|
|
a19bc6 |
+ printf(" Tasks: %" PRIu64, i->tasks_current);
|
|
|
a19bc6 |
+
|
|
|
a19bc6 |
+ if (i->tasks_max != (uint64_t) -1)
|
|
|
a19bc6 |
+ printf(" (limit: %" PRIi64 ")\n", i->tasks_max);
|
|
|
a19bc6 |
+ else
|
|
|
a19bc6 |
+ printf("\n");
|
|
|
a19bc6 |
+ }
|
|
|
a19bc6 |
+
|
|
|
a19bc6 |
if (i->memory_current != (uint64_t) -1) {
|
|
|
a19bc6 |
char buf[FORMAT_BYTES_MAX];
|
|
|
a19bc6 |
|
|
|
a19bc6 |
@@ -3768,6 +3779,10 @@ static int status_property(const char *name, sd_bus_message *m, UnitStatusInfo *
|
|
|
a19bc6 |
i->memory_current = u;
|
|
|
a19bc6 |
else if (streq(name, "MemoryLimit"))
|
|
|
a19bc6 |
i->memory_limit = u;
|
|
|
a19bc6 |
+ else if (streq(name, "TasksCurrent"))
|
|
|
a19bc6 |
+ i->tasks_current = u;
|
|
|
a19bc6 |
+ else if (streq(name, "TasksMax"))
|
|
|
a19bc6 |
+ i->tasks_max = u;
|
|
|
a19bc6 |
|
|
|
a19bc6 |
break;
|
|
|
a19bc6 |
}
|
|
|
a19bc6 |
@@ -4248,6 +4263,8 @@ static int show_one(
|
|
|
a19bc6 |
UnitStatusInfo info = {
|
|
|
a19bc6 |
.memory_current = (uint64_t) -1,
|
|
|
a19bc6 |
.memory_limit = (uint64_t) -1,
|
|
|
a19bc6 |
+ .tasks_current = (uint64_t) -1,
|
|
|
a19bc6 |
+ .tasks_max = (uint64_t) -1,
|
|
|
a19bc6 |
};
|
|
|
a19bc6 |
ExecStatusInfo *p;
|
|
|
a19bc6 |
int r;
|