1
0
mirror of https://github.com/systemd/systemd.git synced 2024-12-27 07:22:31 +03:00

Merge pull request #6636 from sourcejedi/fsync

"Don't fear the fsync()"
This commit is contained in:
Lennart Poettering 2017-08-29 15:19:44 +02:00 committed by GitHub
commit 54d564a212
8 changed files with 100 additions and 49 deletions

View File

@ -71,7 +71,7 @@ int write_string_stream_ts(FILE *f, const char *line, bool enforce_newline, stru
return fflush_and_check(f); return fflush_and_check(f);
} }
static int write_string_file_atomic(const char *fn, const char *line, bool enforce_newline) { static int write_string_file_atomic(const char *fn, const char *line, bool enforce_newline, bool do_fsync) {
_cleanup_fclose_ FILE *f = NULL; _cleanup_fclose_ FILE *f = NULL;
_cleanup_free_ char *p = NULL; _cleanup_free_ char *p = NULL;
int r; int r;
@ -86,6 +86,9 @@ static int write_string_file_atomic(const char *fn, const char *line, bool enfor
(void) fchmod_umask(fileno(f), 0644); (void) fchmod_umask(fileno(f), 0644);
r = write_string_stream(f, line, enforce_newline); r = write_string_stream(f, line, enforce_newline);
if (r >= 0 && do_fsync)
r = fflush_sync_and_check(f);
if (r >= 0) { if (r >= 0) {
if (rename(p, fn) < 0) if (rename(p, fn) < 0)
r = -errno; r = -errno;
@ -104,10 +107,14 @@ int write_string_file_ts(const char *fn, const char *line, WriteStringFileFlags
assert(fn); assert(fn);
assert(line); assert(line);
/* We don't know how to verify whether the file contents was already on-disk. */
assert(!((flags & WRITE_STRING_FILE_VERIFY_ON_FAILURE) && (flags & WRITE_STRING_FILE_SYNC)));
if (flags & WRITE_STRING_FILE_ATOMIC) { if (flags & WRITE_STRING_FILE_ATOMIC) {
assert(flags & WRITE_STRING_FILE_CREATE); assert(flags & WRITE_STRING_FILE_CREATE);
r = write_string_file_atomic(fn, line, !(flags & WRITE_STRING_FILE_AVOID_NEWLINE)); r = write_string_file_atomic(fn, line, !(flags & WRITE_STRING_FILE_AVOID_NEWLINE),
flags & WRITE_STRING_FILE_SYNC);
if (r < 0) if (r < 0)
goto fail; goto fail;
@ -144,6 +151,12 @@ int write_string_file_ts(const char *fn, const char *line, WriteStringFileFlags
if (r < 0) if (r < 0)
goto fail; goto fail;
if (flags & WRITE_STRING_FILE_SYNC) {
r = fflush_sync_and_check(f);
if (r < 0)
return r;
}
return 0; return 0;
fail: fail:
@ -1126,6 +1139,21 @@ int fflush_and_check(FILE *f) {
return 0; return 0;
} }
int fflush_sync_and_check(FILE *f) {
int r;
assert(f);
r = fflush_and_check(f);
if (r < 0)
return r;
if (fsync(fileno(f)) < 0)
return -errno;
return 0;
}
/* This is much like mkostemp() but is subject to umask(). */ /* This is much like mkostemp() but is subject to umask(). */
int mkostemp_safe(char *pattern) { int mkostemp_safe(char *pattern) {
_cleanup_umask_ mode_t u = 0; _cleanup_umask_ mode_t u = 0;

View File

@ -29,10 +29,11 @@
#include "time-util.h" #include "time-util.h"
typedef enum { typedef enum {
WRITE_STRING_FILE_CREATE = 1, WRITE_STRING_FILE_CREATE = 1<<0,
WRITE_STRING_FILE_ATOMIC = 2, WRITE_STRING_FILE_ATOMIC = 1<<1,
WRITE_STRING_FILE_AVOID_NEWLINE = 4, WRITE_STRING_FILE_AVOID_NEWLINE = 1<<2,
WRITE_STRING_FILE_VERIFY_ON_FAILURE = 8, WRITE_STRING_FILE_VERIFY_ON_FAILURE = 1<<3,
WRITE_STRING_FILE_SYNC = 1<<4,
} WriteStringFileFlags; } WriteStringFileFlags;
int write_string_stream_ts(FILE *f, const char *line, bool enforce_newline, struct timespec *ts); int write_string_stream_ts(FILE *f, const char *line, bool enforce_newline, struct timespec *ts);
@ -77,6 +78,7 @@ int search_and_fopen_nulstr(const char *path, const char *mode, const char *root
} else } else
int fflush_and_check(FILE *f); int fflush_and_check(FILE *f);
int fflush_sync_and_check(FILE *f);
int fopen_temporary(const char *path, FILE **_f, char **_temp_path); int fopen_temporary(const char *path, FILE **_f, char **_temp_path);
int mkostemp_safe(char *pattern); int mkostemp_safe(char *pattern);

View File

@ -539,12 +539,18 @@ static int copy_file_with_version_check(const char *from, const char *to, bool f
r = copy_bytes(fd_from, fd_to, (uint64_t) -1, COPY_REFLINK); r = copy_bytes(fd_from, fd_to, (uint64_t) -1, COPY_REFLINK);
if (r < 0) { if (r < 0) {
unlink(t); (void) unlink(t);
return log_error_errno(errno, "Failed to copy data from \"%s\" to \"%s\": %m", from, t); return log_error_errno(r, "Failed to copy data from \"%s\" to \"%s\": %m", from, t);
} }
(void) copy_times(fd_from, fd_to); (void) copy_times(fd_from, fd_to);
r = fsync(fd_to);
if (r < 0) {
(void) unlink_noerrno(t);
return log_error_errno(errno, "Failed to copy data from \"%s\" to \"%s\": %m", from, t);
}
r = renameat(AT_FDCWD, t, AT_FDCWD, to); r = renameat(AT_FDCWD, t, AT_FDCWD, to);
if (r < 0) { if (r < 0) {
(void) unlink_noerrno(t); (void) unlink_noerrno(t);
@ -912,7 +918,7 @@ static int install_loader_config(const char *esp_path) {
r = sd_id128_get_machine(&machine_id); r = sd_id128_get_machine(&machine_id);
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to get machine did: %m"); return log_error_errno(r, "Failed to get machine id: %m");
p = strjoina(esp_path, "/loader/loader.conf"); p = strjoina(esp_path, "/loader/loader.conf");
@ -932,7 +938,7 @@ static int install_loader_config(const char *esp_path) {
fprintf(f, "#timeout 3\n"); fprintf(f, "#timeout 3\n");
fprintf(f, "default %s-*\n", sd_id128_to_string(machine_id, machine_string)); fprintf(f, "default %s-*\n", sd_id128_to_string(machine_id, machine_string));
r = fflush_and_check(f); r = fflush_sync_and_check(f);
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to write \"%s\": %m", p); return log_error_errno(r, "Failed to write \"%s\": %m", p);

View File

@ -411,7 +411,8 @@ static int process_hostname(void) {
return 0; return 0;
mkdir_parents(etc_hostname, 0755); mkdir_parents(etc_hostname, 0755);
r = write_string_file(etc_hostname, arg_hostname, WRITE_STRING_FILE_CREATE); r = write_string_file(etc_hostname, arg_hostname,
WRITE_STRING_FILE_CREATE | WRITE_STRING_FILE_SYNC);
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to write %s: %m", etc_hostname); return log_error_errno(r, "Failed to write %s: %m", etc_hostname);
@ -432,7 +433,8 @@ static int process_machine_id(void) {
return 0; return 0;
mkdir_parents(etc_machine_id, 0755); mkdir_parents(etc_machine_id, 0755);
r = write_string_file(etc_machine_id, sd_id128_to_string(arg_machine_id, id), WRITE_STRING_FILE_CREATE); r = write_string_file(etc_machine_id, sd_id128_to_string(arg_machine_id, id),
WRITE_STRING_FILE_CREATE | WRITE_STRING_FILE_SYNC);
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to write machine id: %m"); return log_error_errno(r, "Failed to write machine id: %m");
@ -503,7 +505,7 @@ static int write_root_shadow(const char *path, const struct spwd *p) {
if (putspent(p, f) != 0) if (putspent(p, f) != 0)
return errno > 0 ? -errno : -EIO; return errno > 0 ? -errno : -EIO;
return fflush_and_check(f); return fflush_sync_and_check(f);
} }
static int process_root_password(void) { static int process_root_password(void) {

View File

@ -410,7 +410,7 @@ static int trie_store(struct trie *trie, const char *filename) {
/* write nodes */ /* write nodes */
if (fseeko(t.f, sizeof(struct trie_header_f), SEEK_SET) < 0) if (fseeko(t.f, sizeof(struct trie_header_f), SEEK_SET) < 0)
goto error; goto error_fclose;
root_off = trie_store_nodes(&t, trie->root); root_off = trie_store_nodes(&t, trie->root);
h.nodes_root_off = htole64(root_off); h.nodes_root_off = htole64(root_off);
@ -425,13 +425,20 @@ static int trie_store(struct trie *trie, const char *filename) {
size = ftello(t.f); size = ftello(t.f);
h.file_size = htole64(size); h.file_size = htole64(size);
if (fseeko(t.f, 0, SEEK_SET) < 0) if (fseeko(t.f, 0, SEEK_SET) < 0)
goto error; goto error_fclose;
fwrite(&h, sizeof(struct trie_header_f), 1, t.f); fwrite(&h, sizeof(struct trie_header_f), 1, t.f);
if (fclose(t.f) < 0 || rename(filename_tmp, filename) < 0) {
unlink_noerrno(filename_tmp); if (ferror(t.f))
return -errno; goto error_fclose;
} if (fflush(t.f) < 0)
goto error_fclose;
if (fsync(fileno(t.f)) < 0)
goto error_fclose;
if (rename(filename_tmp, filename) < 0)
goto error_fclose;
/* write succeeded */
fclose(t.f);
log_debug("=== trie on-disk ==="); log_debug("=== trie on-disk ===");
log_debug("size: %8"PRIi64" bytes", size); log_debug("size: %8"PRIi64" bytes", size);
@ -446,7 +453,7 @@ static int trie_store(struct trie *trie, const char *filename) {
log_debug("strings start: %8"PRIu64, t.strings_off); log_debug("strings start: %8"PRIu64, t.strings_off);
return 0; return 0;
error: error_fclose:
r = -errno; r = -errno;
fclose(t.f); fclose(t.f);
unlink(filename_tmp); unlink(filename_tmp);

View File

@ -382,7 +382,7 @@ int x11_write_data(Context *c) {
fputs_unlocked("EndSection\n", f); fputs_unlocked("EndSection\n", f);
r = fflush_and_check(f); r = fflush_sync_and_check(f);
if (r < 0) if (r < 0)
goto fail; goto fail;
@ -394,8 +394,6 @@ int x11_write_data(Context *c) {
return 0; return 0;
fail: fail:
(void) unlink("/etc/X11/xorg.conf.d/00-keyboard.conf");
if (temp_path) if (temp_path)
(void) unlink(temp_path); (void) unlink(temp_path);

View File

@ -233,9 +233,15 @@ static int make_backup(const char *target, const char *x) {
if (futimens(fileno(dst), ts) < 0) if (futimens(fileno(dst), ts) < 0)
log_warning_errno(errno, "Failed to fix access and modification time of %s: %m", backup); log_warning_errno(errno, "Failed to fix access and modification time of %s: %m", backup);
if (rename(temp, backup) < 0) r = fflush_sync_and_check(dst);
if (r < 0)
goto fail; goto fail;
if (rename(temp, backup) < 0) {
r = -errno;
goto fail;
}
return 0; return 0;
fail: fail:
@ -532,7 +538,7 @@ static int write_temporary_shadow(const char *shadow_path, FILE **tmpfile, char
return errno ? -errno : -EIO; return errno ? -errno : -EIO;
} }
r = fflush_and_check(shadow); r = fflush_sync_and_check(shadow);
if (r < 0) if (r < 0)
return r; return r;
@ -616,7 +622,7 @@ static int write_temporary_group(const char *group_path, FILE **tmpfile, char **
group_changed = true; group_changed = true;
} }
r = fflush_and_check(group); r = fflush_sync_and_check(group);
if (r < 0) if (r < 0)
return r; return r;
@ -693,7 +699,7 @@ static int write_temporary_gshadow(const char * gshadow_path, FILE **tmpfile, ch
group_changed = true; group_changed = true;
} }
r = fflush_and_check(gshadow); r = fflush_sync_and_check(gshadow);
if (r < 0) if (r < 0)
return r; return r;

View File

@ -370,12 +370,8 @@ static int trie_store(struct trie *trie, const char *filename) {
fchmod(fileno(t.f), 0444); fchmod(fileno(t.f), 0444);
/* write nodes */ /* write nodes */
err = fseeko(t.f, sizeof(struct trie_header_f), SEEK_SET); if (fseeko(t.f, sizeof(struct trie_header_f), SEEK_SET) < 0)
if (err < 0) { goto error_fclose;
fclose(t.f);
unlink_noerrno(filename_tmp);
return -errno;
}
root_off = trie_store_nodes(&t, trie->root); root_off = trie_store_nodes(&t, trie->root);
h.nodes_root_off = htole64(root_off); h.nodes_root_off = htole64(root_off);
pos = ftello(t.f); pos = ftello(t.f);
@ -388,21 +384,21 @@ static int trie_store(struct trie *trie, const char *filename) {
/* write header */ /* write header */
size = ftello(t.f); size = ftello(t.f);
h.file_size = htole64(size); h.file_size = htole64(size);
err = fseeko(t.f, 0, SEEK_SET); if (fseeko(t.f, 0, SEEK_SET < 0))
if (err < 0) { goto error_fclose;
fclose(t.f);
unlink_noerrno(filename_tmp);
return -errno;
}
fwrite(&h, sizeof(struct trie_header_f), 1, t.f); fwrite(&h, sizeof(struct trie_header_f), 1, t.f);
err = ferror(t.f);
if (err) if (ferror(t.f))
err = -errno; goto error_fclose;
if (fflush(t.f) < 0)
goto error_fclose;
if (fsync(fileno(t.f)) < 0)
goto error_fclose;
if (rename(filename_tmp, filename) < 0)
goto error_fclose;
/* write succeeded */
fclose(t.f); fclose(t.f);
if (err < 0 || rename(filename_tmp, filename) < 0) {
unlink_noerrno(filename_tmp);
return err < 0 ? err : -errno;
}
log_debug("=== trie on-disk ==="); log_debug("=== trie on-disk ===");
log_debug("size: %8"PRIi64" bytes", size); log_debug("size: %8"PRIi64" bytes", size);
@ -417,6 +413,12 @@ static int trie_store(struct trie *trie, const char *filename) {
log_debug("strings start: %8"PRIu64, t.strings_off); log_debug("strings start: %8"PRIu64, t.strings_off);
return 0; return 0;
error_fclose:
err = -errno;
fclose(t.f);
unlink(filename_tmp);
return err;
} }
static int insert_data(struct trie *trie, struct udev_list *match_list, static int insert_data(struct trie *trie, struct udev_list *match_list,