--- open-vm-tools-10.0.5-3227872/lib/include/vmware/guestrpc/vmbackup.h 2015-11-23 23:07:44.000000000 -0800
+++ open-vm-tools-10.0.5-3227872/lib/include/vmware/guestrpc/vmbackup.h 2017-01-11 02:08:21.000000000 -0800
@@ -1,5 +1,5 @@
/*********************************************************
- * Copyright (C) 2007-2015 VMware, Inc. All rights reserved.
+ * Copyright (C) 2007-2016 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
@@ -54,6 +54,8 @@
#define VMBACKUP_PROTOCOL_ABORT VMBACKUP_PROTOCOL_PREFIX"abort"
#define VMBACKUP_PROTOCOL_SNAPSHOT_DONE VMBACKUP_PROTOCOL_PREFIX"snapshotDone"
#define VMBACKUP_PROTOCOL_EVENT_SET VMBACKUP_PROTOCOL_PREFIX"eventSet"
+#define VMBACKUP_PROTOCOL_SNAPSHOT_COMPLETED \
+ VMBACKUP_PROTOCOL_PREFIX"snapshotCompleted"
/* These are responses to messages sent to the guest. */
#define VMBACKUP_PROTOCOL_ERROR "protocol.error"
--- open-vm-tools-10.0.5-3227872/services/plugins/vmbackup/guestQuiesce.x 2015-11-23 23:07:44.000000000 -0800
+++ open-vm-tools-10.0.5-3227872/services/plugins/vmbackup/guestQuiesce.x 2017-01-11 02:08:21.000000000 -0800
@@ -1,5 +1,5 @@
/*********************************************************
- * Copyright (C) 2010-2015 VMware, Inc. All rights reserved.
+ * Copyright (C) 2010-2016 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
@@ -24,12 +24,14 @@
*/
enum GuestQuiesceParamsVersion {
- GUESTQUIESCEPARAMS_V1 = 1
+ GUESTQUIESCEPARAMS_V1 = 1,
+ GUESTQUIESCEPARAMS_V2 = 2
};
const GUESTQUIESCE_SCRIPTARG_MAX_LEN = 256;
const GUESTQUIESCE_DISKUUID_MAX_LEN = 3200; /* (UUID_MAXLEN + 1) * 64 disks */
+
/* Guest Quiescing parameters. */
struct GuestQuiesceParamsV1 {
Bool createManifest; /* Create manifest describing the operations */
@@ -42,7 +44,19 @@
string diskUuids<GUESTQUIESCE_DISKUUID_MAX_LEN>; /* disk Uuids */
};
+/* Guest Quiescing parameters V2. */
+struct GuestQuiesceParamsV2 {
+ struct GuestQuiesceParamsV1 paramsV1;
+ uint32 vssBackupContext;
+ uint32 vssBackupType;
+ Bool vssBootableSystemState;
+ Bool vssPartialFileSupport;
+};
+
+
union GuestQuiesceParams switch (GuestQuiesceParamsVersion ver) {
case GUESTQUIESCEPARAMS_V1:
struct GuestQuiesceParamsV1 *guestQuiesceParamsV1;
+case GUESTQUIESCEPARAMS_V2:
+ struct GuestQuiesceParamsV2 *guestQuiesceParamsV2;
};
--- open-vm-tools-10.0.5-3227872/lib/include/vmware/tools/utils.h 2015-11-23 23:07:44.000000000 -0800
+++ open-vm-tools-10.0.5-3227872/lib/include/vmware/tools/utils.h 2017-01-11 02:07:50.000000000 -0800
@@ -1,5 +1,5 @@
/*********************************************************
- * Copyright (C) 2008-2015 VMware, Inc. All rights reserved.
+ * Copyright (C) 2008-2016 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
@@ -121,6 +121,24 @@
const gchar *domain,
GKeyFile *conf);
+gboolean
+VMTools_ConfigGetBoolean(GKeyFile *config,
+ const gchar *section,
+ const gchar *key,
+ gboolean defValue);
+
+gint
+VMTools_ConfigGetInteger(GKeyFile *config,
+ const gchar *section,
+ const gchar *key,
+ gint defValue);
+
+gchar *
+VMTools_ConfigGetString(GKeyFile *config,
+ const gchar *section,
+ const gchar *key,
+ gchar *defValue);
+
#if defined(G_PLATFORM_WIN32)
gboolean
--- open-vm-tools-10.0.5-3227872/libvmtools/vmtoolsConfig.c 2015-11-23 23:07:44.000000000 -0800
+++ open-vm-tools-10.0.5-3227872/libvmtools/vmtoolsConfig.c 2017-01-11 02:07:50.000000000 -0800
@@ -1,5 +1,5 @@
/*********************************************************
- * Copyright (C) 2008-2015 VMware, Inc. All rights reserved.
+ * Copyright (C) 2008-2016 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
@@ -329,7 +329,12 @@
gchar *backup = NULL;
gchar *defaultPath = NULL;
gchar *localPath = NULL;
+ /* GStatBuf was added in 2.26. */
+#if GLIB_CHECK_VERSION(2, 26, 0)
+ GStatBuf confStat;
+#else
struct stat confStat;
+#endif
GHashTable *old = NULL;
GError *err = NULL;
GKeyFile *cfg = NULL;
@@ -527,3 +532,122 @@
return ret;
}
+
+/**
+ * Loads boolean value for a key from the specified config section.
+ *
+ * @param[in] config Config file to read the key from.
+ * @param[in] section Section to look for in the config file.
+ * @param[in] defValue Default value if the key is not found or error.
+ *
+ * @return value of the key if value was read successfully, else defValue.
+ */
+
+gboolean
+VMTools_ConfigGetBoolean(GKeyFile *config,
+ const gchar *section,
+ const gchar *key,
+ gboolean defValue)
+{
+ GError *err = NULL;
+ gboolean value;
+
+ if (config == NULL || section == NULL || key == NULL) {
+ g_debug("%s: Returning default value for '[%s] %s'=%s.\n",
+ __FUNCTION__, section ? section : "(null)",
+ key ? key : "(null)", defValue ? "TRUE" : "FALSE");
+ return defValue;
+ }
+
+ value = g_key_file_get_boolean(config, section, key, &err);
+ if (err != NULL) {
+ if (err->code != G_KEY_FILE_ERROR_KEY_NOT_FOUND &&
+ err->code != G_KEY_FILE_ERROR_GROUP_NOT_FOUND) {
+ g_warning("%s: Failed to get value for '[%s] %s': %s (err=%d).\n",
+ __FUNCTION__, section, key, err->message, err->code);
+ }
+ g_debug("%s: Returning default value for '[%s] %s'=%s.\n",
+ __FUNCTION__, section, key, defValue ? "TRUE" : "FALSE");
+ value = defValue;
+ g_clear_error(&err);
+ }
+ return value;
+}
+
+
+/**
+ * Loads integer value for a key from the specified config section.
+ *
+ * @param[in] config Config file to read the key from.
+ * @param[in] section Section to look for in the config file.
+ * @param[in] defValue Default value if the key is not found or error.
+ *
+ * @return value of the key if value was read successfully, else defValue.
+ */
+
+gint
+VMTools_ConfigGetInteger(GKeyFile *config,
+ const gchar *section,
+ const gchar *key,
+ gint defValue)
+{
+ GError *err = NULL;
+ gint value;
+
+ ASSERT(config);
+ ASSERT(key);
+ ASSERT(section);
+
+ value = g_key_file_get_integer(config, section, key, &err);
+ if (err != NULL) {
+ if (err->code != G_KEY_FILE_ERROR_KEY_NOT_FOUND &&
+ err->code != G_KEY_FILE_ERROR_GROUP_NOT_FOUND) {
+ g_warning("%s: Failed to get value for '[%s] %s': %s (err=%d).\n",
+ __FUNCTION__, section, key, err->message, err->code);
+ }
+ g_debug("%s: Returning default value for '[%s] %s'=%d.\n",
+ __FUNCTION__, section, key, defValue);
+ value = defValue;
+ g_clear_error(&err);
+ }
+ return value;
+}
+
+
+/**
+ * Loads string value for a key from the specified config section.
+ *
+ * @param[in] config Config file to read the key from.
+ * @param[in] section Section to look for in the config file.
+ * @param[in] defValue Default value if the key is not found or error.
+ *
+ * @return value of the key if value was read successfully, else defValue.
+ */
+
+gchar *
+VMTools_ConfigGetString(GKeyFile *config,
+ const gchar *section,
+ const gchar *key,
+ gchar *defValue)
+{
+ GError *err = NULL;
+ gchar *value;
+
+ ASSERT(config);
+ ASSERT(key);
+ ASSERT(section);
+
+ value = g_key_file_get_string(config, section, key, &err);
+ if (err != NULL) {
+ if (err->code != G_KEY_FILE_ERROR_KEY_NOT_FOUND &&
+ err->code != G_KEY_FILE_ERROR_GROUP_NOT_FOUND) {
+ g_warning("%s: Failed to get value for '[%s] %s': %s (err=%d).\n",
+ __FUNCTION__, section, key, err->message, err->code);
+ }
+ g_debug("%s: Returning default value for '[%s] %s'=%s.\n",
+ __FUNCTION__, section, key, defValue ? defValue : "(null)");
+ value = defValue;
+ g_clear_error(&err);
+ }
+ return value;
+}
--- open-vm-tools-10.0.5-3227872/lib/syncDriver/Makefile.am 2015-11-23 23:07:44.000000000 -0800
+++ open-vm-tools-10.0.5-3227872/lib/syncDriver/Makefile.am 2017-01-11 02:07:53.000000000 -0800
@@ -1,5 +1,5 @@
################################################################################
-### Copyright (C) 2007-2015 VMware, Inc. All rights reserved.
+### Copyright (C) 2007-2016 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
@@ -17,6 +17,9 @@
noinst_LTLIBRARIES = libSyncDriver.la
+libSyncDriver_la_CPPFLAGS =
+libSyncDriver_la_CPPFLAGS += @GLIB2_CPPFLAGS@
+
libSyncDriver_la_SOURCES =
libSyncDriver_la_SOURCES += syncDriverPosix.c
--- open-vm-tools-10.0.5-3227872/lib/syncDriver/nullDriver.c 2015-11-23 23:07:44.000000000 -0800
+++ open-vm-tools-10.0.5-3227872/lib/syncDriver/nullDriver.c 2017-01-11 02:08:10.000000000 -0800
@@ -1,5 +1,5 @@
/*********************************************************
- * Copyright (C) 2011-2015 VMware, Inc. All rights reserved.
+ * Copyright (C) 2011-2016 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
@@ -63,7 +63,7 @@
*/
SyncDriverErr
-NullDriver_Freeze(const char *paths,
+NullDriver_Freeze(const GSList *paths,
SyncDriverHandle *handle)
{
/*
--- open-vm-tools-10.0.5-3227872/lib/syncDriver/syncDriverInt.h 2015-11-23 23:07:44.000000000 -0800
+++ open-vm-tools-10.0.5-3227872/lib/syncDriver/syncDriverInt.h 2017-01-11 02:08:10.000000000 -0800
@@ -1,5 +1,5 @@
/*********************************************************
- * Copyright (C) 2011-2015 VMware, Inc. All rights reserved.
+ * Copyright (C) 2011-2016 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
@@ -25,19 +25,22 @@
* Internal definitions for the sync driver library.
*/
+#include <glib.h>
#include "syncDriver.h"
#define LGPFX "SyncDriver: "
#if !defined(Win32)
+#define SYNCDRIVER_PATH_SEPARATOR ':'
+
typedef enum {
SD_SUCCESS,
SD_ERROR,
SD_UNAVAILABLE,
} SyncDriverErr;
-typedef SyncDriverErr (*SyncFreezeFn)(const char *paths,
+typedef SyncDriverErr (*SyncFreezeFn)(const GSList *paths,
SyncDriverHandle *handle);
typedef struct SyncHandle {
@@ -47,15 +50,15 @@
#if defined(linux)
SyncDriverErr
-LinuxDriver_Freeze(const char *userPaths,
+LinuxDriver_Freeze(const GSList *userPaths,
SyncDriverHandle *handle);
SyncDriverErr
-VmSync_Freeze(const char *userPaths,
+VmSync_Freeze(const GSList *userPaths,
SyncDriverHandle *handle);
SyncDriverErr
-NullDriver_Freeze(const char *userPaths,
+NullDriver_Freeze(const GSList *userPaths,
SyncDriverHandle *handle);
#endif
--- open-vm-tools-10.0.5-3227872/lib/syncDriver/syncDriverLinux.c 2015-11-23 23:07:44.000000000 -0800
+++ open-vm-tools-10.0.5-3227872/lib/syncDriver/syncDriverLinux.c 2017-01-11 02:08:10.000000000 -0800
@@ -1,5 +1,5 @@
/*********************************************************
- * Copyright (C) 2011-2015 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
@@ -32,7 +32,6 @@
#include <sys/ioctl.h>
#include "debug.h"
#include "dynbuf.h"
-#include "strutil.h"
#include "syncDriverInt.h"
/* Out toolchain headers are somewhat outdated and don't define these. */
@@ -70,8 +69,13 @@
LinuxDriver *sync = (LinuxDriver *) handle;
SyncDriverErr err = SD_SUCCESS;
- for (i = 0; i < sync->fdCnt; i++) {
- if (ioctl(sync->fds[i], FITHAW) == -1) {
+ /*
+ * Thaw in the reverse order of freeze
+ */
+ for (i = sync->fdCnt; i > 0; i--) {
+ Debug(LGPFX "Thawing fd=%d.\n", sync->fds[i-1]);
+ if (ioctl(sync->fds[i-1], FITHAW) == -1) {
+ Debug(LGPFX "Thaw failed for fd=%d.\n", sync->fds[i-1]);
err = SD_ERROR;
}
}
@@ -98,8 +102,12 @@
LinuxDriver *sync = (LinuxDriver *) handle;
size_t i;
- for (i = 0; i < sync->fdCnt; i++) {
- close(sync->fds[i]);
+ /*
+ * Close in the reverse order of open
+ */
+ for (i = sync->fdCnt; i > 0; i--) {
+ Debug(LGPFX "Closing fd=%d.\n", sync->fds[i-1]);
+ close(sync->fds[i-1]);
}
free(sync->fds);
free(sync);
@@ -120,7 +128,7 @@
* slow when guest is performing significant IO. Therefore, caller should
* consider running this function in a separate thread.
*
- * @param[in] paths Paths to freeze (colon-separated).
+ * @param[in] paths List of paths to freeze.
* @param[out] handle Handle to use for thawing.
*
* @return A SyncDriverErr.
@@ -129,13 +137,10 @@
*/
SyncDriverErr
-LinuxDriver_Freeze(const char *paths,
+LinuxDriver_Freeze(const GSList *paths,
SyncDriverHandle *handle)
{
- char *path;
- int fd;
- size_t count = 0;
- unsigned int index = 0;
+ ssize_t count = 0;
Bool first = TRUE;
DynBuf fds;
LinuxDriver *sync = NULL;
@@ -143,7 +148,7 @@
DynBuf_Init(&fds);
- Debug(LGPFX "Freezing %s using Linux ioctls...\n", paths);
+ Debug(LGPFX "Freezing using Linux ioctls...\n");
sync = calloc(1, sizeof *sync);
if (sync == NULL) {
@@ -154,12 +159,20 @@
sync->driver.close = LinuxFiClose;
/*
+ * Ensure we did not get an empty list
+ */
+ VERIFY(paths != NULL);
+
+ /*
* Iterate through the requested paths. If we get an error for the first
* path, and it's not EPERM, assume that the ioctls are not available in
* the current kernel.
*/
- while ((path = StrUtil_GetNextToken(&index, paths, ":")) != NULL) {
+ while (paths != NULL) {
+ int fd;
+ const char *path = paths->data;
Debug(LGPFX "opening path '%s'.\n", path);
+ paths = g_slist_next(paths);
fd = open(path, O_RDONLY);
if (fd == -1) {
switch (errno) {
@@ -169,7 +182,6 @@
* as users with permission 700, so just ignore these.
*/
Debug(LGPFX "cannot access mounted directory '%s'.\n", path);
- free(path);
continue;
case EIO:
@@ -179,19 +191,17 @@
* this should be enough. Just skip.
*/
Debug(LGPFX "I/O error reading directory '%s'.\n", path);
- free(path);
continue;
default:
Debug(LGPFX "failed to open '%s': %d (%s)\n",
path, errno, strerror(errno));
err = SD_ERROR;
- free(path);
goto exit;
}
}
- Debug(LGPFX "freezing path '%s'.\n", path);
+ Debug(LGPFX "freezing path '%s' (fd=%d).\n", path, fd);
if (ioctl(fd, FIFREEZE) == -1) {
int ioctlerr = errno;
/*
@@ -211,17 +221,15 @@
Debug(LGPFX "failed to freeze '%s': %d (%s)\n",
path, ioctlerr, strerror(ioctlerr));
err = first && ioctlerr == ENOTTY ? SD_UNAVAILABLE : SD_ERROR;
- free(path);
break;
}
} else {
- Debug(LGPFX "successfully froze '%s'.\n", path);
+ Debug(LGPFX "successfully froze '%s' (fd=%d).\n", path, fd);
if (!DynBuf_Append(&fds, &fd, sizeof fd)) {
if (ioctl(fd, FITHAW) == -1) {
Warning(LGPFX "failed to thaw '%s': %d (%s)\n",
path, errno, strerror(errno));
}
- free(path);
close(fd);
err = SD_ERROR;
break;
@@ -229,7 +237,6 @@
count++;
}
- free(path);
first = FALSE;
}
--- open-vm-tools-10.0.5-3227872/lib/syncDriver/syncDriverPosix.c 2015-11-23 23:07:44.000000000 -0800
+++ open-vm-tools-10.0.5-3227872/lib/syncDriver/syncDriverPosix.c 2017-01-11 02:08:10.000000000 -0800
@@ -1,5 +1,5 @@
/*********************************************************
- * Copyright (C) 2005-2015 VMware, Inc. All rights reserved.
+ * Copyright (C) 2005-2016 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
@@ -25,9 +25,9 @@
#include <stdio.h>
#include <sys/param.h>
#include <sys/mount.h>
+#include <glib.h>
#include "vmware.h"
#include "debug.h"
-#include "dynbuf.h"
#include "str.h"
#include "syncDriverInt.h"
#include "util.h"
@@ -85,19 +85,21 @@
/*
*-----------------------------------------------------------------------------
*
- * SyncDriverListMounts --
+ * SyncDriverLocalMounts --
*
- * Returns a newly allocated string containing a list of colon-separated
- * mount paths in the system. No filtering is done, so all paths are added.
- * This assumes that the driver allows "unfreezable" paths to be provided
- * to the freeze command.
+ * Returns a singly-linked list of all local disk paths mounted in the
+ * system filtering out remote file systems. There is no filtering for
+ * other mount points because we assume that the underlying driver and
+ * IOCTL can deal with "unfreezable" paths. The returned list of paths
+ * is in the reverse order of the paths returned by GETNEXT_MNTINFO.
+ * Caller must free each path and the list itself.
*
* XXX: mntinfo.h mentions Solaris and Linux, but not FreeBSD. If we ever
* have a FreeBSD sync driver, we should make sure this function also
* works there.
*
* Results:
- * The list of devices to freeze, or NULL on failure.
+ * GSList* on success, NULL on failure.
*
* Side effects:
* None
@@ -105,21 +107,20 @@
*-----------------------------------------------------------------------------
*/
-static char *
-SyncDriverListMounts(void)
+static GSList *
+SyncDriverLocalMounts(void)
{
- char *paths = NULL;
- DynBuf buf;
+ GSList *paths = NULL;
MNTHANDLE mounts;
DECLARE_MNTINFO(mntinfo);
if ((mounts = OPEN_MNTFILE("r")) == NULL) {
+ Warning(LGPFX "Failed to open mount point table.\n");
return NULL;
}
- DynBuf_Init(&buf);
-
while (GETNEXT_MNTINFO(mounts, mntinfo)) {
+ char *path;
/*
* Skip remote mounts because they are not freezable and opening them
* could lead to hangs. See PR 1196785.
@@ -130,29 +131,21 @@
continue;
}
+ path = Util_SafeStrdup(MNTINFO_MNTPT(mntinfo));
+
/*
- * Add a separator if it's not the first path, and add the path to the
- * tail of the list.
+ * A mount point could depend on existence of a previous mount
+ * point like a loopback. In order to avoid deadlock/hang in
+ * freeze operation, a mount point needs to be frozen before
+ * its dependency is frozen.
+ * Typically, mount points are listed in the order they are
+ * mounted by the system i.e. dependent comes after the
+ * dependency. So, we need to keep them in reverse order of
+ * mount points to achieve the dependency order.
*/
- if ((DynBuf_GetSize(&buf) != 0 && !DynBuf_Append(&buf, ":", 1))
- || !DynBuf_Append(&buf,
- MNTINFO_MNTPT(mntinfo),
- strlen(MNTINFO_MNTPT(mntinfo)))) {
- goto exit;
- }
- }
-
- if (!DynBuf_Append(&buf, "\0", 1)) {
- goto exit;
+ paths = g_slist_prepend(paths, path);
}
- paths = DynBuf_AllocGet(&buf);
- if (paths == NULL) {
- Debug(LGPFX "Failed to allocate path list.\n");
- }
-
-exit:
- DynBuf_Destroy(&buf);
(void) CLOSE_MNTFILE(mounts);
return paths;
}
@@ -185,6 +178,29 @@
/*
*-----------------------------------------------------------------------------
*
+ * SyncDriverFreePath --
+ *
+ * A GFunc for freeing path strings. It is intended for g_slist_foreach.
+ *
+ * Results:
+ * None
+ *
+ * Side effects:
+ * None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static void
+SyncDriverFreePath(gpointer data, gpointer userData)
+{
+ free(data);
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
* SyncDriver_Freeze --
*
* Freeze I/O on the indicated drives. "all" means all drives.
@@ -214,14 +230,11 @@
Bool enableNullDriver, // IN
SyncDriverHandle *handle) // OUT
{
- char *paths = NULL;
+ GSList *paths = NULL;
SyncDriverErr err = SD_UNAVAILABLE;
size_t i = 0;
/*
- * First, convert the given path list to something the backends will
- * understand: a colon-separated list of paths.
- *
* NOTE: Ignore disk UUIDs. We ignore the userPaths if it does
* not start with '/' because all paths are absolute and it is
* possible only when we get diskUUID as userPaths. So, all
@@ -229,26 +242,42 @@
*/
if (userPaths == NULL ||
Str_Strncmp(userPaths, "all", sizeof "all") == 0 ||
- *userPaths != '/') {
- paths = SyncDriverListMounts();
- if (paths == NULL) {
- Debug(LGPFX "Failed to list mount points.\n");
- return SD_ERROR;
- }
+ userPaths[0] != '/') {
+ paths = SyncDriverLocalMounts();
} else {
/*
- * The sync driver API specifies spaces as separators, but the driver
- * uses colons as the path separator on Unix.
+ * The sync driver API specifies spaces as separators.
*/
- char *c;
- paths = Util_SafeStrdup(userPaths);
- for (c = paths; *c != '\0'; c++) {
- if (*c == ' ') {
- *c = ':';
+ while (*userPaths != '\0') {
+ const char *c;
+ char *path;
+
+ if (*userPaths == ' ') {
+ /*
+ * Trim spaces from beginning
+ */
+ userPaths++;
+ continue;
+ }
+
+ c = strchr(userPaths, ' ');
+ if (c == NULL) {
+ path = Util_SafeStrdup(userPaths);
+ paths = g_slist_append(paths, path);
+ break;
+ } else {
+ path = Util_SafeStrndup(userPaths, c - userPaths);
+ paths = g_slist_append(paths, path);
+ userPaths = c;
}
}
}
+ if (paths == NULL) {
+ Warning(LGPFX "No paths to freeze.\n");
+ return SD_ERROR;
+ }
+
while (err == SD_UNAVAILABLE && i < ARRAYSIZE(gBackends)) {
SyncFreezeFn freezeFn = gBackends[i];
Debug(LGPFX "Calling backend %d.\n", (int) i);
@@ -262,7 +291,12 @@
err = freezeFn(paths, handle);
}
- free(paths);
+ /*
+ * g_slist_free_full requires glib >= v2.28
+ */
+ g_slist_foreach(paths, SyncDriverFreePath, NULL);
+ g_slist_free(paths);
+
return err == SD_SUCCESS;
}
--- open-vm-tools-10.0.5-3227872/lib/syncDriver/vmSyncDriver.c 2015-11-23 23:07:44.000000000 -0800
+++ open-vm-tools-10.0.5-3227872/lib/syncDriver/vmSyncDriver.c 2017-01-11 02:08:10.000000000 -0800
@@ -1,5 +1,5 @@
/*********************************************************
- * Copyright (C) 2011-2015 VMware, Inc. All rights reserved.
+ * Copyright (C) 2011-2016 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
@@ -24,9 +24,11 @@
#include <fcntl.h>
#include <sys/ioctl.h>
+#include <glib.h>
#include "debug.h"
#include "syncDriverInt.h"
#include "syncDriverIoc.h"
+#include "strutil.h"
#include "util.h"
#define SYNC_PROC_PATH "/proc/driver/vmware-sync"
@@ -89,7 +91,7 @@
* Opens a description to the driver's proc node, and if successful, send an
* ioctl to freeze the requested filesystems.
*
- * @param[in] paths Paths to freeze (colon-delimited).
+ * @param[in] paths List of paths to freeze.
* @param[out] handle Where to store the handle to use for thawing.
*
* @return A SyncDriverErr.
@@ -98,19 +100,41 @@
*/
SyncDriverErr
-VmSync_Freeze(const char *paths,
+VmSync_Freeze(const GSList *paths,
SyncDriverHandle *handle)
{
int file;
+ Bool first = TRUE;
+ char *allPaths = NULL;
VmSyncDriver *sync = NULL;
- Debug(LGPFX "Freezing %s using vmsync driver...\n", paths);
+ Debug(LGPFX "Freezing using vmsync driver...\n");
file = open(SYNC_PROC_PATH, O_RDONLY);
if (file == -1) {
return SD_UNAVAILABLE;
}
+ /*
+ * Ensure we did not get an empty list
+ */
+ VERIFY(paths != NULL);
+
+ /*
+ * Concatenate all paths in the list into one string
+ */
+ while (paths != NULL) {
+ if (!first) {
+ /*
+ * Append the separator (':')
+ */
+ StrUtil_SafeStrcat(&allPaths, ":");
+ }
+ StrUtil_SafeStrcat(&allPaths, paths->data);
+ first = FALSE;
+ paths = g_slist_next(paths);
+ }
+
sync = calloc(1, sizeof *sync);
if (sync == NULL) {
goto exit;
@@ -120,7 +144,9 @@
sync->driver.close = VmSyncClose;
sync->fd = file;
- if (ioctl(file, SYNC_IOC_FREEZE, paths) == -1) {
+ Debug(LGPFX "Freezing %s using vmsync driver...\n", allPaths);
+
+ if (ioctl(file, SYNC_IOC_FREEZE, allPaths) == -1) {
free(sync);
sync = NULL;
}
@@ -133,6 +159,7 @@
} else {
*handle = &sync->driver;
}
+ free(allPaths);
return sync != NULL ? SD_SUCCESS : SD_ERROR;
}
--- open-vm-tools-10.0.5-3227872/services/plugins/vmbackup/README 2015-11-23 23:07:44.000000000 -0800
+++ open-vm-tools-10.0.5-3227872/services/plugins/vmbackup/README 2017-01-11 02:08:10.000000000 -0800
@@ -24,6 +24,10 @@
| d |
\/ |
SCRIPT_THAW --------
+ | |
+ | f | g
+ \/ |
+ COMPLETE_WAIT-------
The transitions mean the following events / conditions:
@@ -33,6 +37,8 @@
c. vmbackup.snapshotDone RPC
d. sync provider operation is finished
e. error condition: runtime error, or vmbackup.abort RPC
+f. thaw scripts run finished
+g. get notification that snapshot succeeds
Sending a vmbackup.start RPC while the state machine is not IDLE causes an
error to be returned to the client, but the state machine is not changed.
--- open-vm-tools-10.0.5-3227872/services/plugins/vmbackup/nullProvider.c 2015-11-23 23:07:44.000000000 -0800
+++ open-vm-tools-10.0.5-3227872/services/plugins/vmbackup/nullProvider.c 2017-01-11 02:08:10.000000000 -0800
@@ -1,5 +1,5 @@
/*********************************************************
- * Copyright (C) 2010-2015 VMware, Inc. All rights reserved.
+ * Copyright (C) 2010-2016 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
@@ -32,6 +32,7 @@
#if defined(_WIN32)
+
/*
******************************************************************************
* VmBackupNullStart -- */ /**
@@ -54,14 +55,128 @@
return VmBackup_SendEvent(VMBACKUP_EVENT_SNAPSHOT_COMMIT, 0, "");
}
+
+/*
+ ******************************************************************************
+ * VmBackupNullSnapshotDone -- */ /**
+ *
+ * Does nothing, just keep the backup state machine alive.
+ *
+ * @param[in] state Backup state.
+ * @param[in] clientData Unused.
+ *
+ * @return TRUE.
+ *
+ ******************************************************************************
+ */
+
+static Bool
+VmBackupNullSnapshotDone(VmBackupState *state,
+ void *clientData)
+{
+ VmBackup_SetCurrentOp(state, NULL, NULL, __FUNCTION__);
+ return TRUE;
+}
+
#else
/*
******************************************************************************
+ * VmBackupNullReadyForSnapshot -- */ /**
+ *
+ * Sends an event to the VMX indicating that the guest is ready for a
+ * snapshot to be taken (i.e., scripts have run and Nulldriver is
+ * enabled).
+ *
+ * @param[in] state Backup state.
+ *
+ * @return TRUE, unless sending the message fails.
+ *
+ ******************************************************************************
+ */
+
+static Bool
+VmBackupNullReadyForSnapshot(VmBackupState *state)
+{
+ Bool success;
+
+ g_debug("*** %s\n", __FUNCTION__);
+ success = VmBackup_SendEvent(VMBACKUP_EVENT_SNAPSHOT_COMMIT, 0, "");
+ if (success) {
+ state->freezeStatus = VMBACKUP_FREEZE_FINISHED;
+ } else {
+ g_warning("Failed to send commit event to host");
+ state->freezeStatus = VMBACKUP_FREEZE_ERROR;
+ }
+ return success;
+}
+
+
+/*
+ ******************************************************************************
+ * VmBackupNullOpQuery -- */ /**
+ *
+ * Checks the status of the operation that is enabling or disabling the
+ * Null driver. Nulldriver is enabled immediately and there is nothing
+ * to disable.
+ *
+ * @param[in] op VmBackupOp.
+ *
+ * @return VMBACKUP_STATUS_FINISHED always.
+ *
+ ******************************************************************************
+ */
+
+static VmBackupOpStatus
+VmBackupNullOpQuery(VmBackupOp *op) // IN
+{
+ return VMBACKUP_STATUS_FINISHED;
+}
+
+
+/*
+ ******************************************************************************
+ * VmBackupNullOpRelease -- */ /**
+ *
+ * Cleans up data held by the op object.
+ *
+ * @param[in] op VmBackupOp.
+ *
+ ******************************************************************************
+ */
+
+static void
+VmBackupNullOpRelease(VmBackupOp *op) // IN
+{
+ g_free(op);
+}
+
+
+/*
+ ******************************************************************************
+ * VmBackupNullOpCancel -- */ /**
+ *
+ * Cancel an ongoing Nulldriver operation. This doesn't actually
+ * do anything because there is no operation to cancel as such.
+ *
+ * @param[in] op VmBackupOp.
+ *
+ ******************************************************************************
+ */
+
+static void
+VmBackupNullOpCancel(VmBackupOp *op) // IN
+{
+ /* Nothing to do */
+}
+
+
+/*
+ ******************************************************************************
* VmBackupNullStart -- */ /**
*
- * Calls sync(2) on POSIX systems. Sends the "commit snapshot" event to the
- * host.
+ * Calls sync(2) on POSIX systems. Sets up an asynchronous operation
+ * for tracking.
*
* @param[in] ctx Plugin context.
* @param[in] state Backup state.
@@ -73,28 +188,35 @@
VmBackupNullStart(ToolsAppCtx *ctx,
void *clientData)
{
+ VmBackupOp *op;
VmBackupState *state = (VmBackupState*) clientData;
+
+ g_debug("*** %s\n", __FUNCTION__);
+
+ op = g_new0(VmBackupOp, 1);
+ op->queryFn = VmBackupNullOpQuery;
+ op->cancelFn = VmBackupNullOpCancel;
+ op->releaseFn = VmBackupNullOpRelease;
+
/*
* This is more of a "let's at least do something" than something that
* will actually ensure data integrity...
*/
sync();
- VmBackup_SetCurrentOp(state, NULL, NULL, __FUNCTION__);
- if (!VmBackup_SendEvent(VMBACKUP_EVENT_SNAPSHOT_COMMIT, 0, "")) {
- g_warning("Failed to send commit event to host");
- state->freezeStatus = VMBACKUP_FREEZE_ERROR;
- } else {
- state->freezeStatus = VMBACKUP_FREEZE_FINISHED;
- }
+
+ VmBackup_SetCurrentOp(state,
+ op,
+ VmBackupNullReadyForSnapshot,
+ __FUNCTION__);
}
-#endif
/*
******************************************************************************
* VmBackupNullSnapshotDone -- */ /**
*
- * Does nothing, just keep the backup state machine alive.
+ * Does nothing except setting up an asynchronous operation to keep the
+ * backup state machine alive.
*
* @param[in] state Backup state.
* @param[in] clientData Unused.
@@ -108,10 +230,20 @@
VmBackupNullSnapshotDone(VmBackupState *state,
void *clientData)
{
- VmBackup_SetCurrentOp(state, NULL, NULL, __FUNCTION__);
+ VmBackupOp *op;
+
+ g_debug("*** %s\n", __FUNCTION__);
+
+ op = g_new0(VmBackupOp, 1);
+ op->queryFn = VmBackupNullOpQuery;
+ op->cancelFn = VmBackupNullOpCancel;
+ op->releaseFn = VmBackupNullOpRelease;
+
+ VmBackup_SetCurrentOp(state, op, NULL, __FUNCTION__);
return TRUE;
}
+#endif
/*
******************************************************************************
--- open-vm-tools-10.0.5-3227872/services/plugins/vmbackup/stateMachine.c 2015-11-23 23:07:44.000000000 -0800
+++ open-vm-tools-10.0.5-3227872/services/plugins/vmbackup/stateMachine.c 2017-01-11 02:08:10.000000000 -0800
@@ -1,5 +1,5 @@
/*********************************************************
- * Copyright (C) 2007-2015 VMware, Inc. All rights reserved.
+ * Copyright (C) 2007-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
@@ -74,6 +74,18 @@
NULL); \
} while (0)
+/*
+ * Macros to read values from config file.
+ */
+#define VMBACKUP_CONFIG_GET_BOOL(config, key, defVal) \
+ VMTools_ConfigGetBoolean(config, "vmbackup", key, defVal)
+
+#define VMBACKUP_CONFIG_GET_STR(config, key, defVal) \
+ VMTools_ConfigGetString(config, "vmbackup", key, defVal)
+
+#define VMBACKUP_CONFIG_GET_INT(config, key, defVal) \
+ VMTools_ConfigGetInteger(config, "vmbackup", key, defVal)
+
static VmBackupState *gBackupState = NULL;
static Bool
@@ -82,6 +94,9 @@
static Bool
VmBackupEnableSyncWait(void);
+static Bool
+VmBackupEnableCompleteWait(void);
+
/**
* Returns a string representation of the given state machine state.
@@ -113,6 +128,9 @@
case VMBACKUP_MSTATE_SCRIPT_THAW:
return "SCRIPT_THAW";
+ case VMBACKUP_MSTATE_COMPLETE_WAIT:
+ return "COMPLETE_WAIT";
+
case VMBACKUP_MSTATE_SCRIPT_ERROR:
return "SCRIPT_ERROR";
@@ -249,7 +267,8 @@
#endif
if (!success) {
- g_warning("Failed to send vmbackup event: %s.\n", result);
+ g_warning("Failed to send vmbackup event: %s, result: %s.\n",
+ msg, result);
}
vm_free(result);
g_free(msg);
@@ -299,6 +318,9 @@
}
gBackupState->provider->release(gBackupState->provider);
+ if (gBackupState->completer != NULL) {
+ gBackupState->completer->release(gBackupState->completer);
+ }
g_static_mutex_free(&gBackupState->opLock);
g_free(gBackupState->scriptArg);
g_free(gBackupState->volumes);
@@ -393,6 +415,7 @@
break;
case VMBACKUP_MSTATE_SCRIPT_THAW:
+ case VMBACKUP_MSTATE_COMPLETE_WAIT:
/* Next state is "idle". */
gBackupState->machineState = VMBACKUP_MSTATE_IDLE;
break;
@@ -417,6 +440,7 @@
ASSERT(gBackupState != NULL);
if (gBackupState->machineState != VMBACKUP_MSTATE_SCRIPT_ERROR &&
gBackupState->machineState != VMBACKUP_MSTATE_SYNC_ERROR) {
+ const char *eventMsg = "Quiesce aborted.";
/* Mark the current operation as cancelled. */
g_static_mutex_lock(&gBackupState->opLock);
if (gBackupState->currentOp != NULL) {
@@ -426,9 +450,21 @@
}
g_static_mutex_unlock(&gBackupState->opLock);
+#ifdef __linux__
+ /* Thaw the guest if already quiesced */
+ if (gBackupState->machineState == VMBACKUP_MSTATE_SYNC_FREEZE) {
+ g_debug("Guest already quiesced, thawing for abort\n");
+ if (!gBackupState->provider->snapshotDone(gBackupState,
+ gBackupState->provider->clientData)) {
+ g_debug("Thaw during abort failed\n");
+ eventMsg = "Quiesce could not be aborted.";
+ }
+ }
+#endif
+
VmBackup_SendEvent(VMBACKUP_EVENT_REQUESTOR_ABORT,
VMBACKUP_REMOTE_ABORT,
- "Quiesce aborted.");
+ eventMsg);
/* Transition to the error state. */
if (VmBackupOnError()) {
@@ -459,51 +495,49 @@
/**
- * Callback that checks for the status of the current operation. Calls the
- * queued operations as needed.
+ * Post-process the current operation. Calls the queued
+ * operations as needed.
*
- * @param[in] clientData Unused.
+ * @param[out] pending Tells if currentOp is pending.
*
- * @return FALSE
+ * @return TRUE if currentOp finished or pending, FALSE on error.
*/
static gboolean
-VmBackupAsyncCallback(void *clientData)
+VmBackupPostProcessCurrentOp(gboolean *pending)
{
+ gboolean retVal = TRUE;
VmBackupOpStatus status = VMBACKUP_STATUS_FINISHED;
g_debug("*** %s\n", __FUNCTION__);
ASSERT(gBackupState != NULL);
- g_source_unref(gBackupState->timerEvent);
- gBackupState->timerEvent = NULL;
+ *pending = FALSE;
g_static_mutex_lock(&gBackupState->opLock);
+
if (gBackupState->currentOp != NULL) {
- g_debug("VmBackupAsyncCallback: checking %s\n", gBackupState->currentOpName);
+ g_debug("%s: checking %s\n", __FUNCTION__, gBackupState->currentOpName);
status = VmBackup_QueryStatus(gBackupState->currentOp);
}
- g_static_mutex_unlock(&gBackupState->opLock);
switch (status) {
case VMBACKUP_STATUS_PENDING:
+ *pending = TRUE;
goto exit;
case VMBACKUP_STATUS_FINISHED:
- g_static_mutex_lock(&gBackupState->opLock);
if (gBackupState->currentOpName != NULL) {
g_debug("Async request '%s' completed\n", gBackupState->currentOpName);
VmBackup_Release(gBackupState->currentOp);
gBackupState->currentOpName = NULL;
}
gBackupState->currentOp = NULL;
- g_static_mutex_unlock(&gBackupState->opLock);
break;
default:
{
gchar *msg;
- g_static_mutex_lock(&gBackupState->opLock);
if (gBackupState->errorMsg != NULL) {
msg = g_strdup_printf("'%s' operation failed: %s",
gBackupState->currentOpName,
@@ -519,8 +553,7 @@
VmBackup_Release(gBackupState->currentOp);
gBackupState->currentOp = NULL;
- g_static_mutex_unlock(&gBackupState->opLock);
- VmBackupOnError();
+ retVal = FALSE;
goto exit;
}
}
@@ -533,23 +566,62 @@
VmBackupCallback cb = gBackupState->callback;
gBackupState->callback = NULL;
+ /*
+ * Callback should not acquire opLock, but instead assume that
+ * it holds the lock already.
+ */
if (cb(gBackupState)) {
- g_static_mutex_lock(&gBackupState->opLock);
if (gBackupState->currentOp != NULL || gBackupState->forceRequeue) {
- g_static_mutex_unlock(&gBackupState->opLock);
goto exit;
}
- g_static_mutex_unlock(&gBackupState->opLock);
} else {
- VmBackupOnError();
+ retVal = FALSE;
goto exit;
}
}
+exit:
+ g_static_mutex_unlock(&gBackupState->opLock);
+ return retVal;
+}
+
+
+/**
+ * Callback to advance the state machine to next state once
+ * current operation finishes.
+ *
+ * @param[in] clientData Unused.
+ *
+ * @return FALSE
+ */
+
+static gboolean
+VmBackupAsyncCallback(void *clientData)
+{
+ gboolean opPending;
+ g_debug("*** %s\n", __FUNCTION__);
+ ASSERT(gBackupState != NULL);
+
+ g_source_unref(gBackupState->timerEvent);
+ gBackupState->timerEvent = NULL;
+
/*
- * At this point, the current operation can be declared finished, and the
- * state machine can move to the next state.
+ * Move the state machine to the next state, if the
+ * currentOp has finished.
*/
+ if (!VmBackupPostProcessCurrentOp(&opPending)) {
+ VmBackupOnError();
+ goto exit;
+ } else {
+ /*
+ * State transition can't be done if currentOp
+ * has not finished yet.
+ */
+ if (opPending) {
+ goto exit;
+ }
+ }
+
switch (gBackupState->machineState) {
case VMBACKUP_MSTATE_SCRIPT_FREEZE:
/* Next state is "sync freeze wait". */
@@ -583,8 +655,15 @@
}
break;
- case VMBACKUP_MSTATE_SCRIPT_ERROR:
case VMBACKUP_MSTATE_SCRIPT_THAW:
+ /* Next state is "complete wait" or "idle". */
+ if (!VmBackupEnableCompleteWait()) {
+ VmBackupOnError();
+ }
+ break;
+
+ case VMBACKUP_MSTATE_SCRIPT_ERROR:
+ case VMBACKUP_MSTATE_COMPLETE_WAIT:
/* Next state is "idle". */
gBackupState->machineState = VMBACKUP_MSTATE_IDLE;
break;
@@ -676,6 +755,62 @@
/**
+ * Calls the completer's start function and moves the state
+ * machine to next state.
+ *
+ * @return Whether the completer's start callback was successful.
+ */
+
+static Bool
+VmBackupEnableCompleteWait(void)
+{
+ Bool ret = TRUE;
+
+ g_debug("*** %s\n", __FUNCTION__);
+
+ if (gBackupState->completer == NULL) {
+ gBackupState->machineState = VMBACKUP_MSTATE_IDLE;
+ goto exit;
+ }
+
+ if (gBackupState->abortTimer != NULL) {
+ g_source_destroy(gBackupState->abortTimer);
+ g_source_unref(gBackupState->abortTimer);
+
+ /* Host make timeout maximum as 15 minutes for complete process. */
+ if (gBackupState->timeout > GUEST_QUIESCE_DEFAULT_TIMEOUT_IN_SEC) {
+ gBackupState->timeout = GUEST_QUIESCE_DEFAULT_TIMEOUT_IN_SEC;
+ }
+
+ if (gBackupState->timeout != 0) {
+ g_debug("Using completer timeout: %u\n", gBackupState->timeout);
+ gBackupState->abortTimer =
+ g_timeout_source_new_seconds(gBackupState->timeout);
+ VMTOOLSAPP_ATTACH_SOURCE(gBackupState->ctx,
+ gBackupState->abortTimer,
+ VmBackupAbortTimer,
+ NULL,
+ NULL);
+ }
+ }
+
+ if (gBackupState->completer->start(gBackupState,
+ gBackupState->completer->clientData)) {
+ /* Move to next state */
+ gBackupState->machineState = VMBACKUP_MSTATE_COMPLETE_WAIT;
+ } else {
+ VmBackup_SendEvent(VMBACKUP_EVENT_REQUESTOR_ERROR,
+ VMBACKUP_SYNC_ERROR,
+ "Error when enabling the sync provider.");
+ ret = FALSE;
+ }
+
+exit:
+ return ret;
+}
+
+
+/**
* After sync provider's start function returns and moves the state
* machine to VMBACKUP_MSTATE_SYNC_FREEZE state.
*
@@ -709,36 +844,6 @@
/**
- * Get boolean entry for the key from the config file.
- *
- * @param[in] config Config file to read the key from.
- * @param[in] key Key to look for in the config file.
- * @param[in] defaultValue Default value if the key is not found.
- */
-
-static gboolean
-VmBackupConfigGetBoolean(GKeyFile *config,
- const char *key,
- gboolean defValue)
-{
- GError *err = NULL;
- gboolean value = defValue;
-
- if (key != NULL) {
- value = g_key_file_get_boolean(config,
- "vmbackup",
- key,
- &err);
- if (err != NULL) {
- g_clear_error(&err);
- value = defValue;
- }
- }
- return value;
-}
-
-
-/**
* Starts the quiesce operation according to the supplied specification unless
* some unexpected error occurs.
*
@@ -754,9 +859,9 @@
VmBackupStartCommon(RpcInData *data,
gboolean forceQuiesce)
{
- GError *err = NULL;
ToolsAppCtx *ctx = data->appCtx;
VmBackupSyncProvider *provider = NULL;
+ VmBackupSyncCompleter *completer = NULL;
size_t i;
@@ -779,7 +884,7 @@
* only allow VSS provider
*/
#if defined(_WIN32)
- if (VmBackupConfigGetBoolean(ctx->config, "enableVSS", TRUE)) {
+ if (VMBACKUP_CONFIG_GET_BOOL(ctx->config, "enableVSS", TRUE)) {
provider = VmBackup_NewVssProvider();
}
#elif defined(_LINUX) || defined(__linux__)
@@ -788,9 +893,9 @@
* only allow SyncDriver provider
*/
if (gBackupState->quiesceFS &&
- VmBackupConfigGetBoolean(ctx->config, "enableSyncDriver", TRUE)) {
+ VMBACKUP_CONFIG_GET_BOOL(ctx->config, "enableSyncDriver", TRUE)) {
provider = VmBackup_NewSyncDriverOnlyProvider();
- }
+ }
#endif
} else {
/* If no quiescing is requested only allow null provider */
@@ -805,7 +910,7 @@
for (i = 0; i < ARRAYSIZE(providers); i++) {
struct SyncProvider *sp = &providers[i];
- if (VmBackupConfigGetBoolean(ctx->config, sp->cfgEntry, TRUE)) {
+ if (VMBACKUP_CONFIG_GET_BOOL(ctx->config, sp->cfgEntry, TRUE)) {
provider = sp->ctor();
if (provider != NULL) {
break;
@@ -816,15 +921,27 @@
ASSERT(provider != NULL);
+#if defined(_WIN32)
+ if (VMBACKUP_CONFIG_GET_BOOL(ctx->config, "enableVSS", TRUE)) {
+ completer = VmBackup_NewVssCompleter(provider);
+ if (completer == NULL) {
+ provider->release(provider);
+ g_warning("Requested quiescing cannot be initialized.");
+ goto error;
+ }
+ }
+#endif
+
/* Instantiate the backup state and start the operation. */
gBackupState->ctx = data->appCtx;
gBackupState->pollPeriod = 1000;
gBackupState->machineState = VMBACKUP_MSTATE_IDLE;
gBackupState->freezeStatus = VMBACKUP_FREEZE_FINISHED;
gBackupState->provider = provider;
+ gBackupState->completer = completer;
gBackupState->needsPriv = FALSE;
g_static_mutex_init(&gBackupState->opLock);
- gBackupState->enableNullDriver = VmBackupConfigGetBoolean(ctx->config,
+ gBackupState->enableNullDriver = VMBACKUP_CONFIG_GET_BOOL(ctx->config,
"enableNullDriver",
TRUE);
@@ -864,15 +981,8 @@
* See bug 506106.
*/
if (gBackupState->timeout == 0) {
- gBackupState->timeout = (guint) g_key_file_get_integer(
- gBackupState->ctx->config,
- "vmbackup",
- "timeout",
- &err);
- if (err != NULL) {
- g_clear_error(&err);
- gBackupState->timeout = 15 * 60;
- }
+ gBackupState->timeout = VMBACKUP_CONFIG_GET_INT(ctx->config, "timeout",
+ GUEST_QUIESCE_DEFAULT_TIMEOUT_IN_SEC);
}
/* Treat "0" as no timeout. */
@@ -898,6 +1008,9 @@
if (gBackupState->provider) {
gBackupState->provider->release(gBackupState->provider);
}
+ if (gBackupState->completer) {
+ gBackupState->completer->release(gBackupState->completer);
+ }
g_free(gBackupState->scriptArg);
g_free(gBackupState->volumes);
g_free(gBackupState);
@@ -923,6 +1036,8 @@
static gboolean
VmBackupStart(RpcInData *data)
{
+ ToolsAppCtx *ctx = data->appCtx;
+
g_debug("*** %s\n", __FUNCTION__);
if (gBackupState != NULL) {
return RPCIN_SETRETVALS(data, "Quiesce operation already in progress.",
@@ -936,12 +1051,26 @@
if (StrUtil_GetNextIntToken(&generateManifests, &index, data->args, " ")) {
gBackupState->generateManifests = generateManifests;
}
- gBackupState->quiesceApps = TRUE;
- gBackupState->quiesceFS = TRUE;
- gBackupState->allowHWProvider = TRUE;
- gBackupState->execScripts = TRUE;
- gBackupState->scriptArg = NULL;
- gBackupState->timeout = 0;
+ gBackupState->quiesceApps = VMBACKUP_CONFIG_GET_BOOL(ctx->config,
+ "quiesceApps",
+ TRUE);
+ gBackupState->quiesceFS = VMBACKUP_CONFIG_GET_BOOL(ctx->config,
+ "quiesceFS",
+ TRUE);
+ gBackupState->allowHWProvider = VMBACKUP_CONFIG_GET_BOOL(ctx->config,
+ "allowHWProvider",
+ TRUE);
+ gBackupState->execScripts = VMBACKUP_CONFIG_GET_BOOL(ctx->config,
+ "execScripts",
+ TRUE);
+ gBackupState->scriptArg = VMBACKUP_CONFIG_GET_STR(ctx->config,
+ "scriptArg",
+ NULL);
+ gBackupState->timeout = VMBACKUP_CONFIG_GET_INT(ctx->config,
+ "timeout", 0);
+ gBackupState->vssUseDefault = VMBACKUP_CONFIG_GET_BOOL(ctx->config,
+ "vssUseDefault",
+ TRUE);
/* get volume uuids if provided */
if (data->args[index] != '\0') {
@@ -949,7 +1078,9 @@
data->argsSize - index);
}
}
- return VmBackupStartCommon(data, FALSE);
+ return VmBackupStartCommon(data, VMBACKUP_CONFIG_GET_BOOL(ctx->config,
+ "forceQuiesce",
+ FALSE));
}
@@ -987,8 +1118,10 @@
static gboolean
VmBackupStartWithOpts(RpcInData *data)
{
+ ToolsAppCtx *ctx = data->appCtx;
GuestQuiesceParams *params;
- GuestQuiesceParamsV1 *paramsV1;
+ GuestQuiesceParamsV1 *paramsV1 = NULL;
+ GuestQuiesceParamsV2 *paramsV2;
gboolean retval;
g_debug("*** %s\n", __FUNCTION__);
@@ -997,24 +1130,57 @@
FALSE);
}
params = (GuestQuiesceParams *)data->args;
+
+#if defined(_WIN32)
+ if (params->ver != GUESTQUIESCEPARAMS_V1 &&
+ params->ver != GUESTQUIESCEPARAMS_V2) {
+ g_warning("%s: Incompatible quiesce parameter version. \n", __FUNCTION__);
+ return RPCIN_SETRETVALS(data, "Incompatible quiesce parameter version",
+ FALSE);
+ }
+#else
if (params->ver != GUESTQUIESCEPARAMS_V1) {
g_warning("%s: Incompatible quiesce parameter version. \n", __FUNCTION__);
return RPCIN_SETRETVALS(data, "Incompatible quiesce parameter version",
FALSE);
}
+#endif
+
gBackupState = g_new0(VmBackupState, 1);
- paramsV1 = params->GuestQuiesceParams_u.guestQuiesceParamsV1;
- gBackupState->generateManifests = paramsV1->createManifest;
- gBackupState->quiesceApps = paramsV1->quiesceApps;
- gBackupState->quiesceFS = paramsV1->quiesceFS;
- gBackupState->allowHWProvider = paramsV1->writableSnapshot;
- gBackupState->execScripts = paramsV1->execScripts;
- gBackupState->scriptArg = g_strndup(paramsV1->scriptArg,
- strlen(paramsV1->scriptArg));
- gBackupState->timeout = paramsV1->timeout;
- gBackupState->volumes = g_strndup(paramsV1->diskUuids,
- strlen(paramsV1->diskUuids));
- retval = VmBackupStartCommon(data, TRUE);
+
+ if (params->ver == GUESTQUIESCEPARAMS_V1) {
+ paramsV1 = params->GuestQuiesceParams_u.guestQuiesceParamsV1;
+ gBackupState->vssUseDefault = VMBACKUP_CONFIG_GET_BOOL(ctx->config,
+ "vssUseDefault",
+ TRUE);
+ } else if (params->ver == GUESTQUIESCEPARAMS_V2) {
+ paramsV2 = params->GuestQuiesceParams_u.guestQuiesceParamsV2;
+ paramsV1 = ¶msV2->paramsV1;
+ gBackupState->vssBackupContext = paramsV2->vssBackupContext;
+ gBackupState->vssBackupType = paramsV2->vssBackupType;
+ gBackupState->vssBootableSystemState = paramsV2->vssBootableSystemState;
+ gBackupState->vssPartialFileSupport = paramsV2->vssPartialFileSupport;
+ gBackupState->vssUseDefault = VMBACKUP_CONFIG_GET_BOOL(ctx->config,
+ "vssUseDefault",
+ FALSE);
+ }
+
+ if (paramsV1 != NULL) {
+ gBackupState->generateManifests = paramsV1->createManifest;
+ gBackupState->quiesceApps = paramsV1->quiesceApps;
+ gBackupState->quiesceFS = paramsV1->quiesceFS;
+ gBackupState->allowHWProvider = paramsV1->writableSnapshot;
+ gBackupState->execScripts = paramsV1->execScripts;
+ gBackupState->scriptArg = g_strndup(paramsV1->scriptArg,
+ strlen(paramsV1->scriptArg));
+ gBackupState->timeout = paramsV1->timeout;
+ gBackupState->volumes = g_strndup(paramsV1->diskUuids,
+ strlen(paramsV1->diskUuids));
+ }
+
+ retval = VmBackupStartCommon(data, VMBACKUP_CONFIG_GET_BOOL(ctx->config,
+ "forceQuiesce",
+ TRUE));
return retval;
}
@@ -1085,6 +1251,45 @@
/**
+ * Notifies the completer to complete the provider process
+ * machine in the COMPLETE_WAIT state.
+ *
+ * @param[in] data RPC data.
+ *
+ * @return TRUE
+ */
+
+static gboolean
+VmBackupSnapshotCompleted(RpcInData *data)
+{
+ g_debug("*** %s\n", __FUNCTION__);
+
+ if (gBackupState == NULL ||
+ gBackupState->completer == NULL) {
+ return RPCIN_SETRETVALS(data, "Error: no quiesce complete in progress",
+ FALSE);
+ } else if (gBackupState->machineState != VMBACKUP_MSTATE_COMPLETE_WAIT) {
+ g_warning("Error: unexpected state for snapshot complete message: %s",
+ VmBackupGetStateName(gBackupState->machineState));
+ return RPCIN_SETRETVALS(data,
+ "Error: unexpected state for complete message.",
+ FALSE);
+ } else {
+ if (!gBackupState->completer->snapshotCompleted(gBackupState,
+ gBackupState->completer->clientData)) {
+ VmBackup_SendEvent(VMBACKUP_EVENT_REQUESTOR_ERROR,
+ VMBACKUP_SYNC_ERROR,
+ "Error when notifying the sync completer.");
+ if (VmBackupOnError()) {
+ VmBackupFinalize();
+ }
+ }
+ return RPCIN_SETRETVALS(data, "", TRUE);
+ }
+}
+
+
+/**
* Prints some information about the plugin's state to the log.
*
* @param[in] src The source object.
@@ -1167,6 +1372,8 @@
{ VMBACKUP_PROTOCOL_START_WITH_OPTS, VmBackupStartWithOpts, NULL,
xdr_GuestQuiesceParams, NULL, sizeof (GuestQuiesceParams) },
{ VMBACKUP_PROTOCOL_ABORT, VmBackupAbort, NULL, NULL, NULL, 0 },
+ { VMBACKUP_PROTOCOL_SNAPSHOT_COMPLETED, VmBackupSnapshotCompleted, NULL,
+ NULL, NULL, 0 },
{ VMBACKUP_PROTOCOL_SNAPSHOT_DONE, VmBackupSnapshotDone, NULL, NULL, NULL, 0 }
};
ToolsPluginSignalCb sigs[] = {
--- open-vm-tools-10.0.5-3227872/services/plugins/vmbackup/syncDriverOps.c 2015-11-23 23:07:44.000000000 -0800
+++ open-vm-tools-10.0.5-3227872/services/plugins/vmbackup/syncDriverOps.c 2017-01-11 02:08:10.000000000 -0800
@@ -1,5 +1,5 @@
/*********************************************************
- * Copyright (C) 2007-2015 VMware, Inc. All rights reserved.
+ * Copyright (C) 2007-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
@@ -61,10 +61,10 @@
*/
static Bool
-VmBackupDriverThaw(VmBackupDriverOp *op)
+VmBackupDriverThaw(SyncDriverHandle *handle)
{
- Bool success = SyncDriver_Thaw(*op->syncHandle);
- SyncDriver_CloseHandle(op->syncHandle);
+ Bool success = SyncDriver_Thaw(*handle);
+ SyncDriver_CloseHandle(handle);
return success;
}
@@ -106,7 +106,7 @@
case SYNCDRIVER_IDLE:
if (op->canceled) {
- VmBackupDriverThaw(op);
+ VmBackupDriverThaw(op->syncHandle);
}
/*
* This prevents the release callback from freeing the handle, which
@@ -117,7 +117,7 @@
break;
default:
- VmBackupDriverThaw(op);
+ VmBackupDriverThaw(op->syncHandle);
ret = VMBACKUP_STATUS_ERROR;
break;
}
@@ -231,7 +231,7 @@
state->enableNullDriver : FALSE,
op->syncHandle);
} else {
- success = VmBackupDriverThaw(op);
+ success = VmBackupDriverThaw(op->syncHandle);
}
if (!success) {
g_warning("Error %s filesystems.", freeze ? "freezing" : "thawing");
@@ -264,15 +264,24 @@
static Bool
VmBackupSyncDriverReadyForSnapshot(VmBackupState *state)
{
- Bool success;
SyncDriverHandle *handle = state->clientData;
g_debug("*** %s\n", __FUNCTION__);
if (handle != NULL && *handle != SYNCDRIVER_INVALID_HANDLE) {
+ Bool success;
success = VmBackup_SendEvent(VMBACKUP_EVENT_SNAPSHOT_COMMIT, 0, "");
if (success) {
state->freezeStatus = VMBACKUP_FREEZE_FINISHED;
} else {
+ /*
+ * If the vmx does not know this event (e.g. due to an RPC timeout),
+ * then filesystems need to be thawed here because snapshotDone
+ * will not be sent by the vmx.
+ */
+ g_debug("VMX state changed; thawing filesystems.\n");
+ if (!VmBackupDriverThaw(handle)) {
+ g_warning("Error thawing filesystems.\n");
+ }
state->freezeStatus = VMBACKUP_FREEZE_ERROR;
}
return success;
@@ -488,7 +497,7 @@
static Bool
VmBackupSyncDriverOnlySnapshotDone(VmBackupState *state,
- void *clientData)
+ void *clientData)
{
VmBackupDriverOp *op;
--- open-vm-tools-10.0.5-3227872/services/plugins/vmbackup/vmBackupInt.h 2015-11-23 23:07:44.000000000 -0800
+++ open-vm-tools-10.0.5-3227872/services/plugins/vmbackup/vmBackupInt.h 2017-01-11 02:08:10.000000000 -0800
@@ -1,5 +1,5 @@
/*********************************************************
- * Copyright (C) 2008-2015 VMware, Inc. All rights reserved.
+ * Copyright (C) 2008-2016 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
@@ -35,6 +35,11 @@
#include "vmware/tools/threadPool.h"
#endif
+/*
+ * The default timeout in seconds for guest OS quiescing process
+ */
+#define GUEST_QUIESCE_DEFAULT_TIMEOUT_IN_SEC (15 * 60)
+
typedef enum {
VMBACKUP_STATUS_PENDING,
VMBACKUP_STATUS_FINISHED,
@@ -62,6 +67,7 @@
VMBACKUP_MSTATE_SYNC_FREEZE,
VMBACKUP_MSTATE_SYNC_THAW,
VMBACKUP_MSTATE_SCRIPT_THAW,
+ VMBACKUP_MSTATE_COMPLETE_WAIT,
VMBACKUP_MSTATE_SCRIPT_ERROR,
VMBACKUP_MSTATE_SYNC_ERROR
} VmBackupMState;
@@ -81,6 +87,7 @@
struct VmBackupSyncProvider;
+struct VmBackupSyncCompleter;
/**
* Holds information about the current state of the backup operation.
@@ -114,7 +121,7 @@
Bool execScripts;
Bool enableNullDriver;
Bool needsPriv;
- char *scriptArg;
+ gchar *scriptArg;
guint timeout;
gpointer clientData;
void *scripts;
@@ -124,10 +131,17 @@
VmBackupMState machineState;
VmBackupFreezeStatus freezeStatus;
struct VmBackupSyncProvider *provider;
+ struct VmBackupSyncCompleter *completer;
+ gint vssBackupContext;
+ gint vssBackupType;
+ Bool vssBootableSystemState;
+ Bool vssPartialFileSupport;
+ Bool vssUseDefault;
} VmBackupState;
typedef Bool (*VmBackupCallback)(VmBackupState *);
typedef Bool (*VmBackupProviderCallback)(VmBackupState *, void *clientData);
+typedef Bool (*VmBackupCompleterCallback)(VmBackupState *, void *clientData);
/**
@@ -147,6 +161,19 @@
void *clientData;
} VmBackupSyncProvider;
+/**
+ * Defines the interface between the state machine and the implementation
+ * of the "sync completer": either the VSS completer or the sync driver
+ * completer, currently.
+ */
+
+typedef struct VmBackupSyncCompleter {
+ VmBackupCompleterCallback start;
+ VmBackupCompleterCallback snapshotCompleted;
+ void (*release)(struct VmBackupSyncCompleter *);
+ void *clientData;
+} VmBackupSyncCompleter;
+
/**
* Sets the current asynchronous operation being monitored, and an
@@ -251,6 +278,9 @@
VmBackupSyncProvider *
VmBackup_NewVssProvider(void);
+VmBackupSyncCompleter *
+VmBackup_NewVssCompleter(VmBackupSyncProvider *provider);
+
void
VmBackup_UnregisterSnapshotProvider(void);
#endif