2 * QEMU Guest Agent win32 VSS Requester implementations
4 * Copyright Hitachi Data Systems Corp. 2013
7 * Tomoki Sekiyama <tomoki.sekiyama@hds.com>
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"
17 #include <inc/win2003/vswriter.h>
18 #include <inc/win2003/vsbackup.h>
20 /* Max wait time for frozen event (VSS can only hold writes for 10 seconds) */
21 #define VSS_TIMEOUT_FREEZE_MSEC 10000
23 /* Call QueryStatus every 10 ms while waiting for frozen event */
24 #define VSS_TIMEOUT_EVENT_MSEC 10
26 #define err_set(e, err, fmt, ...) \
27 ((e)->error_setg_win32_wrapper((e)->errp, __FILE__, __LINE__, __func__, \
28 err, fmt, ## __VA_ARGS__))
29 /* Bad idea, works only when (e)->errp != NULL: */
30 #define err_is_set(e) ((e)->errp && *(e)->errp)
31 /* To lift this restriction, error_propagate(), like we do in QEMU code */
33 /* Handle to VSSAPI.DLL */
36 /* Functions in VSSAPI.DLL */
37 typedef HRESULT(STDAPICALLTYPE
* t_CreateVssBackupComponents
)(
38 OUT IVssBackupComponents
**);
39 typedef void(APIENTRY
* t_VssFreeSnapshotProperties
)(IN VSS_SNAPSHOT_PROP
*);
40 static t_CreateVssBackupComponents pCreateVssBackupComponents
;
41 static t_VssFreeSnapshotProperties pVssFreeSnapshotProperties
;
43 /* Variables used while applications and filesystes are frozen by VSS */
44 static struct QGAVSSContext
{
45 IVssBackupComponents
*pVssbc
; /* VSS requester interface */
46 IVssAsync
*pAsyncSnapshot
; /* async info of VSS snapshot operation */
47 HANDLE hEventFrozen
; /* notify fs/writer freeze from provider */
48 HANDLE hEventThaw
; /* request provider to thaw */
49 HANDLE hEventTimeout
; /* notify timeout in provider */
50 int cFrozenVols
; /* number of frozen volumes */
53 STDAPI
requester_init(void)
55 COMInitializer initializer
; /* to call CoInitializeSecurity */
56 HRESULT hr
= CoInitializeSecurity(
57 NULL
, -1, NULL
, NULL
, RPC_C_AUTHN_LEVEL_PKT_PRIVACY
,
58 RPC_C_IMP_LEVEL_IDENTIFY
, NULL
, EOAC_NONE
, NULL
);
60 fprintf(stderr
, "failed to CoInitializeSecurity (error %lx)\n", hr
);
64 hLib
= LoadLibraryA("VSSAPI.DLL");
66 fprintf(stderr
, "failed to load VSSAPI.DLL\n");
67 return HRESULT_FROM_WIN32(GetLastError());
70 pCreateVssBackupComponents
= (t_CreateVssBackupComponents
)
72 #ifdef _WIN64 /* 64bit environment */
73 "?CreateVssBackupComponents@@YAJPEAPEAVIVssBackupComponents@@@Z"
74 #else /* 32bit environment */
75 "?CreateVssBackupComponents@@YGJPAPAVIVssBackupComponents@@@Z"
78 if (!pCreateVssBackupComponents
) {
79 fprintf(stderr
, "failed to get proc address from VSSAPI.DLL\n");
80 return HRESULT_FROM_WIN32(GetLastError());
83 pVssFreeSnapshotProperties
= (t_VssFreeSnapshotProperties
)
84 GetProcAddress(hLib
, "VssFreeSnapshotProperties");
85 if (!pVssFreeSnapshotProperties
) {
86 fprintf(stderr
, "failed to get proc address from VSSAPI.DLL\n");
87 return HRESULT_FROM_WIN32(GetLastError());
93 static void requester_cleanup(void)
95 if (vss_ctx
.hEventFrozen
) {
96 CloseHandle(vss_ctx
.hEventFrozen
);
97 vss_ctx
.hEventFrozen
= NULL
;
99 if (vss_ctx
.hEventThaw
) {
100 CloseHandle(vss_ctx
.hEventThaw
);
101 vss_ctx
.hEventThaw
= NULL
;
103 if (vss_ctx
.hEventTimeout
) {
104 CloseHandle(vss_ctx
.hEventTimeout
);
105 vss_ctx
.hEventTimeout
= NULL
;
107 if (vss_ctx
.pAsyncSnapshot
) {
108 vss_ctx
.pAsyncSnapshot
->Release();
109 vss_ctx
.pAsyncSnapshot
= NULL
;
111 if (vss_ctx
.pVssbc
) {
112 vss_ctx
.pVssbc
->Release();
113 vss_ctx
.pVssbc
= NULL
;
115 vss_ctx
.cFrozenVols
= 0;
118 STDAPI
requester_deinit(void)
122 pCreateVssBackupComponents
= NULL
;
123 pVssFreeSnapshotProperties
= NULL
;
132 static HRESULT
WaitForAsync(IVssAsync
*pAsync
)
142 hr
= pAsync
->QueryStatus(&ret
, NULL
);
147 } while (ret
== VSS_S_ASYNC_PENDING
);
152 static void AddComponents(ErrorSet
*errset
)
154 unsigned int cWriters
, i
;
155 VSS_ID id
, idInstance
, idWriter
;
156 BSTR bstrWriterName
= NULL
;
157 VSS_USAGE_TYPE usage
;
158 VSS_SOURCE_TYPE source
;
159 unsigned int cComponents
, c1
, c2
, j
;
160 COMPointer
<IVssExamineWriterMetadata
> pMetadata
;
161 COMPointer
<IVssWMComponent
> pComponent
;
162 PVSSCOMPONENTINFO info
;
165 hr
= vss_ctx
.pVssbc
->GetWriterMetadataCount(&cWriters
);
167 err_set(errset
, hr
, "failed to get writer metadata count");
171 for (i
= 0; i
< cWriters
; i
++) {
172 hr
= vss_ctx
.pVssbc
->GetWriterMetadata(i
, &id
, pMetadata
.replace());
174 err_set(errset
, hr
, "failed to get writer metadata of %d/%d",
179 hr
= pMetadata
->GetIdentity(&idInstance
, &idWriter
,
180 &bstrWriterName
, &usage
, &source
);
182 err_set(errset
, hr
, "failed to get identity of writer %d/%d",
187 hr
= pMetadata
->GetFileCounts(&c1
, &c2
, &cComponents
);
189 err_set(errset
, hr
, "failed to get file counts of %S",
194 for (j
= 0; j
< cComponents
; j
++) {
195 hr
= pMetadata
->GetComponent(j
, pComponent
.replace());
198 "failed to get component %d/%d of %S",
199 j
, cComponents
, bstrWriterName
);
203 hr
= pComponent
->GetComponentInfo(&info
);
206 "failed to get component info %d/%d of %S",
207 j
, cComponents
, bstrWriterName
);
211 if (info
->bSelectable
) {
212 hr
= vss_ctx
.pVssbc
->AddComponent(idInstance
, idWriter
,
214 info
->bstrLogicalPath
,
215 info
->bstrComponentName
);
217 err_set(errset
, hr
, "failed to add component %S(%S)",
218 info
->bstrComponentName
, bstrWriterName
);
222 SysFreeString(bstrWriterName
);
223 bstrWriterName
= NULL
;
224 pComponent
->FreeComponentInfo(info
);
229 if (bstrWriterName
) {
230 SysFreeString(bstrWriterName
);
232 if (pComponent
&& info
) {
233 pComponent
->FreeComponentInfo(info
);
237 void requester_freeze(int *num_vols
, void *mountpoints
, ErrorSet
*errset
)
239 COMPointer
<IVssAsync
> pAsync
;
243 GUID guidSnapshotSet
= GUID_NULL
;
244 SECURITY_DESCRIPTOR sd
;
245 SECURITY_ATTRIBUTES sa
;
246 WCHAR short_volume_name
[64], *display_name
= short_volume_name
;
248 int num_fixed_drives
= 0, i
;
249 int num_mount_points
= 0;
251 if (vss_ctx
.pVssbc
) { /* already frozen */
258 /* Allow unrestricted access to events */
259 InitializeSecurityDescriptor(&sd
, SECURITY_DESCRIPTOR_REVISION
);
260 SetSecurityDescriptorDacl(&sd
, TRUE
, NULL
, FALSE
);
261 sa
.nLength
= sizeof(sa
);
262 sa
.lpSecurityDescriptor
= &sd
;
263 sa
.bInheritHandle
= FALSE
;
265 vss_ctx
.hEventFrozen
= CreateEvent(&sa
, TRUE
, FALSE
, EVENT_NAME_FROZEN
);
266 if (!vss_ctx
.hEventFrozen
) {
267 err_set(errset
, GetLastError(), "failed to create event %s",
271 vss_ctx
.hEventThaw
= CreateEvent(&sa
, TRUE
, FALSE
, EVENT_NAME_THAW
);
272 if (!vss_ctx
.hEventThaw
) {
273 err_set(errset
, GetLastError(), "failed to create event %s",
277 vss_ctx
.hEventTimeout
= CreateEvent(&sa
, TRUE
, FALSE
, EVENT_NAME_TIMEOUT
);
278 if (!vss_ctx
.hEventTimeout
) {
279 err_set(errset
, GetLastError(), "failed to create event %s",
284 assert(pCreateVssBackupComponents
!= NULL
);
285 hr
= pCreateVssBackupComponents(&vss_ctx
.pVssbc
);
287 err_set(errset
, hr
, "failed to create VSS backup components");
291 hr
= vss_ctx
.pVssbc
->InitializeForBackup();
293 err_set(errset
, hr
, "failed to initialize for backup");
297 hr
= vss_ctx
.pVssbc
->SetBackupState(true, true, VSS_BT_FULL
, false);
299 err_set(errset
, hr
, "failed to set backup state");
304 * Currently writable snapshots are not supported.
305 * To prevent the final commit (which requires to write to snapshots),
306 * ATTR_NO_AUTORECOVERY and ATTR_TRANSPORTABLE are specified here.
308 ctx
= VSS_CTX_APP_ROLLBACK
| VSS_VOLSNAP_ATTR_TRANSPORTABLE
|
309 VSS_VOLSNAP_ATTR_NO_AUTORECOVERY
| VSS_VOLSNAP_ATTR_TXF_RECOVERY
;
310 hr
= vss_ctx
.pVssbc
->SetContext(ctx
);
311 if (hr
== (HRESULT
)VSS_E_UNSUPPORTED_CONTEXT
) {
312 /* Non-server version of Windows doesn't support ATTR_TRANSPORTABLE */
313 ctx
&= ~VSS_VOLSNAP_ATTR_TRANSPORTABLE
;
314 hr
= vss_ctx
.pVssbc
->SetContext(ctx
);
317 err_set(errset
, hr
, "failed to set backup context");
321 hr
= vss_ctx
.pVssbc
->GatherWriterMetadata(pAsync
.replace());
323 hr
= WaitForAsync(pAsync
);
326 err_set(errset
, hr
, "failed to gather writer metadata");
330 AddComponents(errset
);
331 if (err_is_set(errset
)) {
335 hr
= vss_ctx
.pVssbc
->StartSnapshotSet(&guidSnapshotSet
);
337 err_set(errset
, hr
, "failed to start snapshot set");
342 PWCHAR volume_name_wchar
;
343 for (volList
*list
= (volList
*)mountpoints
; list
; list
= list
->next
) {
344 size_t len
= strlen(list
->value
) + 1;
345 size_t converted
= 0;
348 volume_name_wchar
= new wchar_t[len
];
349 mbstowcs_s(&converted
, volume_name_wchar
, len
,
350 list
->value
, _TRUNCATE
);
352 hr
= vss_ctx
.pVssbc
->AddToSnapshotSet(volume_name_wchar
,
353 g_gProviderId
, &pid
);
355 err_set(errset
, hr
, "failed to add %S to snapshot set",
357 delete volume_name_wchar
;
362 delete volume_name_wchar
;
365 if (num_mount_points
== 0) {
366 /* If there is no valid mount points, just exit. */
372 volume
= FindFirstVolumeW(short_volume_name
, sizeof(short_volume_name
));
373 if (volume
== INVALID_HANDLE_VALUE
) {
374 err_set(errset
, hr
, "failed to find first volume");
379 if (GetDriveTypeW(short_volume_name
) == DRIVE_FIXED
) {
381 hr
= vss_ctx
.pVssbc
->AddToSnapshotSet(short_volume_name
,
382 g_gProviderId
, &pid
);
384 WCHAR volume_path_name
[PATH_MAX
];
385 if (GetVolumePathNamesForVolumeNameW(
386 short_volume_name
, volume_path_name
,
387 sizeof(volume_path_name
), NULL
) &&
389 display_name
= volume_path_name
;
391 err_set(errset
, hr
, "failed to add %S to snapshot set",
393 FindVolumeClose(volume
);
398 if (!FindNextVolumeW(volume
, short_volume_name
,
399 sizeof(short_volume_name
))) {
400 FindVolumeClose(volume
);
405 if (num_fixed_drives
== 0) {
406 goto out
; /* If there is no fixed drive, just exit. */
410 hr
= vss_ctx
.pVssbc
->PrepareForBackup(pAsync
.replace());
412 hr
= WaitForAsync(pAsync
);
415 err_set(errset
, hr
, "failed to prepare for backup");
419 hr
= vss_ctx
.pVssbc
->GatherWriterStatus(pAsync
.replace());
421 hr
= WaitForAsync(pAsync
);
424 err_set(errset
, hr
, "failed to gather writer status");
429 * Start VSS quiescing operations.
430 * CQGAVssProvider::CommitSnapshots will kick vss_ctx.hEventFrozen
431 * after the applications and filesystems are frozen.
433 hr
= vss_ctx
.pVssbc
->DoSnapshotSet(&vss_ctx
.pAsyncSnapshot
);
435 err_set(errset
, hr
, "failed to do snapshot set");
439 /* Need to call QueryStatus several times to make VSS provider progress */
440 for (i
= 0; i
< VSS_TIMEOUT_FREEZE_MSEC
/VSS_TIMEOUT_EVENT_MSEC
; i
++) {
441 HRESULT hr2
= vss_ctx
.pAsyncSnapshot
->QueryStatus(&hr
, NULL
);
443 err_set(errset
, hr
, "failed to do snapshot set");
446 if (hr
!= VSS_S_ASYNC_PENDING
) {
447 err_set(errset
, E_FAIL
,
448 "DoSnapshotSet exited without Frozen event");
451 wait_status
= WaitForSingleObject(vss_ctx
.hEventFrozen
,
452 VSS_TIMEOUT_EVENT_MSEC
);
453 if (wait_status
!= WAIT_TIMEOUT
) {
458 if (wait_status
== WAIT_TIMEOUT
) {
459 err_set(errset
, E_FAIL
,
460 "timeout when try to receive Frozen event from VSS provider");
461 /* If we are here, VSS had timeout.
462 * Don't call AbortBackup, just return directly.
467 if (wait_status
!= WAIT_OBJECT_0
) {
468 err_set(errset
, E_FAIL
,
469 "couldn't receive Frozen event from VSS provider");
474 *num_vols
= vss_ctx
.cFrozenVols
= num_mount_points
;
476 *num_vols
= vss_ctx
.cFrozenVols
= num_fixed_drives
;
482 if (vss_ctx
.pVssbc
) {
483 vss_ctx
.pVssbc
->AbortBackup();
492 void requester_thaw(int *num_vols
, void *mountpints
, ErrorSet
*errset
)
494 COMPointer
<IVssAsync
> pAsync
;
496 if (!vss_ctx
.hEventThaw
) {
498 * In this case, DoSnapshotSet is aborted or not started,
499 * and no volumes must be frozen. We return without an error.
505 /* Tell the provider that the snapshot is finished. */
506 SetEvent(vss_ctx
.hEventThaw
);
508 assert(vss_ctx
.pVssbc
);
509 assert(vss_ctx
.pAsyncSnapshot
);
511 HRESULT hr
= WaitForAsync(vss_ctx
.pAsyncSnapshot
);
513 case VSS_S_ASYNC_FINISHED
:
514 hr
= vss_ctx
.pVssbc
->BackupComplete(pAsync
.replace());
516 hr
= WaitForAsync(pAsync
);
519 err_set(errset
, hr
, "failed to complete backup");
523 case (HRESULT
)VSS_E_OBJECT_NOT_FOUND
:
525 * On Windows earlier than 2008 SP2 which does not support
526 * VSS_VOLSNAP_ATTR_NO_AUTORECOVERY context, the final commit is not
527 * skipped and VSS is aborted by VSS_E_OBJECT_NOT_FOUND. However, as
528 * the system had been frozen until fsfreeze-thaw command was issued,
529 * we ignore this error.
531 vss_ctx
.pVssbc
->AbortBackup();
534 case VSS_E_UNEXPECTED_PROVIDER_ERROR
:
535 if (WaitForSingleObject(vss_ctx
.hEventTimeout
, 0) != WAIT_OBJECT_0
) {
536 err_set(errset
, hr
, "unexpected error in VSS provider");
539 /* fall through if hEventTimeout is signaled */
541 case (HRESULT
)VSS_E_HOLD_WRITES_TIMEOUT
:
542 err_set(errset
, hr
, "couldn't hold writes: "
543 "fsfreeze is limited up to 10 seconds");
547 err_set(errset
, hr
, "failed to do snapshot set");
550 if (err_is_set(errset
)) {
551 vss_ctx
.pVssbc
->AbortBackup();
553 *num_vols
= vss_ctx
.cFrozenVols
;