test-async: Wait for asynchronous_sync() to finish (#36611)

Otherwise, if the system is busy, TEST-02-UNITTESTS will fail as
systemd will time out trying to kill the transient unit that we're
running test-async in.
This commit is contained in:
Luca Boccassi
2025-03-05 12:36:45 +00:00
committed by GitHub
4 changed files with 22 additions and 17 deletions
+10 -8
View File
@@ -14,7 +14,7 @@
#include "process-util.h"
#include "signal-util.h"
int asynchronous_sync(pid_t *ret_pid) {
int asynchronous_sync(PidRef *ret_pid) {
int r;
/* This forks off an invocation of fork() as a child process, in order to initiate synchronization to
@@ -22,7 +22,7 @@ int asynchronous_sync(pid_t *ret_pid) {
* original process ever, and a thread would do that as the process can't exit with threads hanging in blocking
* syscalls. */
r = safe_fork("(sd-sync)", FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|(ret_pid ? 0 : FORK_DETACH), ret_pid);
r = pidref_safe_fork("(sd-sync)", FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|(ret_pid ? 0 : FORK_DETACH), ret_pid);
if (r < 0)
return r;
if (r == 0) {
@@ -34,17 +34,19 @@ int asynchronous_sync(pid_t *ret_pid) {
return 0;
}
int asynchronous_fsync(int fd, pid_t *ret_pid) {
int asynchronous_fsync(int fd, PidRef *ret_pid) {
int r;
assert(fd >= 0);
/* Same as asynchronous_sync() above, but calls fsync() on a specific fd */
r = safe_fork_full("(sd-fsync)",
/* stdio_fds= */ NULL,
/* except_fds= */ &fd,
/* n_except_fds= */ 1,
FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|(ret_pid ? 0 : FORK_DETACH), ret_pid);
r = pidref_safe_fork_full(
"(sd-fsync)",
/* stdio_fds= */ NULL,
/* except_fds= */ &fd,
/* n_except_fds= */ 1,
FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|(ret_pid ? 0 : FORK_DETACH),
ret_pid);
if (r < 0)
return r;
if (r == 0) {
+3 -2
View File
@@ -4,6 +4,7 @@
#include <sys/types.h>
#include "macro.h"
#include "pidref.h"
#include "rm-rf.h"
/* These functions implement various potentially slow operations that are executed asynchronously. They are
@@ -19,8 +20,8 @@
* child, or never use clone()/clone3() and stick to fork() only. Because we need clone()/clone3() we opted
* for avoiding threads. */
int asynchronous_sync(pid_t *ret_pid);
int asynchronous_fsync(int fd, pid_t *ret_pid);
int asynchronous_sync(PidRef *ret_pid);
int asynchronous_fsync(int fd, PidRef *ret_pid);
int asynchronous_close(int fd);
void asynchronous_close_many(const int fds[], size_t n_fds);
+6 -6
View File
@@ -226,7 +226,7 @@ int sync_with_progress(int fd) {
unsigned long long dirty = ULLONG_MAX;
_cleanup_free_ char *path = NULL;
const char *what;
pid_t pid;
_cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;
int r;
BLOCK_SIGNALS(SIGCHLD);
@@ -235,13 +235,13 @@ int sync_with_progress(int fd) {
* the progress. If the timeout lapses, the assumption is that the particular sync stalled. */
if (fd >= 0) {
r = asynchronous_fsync(fd, &pid);
r = asynchronous_fsync(fd, &pidref);
if (r < 0)
return log_error_errno(r, "Failed to fork fsync(): %m");
(void) fd_get_path(fd, &path);
} else {
r = asynchronous_sync(&pid);
r = asynchronous_sync(&pidref);
if (r < 0)
return log_error_errno(r, "Failed to fork sync(): %m");
}
@@ -253,7 +253,7 @@ int sync_with_progress(int fd) {
* SYNC_PROGRESS_ATTEMPTS lapse without progress being made,
* we assume that the sync is stalled */
for (unsigned checks = 0; checks < SYNC_PROGRESS_ATTEMPTS; checks++) {
r = wait_for_terminate_with_timeout(pid, SYNC_TIMEOUT_USEC);
r = wait_for_terminate_with_timeout(pidref.pid, SYNC_TIMEOUT_USEC);
if (r == 0)
/* Sync finished without error (sync() call itself does not return an error code) */
return 0;
@@ -267,8 +267,8 @@ int sync_with_progress(int fd) {
/* Only reached in the event of a timeout. We should issue a kill to the stray process. */
r = log_error_errno(SYNTHETIC_ERRNO(ETIMEDOUT),
"Syncing %s - timed out, issuing SIGKILL to PID "PID_FMT".", what, pid);
(void) kill(pid, SIGKILL);
"Syncing %s - timed out, issuing SIGKILL to PID "PID_FMT".", what, pidref.pid);
(void) pidref_kill(&pidref, SIGKILL);
return r;
}
+3 -1
View File
@@ -15,7 +15,9 @@
#include "tmpfile-util.h"
TEST(asynchronous_sync) {
ASSERT_OK(asynchronous_sync(NULL));
_cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;
ASSERT_OK(asynchronous_sync(&pidref));
ASSERT_OK(pidref_wait_for_terminate(&pidref, /* ret= */ NULL));
}
static void wait_fd_closed(int fd) {