]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
sync: fork off sync() in a process instead of a thread
authorLennart Poettering <lennart@poettering.net>
Thu, 21 Dec 2017 17:24:28 +0000 (18:24 +0100)
committerLennart Poettering <lennart@poettering.net>
Mon, 25 Dec 2017 10:48:21 +0000 (11:48 +0100)
Let's fork off sync() ina process instead of a thread, as a safety
measure. This is beneficial to ensure that the original process can exit
without having to wait for the sync() to finish (note that the kernel
will delay process termination until all threads finished their
syscalls). In case of hanging NFS this increases the chance that PID 1
can safely transition to the "systemd-shutdown" process as the sync() is
initiated early on but definitely not waited for.

src/basic/async.c
src/core/job.c

index d368b925223fd01c959a8d2befb7d097d1a37abb..c510cbd7f55ee8ca80501d1de4ca7ef9ac334c50 100644 (file)
@@ -27,6 +27,8 @@
 #include "fd-util.h"
 #include "log.h"
 #include "macro.h"
+#include "process-util.h"
+#include "signal-util.h"
 #include "util.h"
 
 int asynchronous_job(void* (*func)(void *p), void *arg) {
@@ -58,15 +60,36 @@ finish:
         return -r;
 }
 
-static void *sync_thread(void *p) {
-        sync();
-        return NULL;
-}
-
 int asynchronous_sync(void) {
-        log_debug("Spawning new thread for sync");
+        pid_t pid;
+
+        /* This forks off an invocation of fork() as a child process, in order to initiate synchronization to
+         * disk. Note that we implement this as helper process rather than thread as we don't want the sync() to hang our
+         * original process ever, and a thread would do that as the process can't exit with threads hanging in blocking
+         * syscalls. */
+
+        log_debug("Spawning new process for sync");
+
+        pid = fork();
+        if (pid < 0)
+                return -errno;
+
+        if (pid == 0) {
+                /* Child process */
+
+                (void) rename_process("(sd-sync)");
+
+                (void) reset_all_signal_handlers();
+                (void) reset_signal_mask();
+
+                (void) close_all_fds(NULL, 0);
+
+                (void) sync();
+                _exit(EXIT_SUCCESS);
+        }
 
-        return asynchronous_job(sync_thread, NULL);
+        /* We don' really care about the PID from here on. It will exit when it's done. */
+        return 0;
 }
 
 static void *close_thread(void *p) {
index 2ea7834dfd253e6ffb29e5775c41c4713cbf0821..9ff5b288f9de38bd72e9a9dd4f2f9ede0cf37fa7 100644 (file)
@@ -1244,7 +1244,7 @@ void job_shutdown_magic(Job *j) {
         if (detect_container() > 0)
                 return;
 
-        asynchronous_sync();
+        (void) asynchronous_sync();
 }
 
 int job_get_timeout(Job *j, usec_t *timeout) {