From: Lennart Poettering Date: Thu, 21 Dec 2017 17:24:28 +0000 (+0100) Subject: sync: fork off sync() in a process instead of a thread X-Git-Tag: v237~173^2~15 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=41bd3379efc0e5b5621c329ff55b99b2825f06c0;p=thirdparty%2Fsystemd.git sync: fork off sync() in a process instead of a thread 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. --- diff --git a/src/basic/async.c b/src/basic/async.c index d368b925223..c510cbd7f55 100644 --- a/src/basic/async.c +++ b/src/basic/async.c @@ -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) { diff --git a/src/core/job.c b/src/core/job.c index 2ea7834dfd2..9ff5b288f9d 100644 --- a/src/core/job.c +++ b/src/core/job.c @@ -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) {