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:
commit
54d564a212
@ -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;
|
||||||
|
@ -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);
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
@ -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) {
|
||||||
|
@ -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);
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
@ -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,
|
||||||
|
Loading…
Reference in New Issue
Block a user