Skip to content

Commit 6bf0f40

Browse files
committed
core: make the StartLimitXYZ= settings generic and apply to any kind of unit, not just services
This moves the StartLimitBurst=, StartLimitInterval=, StartLimitAction=, RebootArgument= from the [Service] section into the [Unit] section of unit files, and thus support it in all unit types, not just in services. This way we can enforce the start limit much earlier, in particular before testing the unit conditions, so that repeated start-up failure due to failed conditions is also considered for the start limit logic. For compatibility the four options may also be configured in the [Service] section still, but we only document them in their new section [Unit]. This also renamed the socket unit failure code "service-failed-permanent" into "service-start-limit-hit" to express more clearly what it is about, after all it's only triggered through the start limit being hit. Finally, the code in busname_trigger_notify() and socket_trigger_notify() is altered to become more alike. Fixes: #2467
1 parent bae687d commit 6bf0f40

13 files changed

Lines changed: 143 additions & 172 deletions

man/systemd.service.xml

Lines changed: 4 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -873,86 +873,12 @@
873873
effect.</para></listitem>
874874
</varlistentry>
875875

876-
<varlistentry>
877-
<term><varname>StartLimitInterval=</varname></term>
878-
<term><varname>StartLimitBurst=</varname></term>
879-
880-
<listitem><para>Configure service start rate limiting. By
881-
default, services which are started more than 5 times within
882-
10 seconds are not permitted to start any more times until the
883-
10 second interval ends. With these two options, this rate
884-
limiting may be modified. Use
885-
<varname>StartLimitInterval=</varname> to configure the
886-
checking interval (defaults to
887-
<varname>DefaultStartLimitInterval=</varname> in manager
888-
configuration file, set to 0 to disable any kind of rate
889-
limiting). Use <varname>StartLimitBurst=</varname> to
890-
configure how many starts per interval are allowed (defaults
891-
to <varname>DefaultStartLimitBurst=</varname> in manager
892-
configuration file). These configuration options are
893-
particularly useful in conjunction with
894-
<varname>Restart=</varname>; however, they apply to all kinds
895-
of starts (including manual), not just those triggered by the
896-
<varname>Restart=</varname> logic. Note that units which are
897-
configured for <varname>Restart=</varname> and which reach the
898-
start limit are not attempted to be restarted anymore;
899-
however, they may still be restarted manually at a later
900-
point, from which point on, the restart logic is again
901-
activated. Note that <command>systemctl reset-failed</command>
902-
will cause the restart rate counter for a service to be
903-
flushed, which is useful if the administrator wants to
904-
manually start a service and the start limit interferes with
905-
that.</para></listitem>
906-
</varlistentry>
907-
908-
<varlistentry>
909-
<term><varname>StartLimitAction=</varname></term>
910-
911-
<listitem><para>Configure the action to take if the rate limit
912-
configured with <varname>StartLimitInterval=</varname> and
913-
<varname>StartLimitBurst=</varname> is hit. Takes one of
914-
<option>none</option>,
915-
<option>reboot</option>,
916-
<option>reboot-force</option>,
917-
<option>reboot-immediate</option>,
918-
<option>poweroff</option>,
919-
<option>poweroff-force</option> or
920-
<option>poweroff-immediate</option>. If
921-
<option>none</option> is set, hitting the rate limit will
922-
trigger no action besides that the start will not be
923-
permitted. <option>reboot</option> causes a reboot following
924-
the normal shutdown procedure (i.e. equivalent to
925-
<command>systemctl reboot</command>).
926-
<option>reboot-force</option> causes a forced reboot which
927-
will terminate all processes forcibly but should cause no
928-
dirty file systems on reboot (i.e. equivalent to
929-
<command>systemctl reboot -f</command>) and
930-
<option>reboot-immediate</option> causes immediate execution
931-
of the
932-
<citerefentry><refentrytitle>reboot</refentrytitle><manvolnum>2</manvolnum></citerefentry>
933-
system call, which might result in data loss. Similarly,
934-
<option>poweroff</option>, <option>poweroff-force</option>,
935-
<option>poweroff-immediate</option> have the effect of
936-
powering down the system with similar semantics. Defaults to
937-
<option>none</option>.</para></listitem>
938-
</varlistentry>
939-
940876
<varlistentry>
941877
<term><varname>FailureAction=</varname></term>
942-
<listitem><para>Configure the action to take when the service
943-
enters a failed state. Takes the same values as
944-
<varname>StartLimitAction=</varname> and executes the same
945-
actions. Defaults to <option>none</option>. </para></listitem>
946-
</varlistentry>
947-
948-
<varlistentry>
949-
<term><varname>RebootArgument=</varname></term>
950-
<listitem><para>Configure the optional argument for the
951-
<citerefentry><refentrytitle>reboot</refentrytitle><manvolnum>2</manvolnum></citerefentry>
952-
system call if <varname>StartLimitAction=</varname> or
953-
<varname>FailureAction=</varname> is a reboot action. This
954-
works just like the optional argument to <command>systemctl
955-
reboot</command> command.</para></listitem>
878+
<listitem><para>Configure the action to take when the service enters a failed state. Takes the same values as
879+
the unit setting <varname>StartLimitAction=</varname> and executes the same actions (see
880+
<citerefentry><refentrytitle>systemd.unit</refentrytitle><manvolnum>5</manvolnum></citerefentry>). Defaults to
881+
<option>none</option>. </para></listitem>
956882
</varlistentry>
957883

958884
<varlistentry>

man/systemd.unit.xml

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -759,6 +759,55 @@
759759
system call.</para></listitem>
760760
</varlistentry>
761761

762+
<varlistentry>
763+
<term><varname>StartLimitInterval=</varname></term>
764+
<term><varname>StartLimitBurst=</varname></term>
765+
766+
<listitem><para>Configure unit start rate limiting. By default, units which are started more than 5 times
767+
within 10 seconds are not permitted to start any more times until the 10 second interval ends. With these two
768+
options, this rate limiting may be modified. Use <varname>StartLimitInterval=</varname> to configure the
769+
checking interval (defaults to <varname>DefaultStartLimitInterval=</varname> in manager configuration file, set
770+
to 0 to disable any kind of rate limiting). Use <varname>StartLimitBurst=</varname> to configure how many
771+
starts per interval are allowed (defaults to <varname>DefaultStartLimitBurst=</varname> in manager
772+
configuration file). These configuration options are particularly useful in conjunction with the service
773+
setting <varname>Restart=</varname> (see
774+
<citerefentry><refentrytitle>systemd.service</refentrytitle><manvolnum>5</manvolnum></citerefentry>); however,
775+
they apply to all kinds of starts (including manual), not just those triggered by the
776+
<varname>Restart=</varname> logic. Note that units which are configured for <varname>Restart=</varname> and
777+
which reach the start limit are not attempted to be restarted anymore; however, they may still be restarted
778+
manually at a later point, from which point on, the restart logic is again activated. Note that
779+
<command>systemctl reset-failed</command> will cause the restart rate counter for a service to be flushed,
780+
which is useful if the administrator wants to manually start a unit and the start limit interferes with
781+
that.</para></listitem>
782+
</varlistentry>
783+
784+
<varlistentry>
785+
<term><varname>StartLimitAction=</varname></term>
786+
787+
<listitem><para>Configure the action to take if the rate limit configured with
788+
<varname>StartLimitInterval=</varname> and <varname>StartLimitBurst=</varname> is hit. Takes one of
789+
<option>none</option>, <option>reboot</option>, <option>reboot-force</option>,
790+
<option>reboot-immediate</option>, <option>poweroff</option>, <option>poweroff-force</option> or
791+
<option>poweroff-immediate</option>. If <option>none</option> is set, hitting the rate limit will trigger no
792+
action besides that the start will not be permitted. <option>reboot</option> causes a reboot following the
793+
normal shutdown procedure (i.e. equivalent to <command>systemctl reboot</command>).
794+
<option>reboot-force</option> causes a forced reboot which will terminate all processes forcibly but should
795+
cause no dirty file systems on reboot (i.e. equivalent to <command>systemctl reboot -f</command>) and
796+
<option>reboot-immediate</option> causes immediate execution of the
797+
<citerefentry><refentrytitle>reboot</refentrytitle><manvolnum>2</manvolnum></citerefentry> system call, which
798+
might result in data loss. Similarly, <option>poweroff</option>, <option>poweroff-force</option>,
799+
<option>poweroff-immediate</option> have the effect of powering down the system with similar
800+
semantics. Defaults to <option>none</option>.</para></listitem>
801+
</varlistentry>
802+
803+
<varlistentry>
804+
<term><varname>RebootArgument=</varname></term>
805+
<listitem><para>Configure the optional argument for the
806+
<citerefentry><refentrytitle>reboot</refentrytitle><manvolnum>2</manvolnum></citerefentry> system call if
807+
<varname>StartLimitAction=</varname> or a service's <varname>FailureAction=</varname> is a reboot action. This
808+
works just like the optional argument to <command>systemctl reboot</command> command.</para></listitem>
809+
</varlistentry>
810+
762811
<varlistentry>
763812
<term><varname>ConditionArchitecture=</varname></term>
764813
<term><varname>ConditionVirtualization=</varname></term>

src/core/busname.c

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -945,27 +945,29 @@ static void busname_reset_failed(Unit *u) {
945945

946946
static void busname_trigger_notify(Unit *u, Unit *other) {
947947
BusName *n = BUSNAME(u);
948-
Service *s;
949948

950949
assert(n);
951950
assert(other);
952951

953952
if (!IN_SET(n->state, BUSNAME_RUNNING, BUSNAME_LISTENING))
954953
return;
955954

956-
if (other->load_state != UNIT_LOADED || other->type != UNIT_SERVICE)
955+
if (other->start_limit_hit) {
956+
busname_enter_dead(n, BUSNAME_FAILURE_SERVICE_START_LIMIT_HIT);
957957
return;
958+
}
958959

959-
s = SERVICE(other);
960+
if (other->load_state != UNIT_LOADED || other->type != UNIT_SERVICE)
961+
return;
960962

961-
if (s->state == SERVICE_FAILED && s->result == SERVICE_FAILURE_START_LIMIT)
962-
busname_enter_dead(n, BUSNAME_FAILURE_SERVICE_FAILED_PERMANENT);
963-
else if (IN_SET(s->state,
964-
SERVICE_DEAD, SERVICE_FAILED,
965-
SERVICE_STOP, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL,
966-
SERVICE_STOP_POST, SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL,
967-
SERVICE_AUTO_RESTART))
963+
if (IN_SET(SERVICE(other)->state,
964+
SERVICE_DEAD, SERVICE_FAILED,
965+
SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL,
966+
SERVICE_AUTO_RESTART))
968967
busname_enter_listening(n);
968+
969+
if (SERVICE(other)->state == SERVICE_RUNNING)
970+
busname_set_state(n, BUSNAME_RUNNING);
969971
}
970972

971973
static int busname_kill(Unit *u, KillWho who, int signo, sd_bus_error *error) {
@@ -1006,7 +1008,7 @@ static const char* const busname_result_table[_BUSNAME_RESULT_MAX] = {
10061008
[BUSNAME_FAILURE_EXIT_CODE] = "exit-code",
10071009
[BUSNAME_FAILURE_SIGNAL] = "signal",
10081010
[BUSNAME_FAILURE_CORE_DUMP] = "core-dump",
1009-
[BUSNAME_FAILURE_SERVICE_FAILED_PERMANENT] = "service-failed-permanent",
1011+
[BUSNAME_FAILURE_SERVICE_START_LIMIT_HIT] = "service-start-limit-hit",
10101012
};
10111013

10121014
DEFINE_STRING_TABLE_LOOKUP(busname_result, BusNameResult);

src/core/busname.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ typedef enum BusNameResult {
3333
BUSNAME_FAILURE_EXIT_CODE,
3434
BUSNAME_FAILURE_SIGNAL,
3535
BUSNAME_FAILURE_CORE_DUMP,
36-
BUSNAME_FAILURE_SERVICE_FAILED_PERMANENT,
36+
BUSNAME_FAILURE_SERVICE_START_LIMIT_HIT,
3737
_BUSNAME_RESULT_MAX,
3838
_BUSNAME_RESULT_INVALID = -1
3939
} BusNameResult;

src/core/dbus-service.c

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -52,10 +52,11 @@ const sd_bus_vtable bus_service_vtable[] = {
5252
SD_BUS_PROPERTY("RuntimeMaxUSec", "t", bus_property_get_usec, offsetof(Service, runtime_max_usec), SD_BUS_VTABLE_PROPERTY_CONST),
5353
SD_BUS_PROPERTY("WatchdogUSec", "t", bus_property_get_usec, offsetof(Service, watchdog_usec), SD_BUS_VTABLE_PROPERTY_CONST),
5454
BUS_PROPERTY_DUAL_TIMESTAMP("WatchdogTimestamp", offsetof(Service, watchdog_timestamp), 0),
55-
SD_BUS_PROPERTY("StartLimitInterval", "t", bus_property_get_usec, offsetof(Service, start_limit.interval), SD_BUS_VTABLE_PROPERTY_CONST),
56-
SD_BUS_PROPERTY("StartLimitBurst", "u", bus_property_get_unsigned, offsetof(Service, start_limit.burst), SD_BUS_VTABLE_PROPERTY_CONST),
57-
SD_BUS_PROPERTY("StartLimitAction", "s", property_get_failure_action, offsetof(Service, start_limit_action), SD_BUS_VTABLE_PROPERTY_CONST),
58-
SD_BUS_PROPERTY("RebootArgument", "s", NULL, offsetof(Service, reboot_arg), SD_BUS_VTABLE_PROPERTY_CONST),
55+
/* The following four are obsolete, and thus marked hidden here. They moved into the Unit interface */
56+
SD_BUS_PROPERTY("StartLimitInterval", "t", bus_property_get_usec, offsetof(Unit, start_limit.interval), SD_BUS_VTABLE_PROPERTY_CONST|SD_BUS_VTABLE_HIDDEN),
57+
SD_BUS_PROPERTY("StartLimitBurst", "u", bus_property_get_unsigned, offsetof(Unit, start_limit.burst), SD_BUS_VTABLE_PROPERTY_CONST|SD_BUS_VTABLE_HIDDEN),
58+
SD_BUS_PROPERTY("StartLimitAction", "s", property_get_failure_action, offsetof(Unit, start_limit_action), SD_BUS_VTABLE_PROPERTY_CONST|SD_BUS_VTABLE_HIDDEN),
59+
SD_BUS_PROPERTY("RebootArgument", "s", NULL, offsetof(Unit, reboot_arg), SD_BUS_VTABLE_PROPERTY_CONST|SD_BUS_VTABLE_HIDDEN),
5960
SD_BUS_PROPERTY("FailureAction", "s", property_get_failure_action, offsetof(Service, failure_action), SD_BUS_VTABLE_PROPERTY_CONST),
6061
SD_BUS_PROPERTY("PermissionsStartOnly", "b", bus_property_get_bool, offsetof(Service, permissions_start_only), SD_BUS_VTABLE_PROPERTY_CONST),
6162
SD_BUS_PROPERTY("RootDirectoryStartOnly", "b", bus_property_get_bool, offsetof(Service, root_directory_start_only), SD_BUS_VTABLE_PROPERTY_CONST),

src/core/dbus-unit.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -704,6 +704,10 @@ const sd_bus_vtable bus_unit_vtable[] = {
704704
SD_BUS_PROPERTY("LoadError", "(ss)", property_get_load_error, 0, SD_BUS_VTABLE_PROPERTY_CONST),
705705
SD_BUS_PROPERTY("Transient", "b", bus_property_get_bool, offsetof(Unit, transient), SD_BUS_VTABLE_PROPERTY_CONST),
706706
SD_BUS_PROPERTY("NetClass", "u", NULL, offsetof(Unit, cgroup_netclass_id), 0),
707+
SD_BUS_PROPERTY("StartLimitInterval", "t", bus_property_get_usec, offsetof(Unit, start_limit.interval), SD_BUS_VTABLE_PROPERTY_CONST),
708+
SD_BUS_PROPERTY("StartLimitBurst", "u", bus_property_get_unsigned, offsetof(Unit, start_limit.burst), SD_BUS_VTABLE_PROPERTY_CONST),
709+
SD_BUS_PROPERTY("StartLimitAction", "s", property_get_failure_action, offsetof(Unit, start_limit_action), SD_BUS_VTABLE_PROPERTY_CONST),
710+
SD_BUS_PROPERTY("RebootArgument", "s", NULL, offsetof(Unit, reboot_arg), SD_BUS_VTABLE_PROPERTY_CONST),
707711

708712
SD_BUS_METHOD("Start", "s", "o", method_start, SD_BUS_VTABLE_UNPRIVILEGED),
709713
SD_BUS_METHOD("Stop", "s", "o", method_stop, SD_BUS_VTABLE_UNPRIVILEGED),

src/core/load-fragment-gperf.gperf.m4

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,10 @@ Unit.IgnoreOnSnapshot, config_parse_warn_compat, DISABLED_LE
164164
Unit.JobTimeoutSec, config_parse_sec, 0, offsetof(Unit, job_timeout)
165165
Unit.JobTimeoutAction, config_parse_failure_action, 0, offsetof(Unit, job_timeout_action)
166166
Unit.JobTimeoutRebootArgument, config_parse_string, 0, offsetof(Unit, job_timeout_reboot_arg)
167+
Unit.StartLimitInterval, config_parse_sec, 0, offsetof(Unit, start_limit.interval)
168+
Unit.StartLimitBurst, config_parse_unsigned, 0, offsetof(Unit, start_limit.burst)
169+
Unit.StartLimitAction, config_parse_failure_action, 0, offsetof(Unit, start_limit_action)
170+
Unit.RebootArgument, config_parse_string, 0, offsetof(Unit, reboot_arg)
167171
Unit.ConditionPathExists, config_parse_unit_condition_path, CONDITION_PATH_EXISTS, offsetof(Unit, conditions)
168172
Unit.ConditionPathExistsGlob, config_parse_unit_condition_path, CONDITION_PATH_EXISTS_GLOB, offsetof(Unit, conditions)
169173
Unit.ConditionPathIsDirectory, config_parse_unit_condition_path, CONDITION_PATH_IS_DIRECTORY, offsetof(Unit, conditions)
@@ -216,10 +220,10 @@ Service.TimeoutStartSec, config_parse_service_timeout, 0,
216220
Service.TimeoutStopSec, config_parse_service_timeout, 0, offsetof(Service, timeout_stop_usec)
217221
Service.RuntimeMaxSec, config_parse_sec, 0, offsetof(Service, runtime_max_usec)
218222
Service.WatchdogSec, config_parse_sec, 0, offsetof(Service, watchdog_usec)
219-
Service.StartLimitInterval, config_parse_sec, 0, offsetof(Service, start_limit.interval)
220-
Service.StartLimitBurst, config_parse_unsigned, 0, offsetof(Service, start_limit.burst)
221-
Service.StartLimitAction, config_parse_failure_action, 0, offsetof(Service, start_limit_action)
222-
Service.RebootArgument, config_parse_string, 0, offsetof(Service, reboot_arg)
223+
Service.StartLimitInterval, config_parse_sec, 0, offsetof(Unit, start_limit.interval)
224+
Service.StartLimitBurst, config_parse_unsigned, 0, offsetof(Unit, start_limit.burst)
225+
Service.StartLimitAction, config_parse_failure_action, 0, offsetof(Unit, start_limit_action)
226+
Service.RebootArgument, config_parse_string, 0, offsetof(Unit, reboot_arg)
223227
Service.FailureAction, config_parse_failure_action, 0, offsetof(Service, failure_action)
224228
Service.Type, config_parse_service_type, 0, offsetof(Service, type)
225229
Service.Restart, config_parse_service_restart, 0, offsetof(Service, restart)

0 commit comments

Comments
 (0)