core: increment start limit counter only when we can start the unit

Otherwise, e.g. requesting to start a unit that is under stopping may
enter the failed state.

This makes
- rename .can_start() -> .test_startable(), and make it allow to return
  boolean and refuse to start units when it returns false,
- refuse earlier to start units that are in the deactivating state, so
  several redundant conditions in .start() can be dropped,
- move checks for unit states mapped to UNIT_ACTIVATING from .start() to
  .test_startable().

Fixes #39247.
This commit is contained in:
Yu Watanabe
2025-10-23 15:51:28 +02:00
committed by Mike Yuan
parent c05758663b
commit 8eefd0f4de
10 changed files with 94 additions and 85 deletions
+6 -5
View File
@@ -1936,7 +1936,7 @@ int unit_start(Unit *u, ActivationDetails *details) {
state = unit_active_state(u);
if (UNIT_IS_ACTIVE_OR_RELOADING(state))
return -EALREADY;
if (state == UNIT_MAINTENANCE)
if (IN_SET(state, UNIT_DEACTIVATING, UNIT_MAINTENANCE))
return -EAGAIN;
/* Units that aren't loaded cannot be started */
@@ -1983,10 +1983,11 @@ int unit_start(Unit *u, ActivationDetails *details) {
if (u->freezer_state != FREEZER_RUNNING)
return -EDEADLK;
/* Check our ability to start early so that failure conditions don't cause us to enter a busy loop. */
if (UNIT_VTABLE(u)->can_start) {
r = UNIT_VTABLE(u)->can_start(u);
if (r < 0)
/* Check our ability to start early so that ratelimited or already starting/started units don't
* cause us to enter a busy loop. */
if (UNIT_VTABLE(u)->test_startable) {
r = UNIT_VTABLE(u)->test_startable(u);
if (r <= 0)
return r;
}