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 <jtomko@redhat.com>
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
This commit is contained in:
Daniel P. Berrangé 2022-02-03 16:15:51 +00:00
parent 2df9031a0e
commit 5e3498744e

View File

@ -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);