Quoting Tomoki Sekiyama (2013-07-23 17:45:58) > Support guest-fsfreeze-freeze and guest-fsfreeze-thaw commands for Windows > guests. When fsfreeze command is issued, it calls the VSS requester to > freeze filesystems and applications. On thaw command, it again tells the VSS > requester to thaw them. > > This also adds calling of initialize functions for the VSS requester. > > Signed-off-by: Tomoki Sekiyama <tomoki.sekiy...@hds.com>
Other than s/Reqeuster/Requester/ typo mentioned in 7/10, looks good: Reviewed-by: Michael Roth <mdr...@linux.vnet.ibm.com> > --- > qga/Makefile.objs | 1 > qga/commands-win32.c | 82 ++++++++++++++++++++++++++--- > qga/vss-win32.c | 141 > ++++++++++++++++++++++++++++++++++++++++++++++++++ > qga/vss-win32.h | 24 +++++++++ > 4 files changed, 240 insertions(+), 8 deletions(-) > create mode 100644 qga/vss-win32.c > create mode 100644 qga/vss-win32.h > > diff --git a/qga/Makefile.objs b/qga/Makefile.objs > index 4891732..ae1c28b 100644 > --- a/qga/Makefile.objs > +++ b/qga/Makefile.objs > @@ -1,6 +1,7 @@ > qga-obj-y = commands.o guest-agent-command-state.o main.o > qga-obj-$(CONFIG_POSIX) += commands-posix.o channel-posix.o > qga-obj-$(CONFIG_WIN32) += commands-win32.o channel-win32.o service-win32.o > +qga-obj-$(CONFIG_WIN32) += vss-win32.o > qga-obj-y += qapi-generated/qga-qapi-types.o qapi-generated/qga-qapi-visit.o > qga-obj-y += qapi-generated/qga-qmp-marshal.o > > diff --git a/qga/commands-win32.c b/qga/commands-win32.c > index 24e4ad0..7a37f5c 100644 > --- a/qga/commands-win32.c > +++ b/qga/commands-win32.c > @@ -15,6 +15,7 @@ > #include <wtypes.h> > #include <powrprof.h> > #include "qga/guest-agent-core.h" > +#include "qga/vss-win32.h" > #include "qga-qmp-commands.h" > #include "qapi/qmp/qerror.h" > > @@ -156,27 +157,89 @@ void qmp_guest_file_flush(int64_t handle, Error **err) > */ > GuestFsfreezeStatus qmp_guest_fsfreeze_status(Error **err) > { > - error_set(err, QERR_UNSUPPORTED); > - return 0; > + if (!vss_initialized()) { > + error_set(err, QERR_UNSUPPORTED); > + return 0; > + } > + > + if (ga_is_frozen(ga_state)) { > + return GUEST_FSFREEZE_STATUS_FROZEN; > + } > + > + return GUEST_FSFREEZE_STATUS_THAWED; > } > > /* > - * Walk list of mounted file systems in the guest, and freeze the ones which > - * are real local file systems. > + * Freeze local file systems using Volume Shadow-copy Service. > + * The frozen state is limited for up to 10 seconds by VSS. > */ > int64_t qmp_guest_fsfreeze_freeze(Error **err) > { > - error_set(err, QERR_UNSUPPORTED); > + int i; > + Error *local_err = NULL; > + > + if (!vss_initialized()) { > + error_set(err, QERR_UNSUPPORTED); > + return 0; > + } > + > + slog("guest-fsfreeze called"); > + > + /* cannot risk guest agent blocking itself on a write in this state */ > + ga_set_frozen(ga_state); > + > + qga_vss_fsfreeze(&i, err, true); > + if (error_is_set(err)) { > + goto error; > + } > + > + return i; > + > +error: > + qmp_guest_fsfreeze_thaw(&local_err); > + if (error_is_set(&local_err)) { > + g_debug("cleanup thaw: %s", error_get_pretty(local_err)); > + error_free(local_err); > + } > return 0; > } > > /* > - * Walk list of frozen file systems in the guest, and thaw them. > + * Thaw local file systems using Volume Shadow-copy Service. > */ > int64_t qmp_guest_fsfreeze_thaw(Error **err) > { > - error_set(err, QERR_UNSUPPORTED); > - return 0; > + int i; > + > + if (!vss_initialized()) { > + error_set(err, QERR_UNSUPPORTED); > + return 0; > + } > + > + qga_vss_fsfreeze(&i, err, false); > + > + ga_unset_frozen(ga_state); > + return i; > +} > + > +static void guest_fsfreeze_cleanup(void) > +{ > + Error *err = NULL; > + > + if (!vss_initialized()) { > + return; > + } > + > + if (ga_is_frozen(ga_state) == GUEST_FSFREEZE_STATUS_FROZEN) { > + qmp_guest_fsfreeze_thaw(&err); > + if (err) { > + slog("failed to clean up frozen filesystems: %s", > + error_get_pretty(err)); > + error_free(err); > + } > + } > + > + vss_deinit(true); > } > > /* > @@ -354,4 +417,7 @@ int64_t qmp_guest_set_vcpus(GuestLogicalProcessorList > *vcpus, Error **errp) > /* register init/cleanup routines for stateful command groups */ > void ga_command_state_init(GAState *s, GACommandState *cs) > { > + if (vss_init(true)) { > + ga_command_state_add(cs, NULL, guest_fsfreeze_cleanup); > + } > } > diff --git a/qga/vss-win32.c b/qga/vss-win32.c > new file mode 100644 > index 0000000..ef5f0df > --- /dev/null > +++ b/qga/vss-win32.c > @@ -0,0 +1,141 @@ > +/* > + * QEMU Guest Agent VSS utility functions > + * > + * Copyright Hitachi Data Systems Corp. 2013 > + * > + * Authors: > + * Tomoki Sekiyama <tomoki.sekiy...@hds.com> > + * > + * This work is licensed under the terms of the GNU GPL, version 2 or later. > + * See the COPYING file in the top-level directory. > + */ > + > +#include <stdio.h> > +#include <windows.h> > +#include "qga/guest-agent-core.h" > +#include "qga/vss-win32.h" > +#include "qga/vss-win32/requester.h" > + > +#define QGA_VSS_DLL "qga-vss.dll" > + > +static HMODULE provider_lib; > + > +/* Call a function in qga-vss.dll with the specified name */ > +static HRESULT call_vss_provider_func(const char *func_name) > +{ > + FARPROC WINAPI func; > + > + g_assert(provider_lib); > + > + func = GetProcAddress(provider_lib, func_name); > + if (!func) { > + char *msg; > + FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | > + FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), > + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), > + (char *)&msg, 0, NULL); > + fprintf(stderr, "failed to load %s from %s: %s", > + func_name, QGA_VSS_DLL, msg); > + LocalFree(msg); > + return E_FAIL; > + } > + > + return func(); > +} > + > +/* Check whether this OS version supports VSS providers */ > +static bool vss_check_os_version(void) > +{ > + OSVERSIONINFO OSver; > + > + OSver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); > + GetVersionEx(&OSver); > + if ((OSver.dwMajorVersion == 5 && OSver.dwMinorVersion >= 2) || > + OSver.dwMajorVersion > 5) { > + BOOL wow64 = false; > +#ifndef _WIN64 > + /* Provider doesn't work under WOW64 (32bit agent on 64bit OS) */ > + if (!IsWow64Process(GetCurrentProcess(), &wow64)) { > + fprintf(stderr, "failed to IsWow64Process (Error: %lx\n)\n", > + GetLastError()); > + return false; > + } > + if (wow64) { > + fprintf(stderr, "Warning: Running under WOW64\n"); > + } > +#endif > + return !wow64; > + } > + return false; > +} > + > +/* Load qga-vss.dll */ > +bool vss_init(bool init_requester) > +{ > + if (!vss_check_os_version()) { > + /* Do nothing if OS doesn't support providers. */ > + fprintf(stderr, "VSS provider is not supported in this OS version: " > + "fsfreeze is disabled.\n"); > + return false; > + } > + > + provider_lib = LoadLibraryA(QGA_VSS_DLL); > + if (!provider_lib) { > + char *msg; > + FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | > + FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), > + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), > + (char *)&msg, 0, NULL); > + fprintf(stderr, "failed to load %s: %sfsfreeze is disabled\n", > + QGA_VSS_DLL, msg); > + LocalFree(msg); > + return false; > + } > + > + if (init_requester) { > + HRESULT hr = call_vss_provider_func("requester_init"); > + if (FAILED(hr)) { > + fprintf(stderr, "fsfreeze is disabled.\n"); > + vss_deinit(false); > + return false; > + } > + } > + > + return true; > +} > + > +/* Unload qga-provider.dll */ > +void vss_deinit(bool deinit_requester) > +{ > + if (deinit_requester) { > + call_vss_provider_func("requester_deinit"); > + } > + FreeLibrary(provider_lib); > + provider_lib = NULL; > +} > + > +bool vss_initialized(void) > +{ > + return !!provider_lib; > +} > + > +/* Call VSS requester and freeze/thaw filesystems and applications */ > +void qga_vss_fsfreeze(int *nr_volume, Error **err, bool freeze) > +{ > + const char *func_name = freeze ? "requester_freeze" : "requester_thaw"; > + QGAVSSReuqesterFunc func; > + ErrorSet errset = { > + .error_set = (ErrorSetFunc)error_set_win32, > + .errp = (void **)err, > + .err_class = ERROR_CLASS_GENERIC_ERROR > + }; > + > + func = (QGAVSSReuqesterFunc)GetProcAddress(provider_lib, func_name); > + if (!func) { > + error_setg_win32(err, GetLastError(), "failed to load %s from %s", > + func_name, QGA_VSS_DLL); > + return; > + } > + > + func(nr_volume, &errset); > +} > diff --git a/qga/vss-win32.h b/qga/vss-win32.h > new file mode 100644 > index 0000000..eac669c > --- /dev/null > +++ b/qga/vss-win32.h > @@ -0,0 +1,24 @@ > +/* > + * QEMU Guest Agent VSS utility declarations > + * > + * Copyright Hitachi Data Systems Corp. 2013 > + * > + * Authors: > + * Tomoki Sekiyama <tomoki.sekiy...@hds.com> > + * > + * This work is licensed under the terms of the GNU GPL, version 2 or later. > + * See the COPYING file in the top-level directory. > + */ > + > +#ifndef VSS_WIN32_H > +#define VSS_WIN32_H > + > +#include "qapi/error.h" > + > +bool vss_init(bool init_requester); > +void vss_deinit(bool deinit_requester); > +bool vss_initialized(void); > + > +void qga_vss_fsfreeze(int *nr_volume, Error **err, bool freeze); > + > +#endif