From 829e0382ab2a2ad1a741bbabeb5ef9a7fd7cfb75 Mon Sep 17 00:00:00 2001 From: Colin Walters Date: Thu, 3 Apr 2014 22:20:59 -0400 Subject: [PATCH] bootloader: fdatasync() bootloader configuration Let's be a bit more conservative here and actually fdatasync() the configurations we're generating. I'm seeing an issue at the moment where syslinux isn't finding the config sometimes, and while I don't think this is the issue, let's try it. --- src/libostree/ostree-bootloader-syslinux.c | 13 +++-- src/libostree/ostree-bootloader-uboot.c | 13 +++-- src/libotutil/ot-gio-utils.c | 61 ++++++++++++++++++++++ src/libotutil/ot-gio-utils.h | 5 ++ 4 files changed, 82 insertions(+), 10 deletions(-) diff --git a/src/libostree/ostree-bootloader-syslinux.c b/src/libostree/ostree-bootloader-syslinux.c index 43273815..0934bb81 100644 --- a/src/libostree/ostree-bootloader-syslinux.c +++ b/src/libostree/ostree-bootloader-syslinux.c @@ -236,12 +236,15 @@ _ostree_bootloader_syslinux_write_config (OstreeBootloader *bootloader, goto out; new_config_contents = _ostree_sysroot_join_lines (new_lines); + { + gs_unref_bytes GBytes *new_config_contents_bytes = + g_bytes_new_static (new_config_contents, + strlen (new_config_contents)); - if (!g_file_replace_contents (new_config_path, new_config_contents, - strlen (new_config_contents), - NULL, FALSE, G_FILE_CREATE_NONE, - NULL, cancellable, error)) - goto out; + if (!ot_gfile_replace_contents_fsync (new_config_path, new_config_contents_bytes, + cancellable, error)) + goto out; + } ret = TRUE; out: diff --git a/src/libostree/ostree-bootloader-uboot.c b/src/libostree/ostree-bootloader-uboot.c index c56d5ac0..cd25e56f 100644 --- a/src/libostree/ostree-bootloader-uboot.c +++ b/src/libostree/ostree-bootloader-uboot.c @@ -124,12 +124,15 @@ _ostree_bootloader_uboot_write_config (OstreeBootloader *bootloader, return FALSE; new_config_contents = _ostree_sysroot_join_lines (new_lines); + { + gs_unref_bytes GBytes *new_config_contents_bytes = + g_bytes_new_static (new_config_contents, + strlen (new_config_contents)); - if (!g_file_replace_contents (new_config_path, new_config_contents, - strlen (new_config_contents), - NULL, FALSE, G_FILE_CREATE_NONE, - NULL, cancellable, error)) - return FALSE; + if (!ot_gfile_replace_contents_fsync (new_config_path, new_config_contents_bytes, + cancellable, error)) + return FALSE; + } return TRUE; } diff --git a/src/libotutil/ot-gio-utils.c b/src/libotutil/ot-gio-utils.c index f250f15e..da895fbc 100644 --- a/src/libotutil/ot-gio-utils.c +++ b/src/libotutil/ot-gio-utils.c @@ -25,6 +25,7 @@ #include #include #include +#include #include @@ -271,6 +272,66 @@ ot_gfile_load_contents_utf8_allow_noent (GFile *path, return ret; } +/** + * ot_gfile_replace_contents_fsync: + * + * Like g_file_replace_contents(), except always uses fdatasync(). + */ +gboolean +ot_gfile_replace_contents_fsync (GFile *path, + GBytes *contents, + GCancellable *cancellable, + GError **error) +{ + gboolean ret = FALSE; + int fd; + gs_unref_object GFile *parent = NULL; + gs_unref_object GFile *tmpfile = NULL; + gs_unref_object GOutputStream *stream = NULL; + gs_unref_object GInputStream *instream = NULL; + + parent = g_file_get_parent (path); + + if (!gs_file_open_in_tmpdir (parent, 0644, &tmpfile, &stream, + cancellable, error)) + goto out; + + g_assert (G_IS_FILE_DESCRIPTOR_BASED (stream)); + fd = g_file_descriptor_based_get_fd (G_FILE_DESCRIPTOR_BASED (stream)); + + instream = g_memory_input_stream_new_from_bytes (contents); + + if (posix_fallocate (fd, 0, g_bytes_get_size (contents)) != 0) + { + ot_util_set_error_from_errno (error, errno); + goto out; + } + + if (g_output_stream_splice (stream, instream, 0, + cancellable, error) < 0) + goto out; + + if (fdatasync (fd) != 0) + { + ot_util_set_error_from_errno (error, errno); + goto out; + } + + if (!g_output_stream_close (stream, cancellable, error)) + goto out; + + if (!gs_file_rename (tmpfile, path, cancellable, error)) + goto out; + + g_clear_object (&tmpfile); + + ret = TRUE; + out: + if (tmpfile) + (void) gs_file_unlink (tmpfile, NULL, NULL); + return ret; +} + /** * ot_gfile_ensure_unlinked: * diff --git a/src/libotutil/ot-gio-utils.h b/src/libotutil/ot-gio-utils.h index 184c770b..2d585bac 100644 --- a/src/libotutil/ot-gio-utils.h +++ b/src/libotutil/ot-gio-utils.h @@ -69,6 +69,11 @@ gboolean ot_gfile_load_contents_utf8_allow_noent (GFile *path, GCancellable *cancellable, GError **error); +gboolean ot_gfile_replace_contents_fsync (GFile *path, + GBytes *contents, + GCancellable *cancellable, + GError **error); + gboolean ot_gfile_ensure_unlinked (GFile *path, GCancellable *cancellable, GError **error);