qemu-ga: fsfreeze on Windows using VSS
Subsystems (2)
v6 cover qemu-ga: fsfreeze on Windows using VSS
Hi,
This is v6 of patch series to add fsfreeze for Windows qemu-guest-agent.
changes from v5:
- Move VSS requester code into the DLL
-- Merge patch v5 06/11(add provider) and patch v5 08/11(add requester)
(-> patch v6 07/10)
-- Rename qga-provider.dll to qga-vss.dll
-- Rearrange files in qga/vss-win32* and rename some functions -- Introduce ErrorSet structure to call error_set_win32() as callback
in order to set errors in the DLL without linking glib etc.
- Make qemu-ga.exe work without qga-vss.dll even though it is configured "--with-vss-sdk", although fsfreeze is disabled. (patch 08/10, 09/10)
- Introduce COMPointer<T> that automates release of COM objects to avoid leaks. (patch 07/10)
v5: http://lists.nongnu.org/archive/html/qemu-devel/2013-07/msg00605.html
* Description
In Windows, VSS (Volume Shadow Copy Service) provides a facility to quiesce filesystems and applications before disk snapshots are taken. This patch series implements "fsfreeze" command of qemu-ga using VSS.
* How to build & run qemu-ga with VSS support
- Download Microsoft VSS SDK from:
http://www.microsoft.com/en-us/download/details.aspx?id=23490
- Setup the SDK
scripts/extract-vsssdk-headers setup.exe (on POSIX-systems)
- Specify installed SDK directory to configure option as:
./configure -with-vss-sdk="path/to/VSS SDK" --cross-prefix=i686-w64-mingw32-
- make qemu-ga.exe qga/vss-win32/qga-vss.{dll,tlb}
- Install qemu-ga.exe, qga/vss-win32/qga-vss.{dll,tlb}, and the other required mingw libraries into the same directory in guests
- Run qemu-ga.exe -s install' and net start qemu-ga' in the guests
Any feedback are appreciated.
---
Tomoki Sekiyama (10):
configure: Support configuring C++ compiler
Add c++ keywords to QAPI helper script
checkpatch.pl: Check .cpp files
Add a script to extract VSS SDK headers on POSIX system
qemu-ga: Add configure options to specify path to Windows/VSS SDK
error: Add error_set_win32 and error_setg_win32
qemu-ga: Add Windows VSS provider and requester as DLL
qemu-ga: Call Windows VSS requester in fsfreeze command handler
qemu-ga: Install Windows VSS provider on `qemu-ga -s install' QMP/qemu-ga-client: Make timeout longer for guest-fsfreeze-freeze command
.gitignore | 1 Makefile | 3 Makefile.objs | 2 QMP/qemu-ga-client | 4 configure | 87 +++++++ hmp.c | 2 hw/pci/pci.c | 2 include/qapi/error.h | 13 + qga/Makefile.objs | 5 qga/commands-win32.c | 82 ++++++ qga/main.c | 10 + qga/vss-win32.c | 154 ++++++++++++ qga/vss-win32.h | 27 ++ qga/vss-win32/Makefile.objs | 23 ++ qga/vss-win32/install.cpp | 424 +++++++++++++++++++++++++++++++++ qga/vss-win32/provider.cpp | 513 ++++++++++++++++++++++++++++++++++++++++ qga/vss-win32/qga-vss.def | 13 + qga/vss-win32/qga-vss.idl | 20 ++ qga/vss-win32/qga-vss.tlb | Bin qga/vss-win32/requester.cpp | 486 ++++++++++++++++++++++++++++++++++++++ qga/vss-win32/requester.h | 42 +++ qga/vss-win32/vss-common.h | 128 ++++++++++ rules.mak | 9 + scripts/checkpatch.pl | 37 ++- scripts/extract-vsssdk-headers | 35 +++ scripts/qapi.py | 12 + util/error.c | 35 +++ 27 files changed, 2145 insertions(+), 24 deletions(-) create mode 100644 qga/vss-win32.c create mode 100644 qga/vss-win32.h create mode 100644 qga/vss-win32/Makefile.objs create mode 100644 qga/vss-win32/install.cpp create mode 100644 qga/vss-win32/provider.cpp create mode 100644 qga/vss-win32/qga-vss.def create mode 100644 qga/vss-win32/qga-vss.idl create mode 100644 qga/vss-win32/qga-vss.tlb create mode 100644 qga/vss-win32/requester.cpp create mode 100644 qga/vss-win32/requester.h create mode 100644 qga/vss-win32/vss-common.h create mode 100755 scripts/extract-vsssdk-headers
PATCH v6 1/10 configure: Support configuring C++ compiler
Add configuration for C++ compiler in configure and Makefiles. The C++ compiler is choosed as following:
- ${CXX}, if it is specified.
- ${cross_prefix}g++, if ${cross_prefix} is specified.
- Otherwise, c++ is used.
Currently, usage of C++ language is only for access to Windows VSS using COM+ services in qemu-guest-agent for Windows.
--- configure | 13 +++++++++++++ rules.mak | 9 ++++++++- 2 files changed, 21 insertions(+), 1 deletion(-)
configure +13 -0
@@ -251,6 +251,8 @@ for opt do ;; --cc=*) CC="$optarg" ;; + --cxx=*) CXX="$optarg" + ;; --source-path=*) source_path="$optarg" ;; --cpu=*) cpu="$optarg"
@@ -281,6 +283,12 @@ else cc="${CC-${cross_prefix}gcc}" fi +if test -z "${CXX}${cross_prefix}"; then + cxx="c++" +else + cxx="${CXX-${cross_prefix}g++}" +fi + ar="${AR-${cross_prefix}ar}" as="${AS-${cross_prefix}as}" cpp="${CPP-$cc -E}"
@@ -621,6 +629,8 @@ for opt do ;; --host-cc=*) host_cc="$optarg" ;; + --cxx=*) cxx="$optarg" + ;; --objcc=*) objcc="$optarg" ;; --make=*) make="$optarg"
@@ -1022,6 +1032,7 @@ echo " --cross-prefix=PREFIX use PREFIX for compile tools [$cross_prefix]" echo " --cc=CC use C compiler CC [$cc]" echo " --host-cc=CC use C compiler CC [$host_cc] for code run at" echo " build time" +echo " --cxx=CXX use C++ compiler CXX [$cxx]" echo " --objcc=OBJCC use Objective-C compiler OBJCC [$objcc]" echo " --extra-cflags=CFLAGS append extra C compiler flags QEMU_CFLAGS" echo " --extra-ldflags=LDFLAGS append extra linker flags LDFLAGS"
@@ -3466,6 +3477,7 @@ fi echo "Source path $source_path" echo "C compiler $cc" echo "Host C compiler $host_cc" +echo "C++ compiler $cxx" echo "Objective-C compiler $objcc" echo "CFLAGS $CFLAGS" echo "QEMU_CFLAGS $QEMU_CFLAGS"
@@ -4039,6 +4051,7 @@ echo "PYTHON=$python" >> $config_host_mak echo "CC=$cc" >> $config_host_mak echo "CC_I386=$cc_i386" >> $config_host_mak echo "HOST_CC=$host_cc" >> $config_host_mak +echo "CXX=$cxx" >> $config_host_mak echo "OBJCC=$objcc" >> $config_host_mak echo "AR=$ar" >> $config_host_mak echo "AS=$as" >> $config_host_mak
rules.mak +8 -1
@@ -8,9 +8,13 @@ MAKEFLAGS += -rR %.d: %.h: %.c: +%.cpp: %.m: %.mak: +# Flags for C++ compilation +QEMU_CXXFLAGS = -D__STDC_LIMIT_MACROS $(filter-out -Wstrict-prototypes -Wmissing-prototypes -Wnested-externs -Wold-style-declaration -Wold-style-definition -Wredundant-decls, $(QEMU_CFLAGS)) + # Flags for dependency generation QEMU_DGFLAGS += -MMD -MP -MT $@ -MF $(*D)/$(*F).d
@@ -50,6 +54,9 @@ endif %.o: %.asm $(call quiet-command,$(AS) $(ASFLAGS) -o $@ $<," AS $(TARGET_DIR)$@") +%.o: %.cpp + $(call quiet-command,$(CXX) $(QEMU_INCLUDES) $(QEMU_CXXFLAGS) $(QEMU_DGFLAGS) $(CFLAGS) -c -o $@ $<," CXX $(TARGET_DIR)$@") + %.o: %.m $(call quiet-command,$(OBJCC) $(QEMU_INCLUDES) $(QEMU_CFLAGS) $(QEMU_DGFLAGS) $(CFLAGS) -c -o $@ $<," OBJC $(TARGET_DIR)$@")
@@ -70,7 +77,7 @@ quiet-command = $(if $(V),$1,$(if $(2),@echo $2 && $1, @$1)) cc-option = $(if $(shell $(CC) $1 $2 -S -o /dev/null -xc /dev/null \ >/dev/null 2>&1 && echo OK), $2, $3) -VPATH_SUFFIXES = %.c %.h %.S %.m %.mak %.texi %.sh %.rc +VPATH_SUFFIXES = %.c %.h %.S %.cpp %.m %.mak %.texi %.sh %.rc set-vpath = $(if $1,$(foreach PATTERN,$(VPATH_SUFFIXES),$(eval vpath $(PATTERN) $1))) # find-in-path
PATCH v6 2/10 Add c++ keywords to QAPI helper script
In reply to Tomoki SekiyamaAdd c++ keywords to avoid errors in compiling with c++ compiler. This also renames class member of PciDeviceInfo to q_class.
--- hmp.c | 2 +- hw/pci/pci.c | 2 +- scripts/qapi.py | 12 +++++++++++- 3 files changed, 13 insertions(+), 3 deletions(-)
hmp.c +1 -1
@@ -524,7 +524,7 @@ static void hmp_info_pci_device(Monitor *mon, const PciDeviceInfo *dev)if (dev->class_info.has_desc) {monitor_printf (mon,"%s" , dev->class_info.desc); }else { -monitor_printf (mon,"Class %04" PRId64, dev->class_info.class); +monitor_printf (mon,"Class %04" PRId64, dev->class_info.q_class); } monitor_printf(mon, ": PCI device %04" PRIx64 ":%04" PRIx64 "\n",
hw/pci/pci.c +1 -1
@@ -1461,7 +1461,7 @@ static PciDeviceInfo *qmp_query_pci_device(PCIDevice *dev, PCIBus *bus, info->function =PCI_FUNC (dev->devfn); class =pci_get_word (dev->config +PCI_CLASS_DEVICE ); - info->class_info.class = class; + info->class_info.q_class = class; desc =get_class_desc (class);if (desc->desc) { info->class_info.has_desc = true;
scripts/qapi.py +11 -1
@@ -162,9 +162,19 @@ def c_var(name, protect=True): # GCC http://gcc.gnu.org/onlinedocs/gcc-4.7.1/gcc/C-Extensions.html # excluding _.* gcc_words = set(['asm', 'typeof']) + # C++ ISO/IEC 14882:2003 2.11 + cpp_words = set(['bool', 'catch', 'class', 'const_cast', 'delete', + 'dynamic_cast', 'explicit', 'false', 'friend', 'mutable', + 'namespace', 'new', 'operator', 'private', 'protected', + 'public', 'reinterpret_cast', 'static_cast', 'template', + 'this', 'throw', 'true', 'try', 'typeid', 'typename', + 'using', 'virtual', 'wchar_t', + # alternative representations + 'and', 'and_eq', 'bitand', 'bitor', 'compl', 'not', + 'not_eq', 'or', 'or_eq', 'xor', 'xor_eq']) # namespace pollution: polluted_words = set(['unix']) - if protect and (name in c89_words | c99_words | c11_words | gcc_words | polluted_words): + if protect and (name in c89_words | c99_words | c11_words | gcc_words | cpp_words | polluted_words): return "q_" + name return name.replace('-', '_').lstrip("*")
PATCH v6 3/10 checkpatch.pl: Check .cpp files
In reply to Tomoki SekiyamaEnable checkpatch.pl to apply the same checks as C source files for C++ files with .cpp extensions. It also adds some exceptions for C++ sources to suppress errors for:
- <> used in C++ template arguments (e.g. template <class T>)
- :: used to represent namespaces (e.g. SomeClass::method()) - : used in class declaration (e.g. class T : public Super) - ~ used in destructor method name (e.g. T::~T()) - spacing around 'catch' (e.g. catch (...))
--- scripts/checkpatch.pl | 37 +++++++++++++++++++++++++++++-------- 1 file changed, 29 insertions(+), 8 deletions(-)
scripts/checkpatch.pl +29 -8
@@ -1363,7 +1363,7 @@ sub process { # Check for incorrect file permissions if ($line =~ /^new (file )?mode.*[7531]\d{0,2}$/) { my $permhere = $here . "FILE: $realfile\n"; - if ($realfile =~ /(Makefile|Kconfig|\.c|\.h|\.S|\.tmpl)$/) { + if ($realfile =~ /(Makefile|Kconfig|\.c|\.cpp|\.h|\.S|\.tmpl)$/) { ERROR("do not set execute permissions for source files\n" . $permhere); } }
@@ -1460,7 +1460,7 @@ sub process { } # check we are in a valid source file if not then ignore this hunk - next if ($realfile !~ /\.(h|c|s|S|pl|sh)$/); + next if ($realfile !~ /\.(h|c|cpp|s|S|pl|sh)$/); #80 column limit if ($line =~ /^\+/ && $prevrawline !~ /\/\*\*/ &&
@@ -1495,7 +1495,7 @@ sub process { } # check we are in a valid source file C or perl if not then ignore this hunk - next if ($realfile !~ /\.(h|c|pl)$/); + next if ($realfile !~ /\.(h|c|cpp|pl)$/); # in QEMU, no tabs are allowed if ($rawline =~ /^\+.*\t/) {
@@ -1505,7 +1505,7 @@ sub process { } # check we are in a valid C source file if not then ignore this hunk - next if ($realfile !~ /\.(h|c)$/); + next if ($realfile !~ /\.(h|c|cpp)$/); # check for RCS/CVS revision markers if ($rawline =~ /^\+.*\$(Revision|Log|Id)(?:\$|)/) {
@@ -1969,6 +1969,9 @@ sub process { asm|__asm__)$/x) { + # Ignore 'catch (...)' in C++ + } elsif ($name =~ /^catch$/ && $realfile =~ /(\.cpp|\.h)$/) { + # cpp #define statements have non-optional spaces, ie # if there is a space between the name and the open # parenthesis it is simply not a parameter group.
@@ -1992,7 +1995,7 @@ sub process { \+=|-=|\*=|\/=|%=|\^=|\|=|&=| =>|->|<<|>>|<|>|=|!|~| &&|\|\||,|\^|\+\+|--|&|\||\+|-|\*|\/|%| - \?|: + \?|::|: }x; my @elements = split(/($ops|;)/, $opline); my $off = 0;
@@ -2066,7 +2069,8 @@ sub process { # -> # : when part of a bitfield } elsif ($op eq '->' || $opv eq ':B') { - if ($ctx =~ /Wx.|.xW/) { + if ($ctx =~ /Wx.|.xW/ && + !($opv eq ':B' && $line =~ /class/)) { ERROR("spaces prohibited around that '$op' $at\n" . $hereptr); }
@@ -2088,7 +2092,11 @@ sub process { } elsif ($op eq '!' || $op eq '~' || $opv eq '*U' || $opv eq '-U' || $opv eq '&U' || $opv eq '&&U') { - if ($ctx !~ /[WEBC]x./ && $ca !~ /(?:\)|!|~|\*|-|\&|\||\+\+|\-\-|\{)$/) { + if ($op eq '~' && $ca =~ /::$/ && $realfile =~ /(\.cpp|\.h)$/) { + # '~' used as a name of Destructor + + } + elsif ($ctx !~ /[WEBC]x./ && $ca !~ /(?:\)|!|~|\*|-|\&|\||\+\+|\-\-|\{)$/) { ERROR("space required before that '$op' $at\n" . $hereptr); } if ($op eq '*' && $cc =~/\s*$Modifier\b/) {
@@ -2126,8 +2134,9 @@ sub process { # A colon needs no spaces before when it is # terminating a case value or a label. + # Ignored if it is used in class declaration in C++. } elsif ($opv eq ':C' || $opv eq ':L') { - if ($ctx =~ /Wx./) { + if ($ctx =~ /Wx./ && $line !~ /class/) { ERROR("space prohibited before that '$op' $at\n" . $hereptr); }
@@ -2135,6 +2144,18 @@ sub process { } elsif ($ctx !~ /[EWC]x[CWE]/) { my $ok = 0; + if ($realfile =~ /\.cpp|\.h$/) { + # Ignore template arguments <...> in C++ + if (($op eq '<' || $op eq '>') && $line =~ /<.*>/) { + $ok = 1; + } + + # Ignore :: in C++ + if ($op eq '::') { + $ok = 1; + } + } + # Ignore email addresses <foo@bar> if (($op eq '<' && $cc =~ /^\S+\@\S+>/) ||
PATCH v6 4/10 Add a script to extract VSS SDK headers on POSIX system
In reply to Tomoki SekiyamaVSS SDK(*) setup.exe is only runnable on Windows. This adds a script to extract VSS SDK headers on POSIX-systems using msitools.
* http://www.microsoft.com/en-us/download/details.aspx?id=23490
From: Paolo Bonzini <[email protected]>
--- scripts/extract-vsssdk-headers | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100755 scripts/extract-vsssdk-headers
scripts/extract-vsssdk-headers new file +35 -0
@@ -0,0 +1,35 @@ +#! /bin/bash + +# extract-vsssdk-headers +# Author: Paolo Bonzini <[email protected]> + +set -e +if test $# != 1 || ! test -f "$1"; then + echo 'Usage: extract-vsssdk-headers /path/to/setup.exe' >&2 + exit 1 +fi + +if ! command -v msiextract > /dev/null; then + echo 'msiextract not found. Please install msitools.' >&2 + exit 1 +fi + +if test -e inc; then + echo '"inc" already exists.' >&2 + exit 1 +fi + +# Extract .MSI file in the .exe, looking for the OLE compound +# document signature. Extra data at the end does not matter. +export LC_ALL=C +MAGIC=$'\xd0\xcf\x11\xe0\xa1\xb1\x1a\xe1' +offset=$(grep -abom1 "$MAGIC" "$1" | sed -n 's/:/\n/; P') +tmpdir=$(mktemp -d) +trap 'rm -fr -- "$tmpdir" vsssdk.msi' EXIT HUP INT QUIT ALRM TERM +tail -c +$(($offset+1)) -- "$1" > vsssdk.msi + +# Now extract the files. +msiextract -C $tmpdir vsssdk.msi +mv "$tmpdir/Program Files/Microsoft/VSSSDK72/inc" inc +echo 'Extracted SDK headers into "inc" directory.' +exit 0
PATCH v6 5/10 qemu-ga: Add configure options to specify path to Windows/VSS SDK
In reply to Tomoki SekiyamaTo enable VSS support in qemu-ga for Windows, header files included in VSS SDK are required.
The VSS support is enabled by the configure option like below:
./configure --with-vss-sdk="/path/to/VSS SDK"
If the path is omitted, it tries to search the headers from default paths and VSS support is enabled only if the SDK is found.
VSS support is disabled if --without-vss-sdk or --with-vss-sdk=no is specified.
VSS SDK is available from:
http://www.microsoft.com/en-us/download/details.aspx?id=23490
To cross-compile using mingw, you need to setup the SDK on Windows environments to extract headers. You can also extract the SDK headers on POSIX environments using scripts/extract-vss-headers and msitools.
In addition, --with-win-sdk="/path/to/Windows SDK" option is also added to specify path to Windows SDK, which may be used for native-compile of .tlb file of qemu-ga VSS provider. However, this is usually unnecessary because pre-compiled .tlb file is included.
--- .gitignore | 1 + Makefile | 1 + configure | 69 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 71 insertions(+)
.gitignore +1 -0
@@ -79,6 +79,7 @@ fsdev/virtfs-proxy-helper.pod *.la *.pc .libs +.sdk *.swp *.orig .pc
Makefile +1 -0
@@ -273,6 +273,7 @@ distclean: clean for d in $(TARGET_DIRS); do \ rm -rf $$d || exit 1 ; \ done + rm -Rf .sdk if test -f pixman/config.log; then make -C pixman distclean; fi if test -f dtc/version_gen.h; then make $(DTC_MAKE_ARGS) clean; fi
configure +69 -0
111 lines not on this page · raw message
PATCH v6 6/10 error: Add error_set_win32 and error_setg_win32
In reply to Tomoki SekiyamaThese functions help maintaining homogeneous formatting of error messages with Windows error code and description (generated by g_win32_error_message()).
--- include/qapi/error.h | 13 +++++++++++++ util/error.c | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+)
include/qapi/error.h +13 -0
@@ -36,6 +36,15 @@ void error_set(Error **err, ErrorClass err_class, const char *fmt, ...) GCC_FMT_*/ void error_set_errno(Error **err, int os_error, ErrorClass err_class, const char *fmt, ...) GCC_FMT_ATTR(4, 5); +#ifdef _WIN32 +/** +* Set an indirect pointer to an error given a ErrorClass value and a +* printf-style human message, followed by a g_win32_error_message() string if +* @win32_err is not zero. +*/ +void error_set_win32(Error **err, int win32_err, ErrorClass err_class, const char *fmt, ...) GCC_FMT_ATTR(4, 5); +#endif +/** * Same as error_set(), but sets a generic error */
@@ -43,6 +52,10 @@ void error_set_errno(Error **err, int os_error, ErrorClass err_class, const char error_set(err, ERROR_CLASS_GENERIC_ERROR, fmt, ## __VA_ARGS__)#define error_setg_errno (err, os_error, fmt, ...) \ error_set_errno(err, os_error, ERROR_CLASS_GENERIC_ERROR, fmt, ## __VA_ARGS__) +#ifdef _WIN32 +#define error_setg_win32 (err, win32_err, fmt, ...) \ + error_set_win32(err, win32_err, ERROR_CLASS_GENERIC_ERROR, fmt, ## __VA_ARGS__) +#endif /** * Helper for open() errors
util/error.c +35 -0
@@ -76,6 +76,41 @@ void error_setg_file_open(Error **errp, int os_errno, const char *filename)error_setg_errno (errp, os_errno,"Could not open '%s'" , filename); } +#ifdef _WIN32 + +void error_set_win32 (Error **errp,int win32_err,ErrorClass err_class, +const char *fmt, ...) +{ +Error *err; +char *msg1; +va_list ap; + +if (errp ==NULL ) { +return ; + } +assert (*errp ==NULL ); + + err =g_malloc0 (sizeof (*err)); + +va_start (ap, fmt); + msg1 =g_strdup_vprintf (fmt, ap); +if (win32_err !=0 ) { +char *msg2 =g_win32_error_message (win32_err); + err->msg =g_strdup_printf ("%s: %s (error: %x)" , msg1, msg2, + (unsigned )win32_err); +g_free (msg2); +g_free (msg1); + }else { + err->msg = msg1; + } +va_end (ap); + err->err_class = err_class; + + *errp = err; +} + +#endif +Error *error_copy (const Error *err) {Error *err_new;
PATCH v6 7/10 qemu-ga: Add Windows VSS provider and requester as DLL
In reply to Tomoki SekiyamaAdds VSS provider and requester as a qga-vss.dll, which is loaded by Windows VSS service as well as by qemu-ga.
"provider.cpp" implements a basic stub of a software VSS provider. Currently, this module only relays a frozen event from VSS service to the agent, and thaw event from the agent to VSS service, to block VSS process to keep the system frozen while snapshots are taken at the host.
To register the provider to the guest system as COM+ application, the type library (.tlb) for qga-vss.dll is required. To build it from COM IDL (.idl), VisualC++, MIDL and stdole2.tlb in Windows SDK are required. This patch also adds pre-compiled .tlb file in the repository in order to enable cross-compile qemu-ga.exe for Windows with VSS support.
"requester.cpp" provides the VSS requester to kick the VSS snapshot process. Qemu-ga.exe works without the DLL, although fsfreeze features are disabled.
These functions are only supported in Windows 2003 or later. In older systems, fsfreeze features are disabled.
In several versions of Windows which don't support attribute VSS_VOLSNAP_ATTR_NO_AUTORECOVERY, DoSnapshotSet fails with error VSS_E_OBJECT_NOT_FOUND. In this patch, we just ignore this error. To solve this fundamentally, we need a framework to handle mount writable snapshot on guests, which is required by VSS auto-recovery feature (cleanup phase after a snapshot is taken).
--- Makefile | 2 Makefile.objs | 2 configure | 5 qga/Makefile.objs | 4 qga/vss-win32/Makefile.objs | 23 ++ qga/vss-win32/install.cpp | 424 ++++++++++++++++++++++++++++++++++++ qga/vss-win32/provider.cpp | 513 +++++++++++++++++++++++++++++++++++++++++++ qga/vss-win32/qga-vss.def | 13 + qga/vss-win32/qga-vss.idl | 20 ++ qga/vss-win32/qga-vss.tlb | Bin qga/vss-win32/requester.cpp | 486 +++++++++++++++++++++++++++++++++++++++++ qga/vss-win32/requester.h | 42 ++++ qga/vss-win32/vss-common.h | 128 +++++++++++ 13 files changed, 1660 insertions(+), 2 deletions(-) create mode 100644 qga/vss-win32/Makefile.objs create mode 100644 qga/vss-win32/install.cpp create mode 100644 qga/vss-win32/provider.cpp create mode 100644 qga/vss-win32/qga-vss.def create mode 100644 qga/vss-win32/qga-vss.idl create mode 100644 qga/vss-win32/qga-vss.tlb create mode 100644 qga/vss-win32/requester.cpp create mode 100644 qga/vss-win32/requester.h create mode 100644 qga/vss-win32/vss-common.h
Makefile +1 -1
@@ -236,7 +236,7 @@ clean: rm -f qemu-options.def find . -name '*.[oda]' -type f -exec rm -f {} + find . -name '*.l[oa]' -type f -exec rm -f {} + - rm -f $(TOOLS) $(HELPERS-y) qemu-ga TAGS cscope.* *.pod *~ */*~ + rm -f $(filter-out %.tlb,$(TOOLS)) $(HELPERS-y) qemu-ga TAGS cscope.* *.pod *~ */*~ rm -Rf .libs rm -f qemu-img-cmds.h @# May not be present in GENERATED_HEADERS
Makefile.objs +2 -0
@@ -103,6 +103,7 @@ common-obj-y += disas/ # FIXME: a few definitions from qapi-types.o/qapi-visit.o are needed # by libqemuutil.a. These should be moved to a separate .json schema. qga-obj-y = qga/ qapi-types.o qapi-visit.o +qga-vss-dll-obj-y = qga/ vl.o: QEMU_CFLAGS+=$(GPROF_CFLAGS)
@@ -114,6 +115,7 @@ nested-vars += \ stub-obj-y \ util-obj-y \ qga-obj-y \ + qga-vss-dll-obj-y \ block-obj-y \ common-obj-y dummy := $(call unnest-vars)
configure +4 -1
@@ -3497,9 +3497,12 @@ if test "$softmmu" = yes ; then virtfs=no fi fi - if [ "$linux" = "yes" -o "$bsd" = "yes" -o "$solaris" = "yes" ] ; then + if [ "$linux" = "yes" -o "$bsd" = "yes" -o "$solaris" = "yes" -o "$mingw32" = "yes" ] ; then if [ "$guest_agent" = "yes" ]; then tools="qemu-ga\$(EXESUF) $tools" + if [ "$mingw32" = "yes" ]; then + tools="qga/vss-win32-provider/qga-provider.dll qga/vss-win32-provider/qga-provider.tlb $tools" + fi fi fi fi
qga/Makefile.objs +4 -0
@@ -3,3 +3,7 @@ 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-y += qapi-generated/qga-qapi-types.o qapi-generated/qga-qapi-visit.o qga-obj-y += qapi-generated/qga-qmp-marshal.o + +ifeq ($(CONFIG_QGA_VSS),y) +qga-vss-dll-obj-y += vss-win32/ +endif
qga/vss-win32/Makefile.objs new file +23 -0
@@ -0,0 +1,23 @@ +# rules to build qga-vss.dll + +qga-vss-dll-obj-y += requester.o provider.o install.o + +obj-qga-vss-dll-obj-y = $(addprefix $(obj)/, $(qga-vss-dll-obj-y)) +$(obj-qga-vss-dll-obj-y): QEMU_CXXFLAGS = $(filter-out -Wstrict-prototypes -Wmissing-prototypes -Wnested-externs -Wold-style-declaration -Wold-style-definition -Wredundant-decls -fstack-protector-all, $(QEMU_CFLAGS)) -Wno-unknown-pragmas -Wno-delete-non-virtual-dtor + +$(obj)/qga-vss.dll: LDFLAGS = -shared -Wl,--add-stdcall-alias,--enable-stdcall-fixup -lole32 -loleaut32 -lshlwapi -luuid -static +$(obj)/qga-vss.dll: $(obj-qga-vss-dll-obj-y) $(SRC_PATH)/$(obj)/qga-vss.def + $(call quiet-command,$(CXX) -o $@ $(qga-vss-dll-obj-y) $(SRC_PATH)/qga/vss-win32/qga-vss.def $(CXXFLAGS) $(LDFLAGS)," LINK $(TARGET_DIR)$@") + + +# rules to build qga-provider.tlb +# Currently, only native build is supported because building .tlb +# (TypeLibrary) from .idl requires WindowsSDK and MIDL (and cl.exe in VC++). +MIDL=$(WIN_SDK)/Bin/midl + +$(obj)/qga-vss.tlb: $(SRC_PATH)/$(obj)/qga-vss.idl +ifeq ($(wildcard $(SRC_PATH)/$(obj)/qga-vss.tlb),) + $(call quiet-command,$(MIDL) -tlb $@ -I $(WIN_SDK)/Include $<," MIDL $(TARGET_DIR)$@") +else + $(call quiet-command,cp $(dir $<)qga-vss.tlb $@, " COPY $(TARGET_DIR)$@") +endif
qga/vss-win32/install.cpp new file +424 -0
424 lines not on this page · raw message
qga/vss-win32/provider.cpp new file +513 -0
513 lines not on this page · raw message
qga/vss-win32/qga-vss.def new file +13 -0
@@ -0,0 +1,13 @@ +LIBRARY "QGA-PROVIDER.DLL" + +EXPORTS + COMRegister PRIVATE + COMUnregister PRIVATE + DllCanUnloadNow PRIVATE + DllGetClassObject PRIVATE + DllRegisterServer PRIVATE + DllUnregisterServer PRIVATE + requester_init PRIVATE + requester_deinit PRIVATE + requester_freeze PRIVATE + requester_thaw PRIVATE
qga/vss-win32/qga-vss.idl new file +20 -0
@@ -0,0 +1,20 @@ +import "oaidl.idl"; +import "ocidl.idl"; + +[ + uuid(103B8142-6CE5-48A7-BDE1-794D3192FCF1), + version(1.0), + helpstring("QGAVSSProvider Type Library") +] +library QGAVSSHWProviderLib +{ + importlib("stdole2.tlb"); + [ + uuid(6E6A3492-8D4D-440C-9619-5E5D0CC31CA8), + helpstring("QGAVSSProvider Class") + ] + coclass QGAVSSHWProvider + { + [default] interface IUnknown; + }; +};
qga/vss-win32/qga-vss.tlb new file binary +0 -0
qga/vss-win32/requester.cpp new file +486 -0
486 lines not on this page · raw message
qga/vss-win32/requester.h new file +42 -0
42 lines not on this page · raw message
qga/vss-win32/vss-common.h new file +128 -0
128 lines not on this page · raw message
PATCH v6 8/10 qemu-ga: Call Windows VSS requester in fsfreeze command handler
In reply to Tomoki SekiyamaSupport 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.
--- qga/Makefile.objs | 1 qga/commands-win32.c | 82 +++++++++++++++++++++++++++++--- qga/vss-win32.c | 129 ++++++++++++++++++++++++++++++++++++++++++++++++++ qga/vss-win32.h | 24 +++++++++ 4 files changed, 228 insertions(+), 8 deletions(-) create mode 100644 qga/vss-win32.c create mode 100644 qga/vss-win32.h
qga/Makefile.objs +1 -0
@@ -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
qga/commands-win32.c +74 -8
111 lines not on this page · raw message
qga/vss-win32.c new file +129 -0
129 lines not on this page · raw message
qga/vss-win32.h new file +24 -0
@@ -0,0 +1,24 @@ +/* +* QEMU Guest Agent VSS utility declarations +* +* Copyright Hitachi Data Systems Corp. 2013 +* +* Authors: +* Tomoki Sekiyama <[email protected]> +* +* 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
PATCH v6 9/10 qemu-ga: Install Windows VSS provider on `qemu-ga -s install'
In reply to Tomoki SekiyamaRegister QGA VSS provider library into Windows when qemu-ga is installed as Windows service ('-s install' option). It is deregistered when the service is uninstalled ('-s uninstall' option).
--- qga/main.c | 10 +++++++++- qga/vss-win32.c | 25 +++++++++++++++++++++++++ qga/vss-win32.h | 3 +++ 3 files changed, 37 insertions(+), 1 deletion(-)
qga/main.c +9 -1
@@ -34,6 +34,7 @@#include "qemu/bswap.h" #ifdef _WIN32#include "qga/service-win32.h" +#include "qga/vss-win32.h" #include <windows.h> #endif #ifdef __linux__
@@ -1031,8 +1032,15 @@ int main(int argc, char **argv) fixed_state_dir = (state_dir == dfl_pathnames.state_dir) ?NULL : state_dir; -return ga_install_service (path, log_filepath, fixed_state_dir); +if (ga_install_vss_provider ()) { +return EXIT_FAILURE ; + } +if (ga_install_service (path, log_filepath, fixed_state_dir)) { +return EXIT_FAILURE ; + } +return 0 ; }else if (strcmp (service,"uninstall" ) ==0 ) { +ga_uninstall_vss_provider ();return ga_uninstall_service (); }else {printf ("Unknown service command.\n" );
qga/vss-win32.c +25 -0
@@ -107,6 +107,31 @@ bool vss_initialized(void)return !!provider_lib; } +int ga_install_vss_provider (void ) +{ +HRESULT hr; + +if (!vss_init (false)) { +fprintf (stderr,"Installation of VSS provider is skipped. " +"fsfreeze will be disabled.\n" ); +return 0 ; + } + hr =call_vss_provider_func ("COMRegister" ); +vss_deinit (false); + +return SUCCEEDED (hr) ?0 :EXIT_FAILURE ; +} + +void ga_uninstall_vss_provider (void ) +{ +if (!vss_init (false)) { +fprintf (stderr,"Removal of VSS provider is skipped.\n" ); +return ; + } +call_vss_provider_func ("COMUnregister" ); +vss_deinit (false); +} +/* Call VSS requester and freeze/thaw filesystems and applications */ void qga_vss_fsfreeze (int *nr_volume,Error **err,bool freeze) {
qga/vss-win32.h +3 -0
@@ -19,6 +19,9 @@ bool vss_init(bool init_requester);void vss_deinit (bool deinit_requester);bool vss_initialized (void ); +int ga_install_vss_provider (void ); +void ga_uninstall_vss_provider (void ); +void qga_vss_fsfreeze (int *nr_volume,Error **err,bool freeze);#endif
PATCH v6 10/10 QMP/qemu-ga-client: Make timeout longer for guest-fsfreeze-freeze command
In reply to Tomoki Sekiyamaguest-fsfreeze-freeze command can take longer than 3 seconds when heavy disk I/O is running. To avoid unexpected timeout, this changes the timeout to 60 seconds (timeout of pre-commit phase of VSS).
--- QMP/qemu-ga-client | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
QMP/qemu-ga-client +3 -1
@@ -267,7 +267,9 @@ def main(address, cmd, args): print('Hint: qemu is not running?') sys.exit(1) - if cmd != 'ping': + if cmd == 'fsfreeze' and args[0] == 'freeze': + client.sync(60) + elif cmd != 'ping': client.sync() globals()['_cmd_' + cmd](client, args)
Hi tomoki,
I test the patch v6.
When calling the command " guest-fsfreeze-freeze ", an error occurs.
The desc is "{"error": {"class": "GenericError", "desc": "failed to initialize for backup: (error: 80042302)"}}" The eventlog in the guest is : EventID 8193;CoCreateInstanceerror hr= 0x800401f0,CoInitialize is not called.Opertion :backup init.
When executing the qemu-ga.exe from the commandline,it goes well. Running the same configuration with the patch v5,it goes well.
I can provide more information if need.
Thanks
Baiqing.
Quoted 117 lines
-----Original Message-----
From: Tomoki Sekiyama [mailto:[email protected]]
Sent: Thursday, July 11, 2013 5:02 AM
To: [email protected]
Cc: Libaiqing; [email protected]; [email protected]; [email protected]; [email protected]; [email protected]; [email protected]; [email protected]; [email protected]; [email protected]; [email protected]
Subject: [PATCH v6 00/10] qemu-ga: fsfreeze on Windows using VSSHi,
This is v6 of patch series to add fsfreeze for Windows qemu-guest-agent.
changes from v5:
- Move VSS requester code into the DLL
-- Merge patch v5 06/11(add provider) and patch v5 08/11(add requester)(-> patch v6 07/10)-- Rename qga-provider.dll to qga-vss.dll
-- Rearrange files in qga/vss-win32* and rename some functions -- Introduce ErrorSet structure to callerror_set_win32()as callback
in order to set errors in the DLL without linking glib etc.
- Make qemu-ga.exe work without qga-vss.dll even though it is configured "--with-vss-sdk", although fsfreeze is disabled. (patch 08/10, 09/10)
- Introduce COMPointer<T> that automates release of COM objects to
avoid
leaks. (patch 07/10)v5:
http://lists.nongnu.org/archive/html/qemu-devel/2013-07/msg00605.html* Description
In Windows, VSS (Volume Shadow Copy Service) provides a facility to quiesce filesystems and applications before disk snapshots are taken. This patch series implements "fsfreeze" command of qemu-ga using VSS.* How to build & run qemu-ga with VSS support
- Download Microsoft VSS SDK from:
http://www.microsoft.com/en-us/download/details.aspx?id=23490- Setup the SDK
scripts/extract-vsssdk-headerssetup.exe (on POSIX-systems)- Specify installed SDK directory to configure option as:
./configure -with-vss-sdk="path/to/VSS SDK"
--cross-prefix=i686-w64-mingw32-- make qemu-ga.exe qga/vss-win32/qga-vss.{dll,tlb}
- Install qemu-ga.exe, qga/vss-win32/qga-vss.{dll,tlb}, and the other required mingw libraries into the same directory in guests
- Run
qemu-ga.exe -s install' andnet start qemu-ga' in the guestsAny feedback are appreciated.
---
Tomoki Sekiyama (10):
configure: Support configuring C++ compiler
Add c++ keywords to QAPI helper script
checkpatch.pl: Check .cpp files
Add a script to extract VSS SDK headers on POSIX system
qemu-ga: Add configure options to specify path to Windows/VSS SDK
error: Adderror_set_win32anderror_setg_win32
qemu-ga: Add Windows VSS provider and requester as DLL
qemu-ga: Call Windows VSS requester in fsfreeze command handler
qemu-ga: Install Windows VSS provider on `qemu-ga -s install' QMP/qemu-ga-client: Make timeout longer for guest-fsfreeze-freeze
command.gitignore | 1 Makefile | 3 Makefile.objs | 2 QMP/qemu-ga-client | 4 configure | 87 +++++++ hmp.c | 2 hw/pci/pci.c | 2 include/qapi/error.h | 13 + qga/Makefile.objs | 5 qga/commands-win32.c | 82 ++++++ qga/main.c | 10 + qga/vss-win32.c | 154 ++++++++++++ qga/vss-win32.h | 27 ++ qga/vss-win32/Makefile.objs | 23 ++ qga/vss-win32/install.cpp | 424 +++++++++++++++++++++++++++++++++ qga/vss-win32/provider.cpp | 513 ++++++++++++++++++++++++++++++++++++++++ qga/vss-win32/qga-vss.def | 13 + qga/vss-win32/qga-vss.idl | 20 ++ qga/vss-win32/qga-vss.tlb | Bin qga/vss-win32/requester.cpp | 486 ++++++++++++++++++++++++++++++++++++++ qga/vss-win32/requester.h | 42 +++ qga/vss-win32/vss-common.h | 128 ++++++++++ rules.mak | 9 + scripts/checkpatch.pl | 37 ++- scripts/extract-vsssdk-headers | 35 +++ scripts/qapi.py | 12 + util/error.c | 35 +++ 27 files changed, 2145 insertions(+), 24 deletions(-) create mode 100644 qga/vss-win32.c create mode 100644 qga/vss-win32.h create mode 100644 qga/vss-win32/Makefile.objs create mode 100644 qga/vss-win32/install.cpp create mode 100644 qga/vss-win32/provider.cpp create mode 100644 qga/vss-win32/qga-vss.def create mode 100644 qga/vss-win32/qga-vss.idl create mode 100644 qga/vss-win32/qga-vss.tlb create mode 100644 qga/vss-win32/requester.cpp create mode 100644 qga/vss-win32/requester.h create mode 100644 qga/vss-win32/vss-common.h create mode 100755 scripts/extract-vsssdk-headers
Hi Baiqing,
Thank you for reporting the problem.
I found a initialization issue for the Windows service thread in the v6 patch.
The patch attached should fix the problem.
I will submit the v7 patch including this soon.
Thanks,
Tomoki Sekiyama
Quoted 8 lines · Libaiqing
Hi tomoki,
I test the patch v6.
When calling the command " guest-fsfreeze-freeze ", an error occurs. The desc is "{"error": {"class": "GenericError", "desc": "failed to
initialize for backup: (error: 80042302)"}}"
The eventlog in the guest is : EventID 8193;CoCreateInstanceerror hr=
0x800401f0,CoInitialize is not called.Opertion :backup init.
Quoted 7 lines
When executing the qemu-ga.exe from the commandline,it goes well. Running the same configuration with the patch v5,it goes well.
I can provide more information if need.
Thanks
Baiqing.
requester.cpp | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-)
qga/vss-win32/requester.cpp +8 -7
@@ -49,17 +49,15 @@ static struct QGAVSSContext { STDAPI requester_init(void) { - HRESULT hr; - vss_ctx.hEventFrozen = vss_ctx.hEventThaw = INVALID_HANDLE_VALUE; - CoInitialize(NULL); - hr = CoInitializeSecurity( + COMInitializer initializer; /* to call CoInitializeSecurity */ + HRESULT hr = CoInitializeSecurity( NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_PKT_PRIVACY, RPC_C_IMP_LEVEL_IDENTIFY, NULL, EOAC_NONE, NULL); if (FAILED(hr)) { fprintf(stderr, "failed to CoInitializeSecurity (error %lx)\n", hr); - return HRESULT_FROM_WIN32(GetLastError()); + return hr; } hLib = LoadLibraryA("VSSAPI.DLL");
@@ -116,8 +114,6 @@ STDAPI requester_deinit(void) { requester_cleanup(); - CoUninitialize(); - pCreateVssBackupComponents = NULL; pVssFreeSnapshotProperties = NULL; if (hLib) {
@@ -251,6 +247,8 @@ void requester_freeze(int *num_vols, ErrorSet *errset) return; } + CoInitialize(NULL); + assert(pCreateVssBackupComponents != NULL); hr = pCreateVssBackupComponents(&vss_ctx.pVssbc); if (FAILED(hr)) {
@@ -424,6 +422,7 @@ out: vss_ctx.pVssbc->AbortBackup(); } requester_cleanup(); + CoUninitialize(); }
@@ -483,4 +482,6 @@ void requester_thaw(int *num_vols, ErrorSet *errset) } *num_vols = vss_ctx.cFrozenVols; requester_cleanup(); + + CoUninitialize(); }