From 0e2628b2a3b7a83504da4f718ab594d5e7205af1 Mon Sep 17 00:00:00 2001 From: CentOS Sources Date: Mar 02 2017 15:24:51 +0000 Subject: import open-vm-tools-10.0.5-4.el7_3 --- diff --git a/SOURCES/99-vmware-scsi-udev.rules b/SOURCES/99-vmware-scsi-udev.rules new file mode 100644 index 0000000..8963542 --- /dev/null +++ b/SOURCES/99-vmware-scsi-udev.rules @@ -0,0 +1,3 @@ +ACTION=="add", SUBSYSTEMS=="scsi", ATTRS{vendor}=="VMware*" , ATTRS{model}=="Virtual disk*", RUN+="/bin/sh -c 'echo 180 >/sys$DEVPATH/device/timeout'" +ACTION=="add", SUBSYSTEMS=="scsi", ATTRS{vendor}=="VMware*" , ATTRS{model}=="VMware Virtual S", RUN+="/bin/sh -c 'echo 180 >/sys$DEVPATH/device/timeout'" + diff --git a/SOURCES/open-vm-tools-10.0.5-mount-point-bz1406483.patch b/SOURCES/open-vm-tools-10.0.5-mount-point-bz1406483.patch new file mode 100644 index 0000000..daf76bf --- /dev/null +++ b/SOURCES/open-vm-tools-10.0.5-mount-point-bz1406483.patch @@ -0,0 +1,54 @@ +--- lib/syncDriver/syncDriverLinux.c.orig 2017-01-30 14:11:08.001633000 -0800 ++++ lib/syncDriver/syncDriverLinux.c 2017-01-30 14:12:24.000488000 -0800 +@@ -30,6 +30,8 @@ + #include + #include + #include ++#include ++#include + #include "debug.h" + #include "dynbuf.h" + #include "syncDriverInt.h" +@@ -170,12 +172,21 @@ + */ + while (paths != NULL) { + int fd; ++ struct stat sbuf; + 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) { ++ case ENOENT: ++ /* ++ * We sometimes get stale mountpoints or special mountpoints ++ * created by the docker engine. ++ */ ++ Debug(LGPFX "cannot find the directory '%s'.\n", path); ++ continue; ++ + case EACCES: + /* + * We sometimes get access errors to virtual filesystems mounted +@@ -201,6 +212,20 @@ + } + } + ++ if (fstat(fd, &sbuf) == -1) { ++ close(fd); ++ Debug(LGPFX "failed to stat '%s': %d (%s)\n", ++ path, errno, strerror(errno)); ++ err = SD_ERROR; ++ goto exit; ++ } ++ ++ if (!S_ISDIR(sbuf.st_mode)) { ++ close(fd); ++ Debug(LGPFX "Skipping a non-directory path '%s'.\n", path); ++ continue; ++ } ++ + Debug(LGPFX "freezing path '%s' (fd=%d).\n", path, fd); + if (ioctl(fd, FIFREEZE) == -1) { + int ioctlerr = errno; diff --git a/SOURCES/open-vm-tools-10.0.5-quiesce-files-bz1398802.patch b/SOURCES/open-vm-tools-10.0.5-quiesce-files-bz1398802.patch new file mode 100644 index 0000000..35ddfc3 --- /dev/null +++ b/SOURCES/open-vm-tools-10.0.5-quiesce-files-bz1398802.patch @@ -0,0 +1,1885 @@ +--- 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; /* 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 + #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 + #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 + #include + #include ++#include + #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 + #include ++#include + #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 diff --git a/SPECS/open-vm-tools.spec b/SPECS/open-vm-tools.spec index cf24303..07b3515 100644 --- a/SPECS/open-vm-tools.spec +++ b/SPECS/open-vm-tools.spec @@ -28,7 +28,7 @@ Name: open-vm-tools Version: %{toolsversion} -Release: 2%{?dist} +Release: 4%{?dist} Summary: Open Virtual Machine Tools for virtual machines hosted on VMware Group: Applications/System License: GPLv2 @@ -36,6 +36,8 @@ URL: http://%{name}.sourceforge.net/ Source0: http://sourceforge.net/projects/%{name}/files/%{name}/stable-%{majorversion}.x/%{name}-%{version}-%{toolsbuild}.tar.gz Source1: %{toolsdaemon}.service #Source2: %{vgauthdaemon}.service +# Fix for RHBZ#1214347. +Source3: https://raw.githubusercontent.com/vmware/open-vm-tools/master/open-vm-tools/udev/99-vmware-scsi-udev.rules %if 0%{?rhel} >= 7 ExclusiveArch: x86_64 %else @@ -46,6 +48,10 @@ Patch1: no-unused-const.patch Patch2: vmw-bitmask-gcc6.patch # https://bugzilla.redhat.com/show_bug.cgi?id=1313071#c7 Patch3: pam-bz1313071.patch +# https://bugzilla.redhat.com/show_bug.cgi?id=1398802#c12 +Patch4: open-vm-tools-10.0.5-quiesce-files-bz1398802.patch +# https://bugzilla.redhat.com/show_bug.cgi?id=1406483#c26 +Patch5: open-vm-tools-10.0.5-mount-point-bz1406483.patch BuildRequires: autoconf BuildRequires: automake @@ -121,6 +127,8 @@ VMware virtual machines. %patch1 -p0 %patch2 -p0 %patch3 -p1 +%patch4 -p1 +%patch5 -p0 %build # Required for regenerating configure script when @@ -172,6 +180,10 @@ install -p -m 644 -D %{SOURCE1} %{buildroot}%{_unitdir}/%{toolsdaemon}.service # the font file. We can add %%check secion once 'make check' is fixed # upstream +# Install udev rules for RHBZ#1214347. +mkdir -p %{buildroot}%{_udevrulesdir} +install -p -m 644 %{SOURCE3} %{buildroot}%{_udevrulesdir}/ + %post if [ -f %{_bindir}/vmware-guestproxycerttool ]; then mkdir -p %{_sysconfdir}/vmware-tools/GuestProxyData/server @@ -264,6 +276,7 @@ fi %{_datadir}/%{name}/ %{_unitdir}/%{toolsdaemon}.service #%{_unitdir}/%{vgauthdaemon}.service +%{_udevrulesdir}/99-vmware-scsi-udev.rules %files desktop %{_sysconfdir}/xdg/autostart/*.desktop @@ -283,6 +296,15 @@ fi %{_libdir}/libvmtools.so %changelog +* Thu Feb 02 2017 Richard W.M. Jones - 10.0.5-4 +- Fix failure to quiesce filesystem when Docker containers are running + resolves: rhbz#1406483 +- Fix for deadlock when taking a snapshot + resolves: rhbz#1398802 + +* Mon Dec 12 2016 Richard W.M. Jones - 10.0.5-3 +- Increase SCSI timeouts with udev rule (RHBZ#1214347). + * Thu Jun 16 2016 Richard W.M. Jones - 10.0.5-2 - Rebase to open-vm-tools 10.0.5 (from Fedora Rawhide) resolves: rhbz#1268537