[systemd-commits] 3 commits - man/systemd.service.xml src/dbus-service.c src/load-fragment-gperf.gperf.m4 src/load-fragment.c src/load-fragment.h src/service.c src/service.h
Lennart Poettering
lennart at kemper.freedesktop.org
Thu Feb 9 12:11:35 PST 2012
man/systemd.service.xml | 95 +++++++++++++++++++++++++++++++++++----
src/dbus-service.c | 7 ++
src/load-fragment-gperf.gperf.m4 | 3 +
src/load-fragment.c | 1
src/load-fragment.h | 1
src/service.c | 70 ++++++++++++++++++++++++++--
src/service.h | 16 ++++++
7 files changed, 178 insertions(+), 15 deletions(-)
New commits:
commit 02c4ef9c35e90ad562dc70fae25c81a8fd7f40f8
Author: Lennart Poettering <lennart at poettering.net>
Date: Thu Feb 9 21:11:25 2012 +0100
service: imply NotifyAccess=main if WatchdogSec= is used
diff --git a/man/systemd.service.xml b/man/systemd.service.xml
index 513b4e5..837a992 100644
--- a/man/systemd.service.xml
+++ b/man/systemd.service.xml
@@ -198,8 +198,8 @@
below) should be set to open access to
the notification socket provided by
systemd. If
- <varname>NotifyAccess=</varname> is not
- set, it will implicitly be set to
+ <varname>NotifyAccess=</varname> is
+ not set, it will be implicitly set to
<option>main</option>.</para>
</listitem>
</varlistentry>
@@ -478,7 +478,15 @@
time configured here will be passed to
the executed service process in the
<varname>WATCHDOG_USEC=</varname>
- environment variable. Defaults to 0s,
+ environment variable. If
+ this option is used
+ <varname>NotifyAccess=</varname> (see
+ below) should be set to open access to
+ the notification socket provided by
+ systemd. If
+ <varname>NotifyAccess=</varname> is not
+ set, it will be implicitly set to
+ <option>main</option>. Defaults to 0,
which disables this
feature.</para></listitem>
</varlistentry>
@@ -687,10 +695,16 @@
accepted. If <option>all</option> all
services updates from all members of
the service's control group are
- accepted. This option must be set to
+ accepted. This option should be set to
open access to the notification socket
when using
- <varname>Type=notify</varname> (see above).</para></listitem>
+ <varname>Type=notify</varname> or
+ <varname>WatchdogUsec=</varname> (see
+ above). If those options are used but
+ <varname>NotifyAccess=</varname> not
+ configured it will be implicitly set
+ to
+ <option>main</option>.</para></listitem>
</varlistentry>
<varlistentry>
diff --git a/src/service.c b/src/service.c
index e782421..ec2725a 100644
--- a/src/service.c
+++ b/src/service.c
@@ -1235,6 +1235,9 @@ static int service_load(Unit *u) {
if (s->type == SERVICE_NOTIFY && s->notify_access == NOTIFY_NONE)
s->notify_access = NOTIFY_MAIN;
+ if (s->watchdog_usec > 0 && s->notify_access == NOTIFY_NONE)
+ s->notify_access = NOTIFY_MAIN;
+
if (s->type == SERVICE_DBUS || s->bus_name)
if ((r = unit_add_two_dependencies_by_name(u, UNIT_AFTER, UNIT_REQUIRES, SPECIAL_DBUS_SOCKET, NULL, true)) < 0)
return r;
commit 092317d034df0dcde67e8696031557e82c3f7930
Author: Lennart Poettering <lennart at poettering.net>
Date: Thu Feb 9 21:01:18 2012 +0100
man: document restart options
diff --git a/man/systemd.service.xml b/man/systemd.service.xml
index f0c96fd..513b4e5 100644
--- a/man/systemd.service.xml
+++ b/man/systemd.service.xml
@@ -502,16 +502,19 @@
0. If set to
<option>on-failure</option> it will be
restarted only when it exited with an
- exit code not equalling 0, or when
- terminated by a signal. If set to
+ exit code not equalling 0, when
+ terminated by a signal, when an
+ operation times out or when the
+ configured watchdog timeout is
+ triggered. If set to
<option>on-abort</option> it will be
restarted only if it exits due to
reception of an uncaught signal. If
set to <option>always</option> the
service will be restarted regardless
- whether it exited cleanly or not, or
+ whether it exited cleanly or not,
got terminated abnormally by a
- signal.</para></listitem>
+ signal or hit a timeout.</para></listitem>
</varlistentry>
<varlistentry>
@@ -744,6 +747,66 @@
for details.</para></listitem>
</varlistentry>
+ <varlistentry>
+ <term><varname>StartLimitInterval=</varname></term>
+ <term><varname>StartLimitBurst=</varname></term>
+
+ <listitem><para>Configure service
+ start rate limiting. By default
+ services which are started more often
+ than 5 times within 10s are not
+ permitted to start any more times
+ until the 10s interval ends. With
+ these two options this rate limiting
+ may be modified. Use
+ <varname>StartLimitInterval=</varname>
+ to configure the checking interval
+ (defaults to 10s, set to 0 to disable
+ any kind of rate limiting). Use
+ <varname>StartLimitBurst=</varname> to
+ configure how many starts per interval
+ are allowed (defaults to 5). These
+ configuration options are particularly
+ useful in conjunction with
+ <varname>Restart=</varname>.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><varname>StartLimitAction=</varname></term>
+
+ <listitem><para>Configure the action
+ to take if the rate limit configured
+ with
+ <varname>StartLimitInterval=</varname>
+ and
+ <varname>StartLimitBurst=</varname> is
+ hit. Takes one of
+ <option>none</option>,
+ <option>reboot</option>,
+ <option>reboot-force</option> or
+ <option>reboot-immediate</option>. If
+ <option>none</option> is set,
+ hitting the rate limit will trigger no
+ action besides that the start will not
+ be
+ permitted. <option>reboot</option>
+ causes a reboot following the normal
+ shutdown procedure (i.e. equivalent to
+ <command>systemctl reboot</command>),
+ <option>reboot-force</option> causes
+ an forced reboot which will terminate
+ all processes forcibly but should
+ cause no dirty file systems on reboot
+ (i.e. equivalent to <command>systemctl
+ reboot -f</command>) and
+ <option>reboot-immediate</option>
+ causes immediate execution of the
+ <citerefentry><refentrytitle>reboot</refentrytitle><manvolnum>2</manvolnum></citerefentry>
+ system call, which might result in
+ data loss. Defaults to
+ <option>none</option>.</para></listitem>
+ </varlistentry>
+
</variablelist>
</refsect1>
commit 4b9397474f2c80957fd1cedf885061052333fb25
Author: Michael Olbrich <m.olbrich at pengutronix.de>
Date: Thu Feb 9 13:05:23 2012 +0100
service: add StartLimitInterval/StartLimitBurst/StartLimitAction
diff --git a/src/dbus-service.c b/src/dbus-service.c
index fedfc1d..7809164 100644
--- a/src/dbus-service.c
+++ b/src/dbus-service.c
@@ -46,6 +46,9 @@
" <property name=\"WatchdogUSec\" type=\"t\" access=\"read\"/>\n" \
" <property name=\"WatchdogTimestamp\" type=\"t\" access=\"read\"/>\n" \
" <property name=\"WatchdogTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
+ " <property name=\"StartLimitInterval\" type=\"t\" access=\"read\"/>\n" \
+ " <property name=\"StartLimitBurst\" type=\"u\" access=\"read\"/>\n" \
+ " <property name=\"StartLimitAction\" type=\"s\" access=\"read\"/>\n" \
BUS_EXEC_COMMAND_INTERFACE("ExecStartPre") \
BUS_EXEC_COMMAND_INTERFACE("ExecStart") \
BUS_EXEC_COMMAND_INTERFACE("ExecStartPost") \
@@ -101,6 +104,7 @@ static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_service_append_type, service_type, Se
static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_service_append_restart, service_restart, ServiceRestart);
static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_service_append_notify_access, notify_access, NotifyAccess);
static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_service_append_service_result, service_result, ServiceResult);
+static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_service_append_start_limit_action, start_limit_action, StartLimitAction);
static const BusProperty bus_exec_main_status_properties[] = {
{ "ExecMainStartTimestamp", bus_property_append_usec, "t", offsetof(ExecStatus, start_timestamp.realtime) },
@@ -123,6 +127,9 @@ static const BusProperty bus_service_properties[] = {
{ "WatchdogUSec", bus_property_append_usec, "t", offsetof(Service, watchdog_usec) },
{ "WatchdogTimestamp", bus_property_append_usec, "t", offsetof(Service, watchdog_timestamp.realtime) },
{ "WatchdogTimestampMonotonic",bus_property_append_usec, "t", offsetof(Service, watchdog_timestamp.monotonic) },
+ { "StartLimitInterval", bus_property_append_usec, "t", offsetof(Service, start_limit.interval) },
+ { "StartLimitBurst", bus_property_append_uint32, "u", offsetof(Service, start_limit.burst) },
+ { "StartLimitAction", bus_service_append_start_limit_action,"s", offsetof(Service, start_limit_action) },
BUS_EXEC_COMMAND_PROPERTY("ExecStartPre", offsetof(Service, exec_command[SERVICE_EXEC_START_PRE]), true ),
BUS_EXEC_COMMAND_PROPERTY("ExecStart", offsetof(Service, exec_command[SERVICE_EXEC_START]), true ),
BUS_EXEC_COMMAND_PROPERTY("ExecStartPost", offsetof(Service, exec_command[SERVICE_EXEC_START_POST]), true ),
diff --git a/src/load-fragment-gperf.gperf.m4 b/src/load-fragment-gperf.gperf.m4
index 9708ff8..44ce4bb 100644
--- a/src/load-fragment-gperf.gperf.m4
+++ b/src/load-fragment-gperf.gperf.m4
@@ -136,6 +136,9 @@ Service.ExecStopPost, config_parse_exec, SERVICE_EXE
Service.RestartSec, config_parse_usec, 0, offsetof(Service, restart_usec)
Service.TimeoutSec, config_parse_usec, 0, offsetof(Service, timeout_usec)
Service.WatchdogSec, config_parse_usec, 0, offsetof(Service, watchdog_usec)
+Service.StartLimitInterval, config_parse_usec, 0, offsetof(Service, start_limit.interval)
+Service.StartLimitBurst, config_parse_unsigned, 0, offsetof(Service, start_limit.burst)
+Service.StartLimitAction, config_parse_start_limit_action, 0, offsetof(Service, start_limit_action)
Service.Type, config_parse_service_type, 0, offsetof(Service, type)
Service.Restart, config_parse_service_restart, 0, offsetof(Service, restart)
Service.PermissionsStartOnly, config_parse_bool, 0, offsetof(Service, permissions_start_only)
diff --git a/src/load-fragment.c b/src/load-fragment.c
index b2d43fb..b963d7f 100644
--- a/src/load-fragment.c
+++ b/src/load-fragment.c
@@ -1648,6 +1648,7 @@ int config_parse_unit_condition_null(
}
DEFINE_CONFIG_PARSE_ENUM(config_parse_notify_access, notify_access, NotifyAccess, "Failed to parse notify access specifier");
+DEFINE_CONFIG_PARSE_ENUM(config_parse_start_limit_action, start_limit_action, StartLimitAction, "Failed to parse start limit action specifier");
int config_parse_unit_cgroup_attr(
const char *filename,
diff --git a/src/load-fragment.h b/src/load-fragment.h
index fbb31f9..79fc76d 100644
--- a/src/load-fragment.h
+++ b/src/load-fragment.h
@@ -76,6 +76,7 @@ int config_parse_unit_condition_string(const char *filename, unsigned line, cons
int config_parse_unit_condition_null(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_kill_mode(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_notify_access(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+int config_parse_start_limit_action(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_unit_cgroup_attr(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_unit_cpu_shares(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_unit_memory_limit(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
diff --git a/src/service.c b/src/service.c
index 9ccb1b6..e782421 100644
--- a/src/service.c
+++ b/src/service.c
@@ -23,7 +23,9 @@
#include <signal.h>
#include <dirent.h>
#include <unistd.h>
+#include <sys/reboot.h>
+#include "manager.h"
#include "unit.h"
#include "service.h"
#include "load-fragment.h"
@@ -125,7 +127,7 @@ static void service_init(Unit *u) {
exec_context_init(&s->exec_context);
- RATELIMIT_INIT(s->ratelimit, 10*USEC_PER_SEC, 5);
+ RATELIMIT_INIT(s->start_limit, 10*USEC_PER_SEC, 5);
s->control_command_id = _SERVICE_EXEC_COMMAND_INVALID;
}
@@ -2324,8 +2326,56 @@ fail:
service_enter_stop(s, SERVICE_FAILURE_RESOURCES);
}
+static int service_start_limit_test(Service *s) {
+ assert(s);
+
+ if (ratelimit_test(&s->start_limit))
+ return 0;
+
+ switch (s->start_limit_action) {
+
+ case SERVICE_START_LIMIT_NONE:
+ log_warning("%s start request repeated too quickly, refusing to start.", UNIT(s)->id);
+ break;
+
+ case SERVICE_START_LIMIT_REBOOT: {
+ DBusError error;
+ int r;
+
+ dbus_error_init(&error);
+
+ log_warning("%s start request repeated too quickly, rebooting.", UNIT(s)->id);
+
+ r = manager_add_job_by_name(UNIT(s)->manager, JOB_START, SPECIAL_REBOOT_TARGET, JOB_REPLACE, true, &error, NULL);
+ if (r < 0) {
+ log_error("Failed to reboot: %s.", bus_error(&error, r));
+ dbus_error_free(&error);
+ }
+
+ break;
+ }
+
+ case SERVICE_START_LIMIT_REBOOT_FORCE:
+ log_warning("%s start request repeated too quickly, force rebooting.", UNIT(s)->id);
+ UNIT(s)->manager->exit_code = MANAGER_REBOOT;
+ break;
+
+ case SERVICE_START_LIMIT_REBOOT_IMMEDIATE:
+ log_warning("%s start request repeated too quickly, rebooting immediately.", UNIT(s)->id);
+ reboot(RB_AUTOBOOT);
+ break;
+
+ default:
+ log_error("start limit action=%i", s->start_limit_action);
+ assert_not_reached("Unknown StartLimitAction.");
+ }
+
+ return -ECANCELED;
+}
+
static int service_start(Unit *u) {
Service *s = SERVICE(u);
+ int r;
assert(s);
@@ -2348,10 +2398,9 @@ static int service_start(Unit *u) {
assert(s->state == SERVICE_DEAD || s->state == SERVICE_FAILED || s->state == SERVICE_AUTO_RESTART);
/* Make sure we don't enter a busy loop of some kind. */
- if (!ratelimit_test(&s->ratelimit)) {
- log_warning("%s start request repeated too quickly, refusing to start.", u->id);
- return -ECANCELED;
- }
+ r = service_start_limit_test(s);
+ if (r < 0)
+ return r;
s->result = SERVICE_SUCCESS;
s->reload_result = SERVICE_SUCCESS;
@@ -3665,6 +3714,14 @@ static const char* const service_result_table[_SERVICE_RESULT_MAX] = {
DEFINE_STRING_TABLE_LOOKUP(service_result, ServiceResult);
+static const char* const start_limit_action_table[_SERVICE_START_LIMIT_MAX] = {
+ [SERVICE_START_LIMIT_NONE] = "none",
+ [SERVICE_START_LIMIT_REBOOT] = "reboot",
+ [SERVICE_START_LIMIT_REBOOT_FORCE] = "reboot-force",
+ [SERVICE_START_LIMIT_REBOOT_IMMEDIATE] = "reboot-immediate"
+};
+DEFINE_STRING_TABLE_LOOKUP(start_limit_action, StartLimitAction);
+
const UnitVTable service_vtable = {
.suffix = ".service",
.object_size = sizeof(Service),
diff --git a/src/service.h b/src/service.h
index 02726ef..60b1051 100644
--- a/src/service.h
+++ b/src/service.h
@@ -100,6 +100,15 @@ typedef enum ServiceResult {
_SERVICE_RESULT_INVALID = -1
} ServiceResult;
+typedef enum StartLimitAction {
+ SERVICE_START_LIMIT_NONE,
+ SERVICE_START_LIMIT_REBOOT,
+ SERVICE_START_LIMIT_REBOOT_FORCE,
+ SERVICE_START_LIMIT_REBOOT_IMMEDIATE,
+ _SERVICE_START_LIMIT_MAX,
+ _SERVICE_START_LIMIT_INVALID = -1
+} StartLimitAction;
+
struct Service {
Unit meta;
@@ -169,7 +178,9 @@ struct Service {
char *status_text;
- RateLimit ratelimit;
+ RateLimit start_limit;
+ StartLimitAction start_limit_action;
+
UnitRef accept_socket;
@@ -203,4 +214,7 @@ NotifyAccess notify_access_from_string(const char *s);
const char* service_result_to_string(ServiceResult i);
ServiceResult service_result_from_string(const char *s);
+const char* start_limit_action_to_string(StartLimitAction i);
+StartLimitAction start_limit_action_from_string(const char *s);
+
#endif
More information about the systemd-commits
mailing list