]> git.ipfire.org Git - thirdparty/open-vm-tools.git/commitdiff
Generate backup manifest files for quiesced snapshots on Linux.
authorOliver Kurth <okurth@vmware.com>
Fri, 15 Sep 2017 18:23:40 +0000 (11:23 -0700)
committerOliver Kurth <okurth@vmware.com>
Fri, 15 Sep 2017 18:23:40 +0000 (11:23 -0700)
After a successful quiesced snapshot of a Linux guest, the
snapshot is reported as not quiesced.  The underlying cause
is:

- a snapshot is identified as quiesced if and only if a backup
manifest file was provided for the snapshot; and

- backup manifest files are not provided for quiesced snapshots
on Linux.

To fix the problem, VMTools will generate backup manifest files
for quiesced snaphots taken on Linux, and VMX will accept and
store such files.  This change is for the VMTools side of the
change.  The VMX change defines a new VMBACKUP_EVENT value relied
on by the VMTools change.

Changes in this commit include:
- new source files syncManifest.h and syncManifest.c with code
to generate the manifest file, and updates to syncDriverOps.c
to invoke that code.
- a new "SyncDriver_GetAttr" interface in the syncDriver code,
used by the SyncManifest code to obtain the name of the backend
provider and whether or not it is capable of quiescing.
- makefile and configure boiler plate to add the two new source
files to open-vm-tools and tools-for-linux.
- a new tools.conf setting enableXmlManifest that specifies
whether VMTools generates backup manifests for Linux.  For now,
the default value of this setting will be false.

open-vm-tools/lib/include/syncDriver.h
open-vm-tools/lib/syncDriver/syncDriverInt.h
open-vm-tools/lib/syncDriver/syncDriverLinux.c
open-vm-tools/lib/syncDriver/syncDriverPosix.c
open-vm-tools/services/plugins/vmbackup/Makefile.am
open-vm-tools/services/plugins/vmbackup/syncDriverOps.c
open-vm-tools/services/plugins/vmbackup/syncManifest.c [new file with mode: 0644]
open-vm-tools/services/plugins/vmbackup/syncManifest.h [new file with mode: 0644]

index 92452a236bedec8e502b94b02c07f9cf5c2094ab..4cb71b491ae1ceda46fc4a854dc0a2a3b6322bf3 100644 (file)
@@ -1,5 +1,5 @@
 /*********************************************************
- * Copyright (C) 2005-2016 VMware, Inc. All rights reserved.
+ * Copyright (C) 2005-2017 VMware, Inc. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU Lesser General Public License as published
@@ -27,7 +27,7 @@
 
 #include "vm_basic_types.h"
 
-#ifdef _WIN32 /* { */
+#if defined(_WIN32) /* { */
 
 # include <windows.h>
 # define SYNCDRIVER_INVALID_HANDLE INVALID_HANDLE_VALUE
@@ -55,6 +55,10 @@ Bool SyncDriver_Thaw(const SyncDriverHandle handle);
 SyncDriverStatus SyncDriver_QueryStatus(const SyncDriverHandle handle,
                                         int32 timeout);
 void SyncDriver_CloseHandle(SyncDriverHandle *handle);
+#if defined(__linux__)
+void SyncDriver_GetAttr(const SyncDriverHandle handle, const char **name,
+                        Bool *quiesces);
+#endif
 
 #endif
 
index 8878b3c702fb4f7b656179de5624077cc47417b6..04f37bf2394ffad1b3bdb208e9d4554e08a6538c 100644 (file)
@@ -1,5 +1,5 @@
 /*********************************************************
- * Copyright (C) 2011-2016 VMware, Inc. All rights reserved.
+ * Copyright (C) 2011-2017 VMware, Inc. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU Lesser General Public License as published
@@ -46,6 +46,10 @@ typedef SyncDriverErr (*SyncFreezeFn)(const GSList *paths,
 typedef struct SyncHandle {
    SyncDriverErr (*thaw)(const SyncDriverHandle handle);
    void (*close)(SyncDriverHandle handle);
+#if defined(__linux__)
+   void (*getattr)(const SyncDriverHandle handle, const char **name,
+                   Bool *quiesces);
+#endif
 } SyncHandle;
 
 #if defined(__linux__)
index da0a8cb6e554f456f7776ec783f2db886ddfa689..db042da4fea991d21e97c3a60982f9ae50fdb3df 100644 (file)
@@ -116,6 +116,29 @@ LinuxFiClose(SyncDriverHandle handle)
 }
 
 
+/*
+ *******************************************************************************
+ * LinuxFiGetAttr --                                                      */ /**
+ *
+ * Return some attributes of the backend provider
+ *
+ * @param[out] name       name of backend provider
+ * @param[out] quiesces   TRUE (FALSE) if provider is (is not) capable
+ *                        of quiescing.
+ *
+ *******************************************************************************
+ */
+
+static void
+LinuxFiGetAttr(const SyncDriverHandle handle,   // IN (ignored)
+               const char **name,               // OUT
+               Bool *quiesces)                  // OUT
+{
+   *name = "fifreeze";
+   *quiesces = TRUE;
+}
+
+
 /*
  *******************************************************************************
  * LinuxDriver_Freeze --                                                  */ /**
@@ -159,6 +182,7 @@ LinuxDriver_Freeze(const GSList *paths,
 
    sync->driver.thaw = LinuxFiThaw;
    sync->driver.close = LinuxFiClose;
+   sync->driver.getattr = LinuxFiGetAttr;
 
    /*
     * Ensure we did not get an empty list
index f499faa4754d28555d489cffa509c80d66de8ee1..51979b298847cbe74100cece8bc25f11c9ed4ac8 100644 (file)
@@ -1,5 +1,5 @@
 /*********************************************************
- * Copyright (C) 2005-2016 VMware, Inc. All rights reserved.
+ * Copyright (C) 2005-2017 VMware, Inc. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU Lesser General Public License as published
@@ -379,3 +379,40 @@ SyncDriver_CloseHandle(SyncDriverHandle *handle)   // IN/OUT
    }
 }
 
+
+#if defined(__linux__)
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * SyncDriver_GetAttr --
+ *
+ *    Returns attributes of the backend provider for this handle.
+ *    If the backend does not supply a getattr function, it's treated
+ *    as non-quiescing.
+ *
+ * Results:
+ *    No return value.
+ *    Sets OUT parameters:
+ *        *name:      pointer to backend provider name
+ *        *quiesces:  indicates whether backend is capable of quiescing.
+ *
+ * Side effects:
+ *   None.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+void
+SyncDriver_GetAttr(const SyncDriverHandle handle,  // IN
+                   const char **name,              // OUT
+                   Bool *quiesces)                 // OUT
+{
+
+   if (handle != SYNCDRIVER_INVALID_HANDLE && handle->getattr != NULL) {
+      handle->getattr(handle, name, quiesces);
+   } else {
+      *name = NULL;
+      *quiesces = FALSE;
+   }
+}
+#endif /* __linux__ */
index 81fc5c7f2858844a10c1d7d3bd65cc48e2243ff0..ed561a7af842619eb149e554848f8de1ffc3509a 100644 (file)
@@ -1,5 +1,5 @@
 ################################################################################
-### Copyright (C) 2009-2016 VMware, Inc.  All rights reserved.
+### Copyright (C) 2009-2017 VMware, Inc.  All rights reserved.
 ###
 ### This program is free software; you can redistribute it and/or modify
 ### it under the terms of version 2 of the GNU General Public License as
@@ -33,6 +33,7 @@ libvmbackup_la_SOURCES += nullProvider.c
 libvmbackup_la_SOURCES += scriptOps.c
 libvmbackup_la_SOURCES += stateMachine.c
 libvmbackup_la_SOURCES += syncDriverOps.c
+libvmbackup_la_SOURCES += syncManifest.c
 libvmbackup_la_SOURCES += vmBackupSignals.c
 
 BUILT_SOURCES =
index e587f7fcf5581e129b9b45c035838a8e663e779c..682686df08137f206e50df9c890802f0db0cc175 100644 (file)
@@ -28,6 +28,7 @@
 #include "procMgr.h"
 #include "syncDriver.h"
 #include "util.h"
+#include "syncManifest.h"
 
 #ifdef _WIN32
 #include <windows.h>
@@ -40,6 +41,7 @@ typedef struct VmBackupDriverOp {
    Bool freeze;
    Bool canceled;
    SyncDriverHandle *syncHandle;
+   SyncManifest *manifest;
 } VmBackupDriverOp;
 
 
@@ -122,6 +124,9 @@ VmBackupDriverOpQuery(VmBackupOp *_op) // IN
          break;
       }
    } else {
+      if (op->manifest != NULL) {
+         SyncManifestSend(op->manifest);
+      }
       ret = VMBACKUP_STATUS_FINISHED;
    }
 
@@ -149,7 +154,9 @@ static void
 VmBackupDriverOpRelease(VmBackupOp *_op)  // IN
 {
    VmBackupDriverOp *op = (VmBackupDriverOp *) _op;
+
    g_free(op->syncHandle);
+   SyncManifestRelease(op->manifest);
    free(op);
 }
 
@@ -231,11 +238,13 @@ VmBackupNewDriverOp(VmBackupState *state,       // IN
                                   state->enableNullDriver : FALSE,
                                   op->syncHandle);
    } else {
+      op->manifest = SyncNewManifest(state, *op->syncHandle);
       success = VmBackupDriverThaw(op->syncHandle);
    }
    if (!success) {
       g_warning("Error %s filesystems.", freeze ? "freezing" : "thawing");
       g_free(op->syncHandle);
+      SyncManifestRelease(op->manifest);
       free(op);
       op = NULL;
    }
diff --git a/open-vm-tools/services/plugins/vmbackup/syncManifest.c b/open-vm-tools/services/plugins/vmbackup/syncManifest.c
new file mode 100644 (file)
index 0000000..7166ccc
--- /dev/null
@@ -0,0 +1,175 @@
+/*********************************************************
+ * Copyright (C) 2017 VMware, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation version 2.1 and no later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the Lesser GNU General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA.
+ *
+ *********************************************************/
+
+/*
+ * syncManifest.c --
+ *
+ * Implements a simple xml-based backup manifest file for quiesced snapshots
+ * on Linux.
+ */
+
+#include "vmBackupInt.h"
+#include "syncDriver.h"
+#include "syncManifest.h"
+#include "vm_tools_version.h"
+
+#include <unistd.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+/*
+ * Name and format of the manifest file.
+ */
+static const char syncManifestName[] = "quiesce_manifest.xml";
+static const char syncManifestFmt[] = {
+   "<quiesceManifest>\n"
+   "   <productVersion>%d</productVersion>\n"  /* version of tools */
+   "   <providerName>%s</providerName>\n"      /* name of backend provider */
+   "</quiesceManifest>\n"
+};
+
+/*
+ * tools.conf switch to enable manifest generation
+ */
+static const char syncManifestSwitch[] = "enableXmlManifest";
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * SyncNewManifest --
+ *
+ *    Create a new SyncManifest structure.
+ *
+ * Results:
+ *    Pointer to structure on success, otherwise NULL.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+SyncManifest *
+SyncNewManifest(VmBackupState *state,          // IN
+                SyncDriverHandle handle)       // IN
+{
+   Bool providerQuiesces;
+   const char *providerName;
+   SyncManifest *manifest;
+
+   /*
+    * XXX - feature is to be disabled by default until approved by QE.
+    */
+   if (!VMTools_ConfigGetBoolean(state->ctx->config, "vmbackup",
+                                 syncManifestSwitch, FALSE)) {
+      g_debug("No backup manifest - %s is false\n",
+              syncManifestSwitch);
+      return NULL;
+   }
+
+   if (!state->generateManifests) {
+      g_debug("No backup manifest requested\n");
+      return NULL;
+   }
+
+   SyncDriver_GetAttr(handle, &providerName, &providerQuiesces);
+   if (!providerQuiesces) {
+      g_debug("No backup manifest needed since using "
+              "non-quiescing backend.\n");
+      return NULL;
+   }
+
+   manifest = g_new0(SyncManifest, 1);
+   manifest->path = g_strdup_printf("%s/%s", state->configDir,
+                                    syncManifestName);
+   manifest->providerName = g_strdup(providerName);
+   return manifest;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * SyncManifestRelease --
+ *
+ *    Free a manifest structure.
+ *
+ * Results:
+ *    None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+void
+SyncManifestRelease(SyncManifest *manifest)    // IN
+{
+   if (manifest != NULL) {
+      g_free(manifest->path);
+      g_free(manifest->providerName);
+      g_free(manifest);
+   }
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * SyncManifestSend --
+ *
+ *    Generate manifest file and send it to vmx.
+ *
+ * Results:
+ *    TRUE on success, FALSE on failure.
+ *
+ * Side effects:
+ *    On success, writes out the backup manifest file for a quiesced
+ *    snapshot and sends the file's path to vmx.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+Bool
+SyncManifestSend(SyncManifest *manifest)       // IN
+{
+   FILE *f;
+   int ret;
+
+   unlink(manifest->path);
+   f = fopen(manifest->path, "w");
+   if (f == NULL) {
+      g_warning("Error opening backup manifest file %s\n",
+                manifest->path);
+      return FALSE;
+   }
+
+   ret = fprintf(f, syncManifestFmt, TOOLS_VERSION_CURRENT,
+                 manifest->providerName);
+   fclose(f);
+   if (ret < 0) {
+      g_warning("Error writing backup manifest file %s: %d %s\n",
+                manifest->path, errno, strerror(errno));
+      return FALSE;
+   }
+
+   if (!VmBackup_SendEvent(VMBACKUP_EVENT_GENERIC_MANIFEST,
+                           VMBACKUP_SUCCESS, manifest->path)) {
+      g_warning("Error trying to send VMBACKUP_EVENT_GENERIC_MANIFEST.\n");
+      return FALSE;
+   }
+
+   return TRUE;
+}
diff --git a/open-vm-tools/services/plugins/vmbackup/syncManifest.h b/open-vm-tools/services/plugins/vmbackup/syncManifest.h
new file mode 100644 (file)
index 0000000..76966cc
--- /dev/null
@@ -0,0 +1,58 @@
+/*********************************************************
+ * Copyright (C) 2017 VMware, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation version 2.1 and no later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the Lesser GNU General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA.
+ *
+ *********************************************************/
+
+/**
+ * @file syncManifest.h
+ *
+ * Interface definitions for sync driver manifest file generation.
+ * On Linux, generate an xml-format manifest file when quiescing
+ * is done via the sync driver backend that uses "FIFREEZE" and
+ * "FITHAW" ioctls.  On other OSes, or on Linux with other sync
+ * driver backends, no manifest is generated for the sync driver.
+ */
+
+#ifndef _SYNCMANIFEST_H_
+#define _SYNCMANIFEST_H_
+
+#if defined(__linux__)
+
+typedef struct {
+   char *path;
+   char *providerName;
+} SyncManifest;
+
+SyncManifest *
+SyncNewManifest(VmBackupState *state, SyncDriverHandle handle);
+
+Bool
+SyncManifestSend(SyncManifest *manifest);
+
+void
+SyncManifestRelease(SyncManifest *manifest);
+
+#else /* !defined(__linux__) */
+
+typedef void SyncManifest;
+
+#define SyncNewManifest(s, h)            (NULL)
+#define SyncManifestSend(m)              (TRUE)
+#define SyncManifestRelease(m)           ASSERT(m == NULL)
+
+#endif /* defined(__linux__) */
+
+#endif /* _SYNCMANIFEST_H_*/