diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/basic/missing.h | 4 | ||||
-rw-r--r-- | src/basic/rlimit-util.c | 52 | ||||
-rw-r--r-- | src/core/dbus-manager.c | 3 | ||||
-rw-r--r-- | src/core/dbus-socket.c | 2 | ||||
-rw-r--r-- | src/core/dbus-unit.c | 3 | ||||
-rw-r--r-- | src/core/load-fragment-gperf.gperf.m4 | 5 | ||||
-rw-r--r-- | src/core/main.c | 4 | ||||
-rw-r--r-- | src/core/service.c | 34 | ||||
-rw-r--r-- | src/core/service.h | 1 | ||||
-rw-r--r-- | src/core/socket.c | 81 | ||||
-rw-r--r-- | src/core/socket.h | 3 | ||||
-rw-r--r-- | src/core/system.conf | 2 | ||||
-rw-r--r-- | src/core/unit.c | 14 | ||||
-rw-r--r-- | src/core/user.conf | 2 | ||||
-rw-r--r-- | src/journal/journald-gperf.gperf | 2 | ||||
-rw-r--r-- | src/journal/journald.conf | 2 | ||||
-rw-r--r-- | src/test/test-rlimit-util.c | 12 |
17 files changed, 159 insertions, 67 deletions
diff --git a/src/basic/missing.h b/src/basic/missing.h index b389e94cf7..22ea8f67cc 100644 --- a/src/basic/missing.h +++ b/src/basic/missing.h @@ -557,7 +557,7 @@ struct btrfs_ioctl_quota_ctl_args { #define IFLA_INET6_ADDR_GEN_MODE 8 #define __IFLA_INET6_MAX 9 -#define IFLA_INET6_MAX (__IFLA_INET6_MAX - 1) +#define IFLA_INET6_MAX (__IFLA_INET6_MAX - 1) #define IN6_ADDR_GEN_MODE_EUI64 0 #define IN6_ADDR_GEN_MODE_NONE 1 @@ -742,7 +742,7 @@ struct btrfs_ioctl_quota_ctl_args { #define IFLA_BRIDGE_MAX (__IFLA_BRIDGE_MAX - 1) #endif -#if !HAVE_DECL_IFLA_BR_PRIORITY +#if !HAVE_DECL_IFLA_BR_VLAN_DEFAULT_PVID #define IFLA_BR_UNSPEC 0 #define IFLA_BR_FORWARD_DELAY 1 #define IFLA_BR_HELLO_TIME 2 diff --git a/src/basic/rlimit-util.c b/src/basic/rlimit-util.c index 7540b43215..ee063720ed 100644 --- a/src/basic/rlimit-util.c +++ b/src/basic/rlimit-util.c @@ -153,6 +153,56 @@ static int rlimit_parse_usec(const char *val, rlim_t *ret) { return 0; } +static int rlimit_parse_nice(const char *val, rlim_t *ret) { + uint64_t rl; + int r; + + /* So, Linux is weird. The range for RLIMIT_NICE is 40..1, mapping to the nice levels -20..19. However, the + * RLIMIT_NICE limit defaults to 0 by the kernel, i.e. a value that maps to nice level 20, which of course is + * bogus and does not exist. In order to permit parsing the RLIMIT_NICE of 0 here we hence implement a slight + * asymmetry: when parsing as positive nice level we permit 0..19. When parsing as negative nice level, we + * permit -20..0. But when parsing as raw resource limit value then we also allow the special value 0. + * + * Yeah, Linux is quality engineering sometimes... */ + + if (val[0] == '+') { + + /* Prefixed with "+": Parse as positive user-friendly nice value */ + r = safe_atou64(val + 1, &rl); + if (r < 0) + return r; + + if (rl >= PRIO_MAX) + return -ERANGE; + + rl = 20 - rl; + + } else if (val[0] == '-') { + + /* Prefixed with "-": Parse as negative user-friendly nice value */ + r = safe_atou64(val + 1, &rl); + if (r < 0) + return r; + + if (rl > (uint64_t) (-PRIO_MIN)) + return -ERANGE; + + rl = 20 + rl; + } else { + + /* Not prefixed: parse as raw resource limit value */ + r = safe_atou64(val, &rl); + if (r < 0) + return r; + + if (rl > (uint64_t) (20 - PRIO_MIN)) + return -ERANGE; + } + + *ret = (rlim_t) rl; + return 0; +} + static int (*const rlimit_parse_table[_RLIMIT_MAX])(const char *val, rlim_t *ret) = { [RLIMIT_CPU] = rlimit_parse_sec, [RLIMIT_FSIZE] = rlimit_parse_size, @@ -167,7 +217,7 @@ static int (*const rlimit_parse_table[_RLIMIT_MAX])(const char *val, rlim_t *ret [RLIMIT_LOCKS] = rlimit_parse_u64, [RLIMIT_SIGPENDING] = rlimit_parse_u64, [RLIMIT_MSGQUEUE] = rlimit_parse_size, - [RLIMIT_NICE] = rlimit_parse_u64, + [RLIMIT_NICE] = rlimit_parse_nice, [RLIMIT_RTPRIO] = rlimit_parse_u64, [RLIMIT_RTTIME] = rlimit_parse_usec, }; diff --git a/src/core/dbus-manager.c b/src/core/dbus-manager.c index 73c50766d1..d45f511489 100644 --- a/src/core/dbus-manager.c +++ b/src/core/dbus-manager.c @@ -2050,7 +2050,8 @@ const sd_bus_vtable bus_manager_vtable[] = { SD_BUS_PROPERTY("DefaultTimeoutStartUSec", "t", bus_property_get_usec, offsetof(Manager, default_timeout_start_usec), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("DefaultTimeoutStopUSec", "t", bus_property_get_usec, offsetof(Manager, default_timeout_stop_usec), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("DefaultRestartUSec", "t", bus_property_get_usec, offsetof(Manager, default_restart_usec), SD_BUS_VTABLE_PROPERTY_CONST), - SD_BUS_PROPERTY("DefaultStartLimitInterval", "t", bus_property_get_usec, offsetof(Manager, default_start_limit_interval), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("DefaultStartLimitIntervalSec", "t", bus_property_get_usec, offsetof(Manager, default_start_limit_interval), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("DefaultStartLimitInterval", "t", bus_property_get_usec, offsetof(Manager, default_start_limit_interval), SD_BUS_VTABLE_PROPERTY_CONST|SD_BUS_VTABLE_HIDDEN), /* obsolete alias name */ SD_BUS_PROPERTY("DefaultStartLimitBurst", "u", bus_property_get_unsigned, offsetof(Manager, default_start_limit_burst), SD_BUS_VTABLE_PROPERTY_CONST), 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), diff --git a/src/core/dbus-socket.c b/src/core/dbus-socket.c index d33e494f6b..bb09a515f8 100644 --- a/src/core/dbus-socket.c +++ b/src/core/dbus-socket.c @@ -149,6 +149,8 @@ const sd_bus_vtable bus_socket_vtable[] = { SD_BUS_PROPERTY("NAccepted", "u", bus_property_get_unsigned, offsetof(Socket, n_accepted), 0), SD_BUS_PROPERTY("FileDescriptorName", "s", property_get_fdname, 0, 0), SD_BUS_PROPERTY("SocketProtocol", "i", bus_property_get_int, offsetof(Socket, socket_protocol), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("TriggerLimitIntervalSec", "t", bus_property_get_usec, offsetof(Socket, trigger_limit.interval), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("TriggerLimitBurst", "u", bus_property_get_unsigned, offsetof(Socket, trigger_limit.burst), SD_BUS_VTABLE_PROPERTY_CONST), BUS_EXEC_COMMAND_LIST_VTABLE("ExecStartPre", offsetof(Socket, exec_command[SOCKET_EXEC_START_PRE]), SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION), BUS_EXEC_COMMAND_LIST_VTABLE("ExecStartPost", offsetof(Socket, exec_command[SOCKET_EXEC_START_POST]), SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION), BUS_EXEC_COMMAND_LIST_VTABLE("ExecStopPre", offsetof(Socket, exec_command[SOCKET_EXEC_STOP_PRE]), SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION), diff --git a/src/core/dbus-unit.c b/src/core/dbus-unit.c index abe30413c3..e912fe2192 100644 --- a/src/core/dbus-unit.c +++ b/src/core/dbus-unit.c @@ -704,7 +704,8 @@ const sd_bus_vtable bus_unit_vtable[] = { SD_BUS_PROPERTY("Asserts", "a(sbbsi)", property_get_conditions, offsetof(Unit, asserts), 0), SD_BUS_PROPERTY("LoadError", "(ss)", property_get_load_error, 0, SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("Transient", "b", bus_property_get_bool, offsetof(Unit, transient), SD_BUS_VTABLE_PROPERTY_CONST), - SD_BUS_PROPERTY("StartLimitInterval", "t", bus_property_get_usec, offsetof(Unit, start_limit.interval), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("StartLimitIntervalSec", "t", bus_property_get_usec, offsetof(Unit, start_limit.interval), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("StartLimitInterval", "t", bus_property_get_usec, offsetof(Unit, start_limit.interval), SD_BUS_VTABLE_PROPERTY_CONST|SD_BUS_VTABLE_HIDDEN), /* obsolete alias name */ SD_BUS_PROPERTY("StartLimitBurst", "u", bus_property_get_unsigned, offsetof(Unit, start_limit.burst), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("StartLimitAction", "s", property_get_failure_action, offsetof(Unit, start_limit_action), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("RebootArgument", "s", NULL, offsetof(Unit, reboot_arg), SD_BUS_VTABLE_PROPERTY_CONST), diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4 index 5568b4696f..928b913c7b 100644 --- a/src/core/load-fragment-gperf.gperf.m4 +++ b/src/core/load-fragment-gperf.gperf.m4 @@ -164,6 +164,8 @@ Unit.IgnoreOnSnapshot, config_parse_warn_compat, DISABLED_LE Unit.JobTimeoutSec, config_parse_sec_fix_0, 0, offsetof(Unit, job_timeout) Unit.JobTimeoutAction, config_parse_failure_action, 0, offsetof(Unit, job_timeout_action) Unit.JobTimeoutRebootArgument, config_parse_string, 0, offsetof(Unit, job_timeout_reboot_arg) +Unit.StartLimitIntervalSec, config_parse_sec, 0, offsetof(Unit, start_limit.interval) +m4_dnl The following is a legacy alias name for compatibility Unit.StartLimitInterval, config_parse_sec, 0, offsetof(Unit, start_limit.interval) Unit.StartLimitBurst, config_parse_unsigned, 0, offsetof(Unit, start_limit.burst) Unit.StartLimitAction, config_parse_failure_action, 0, offsetof(Unit, start_limit_action) @@ -220,6 +222,7 @@ Service.TimeoutStartSec, config_parse_service_timeout, 0, Service.TimeoutStopSec, config_parse_service_timeout, 0, 0 Service.RuntimeMaxSec, config_parse_sec, 0, offsetof(Service, runtime_max_usec) Service.WatchdogSec, config_parse_sec, 0, offsetof(Service, watchdog_usec) +m4_dnl The following three only exist for compatibility, they moved into Unit, see above Service.StartLimitInterval, config_parse_sec, 0, offsetof(Unit, start_limit.interval) Service.StartLimitBurst, config_parse_unsigned, 0, offsetof(Unit, start_limit.burst) Service.StartLimitAction, config_parse_failure_action, 0, offsetof(Unit, start_limit_action) @@ -297,6 +300,8 @@ Socket.RemoveOnStop, config_parse_bool, 0, Socket.Symlinks, config_parse_unit_path_strv_printf, 0, offsetof(Socket, symlinks) Socket.FileDescriptorName, config_parse_fdname, 0, 0 Socket.Service, config_parse_socket_service, 0, 0 +Socket.TriggerLimitIntervalSec, config_parse_sec, 0, offsetof(Socket, trigger_limit.interval) +Socket.TriggerLimitBurst, config_parse_unsigned, 0, offsetof(Socket, trigger_limit.burst) m4_ifdef(`HAVE_SMACK', `Socket.SmackLabel, config_parse_string, 0, offsetof(Socket, smack) Socket.SmackLabelIPIn, config_parse_string, 0, offsetof(Socket, smack_ip_in) diff --git a/src/core/main.c b/src/core/main.c index 75c5ff81f2..ed4d42c8cc 100644 --- a/src/core/main.c +++ b/src/core/main.c @@ -289,6 +289,7 @@ static int parse_crash_chvt(const char *value) { } static int set_machine_id(const char *m) { + assert(m); if (sd_id128_from_string(m, &arg_machine_id) < 0) return -EINVAL; @@ -669,7 +670,8 @@ static int parse_config_file(void) { { "Manager", "DefaultTimeoutStartSec", config_parse_sec, 0, &arg_default_timeout_start_usec }, { "Manager", "DefaultTimeoutStopSec", config_parse_sec, 0, &arg_default_timeout_stop_usec }, { "Manager", "DefaultRestartSec", config_parse_sec, 0, &arg_default_restart_usec }, - { "Manager", "DefaultStartLimitInterval", config_parse_sec, 0, &arg_default_start_limit_interval }, + { "Manager", "DefaultStartLimitInterval", config_parse_sec, 0, &arg_default_start_limit_interval }, /* obsolete alias */ + { "Manager", "DefaultStartLimitIntervalSec",config_parse_sec, 0, &arg_default_start_limit_interval }, { "Manager", "DefaultStartLimitBurst", config_parse_unsigned, 0, &arg_default_start_limit_burst }, { "Manager", "DefaultEnvironment", config_parse_environ, 0, &arg_default_environment }, { "Manager", "DefaultLimitCPU", config_parse_limit, RLIMIT_CPU, arg_default_rlimit }, diff --git a/src/core/service.c b/src/core/service.c index b46dd8bcdd..f7a3fcf2b9 100644 --- a/src/core/service.c +++ b/src/core/service.c @@ -180,20 +180,17 @@ static int service_set_main_pid(Service *s, pid_t pid) { return 0; } -static void service_close_socket_fd(Service *s) { +void service_close_socket_fd(Service *s) { assert(s); - s->socket_fd = asynchronous_close(s->socket_fd); -} - -static void service_connection_unref(Service *s) { - assert(s); + /* Undo the effect of service_set_socket_fd(). */ - if (!UNIT_ISSET(s->accept_socket)) - return; + s->socket_fd = asynchronous_close(s->socket_fd); - socket_connection_unref(SOCKET(UNIT_DEREF(s->accept_socket))); - unit_ref_unset(&s->accept_socket); + if (UNIT_ISSET(s->accept_socket)) { + socket_connection_unref(SOCKET(UNIT_DEREF(s->accept_socket))); + unit_ref_unset(&s->accept_socket); + } } static void service_stop_watchdog(Service *s) { @@ -321,7 +318,6 @@ static void service_done(Unit *u) { s->bus_name_owner = mfree(s->bus_name_owner); service_close_socket_fd(s); - service_connection_unref(s); unit_ref_unset(&s->accept_socket); @@ -910,10 +906,8 @@ static void service_set_state(Service *s, ServiceState state) { SERVICE_RUNNING, SERVICE_RELOAD, SERVICE_STOP, SERVICE_STOP_SIGABRT, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST, SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL) && - !(state == SERVICE_DEAD && UNIT(s)->job)) { + !(state == SERVICE_DEAD && UNIT(s)->job)) service_close_socket_fd(s); - service_connection_unref(s); - } if (!IN_SET(state, SERVICE_START_POST, SERVICE_RUNNING, SERVICE_RELOAD)) service_stop_watchdog(s); @@ -3139,9 +3133,8 @@ int service_set_socket_fd(Service *s, int fd, Socket *sock, bool selinux_context assert(s); assert(fd >= 0); - /* This is called by the socket code when instantiating a new - * service for a stream socket and the socket needs to be - * configured. */ + /* This is called by the socket code when instantiating a new service for a stream socket and the socket needs + * to be configured. We take ownership of the passed fd on success. */ if (UNIT(s)->load_state != UNIT_LOADED) return -EINVAL; @@ -3169,12 +3162,15 @@ int service_set_socket_fd(Service *s, int fd, Socket *sock, bool selinux_context return r; } + r = unit_add_two_dependencies(UNIT(sock), UNIT_BEFORE, UNIT_TRIGGERS, UNIT(s), false); + if (r < 0) + return r; + s->socket_fd = fd; s->socket_fd_selinux_context_net = selinux_context_net; unit_ref_set(&s->accept_socket, UNIT(sock)); - - return unit_add_two_dependencies(UNIT(sock), UNIT_BEFORE, UNIT_TRIGGERS, UNIT(s), false); + return 0; } static void service_reset_failed(Unit *u) { diff --git a/src/core/service.h b/src/core/service.h index cd9e41646e..c7f1e81bdb 100644 --- a/src/core/service.h +++ b/src/core/service.h @@ -198,6 +198,7 @@ struct Service { extern const UnitVTable service_vtable; int service_set_socket_fd(Service *s, int fd, struct Socket *socket, bool selinux_context_net); +void service_close_socket_fd(Service *s); const char* service_restart_to_string(ServiceRestart i) _const_; ServiceRestart service_restart_from_string(const char *s) _pure_; diff --git a/src/core/socket.c b/src/core/socket.c index a9fff9c259..7eeed068bd 100644 --- a/src/core/socket.c +++ b/src/core/socket.c @@ -99,6 +99,8 @@ static void socket_init(Unit *u) { s->exec_context.std_error = u->manager->default_std_error; s->control_command_id = _SOCKET_EXEC_COMMAND_INVALID; + + RATELIMIT_INIT(s->trigger_limit, 5*USEC_PER_SEC, 2500); } static void socket_unwatch_control_pid(Socket *s) { @@ -227,7 +229,6 @@ int socket_instantiate_service(Socket *s) { if (r < 0) return r; - u->no_gc = true; unit_ref_set(&s->service, u); return unit_add_two_dependencies(UNIT(s), UNIT_BEFORE, UNIT_TRIGGERS, u, false); @@ -792,47 +793,45 @@ static void socket_close_fds(Socket *s) { assert(s); LIST_FOREACH(port, p, s->ports) { + bool was_open; - p->event_source = sd_event_source_unref(p->event_source); - - if (p->fd < 0) - continue; + was_open = p->fd >= 0; + p->event_source = sd_event_source_unref(p->event_source); p->fd = safe_close(p->fd); socket_cleanup_fd_list(p); - /* One little note: we should normally not delete any - * sockets in the file system here! After all some - * other process we spawned might still have a - * reference of this fd and wants to continue to use - * it. Therefore we delete sockets in the file system - * before we create a new one, not after we stopped - * using one! */ + /* One little note: we should normally not delete any sockets in the file system here! After all some + * other process we spawned might still have a reference of this fd and wants to continue to use + * it. Therefore we normally delete sockets in the file system before we create a new one, not after we + * stopped using one! That all said, if the user explicitly requested this, we'll delete them here + * anyway, but only then. */ - if (s->remove_on_stop) { - switch (p->type) { + if (!was_open || !s->remove_on_stop) + continue; - case SOCKET_FIFO: - unlink(p->path); - break; + switch (p->type) { - case SOCKET_MQUEUE: - mq_unlink(p->path); - break; + case SOCKET_FIFO: + (void) unlink(p->path); + break; - case SOCKET_SOCKET: - socket_address_unlink(&p->address); - break; + case SOCKET_MQUEUE: + (void) mq_unlink(p->path); + break; - default: - break; - } + case SOCKET_SOCKET: + (void) socket_address_unlink(&p->address); + break; + + default: + break; } } if (s->remove_on_stop) STRV_FOREACH(i, s->symlinks) - unlink(*i); + (void) unlink(*i); } static void socket_apply_socket_options(Socket *s, int fd) { @@ -1887,6 +1886,9 @@ static void socket_enter_running(Socket *s, int cfd) { _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; int r; + /* Note that this call takes possession of the connection fd passed. It either has to assign it somewhere or + * close it. */ + assert(s); /* We don't take connections anymore if we are supposed to @@ -1896,7 +1898,7 @@ static void socket_enter_running(Socket *s, int cfd) { log_unit_debug(UNIT(s), "Suppressing connection request since unit stop is scheduled."); if (cfd >= 0) - safe_close(cfd); + cfd = safe_close(cfd); else { /* Flush all sockets by closing and reopening them */ socket_close_fds(s); @@ -1918,6 +1920,13 @@ static void socket_enter_running(Socket *s, int cfd) { return; } + if (!ratelimit_test(&s->trigger_limit)) { + safe_close(cfd); + log_unit_warning(UNIT(s), "Trigger limit hit, refusing further activation."); + socket_enter_stop_pre(s, SOCKET_FAILURE_TRIGGER_LIMIT_HIT); + return; + } + if (cfd < 0) { Iterator i; Unit *other; @@ -1949,7 +1958,7 @@ static void socket_enter_running(Socket *s, int cfd) { Service *service; if (s->n_connections >= s->max_connections) { - log_unit_warning(UNIT(s), "Too many incoming connections (%u)", s->n_connections); + log_unit_warning(UNIT(s), "Too many incoming connections (%u), refusing connection attempt.", s->n_connections); safe_close(cfd); return; } @@ -1965,6 +1974,7 @@ static void socket_enter_running(Socket *s, int cfd) { /* ENOTCONN is legitimate if TCP RST was received. * This connection is over, but the socket unit lives on. */ + log_unit_debug(UNIT(s), "Got ENOTCONN on incoming socket, assuming aborted connection attempt, ignoring."); safe_close(cfd); return; } @@ -1983,22 +1993,24 @@ static void socket_enter_running(Socket *s, int cfd) { service = SERVICE(UNIT_DEREF(s->service)); unit_ref_unset(&s->service); - s->n_accepted++; - - UNIT(service)->no_gc = false; + s->n_accepted++; unit_choose_id(UNIT(service), name); r = service_set_socket_fd(service, cfd, s, s->selinux_context_from_net); if (r < 0) goto fail; - cfd = -1; + cfd = -1; /* We passed ownership of the fd to the service now. Forget it here. */ s->n_connections++; r = manager_add_job(UNIT(s)->manager, JOB_START, UNIT(service), JOB_REPLACE, &error, NULL); - if (r < 0) + if (r < 0) { + /* We failed to activate the new service, but it still exists. Let's make sure the service + * closes and forgets the connection fd again, immediately. */ + service_close_socket_fd(service); goto fail; + } /* Notify clients about changed counters */ unit_add_to_dbus_queue(UNIT(s)); @@ -2806,6 +2818,7 @@ static const char* const socket_result_table[_SOCKET_RESULT_MAX] = { [SOCKET_FAILURE_EXIT_CODE] = "exit-code", [SOCKET_FAILURE_SIGNAL] = "signal", [SOCKET_FAILURE_CORE_DUMP] = "core-dump", + [SOCKET_FAILURE_TRIGGER_LIMIT_HIT] = "trigger-limit-hit", [SOCKET_FAILURE_SERVICE_START_LIMIT_HIT] = "service-start-limit-hit" }; diff --git a/src/core/socket.h b/src/core/socket.h index b537b026a7..2a4b1bb674 100644 --- a/src/core/socket.h +++ b/src/core/socket.h @@ -52,6 +52,7 @@ typedef enum SocketResult { SOCKET_FAILURE_EXIT_CODE, SOCKET_FAILURE_SIGNAL, SOCKET_FAILURE_CORE_DUMP, + SOCKET_FAILURE_TRIGGER_LIMIT_HIT, SOCKET_FAILURE_SERVICE_START_LIMIT_HIT, _SOCKET_RESULT_MAX, _SOCKET_RESULT_INVALID = -1 @@ -156,6 +157,8 @@ struct Socket { bool reset_cpu_usage:1; char *fdname; + + RateLimit trigger_limit; }; /* Called from the service code when collecting fds */ diff --git a/src/core/system.conf b/src/core/system.conf index e2ded27333..eacd7ee282 100644 --- a/src/core/system.conf +++ b/src/core/system.conf @@ -34,7 +34,7 @@ #DefaultTimeoutStartSec=90s #DefaultTimeoutStopSec=90s #DefaultRestartSec=100ms -#DefaultStartLimitInterval=10s +#DefaultStartLimitIntervalSec=10s #DefaultStartLimitBurst=5 #DefaultEnvironment= #DefaultCPUAccounting=no diff --git a/src/core/unit.c b/src/core/unit.c index cb79c7c6b1..81cd7ee2b8 100644 --- a/src/core/unit.c +++ b/src/core/unit.c @@ -1497,11 +1497,6 @@ int unit_start(Unit *u) { if (UNIT_IS_ACTIVE_OR_RELOADING(state)) return -EALREADY; - /* Make sure we don't enter a busy loop of some kind. */ - r = unit_start_limit_test(u); - if (r < 0) - return r; - /* Units that aren't loaded cannot be started */ if (u->load_state != UNIT_LOADED) return -EINVAL; @@ -1543,6 +1538,11 @@ int unit_start(Unit *u) { if (!UNIT_VTABLE(u)->start) return -EBADR; + /* Make sure we don't enter a busy loop of some kind. */ + r = unit_start_limit_test(u); + if (r < 0) + return r; + /* We don't suppress calls to ->start() here when we are * already starting, to allow this request to be used as a * "hurry up" call, for example when the unit is in some "auto @@ -3222,6 +3222,10 @@ void unit_ref_unset(UnitRef *ref) { if (!ref->unit) return; + /* We are about to drop a reference to the unit, make sure the garbage collection has a look at it as it might + * be unreferenced now. */ + unit_add_to_gc_queue(ref->unit); + LIST_REMOVE(refs, ref->unit->refs, ref); ref->unit = NULL; } diff --git a/src/core/user.conf b/src/core/user.conf index 87c8164378..b427f1ef6d 100644 --- a/src/core/user.conf +++ b/src/core/user.conf @@ -23,7 +23,7 @@ #DefaultTimeoutStartSec=90s #DefaultTimeoutStopSec=90s #DefaultRestartSec=100ms -#DefaultStartLimitInterval=10s +#DefaultStartLimitIntervalSec=10s #DefaultStartLimitBurst=5 #DefaultEnvironment= #DefaultLimitCPU= diff --git a/src/journal/journald-gperf.gperf b/src/journal/journald-gperf.gperf index c154610c54..7fecd7a964 100644 --- a/src/journal/journald-gperf.gperf +++ b/src/journal/journald-gperf.gperf @@ -19,7 +19,9 @@ Journal.Storage, config_parse_storage, 0, offsetof(Server, storage Journal.Compress, config_parse_bool, 0, offsetof(Server, compress) Journal.Seal, config_parse_bool, 0, offsetof(Server, seal) Journal.SyncIntervalSec, config_parse_sec, 0, offsetof(Server, sync_interval_usec) +# The following is a legacy name for compatibility Journal.RateLimitInterval, config_parse_sec, 0, offsetof(Server, rate_limit_interval) +Journal.RateLimitIntervalSec,config_parse_sec, 0, offsetof(Server, rate_limit_interval) Journal.RateLimitBurst, config_parse_unsigned, 0, offsetof(Server, rate_limit_burst) Journal.SystemMaxUse, config_parse_iec_uint64, 0, offsetof(Server, system_metrics.max_use) Journal.SystemMaxFileSize, config_parse_iec_uint64, 0, offsetof(Server, system_metrics.max_size) diff --git a/src/journal/journald.conf b/src/journal/journald.conf index 7beb96c671..2541b949be 100644 --- a/src/journal/journald.conf +++ b/src/journal/journald.conf @@ -17,7 +17,7 @@ #Seal=yes #SplitMode=uid #SyncIntervalSec=5m -#RateLimitInterval=30s +#RateLimitIntervalSec=30s #RateLimitBurst=1000 #SystemMaxUse= #SystemKeepFree= diff --git a/src/test/test-rlimit-util.c b/src/test/test-rlimit-util.c index d9ac9368cd..62afd2de5e 100644 --- a/src/test/test-rlimit-util.c +++ b/src/test/test-rlimit-util.c @@ -99,6 +99,18 @@ int main(int argc, char *argv[]) { test_rlimit_parse_format(RLIMIT_NOFILE, "", 0, 0, -EINVAL, NULL); test_rlimit_parse_format(RLIMIT_NOFILE, "5:4", 0, 0, -EILSEQ, NULL); test_rlimit_parse_format(RLIMIT_NOFILE, "5:4:3", 0, 0, -EINVAL, NULL); + test_rlimit_parse_format(RLIMIT_NICE, "20", 20, 20, 0, "20"); + test_rlimit_parse_format(RLIMIT_NICE, "40", 40, 40, 0, "40"); + test_rlimit_parse_format(RLIMIT_NICE, "41", 41, 41, -ERANGE, "41"); + test_rlimit_parse_format(RLIMIT_NICE, "0", 0, 0, 0, "0"); + test_rlimit_parse_format(RLIMIT_NICE, "-7", 27, 27, 0, "27"); + test_rlimit_parse_format(RLIMIT_NICE, "-20", 40, 40, 0, "40"); + test_rlimit_parse_format(RLIMIT_NICE, "-21", 41, 41, -ERANGE, "41"); + test_rlimit_parse_format(RLIMIT_NICE, "-0", 20, 20, 0, "20"); + test_rlimit_parse_format(RLIMIT_NICE, "+7", 13, 13, 0, "13"); + test_rlimit_parse_format(RLIMIT_NICE, "+19", 1, 1, 0, "1"); + test_rlimit_parse_format(RLIMIT_NICE, "+20", 0, 0, -ERANGE, "0"); + test_rlimit_parse_format(RLIMIT_NICE, "+0", 20, 20, 0, "20"); return 0; } |