]> xenbits.xensource.com Git - libvirt.git/commitdiff
qemu: do crash safe creation of NVRAM file
authorDaniel P. Berrangé <berrange@redhat.com>
Thu, 3 Feb 2022 16:15:51 +0000 (16:15 +0000)
committerDaniel P. Berrangé <berrange@redhat.com>
Tue, 8 Feb 2022 13:01:24 +0000 (13:01 +0000)
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>
src/qemu/qemu_process.c

index 455de4b5291e17aa5afb76776455d9b5bb176829..64380ff8d36a22c2353d57ca4de74be7a0b6241c 100644 (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);