dcavalca / rpms / systemd

Forked from rpms/systemd 3 months ago
Clone
55853a
From 7c39b498d6ea21b1c6f4d26b74c064ef2b507706 Mon Sep 17 00:00:00 2001
55853a
From: Lennart Poettering <lennart@poettering.net>
55853a
Date: Mon, 13 Nov 2017 15:08:49 +0100
55853a
Subject: [PATCH] unit: rework a bit how we keep the service fdstore from being
55853a
 destroyed during service restart
55853a
55853a
When preparing for a restart we quickly go through the DEAD/INACTIVE
55853a
service state before entering AUTO_RESTART. When doing this, we need to
55853a
make sure we don't destroy the FD store. Previously this was done by
55853a
checking the failure state of the unit, and keeping the FD store around
55853a
when the unit failed, under the assumption that the restart logic will
55853a
then get into action.
55853a
55853a
This is not entirely correct howver, as there might be failure states
55853a
that will no result in restarts.
55853a
55853a
With this commit we slightly alter the logic: a ref counter for the fd
55853a
store is added, that is increased right before we handle the restart
55853a
logic, and decreased again right-after.
55853a
55853a
This should ensure that the fdstore lives exactly as long as it needs.
55853a
55853a
Follow-up for f0bfbfac43b7faa68ef1bb2ad659c191b9ec85d2.
55853a
55853a
(cherry picked from commit 7eb2a8a1259043e107ebec94e30ed160a93f40a7)
55853a
(cherry picked from commit e2636bde0f07319d0d35262dac6ff2638ba4e598)
55853a
(cherry picked from commit 20b18b7b9aac2532215dba4d56f19989a5fca9f0)
55853a
Related: #1798162
55853a
---
55853a
 src/core/service.c | 23 ++++++++++++++++++-----
55853a
 src/core/service.h |  1 +
55853a
 src/core/unit.c    | 12 ++++--------
55853a
 src/core/unit.h    |  5 ++---
55853a
 4 files changed, 25 insertions(+), 16 deletions(-)
55853a
55853a
diff --git a/src/core/service.c b/src/core/service.c
55853a
index ad45a38270..283c2968ea 100644
55853a
--- a/src/core/service.c
55853a
+++ b/src/core/service.c
55853a
@@ -265,6 +265,9 @@ static void service_fd_store_unlink(ServiceFDStore *fs) {
55853a
 static void service_release_fd_store(Service *s) {
55853a
         assert(s);
55853a
 
55853a
+        if (s->n_keep_fd_store > 0)
55853a
+                return;
55853a
+
55853a
         log_unit_debug(UNIT(s)->id, "Releasing all stored fds");
55853a
         while (s->fd_store)
55853a
                 service_fd_store_unlink(s->fd_store);
55853a
@@ -272,7 +275,7 @@ static void service_release_fd_store(Service *s) {
55853a
         assert(s->n_fd_store == 0);
55853a
 }
55853a
 
55853a
-static void service_release_resources(Unit *u, bool inactive) {
55853a
+static void service_release_resources(Unit *u) {
55853a
         Service *s = SERVICE(u);
55853a
 
55853a
         assert(s);
55853a
@@ -282,8 +285,7 @@ static void service_release_resources(Unit *u, bool inactive) {
55853a
 
55853a
         log_unit_debug(u->id, "Releasing resources.");
55853a
 
55853a
-        if (inactive)
55853a
-                service_release_fd_store(s);
55853a
+        service_release_fd_store(s);
55853a
 }
55853a
 
55853a
 static void service_done(Unit *u) {
55853a
@@ -331,7 +333,7 @@ static void service_done(Unit *u) {
55853a
 
55853a
         s->timer_event_source = sd_event_source_unref(s->timer_event_source);
55853a
 
55853a
-        service_release_resources(u, true);
55853a
+        service_release_resources(u);
55853a
 }
55853a
 
55853a
 static int on_fd_store_io(sd_event_source *e, int fd, uint32_t revents, void *userdata) {
55853a
@@ -1354,6 +1356,10 @@ static void service_enter_dead(Service *s, ServiceResult f, bool allow_restart)
55853a
         if (f != SERVICE_SUCCESS)
55853a
                 s->result = f;
55853a
 
55853a
+        /* Make sure service_release_resources() doesn't destroy our FD store, while we are changing through
55853a
+         * SERVICE_FAILED/SERVICE_DEAD before entering into SERVICE_AUTO_RESTART. */
55853a
+        s->n_keep_fd_store++;
55853a
+
55853a
         service_set_state(s, s->result != SERVICE_SUCCESS ? SERVICE_FAILED : SERVICE_DEAD);
55853a
 
55853a
         if (s->result != SERVICE_SUCCESS) {
55853a
@@ -1375,12 +1381,19 @@ static void service_enter_dead(Service *s, ServiceResult f, bool allow_restart)
55853a
             (!IN_SET(s->main_exec_status.code, CLD_KILLED, CLD_DUMPED) || !set_contains(s->restart_prevent_status.signal, INT_TO_PTR(s->main_exec_status.status)))) {
55853a
 
55853a
                 r = service_arm_timer(s, s->restart_usec);
55853a
-                if (r < 0)
55853a
+                if (r < 0) {
55853a
+                        s->n_keep_fd_store--;
55853a
                         goto fail;
55853a
+                }
55853a
 
55853a
                 service_set_state(s, SERVICE_AUTO_RESTART);
55853a
         }
55853a
 
55853a
+        /* The new state is in effect, let's decrease the fd store ref counter again. Let's also readd us to the GC
55853a
+         * queue, so that the fd store is possibly gc'ed again */
55853a
+        s->n_keep_fd_store--;
55853a
+        unit_add_to_gc_queue(UNIT(s));
55853a
+
55853a
         s->forbid_restart = false;
55853a
 
55853a
         /* We want fresh tmpdirs in case service is started again immediately */
55853a
diff --git a/src/core/service.h b/src/core/service.h
55853a
index e0547a464e..81b17db652 100644
55853a
--- a/src/core/service.h
55853a
+++ b/src/core/service.h
55853a
@@ -214,6 +214,7 @@ struct Service {
55853a
         ServiceFDStore *fd_store;
55853a
         unsigned n_fd_store;
55853a
         unsigned n_fd_store_max;
55853a
+        unsigned n_keep_fd_store;
55853a
 };
55853a
 
55853a
 extern const UnitVTable service_vtable;
55853a
diff --git a/src/core/unit.c b/src/core/unit.c
55853a
index 33e0b7126b..e74c6bc2cc 100644
55853a
--- a/src/core/unit.c
55853a
+++ b/src/core/unit.c
55853a
@@ -284,7 +284,6 @@ int unit_set_description(Unit *u, const char *description) {
55853a
 
55853a
 bool unit_may_gc(Unit *u) {
55853a
         UnitActiveState state;
55853a
-        bool inactive;
55853a
         assert(u);
55853a
 
55853a
         /* Checks whether the unit is ready to be unloaded for garbage collection.
55853a
@@ -302,17 +301,14 @@ bool unit_may_gc(Unit *u) {
55853a
                 return false;
55853a
 
55853a
         state = unit_active_state(u);
55853a
-        inactive = state == UNIT_INACTIVE;
55853a
 
55853a
-        /* If the unit is inactive and failed and no job is queued for
55853a
-         * it, then release its runtime resources */
55853a
+        /* If the unit is inactive and failed and no job is queued for it, then release its runtime resources */
55853a
         if (UNIT_IS_INACTIVE_OR_FAILED(state) &&
55853a
             UNIT_VTABLE(u)->release_resources)
55853a
-                UNIT_VTABLE(u)->release_resources(u, inactive);
55853a
+                UNIT_VTABLE(u)->release_resources(u);
55853a
 
55853a
-        /* But we keep the unit object around for longer when it is
55853a
-         * referenced or configured to not be gc'ed */
55853a
-        if (!inactive)
55853a
+        /* But we keep the unit object around for longer when it is referenced or configured to not be gc'ed */
55853a
+        if (state != UNIT_INACTIVE)
55853a
                 return false;
55853a
 
55853a
         if (UNIT_VTABLE(u)->no_gc)
55853a
diff --git a/src/core/unit.h b/src/core/unit.h
55853a
index 97a63f0f8b..61ff59e8c7 100644
55853a
--- a/src/core/unit.h
55853a
+++ b/src/core/unit.h
55853a
@@ -357,9 +357,8 @@ struct UnitVTable {
55853a
          * even though nothing references it and it isn't active in any way. */
55853a
         bool (*may_gc)(Unit *u);
55853a
 
55853a
-        /* When the unit is not running and no job for it queued we
55853a
-         * shall release its runtime resources */
55853a
-        void (*release_resources)(Unit *u, bool inactive);
55853a
+        /* When the unit is not running and no job for it queued we shall release its runtime resources */
55853a
+        void (*release_resources)(Unit *u);
55853a
 
55853a
         /* Return true when this unit is suitable for snapshotting */
55853a
         bool (*check_snapshot)(Unit *u);