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

Reply via email to