From: Daniel P. Berrangé Date: Thu, 3 Feb 2022 16:15:51 +0000 (+0000) Subject: qemu: do crash safe creation of NVRAM file X-Git-Tag: v8.1.0-rc1~154 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=5e3498744ed28a224edf5ab08dfbb5674e4470d4;p=thirdparty%2Flibvirt.git qemu: do crash safe creation of NVRAM file If we crash part way through writing the NVRAM file we end up with an unusable NVRAM on file. To avoid this we need to write to a temporary file and fsync(2) at the end, then rename to the real NVRAM file path. Reviewed-by: Ján Tomko Signed-off-by: Daniel P. Berrangé --- diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c index 455de4b529..64380ff8d3 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -4433,6 +4433,7 @@ qemuPrepareNVRAM(virQEMUDriver *driver, bool created = false; const char *master_nvram_path; ssize_t r; + g_autofree char *tmp_dst_path = NULL; if (!loader || !loader->nvram || virFileExists(loader->nvram)) return 0; @@ -4463,14 +4464,15 @@ qemuPrepareNVRAM(virQEMUDriver *driver, goto cleanup; } - if ((dstFD = virFileOpenAs(loader->nvram, + tmp_dst_path = g_strdup_printf("%s.tmp", loader->nvram); + if ((dstFD = virFileOpenAs(tmp_dst_path, O_WRONLY | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR, cfg->user, cfg->group, VIR_FILE_OPEN_FORCE_OWNER)) < 0) { virReportSystemError(-dstFD, _("Failed to create file '%s'"), - loader->nvram); + tmp_dst_path); goto cleanup; } @@ -4489,7 +4491,7 @@ qemuPrepareNVRAM(virQEMUDriver *driver, if (safewrite(dstFD, buf, r) < 0) { virReportSystemError(errno, _("Unable to write to file '%s'"), - loader->nvram); + tmp_dst_path); goto cleanup; } } while (r); @@ -4500,9 +4502,23 @@ qemuPrepareNVRAM(virQEMUDriver *driver, master_nvram_path); goto cleanup; } + + if (g_fsync(dstFD) < 0) { + virReportSystemError(errno, _("cannot sync file '%s'"), + tmp_dst_path); + goto cleanup; + } + if (VIR_CLOSE(dstFD) < 0) { virReportSystemError(errno, _("Unable to close file '%s'"), + tmp_dst_path); + goto cleanup; + } + + if (rename(tmp_dst_path, loader->nvram) < 0) { + virReportSystemError(errno, + _("Unable to replace '%s'"), loader->nvram); goto cleanup; } @@ -4513,7 +4529,7 @@ qemuPrepareNVRAM(virQEMUDriver *driver, * copy the file content. Roll back. */ if (ret < 0) { if (created) - unlink(loader->nvram); + unlink(tmp_dst_path); } VIR_FORCE_CLOSE(srcFD);