2 * QEMU Guest Agent win32 VSS Requester implementations
4 * Copyright Hitachi Data Systems Corp. 2013
9 * This work is licensed under the terms of the GNU GPL, version 2 or later.
10 * See the COPYING file in the top-level directory.
13 #include "qemu/osdep.h"
14 #include "vss-common.h"
15 #include "requester.h"
16 #include <inc/win2003/vswriter.h>
17 #include <inc/win2003/vsbackup.h>
19 /* Max wait time for frozen event (VSS can only hold writes for 10 seconds) */
20 #define VSS_TIMEOUT_FREEZE_MSEC 10000
22 /* Call QueryStatus every 10 ms while waiting for frozen event */
23 #define VSS_TIMEOUT_EVENT_MSEC 10
25 #define err_set(e, err, fmt, ...) \
26 ((e)->error_setg_win32_wrapper((e)->errp, __FILE__, __LINE__, __func__, \
27 err, fmt, ## __VA_ARGS__))
28 /* Bad idea, works only when (e)->errp != NULL: */
29 #define err_is_set(e) ((e)->errp && *(e)->errp)
30 /* To lift this restriction, error_propagate(), like we do in QEMU code */
32 /* Handle to VSSAPI.DLL */
35 /* Functions in VSSAPI.DLL */
36 typedef HRESULT(STDAPICALLTYPE * t_CreateVssBackupComponents)(
37 OUT IVssBackupComponents**);
38 typedef void(APIENTRY * t_VssFreeSnapshotProperties)(IN VSS_SNAPSHOT_PROP*);
39 static t_CreateVssBackupComponents pCreateVssBackupComponents;
40 static t_VssFreeSnapshotProperties pVssFreeSnapshotProperties;
42 /* Variables used while applications and filesystes are frozen by VSS */
43 static struct QGAVSSContext {
44 IVssBackupComponents *pVssbc; /* VSS requester interface */
45 IVssAsync *pAsyncSnapshot; /* async info of VSS snapshot operation */
46 HANDLE hEventFrozen; /* notify fs/writer freeze from provider */
47 HANDLE hEventThaw; /* request provider to thaw */
48 HANDLE hEventTimeout; /* notify timeout in provider */
49 int cFrozenVols; /* number of frozen volumes */
52 STDAPI requester_init(void)
54 COMInitializer initializer; /* to call CoInitializeSecurity */
55 HRESULT hr = CoInitializeSecurity(
56 NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_PKT_PRIVACY,
57 RPC_C_IMP_LEVEL_IDENTIFY, NULL, EOAC_NONE, NULL);
59 fprintf(stderr, "failed to CoInitializeSecurity (error %lx)\n", hr);
63 hLib = LoadLibraryA("VSSAPI.DLL");
65 fprintf(stderr, "failed to load VSSAPI.DLL\n");
66 return HRESULT_FROM_WIN32(GetLastError());
69 pCreateVssBackupComponents = (t_CreateVssBackupComponents)
71 #ifdef _WIN64 /* 64bit environment */
72 "?CreateVssBackupComponents@@YAJPEAPEAVIVssBackupComponents@@@Z"
73 #else /* 32bit environment */
74 "?CreateVssBackupComponents@@YGJPAPAVIVssBackupComponents@@@Z"
77 if (!pCreateVssBackupComponents) {
78 fprintf(stderr, "failed to get proc address from VSSAPI.DLL\n");
79 return HRESULT_FROM_WIN32(GetLastError());
82 pVssFreeSnapshotProperties = (t_VssFreeSnapshotProperties)
83 GetProcAddress(hLib, "VssFreeSnapshotProperties");
84 if (!pVssFreeSnapshotProperties) {
85 fprintf(stderr, "failed to get proc address from VSSAPI.DLL\n");
86 return HRESULT_FROM_WIN32(GetLastError());
92 static void requester_cleanup(void)
94 if (vss_ctx.hEventFrozen) {
95 CloseHandle(vss_ctx.hEventFrozen);
96 vss_ctx.hEventFrozen = NULL;
98 if (vss_ctx.hEventThaw) {
99 CloseHandle(vss_ctx.hEventThaw);
100 vss_ctx.hEventThaw = NULL;
102 if (vss_ctx.hEventTimeout) {
103 CloseHandle(vss_ctx.hEventTimeout);
104 vss_ctx.hEventTimeout = NULL;
106 if (vss_ctx.pAsyncSnapshot) {
107 vss_ctx.pAsyncSnapshot->Release();
108 vss_ctx.pAsyncSnapshot = NULL;
110 if (vss_ctx.pVssbc) {
111 vss_ctx.pVssbc->Release();
112 vss_ctx.pVssbc = NULL;
114 vss_ctx.cFrozenVols = 0;
117 STDAPI requester_deinit(void)
121 pCreateVssBackupComponents = NULL;
122 pVssFreeSnapshotProperties = NULL;
131 static HRESULT WaitForAsync(IVssAsync *pAsync)
141 hr = pAsync->QueryStatus(&ret, NULL);
146 } while (ret == VSS_S_ASYNC_PENDING);
151 static void AddComponents(ErrorSet *errset)
153 unsigned int cWriters, i;
154 VSS_ID id, idInstance, idWriter;
155 BSTR bstrWriterName = NULL;
156 VSS_USAGE_TYPE usage;
157 VSS_SOURCE_TYPE source;
158 unsigned int cComponents, c1, c2, j;
159 COMPointer<IVssExamineWriterMetadata> pMetadata;
160 COMPointer<IVssWMComponent> pComponent;
161 PVSSCOMPONENTINFO info;
164 hr = vss_ctx.pVssbc->GetWriterMetadataCount(&cWriters);
166 err_set(errset, hr, "failed to get writer metadata count");
170 for (i = 0; i < cWriters; i++) {
171 hr = vss_ctx.pVssbc->GetWriterMetadata(i, &id, pMetadata.replace());
173 err_set(errset, hr, "failed to get writer metadata of %d/%d",
178 hr = pMetadata->GetIdentity(&idInstance, &idWriter,
179 &bstrWriterName, &usage, &source);
181 err_set(errset, hr, "failed to get identity of writer %d/%d",
186 hr = pMetadata->GetFileCounts(&c1, &c2, &cComponents);
188 err_set(errset, hr, "failed to get file counts of %S",
193 for (j = 0; j < cComponents; j++) {
194 hr = pMetadata->GetComponent(j, pComponent.replace());
197 "failed to get component %d/%d of %S",
198 j, cComponents, bstrWriterName);
202 hr = pComponent->GetComponentInfo(&info);
205 "failed to get component info %d/%d of %S",
206 j, cComponents, bstrWriterName);
210 if (info->bSelectable) {
211 hr = vss_ctx.pVssbc->AddComponent(idInstance, idWriter,
213 info->bstrLogicalPath,
214 info->bstrComponentName);
216 err_set(errset, hr, "failed to add component %S(%S)",
217 info->bstrComponentName, bstrWriterName);
221 SysFreeString(bstrWriterName);
222 bstrWriterName = NULL;
223 pComponent->FreeComponentInfo(info);
228 if (bstrWriterName) {
229 SysFreeString(bstrWriterName);
231 if (pComponent && info) {
232 pComponent->FreeComponentInfo(info);
236 void requester_freeze(int *num_vols, ErrorSet *errset)
238 COMPointer<IVssAsync> pAsync;
242 GUID guidSnapshotSet = GUID_NULL;
243 SECURITY_DESCRIPTOR sd;
244 SECURITY_ATTRIBUTES sa;
245 WCHAR short_volume_name[64], *display_name = short_volume_name;
247 int num_fixed_drives = 0, i;
249 if (vss_ctx.pVssbc) { /* already frozen */
256 /* Allow unrestricted access to events */
257 InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION);
258 SetSecurityDescriptorDacl(&sd, TRUE, NULL, FALSE);
259 sa.nLength = sizeof(sa);
260 sa.lpSecurityDescriptor = &sd;
261 sa.bInheritHandle = FALSE;
263 vss_ctx.hEventFrozen = CreateEvent(&sa, TRUE, FALSE, EVENT_NAME_FROZEN);
264 if (!vss_ctx.hEventFrozen) {
265 err_set(errset, GetLastError(), "failed to create event %s",
269 vss_ctx.hEventThaw = CreateEvent(&sa, TRUE, FALSE, EVENT_NAME_THAW);
270 if (!vss_ctx.hEventThaw) {
271 err_set(errset, GetLastError(), "failed to create event %s",
275 vss_ctx.hEventTimeout = CreateEvent(&sa, TRUE, FALSE, EVENT_NAME_TIMEOUT);
276 if (!vss_ctx.hEventTimeout) {
277 err_set(errset, GetLastError(), "failed to create event %s",
282 assert(pCreateVssBackupComponents != NULL);
283 hr = pCreateVssBackupComponents(&vss_ctx.pVssbc);
285 err_set(errset, hr, "failed to create VSS backup components");
289 hr = vss_ctx.pVssbc->InitializeForBackup();
291 err_set(errset, hr, "failed to initialize for backup");
295 hr = vss_ctx.pVssbc->SetBackupState(true, true, VSS_BT_FULL, false);
297 err_set(errset, hr, "failed to set backup state");
302 * Currently writable snapshots are not supported.
303 * To prevent the final commit (which requires to write to snapshots),
304 * ATTR_NO_AUTORECOVERY and ATTR_TRANSPORTABLE are specified here.
306 ctx = VSS_CTX_APP_ROLLBACK | VSS_VOLSNAP_ATTR_TRANSPORTABLE |
307 VSS_VOLSNAP_ATTR_NO_AUTORECOVERY | VSS_VOLSNAP_ATTR_TXF_RECOVERY;
308 hr = vss_ctx.pVssbc->SetContext(ctx);
309 if (hr == (HRESULT)VSS_E_UNSUPPORTED_CONTEXT) {
310 /* Non-server version of Windows doesn't support ATTR_TRANSPORTABLE */
311 ctx &= ~VSS_VOLSNAP_ATTR_TRANSPORTABLE;
312 hr = vss_ctx.pVssbc->SetContext(ctx);
315 err_set(errset, hr, "failed to set backup context");
319 hr = vss_ctx.pVssbc->GatherWriterMetadata(pAsync.replace());
321 hr = WaitForAsync(pAsync);
324 err_set(errset, hr, "failed to gather writer metadata");
328 AddComponents(errset);
329 if (err_is_set(errset)) {
333 hr = vss_ctx.pVssbc->StartSnapshotSet(&guidSnapshotSet);
335 err_set(errset, hr, "failed to start snapshot set");
339 volume = FindFirstVolumeW(short_volume_name, sizeof(short_volume_name));
340 if (volume == INVALID_HANDLE_VALUE) {
341 err_set(errset, hr, "failed to find first volume");
345 if (GetDriveTypeW(short_volume_name) == DRIVE_FIXED) {
347 hr = vss_ctx.pVssbc->AddToSnapshotSet(short_volume_name,
348 g_gProviderId, &pid);
350 WCHAR volume_path_name[PATH_MAX];
351 if (GetVolumePathNamesForVolumeNameW(
352 short_volume_name, volume_path_name,
353 sizeof(volume_path_name), NULL) && *volume_path_name) {
354 display_name = volume_path_name;
356 err_set(errset, hr, "failed to add %S to snapshot set",
358 FindVolumeClose(volume);
363 if (!FindNextVolumeW(volume, short_volume_name,
364 sizeof(short_volume_name))) {
365 FindVolumeClose(volume);
370 if (num_fixed_drives == 0) {
371 goto out; /* If there is no fixed drive, just exit. */
374 hr = vss_ctx.pVssbc->PrepareForBackup(pAsync.replace());
376 hr = WaitForAsync(pAsync);
379 err_set(errset, hr, "failed to prepare for backup");
383 hr = vss_ctx.pVssbc->GatherWriterStatus(pAsync.replace());
385 hr = WaitForAsync(pAsync);
388 err_set(errset, hr, "failed to gather writer status");
393 * Start VSS quiescing operations.
394 * CQGAVssProvider::CommitSnapshots will kick vss_ctx.hEventFrozen
395 * after the applications and filesystems are frozen.
397 hr = vss_ctx.pVssbc->DoSnapshotSet(&vss_ctx.pAsyncSnapshot);
399 err_set(errset, hr, "failed to do snapshot set");
403 /* Need to call QueryStatus several times to make VSS provider progress */
404 for (i = 0; i < VSS_TIMEOUT_FREEZE_MSEC/VSS_TIMEOUT_EVENT_MSEC; i++) {
405 HRESULT hr2 = vss_ctx.pAsyncSnapshot->QueryStatus(&hr, NULL);
407 err_set(errset, hr, "failed to do snapshot set");
410 if (hr != VSS_S_ASYNC_PENDING) {
411 err_set(errset, E_FAIL,
412 "DoSnapshotSet exited without Frozen event");
415 wait_status = WaitForSingleObject(vss_ctx.hEventFrozen,
416 VSS_TIMEOUT_EVENT_MSEC);
417 if (wait_status != WAIT_TIMEOUT) {
421 if (wait_status != WAIT_OBJECT_0) {
422 err_set(errset, E_FAIL,
423 "couldn't receive Frozen event from VSS provider");
427 *num_vols = vss_ctx.cFrozenVols = num_fixed_drives;
431 if (vss_ctx.pVssbc) {
432 vss_ctx.pVssbc->AbortBackup();
439 void requester_thaw(int *num_vols, ErrorSet *errset)
441 COMPointer<IVssAsync> pAsync;
443 if (!vss_ctx.hEventThaw) {
445 * In this case, DoSnapshotSet is aborted or not started,
446 * and no volumes must be frozen. We return without an error.
452 /* Tell the provider that the snapshot is finished. */
453 SetEvent(vss_ctx.hEventThaw);
455 assert(vss_ctx.pVssbc);
456 assert(vss_ctx.pAsyncSnapshot);
458 HRESULT hr = WaitForAsync(vss_ctx.pAsyncSnapshot);
460 case VSS_S_ASYNC_FINISHED:
461 hr = vss_ctx.pVssbc->BackupComplete(pAsync.replace());
463 hr = WaitForAsync(pAsync);
466 err_set(errset, hr, "failed to complete backup");
470 case (HRESULT)VSS_E_OBJECT_NOT_FOUND:
472 * On Windows earlier than 2008 SP2 which does not support
473 * VSS_VOLSNAP_ATTR_NO_AUTORECOVERY context, the final commit is not
474 * skipped and VSS is aborted by VSS_E_OBJECT_NOT_FOUND. However, as
475 * the system had been frozen until fsfreeze-thaw command was issued,
476 * we ignore this error.
478 vss_ctx.pVssbc->AbortBackup();
481 case VSS_E_UNEXPECTED_PROVIDER_ERROR:
482 if (WaitForSingleObject(vss_ctx.hEventTimeout, 0) != WAIT_OBJECT_0) {
483 err_set(errset, hr, "unexpected error in VSS provider");
486 /* fall through if hEventTimeout is signaled */
488 case (HRESULT)VSS_E_HOLD_WRITES_TIMEOUT:
489 err_set(errset, hr, "couldn't hold writes: "
490 "fsfreeze is limited up to 10 seconds");
494 err_set(errset, hr, "failed to do snapshot set");
497 if (err_is_set(errset)) {
498 vss_ctx.pVssbc->AbortBackup();
500 *num_vols = vss_ctx.cFrozenVols;