Skip to content

Commit be91329

Browse files
poetteringbluca
authored andcommitted
shutdown: teach sync_with_progress() to optionally sync a specific fd only
This is preparation for reusing the logic for syncing DM and other devices with a timeout applied. (cherry picked from commit 13b5225) (cherry picked from commit 05df6c3)
1 parent f11fa83 commit be91329

File tree

4 files changed

+49
-9
lines changed

4 files changed

+49
-9
lines changed

src/shared/async.c

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,28 @@ int asynchronous_sync(pid_t *ret_pid) {
3434
return 0;
3535
}
3636

37+
int asynchronous_fsync(int fd, pid_t *ret_pid) {
38+
int r;
39+
40+
assert(fd >= 0);
41+
/* Same as asynchronous_sync() above, but calls fsync() on a specific fd */
42+
43+
r = safe_fork_full("(sd-fsync)",
44+
/* stdio_fds= */ NULL,
45+
/* except_fds= */ &fd,
46+
/* n_except_fds= */ 1,
47+
FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|(ret_pid ? 0 : FORK_DETACH), ret_pid);
48+
if (r < 0)
49+
return r;
50+
if (r == 0) {
51+
/* Child process */
52+
fsync(fd);
53+
_exit(EXIT_SUCCESS);
54+
}
55+
56+
return 0;
57+
}
58+
3759
/* We encode the fd to close in the userdata pointer as an unsigned value. The highest bit indicates whether
3860
* we need to fork again */
3961
#define NEED_DOUBLE_FORK (1U << (sizeof(unsigned) * 8 - 1))

src/shared/async.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
* for avoiding threads. */
2121

2222
int asynchronous_sync(pid_t *ret_pid);
23+
int asynchronous_fsync(int fd, pid_t *ret_pid);
2324
int asynchronous_close(int fd);
2425
int asynchronous_rm_rf(const char *p, RemoveFlags flags);
2526

src/shutdown/shutdown.c

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
#include "process-util.h"
4141
#include "reboot-util.h"
4242
#include "rlimit-util.h"
43+
#include "shutdown.h"
4344
#include "signal-util.h"
4445
#include "string-util.h"
4546
#include "switch-root.h"
@@ -224,8 +225,10 @@ static int sync_making_progress(unsigned long long *prev_dirty) {
224225
return r;
225226
}
226227

227-
static int sync_with_progress(void) {
228+
int sync_with_progress(int fd) {
228229
unsigned long long dirty = ULLONG_MAX;
230+
_cleanup_free_ char *path = NULL;
231+
const char *what;
229232
pid_t pid;
230233
int r;
231234

@@ -234,11 +237,20 @@ static int sync_with_progress(void) {
234237
/* Due to the possibility of the sync operation hanging, we fork a child process and monitor
235238
* the progress. If the timeout lapses, the assumption is that the particular sync stalled. */
236239

237-
r = asynchronous_sync(&pid);
238-
if (r < 0)
239-
return log_error_errno(r, "Failed to fork sync(): %m");
240+
if (fd >= 0) {
241+
r = asynchronous_fsync(fd, &pid);
242+
if (r < 0)
243+
return log_error_errno(r, "Failed to fork fsync(): %m");
244+
245+
(void) fd_get_path(fd, &path);
246+
} else {
247+
r = asynchronous_sync(&pid);
248+
if (r < 0)
249+
return log_error_errno(r, "Failed to fork sync(): %m");
250+
}
240251

241-
log_info("Syncing filesystems and block devices.");
252+
what = path ?: "filesystems and block devices";
253+
log_info("Syncing %s.", what);
242254

243255
/* Start monitoring the sync operation. If more than
244256
* SYNC_PROGRESS_ATTEMPTS lapse without progress being made,
@@ -249,7 +261,7 @@ static int sync_with_progress(void) {
249261
/* Sync finished without error (sync() call itself does not return an error code) */
250262
return 0;
251263
if (r != -ETIMEDOUT)
252-
return log_error_errno(r, "Failed to sync filesystems and block devices: %m");
264+
return log_error_errno(r, "Failed to sync %s: %m", what);
253265

254266
/* Reset the check counter if we made some progress */
255267
if (sync_making_progress(&dirty) > 0)
@@ -259,7 +271,8 @@ static int sync_with_progress(void) {
259271
/* Only reached in the event of a timeout. We should issue a kill to the stray process. */
260272
(void) kill(pid, SIGKILL);
261273
return log_error_errno(SYNTHETIC_ERRNO(ETIMEDOUT),
262-
"Syncing filesystems and block devices - timed out, issuing SIGKILL to PID "PID_FMT".",
274+
"Syncing %s - timed out, issuing SIGKILL to PID "PID_FMT".",
275+
what,
263276
pid);
264277
}
265278

@@ -415,7 +428,7 @@ int main(int argc, char *argv[]) {
415428
* desperately trying to sync IO to disk within their timeout. Do not remove this sync, data corruption will
416429
* result. */
417430
if (!in_container)
418-
(void) sync_with_progress();
431+
(void) sync_with_progress(-EBADF);
419432

420433
disable_coredumps();
421434
disable_binfmt();
@@ -578,7 +591,7 @@ int main(int argc, char *argv[]) {
578591
* which might have caused IO, hence let's do it once more. Do not remove this sync, data corruption
579592
* will result. */
580593
if (!in_container)
581-
(void) sync_with_progress();
594+
(void) sync_with_progress(-EBADF);
582595

583596
if (streq(arg_verb, "exit")) {
584597
if (in_container) {

src/shutdown/shutdown.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
/* SPDX-License-Identifier: LGPL-2.1-or-later */
2+
#pragma once
3+
4+
int sync_with_progress(int fd);

0 commit comments

Comments
 (0)