From 0675e94ab53237ad27bfba929c7490bdd2215cf1 Mon Sep 17 00:00:00 2001 From: Alan Jenkins Date: Thu, 17 Aug 2017 17:09:44 +0100 Subject: "Don't fear the fsync()" For files which are vital to boot 1. Avoid opening any window where power loss will zero them out or worse. I know app developers all coded to the ext3 implementation, but the only formal documentation we have says we're broken if we actually rely on it. E.g. * `man mount`, search for `auto_da_alloc`. * http://www.linux-mtd.infradead.org/faq/ubifs.html#L_atomic_change * https://thunk.org/tytso/blog/2009/03/15/dont-fear-the-fsync/ 2. If we tell the kernel we're interested in writing them to disk, it will tell us if that fails. So at minimum, this means we play our part in notifying the user about errors. I refactored error-handling in `udevadm-hwdb` a little. It turns out I did exactly the same as had already been done in the `systemd-hwdb` version, i.e. commit d702dcd. --- src/hwdb/hwdb.c | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) (limited to 'src/hwdb') diff --git a/src/hwdb/hwdb.c b/src/hwdb/hwdb.c index 793398ca68..ead4e1770b 100644 --- a/src/hwdb/hwdb.c +++ b/src/hwdb/hwdb.c @@ -403,14 +403,14 @@ static int trie_store(struct trie *trie, const char *filename) { t.strings_off = sizeof(struct trie_header_f); trie_store_nodes_size(&t, trie->root); - r = fopen_temporary(filename , &t.f, &filename_tmp); + r = fopen_temporary(filename, &t.f, &filename_tmp); if (r < 0) return r; fchmod(fileno(t.f), 0444); /* write nodes */ 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); 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); h.file_size = htole64(size); if (fseeko(t.f, 0, SEEK_SET) < 0) - goto error; - + goto error_fclose; fwrite(&h, sizeof(struct trie_header_f), 1, t.f); - if (fclose(t.f) < 0 || rename(filename_tmp, filename) < 0) { - unlink_noerrno(filename_tmp); - return -errno; - } + + if (ferror(t.f)) + 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("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); return 0; - error: + error_fclose: r = -errno; fclose(t.f); unlink(filename_tmp); -- cgit v1.2.1