When saving domain XML (either config or status) we just overwrite old content of the file. In case something fails during that process (e.g. disk gets full) we lose both old and new content. This patch makes the process more robust by writing the new content into a separate file and only if that succeeds the original file is atomically replaced with the new one. --- src/conf/domain_conf.c | 25 +++++++++++++++++++++---- 1 files changed, 21 insertions(+), 4 deletions(-) diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index f9007ce..04c2b1c 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -11025,6 +11025,7 @@ int virDomainSaveXML(const char *configDir, const char *xml) { char *configFile = NULL; + char *newfile = NULL; int fd = -1, ret = -1; size_t towrite; @@ -11038,12 +11039,17 @@ int virDomainSaveXML(const char *configDir, goto cleanup; } - if ((fd = open(configFile, + if (virAsprintf(&newfile, "%s.new", configFile) < 0) { + virReportOOMError(); + goto cleanup; + } + + if ((fd = open(newfile, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR )) < 0) { virReportSystemError(errno, _("cannot create config file '%s'"), - configFile); + newfile); goto cleanup; } @@ -11053,14 +11059,21 @@ int virDomainSaveXML(const char *configDir, if (safewrite(fd, xml, towrite) < 0) { virReportSystemError(errno, _("cannot write config file '%s'"), - configFile); + newfile); goto cleanup; } if (VIR_CLOSE(fd) < 0) { virReportSystemError(errno, _("cannot save config file '%s'"), - configFile); + newfile); + goto cleanup; + } + + if (rename(newfile, configFile) < 0) { + virReportSystemError(errno, + _("cannot rename config file '%s' as '%s'"), + newfile, configFile); goto cleanup; } @@ -11068,6 +11081,10 @@ int virDomainSaveXML(const char *configDir, cleanup: VIR_FORCE_CLOSE(fd); + if (newfile) { + unlink(newfile); + VIR_FREE(newfile); + } VIR_FREE(configFile); return ret; } -- 1.7.7 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list