]> git.proxmox.com Git - mirror_qemu.git/blob - qga/vss-win32/requester.cpp
QGA VSS: Replace 'fprintf(stderr' with qga_debug
[mirror_qemu.git] / qga / vss-win32 / requester.cpp
1 /*
2 * QEMU Guest Agent win32 VSS Requester implementations
3 *
4 * Copyright Hitachi Data Systems Corp. 2013
5 *
6 * Authors:
7 * Tomoki Sekiyama <tomoki.sekiyama@hds.com>
8 *
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.
11 */
12
13 #include "qemu/osdep.h"
14 #include "vss-common.h"
15 #include "vss-debug.h"
16 #include "requester.h"
17 #include "install.h"
18 #include <vswriter.h>
19 #include <vsbackup.h>
20
21 /* Max wait time for frozen event (VSS can only hold writes for 10 seconds) */
22 #define VSS_TIMEOUT_FREEZE_MSEC 60000
23
24 /* Call QueryStatus every 10 ms while waiting for frozen event */
25 #define VSS_TIMEOUT_EVENT_MSEC 10
26
27 #define DEFAULT_VSS_BACKUP_TYPE VSS_BT_FULL
28
29 #define err_set(e, err, fmt, ...) \
30 ((e)->error_setg_win32_wrapper((e)->errp, __FILE__, __LINE__, __func__, \
31 err, fmt, ## __VA_ARGS__))
32 /* Bad idea, works only when (e)->errp != NULL: */
33 #define err_is_set(e) ((e)->errp && *(e)->errp)
34 /* To lift this restriction, error_propagate(), like we do in QEMU code */
35
36 /* Handle to VSSAPI.DLL */
37 static HMODULE hLib;
38
39 /* Functions in VSSAPI.DLL */
40 typedef HRESULT(STDAPICALLTYPE * t_CreateVssBackupComponents)(
41 OUT IVssBackupComponents**);
42 typedef void(APIENTRY * t_VssFreeSnapshotProperties)(IN VSS_SNAPSHOT_PROP*);
43 static t_CreateVssBackupComponents pCreateVssBackupComponents;
44 static t_VssFreeSnapshotProperties pVssFreeSnapshotProperties;
45
46 /* Variables used while applications and filesystes are frozen by VSS */
47 static struct QGAVSSContext {
48 IVssBackupComponents *pVssbc; /* VSS requester interface */
49 IVssAsync *pAsyncSnapshot; /* async info of VSS snapshot operation */
50 HANDLE hEventFrozen; /* notify fs/writer freeze from provider */
51 HANDLE hEventThaw; /* request provider to thaw */
52 HANDLE hEventTimeout; /* notify timeout in provider */
53 int cFrozenVols; /* number of frozen volumes */
54 } vss_ctx;
55
56 STDAPI requester_init(void)
57 {
58 COMInitializer initializer; /* to call CoInitializeSecurity */
59 HRESULT hr = CoInitializeSecurity(
60 NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_PKT_PRIVACY,
61 RPC_C_IMP_LEVEL_IDENTIFY, NULL, EOAC_NONE, NULL);
62 if (FAILED(hr)) {
63 qga_debug("failed to CoInitializeSecurity (error %lx)", hr);
64 return hr;
65 }
66
67 hLib = LoadLibraryA("VSSAPI.DLL");
68 if (!hLib) {
69 qga_debug("failed to load VSSAPI.DLL");
70 return HRESULT_FROM_WIN32(GetLastError());
71 }
72
73 pCreateVssBackupComponents = (t_CreateVssBackupComponents)
74 GetProcAddress(hLib,
75 #ifdef _WIN64 /* 64bit environment */
76 "?CreateVssBackupComponents@@YAJPEAPEAVIVssBackupComponents@@@Z"
77 #else /* 32bit environment */
78 "?CreateVssBackupComponents@@YGJPAPAVIVssBackupComponents@@@Z"
79 #endif
80 );
81 if (!pCreateVssBackupComponents) {
82 qga_debug("failed to get proc address from VSSAPI.DLL");
83 return HRESULT_FROM_WIN32(GetLastError());
84 }
85
86 pVssFreeSnapshotProperties = (t_VssFreeSnapshotProperties)
87 GetProcAddress(hLib, "VssFreeSnapshotProperties");
88 if (!pVssFreeSnapshotProperties) {
89 qga_debug("failed to get proc address from VSSAPI.DLL");
90 return HRESULT_FROM_WIN32(GetLastError());
91 }
92
93 return S_OK;
94 }
95
96 static void requester_cleanup(void)
97 {
98 if (vss_ctx.hEventFrozen) {
99 CloseHandle(vss_ctx.hEventFrozen);
100 vss_ctx.hEventFrozen = NULL;
101 }
102 if (vss_ctx.hEventThaw) {
103 CloseHandle(vss_ctx.hEventThaw);
104 vss_ctx.hEventThaw = NULL;
105 }
106 if (vss_ctx.hEventTimeout) {
107 CloseHandle(vss_ctx.hEventTimeout);
108 vss_ctx.hEventTimeout = NULL;
109 }
110 if (vss_ctx.pAsyncSnapshot) {
111 vss_ctx.pAsyncSnapshot->Release();
112 vss_ctx.pAsyncSnapshot = NULL;
113 }
114 if (vss_ctx.pVssbc) {
115 vss_ctx.pVssbc->Release();
116 vss_ctx.pVssbc = NULL;
117 }
118 vss_ctx.cFrozenVols = 0;
119 }
120
121 STDAPI requester_deinit(void)
122 {
123 requester_cleanup();
124
125 pCreateVssBackupComponents = NULL;
126 pVssFreeSnapshotProperties = NULL;
127 if (hLib) {
128 FreeLibrary(hLib);
129 hLib = NULL;
130 }
131
132 return S_OK;
133 }
134
135 static HRESULT WaitForAsync(IVssAsync *pAsync)
136 {
137 HRESULT ret, hr;
138
139 do {
140 hr = pAsync->Wait();
141 if (FAILED(hr)) {
142 ret = hr;
143 break;
144 }
145 hr = pAsync->QueryStatus(&ret, NULL);
146 if (FAILED(hr)) {
147 ret = hr;
148 break;
149 }
150 } while (ret == VSS_S_ASYNC_PENDING);
151
152 return ret;
153 }
154
155 static void AddComponents(ErrorSet *errset)
156 {
157 unsigned int cWriters, i;
158 VSS_ID id, idInstance, idWriter;
159 BSTR bstrWriterName = NULL;
160 VSS_USAGE_TYPE usage;
161 VSS_SOURCE_TYPE source;
162 unsigned int cComponents, c1, c2, j;
163 COMPointer<IVssExamineWriterMetadata> pMetadata;
164 COMPointer<IVssWMComponent> pComponent;
165 PVSSCOMPONENTINFO info;
166 HRESULT hr;
167
168 hr = vss_ctx.pVssbc->GetWriterMetadataCount(&cWriters);
169 if (FAILED(hr)) {
170 err_set(errset, hr, "failed to get writer metadata count");
171 goto out;
172 }
173
174 for (i = 0; i < cWriters; i++) {
175 hr = vss_ctx.pVssbc->GetWriterMetadata(i, &id, pMetadata.replace());
176 if (FAILED(hr)) {
177 err_set(errset, hr, "failed to get writer metadata of %d/%d",
178 i, cWriters);
179 goto out;
180 }
181
182 hr = pMetadata->GetIdentity(&idInstance, &idWriter,
183 &bstrWriterName, &usage, &source);
184 if (FAILED(hr)) {
185 err_set(errset, hr, "failed to get identity of writer %d/%d",
186 i, cWriters);
187 goto out;
188 }
189
190 hr = pMetadata->GetFileCounts(&c1, &c2, &cComponents);
191 if (FAILED(hr)) {
192 err_set(errset, hr, "failed to get file counts of %S",
193 bstrWriterName);
194 goto out;
195 }
196
197 for (j = 0; j < cComponents; j++) {
198 hr = pMetadata->GetComponent(j, pComponent.replace());
199 if (FAILED(hr)) {
200 err_set(errset, hr,
201 "failed to get component %d/%d of %S",
202 j, cComponents, bstrWriterName);
203 goto out;
204 }
205
206 hr = pComponent->GetComponentInfo(&info);
207 if (FAILED(hr)) {
208 err_set(errset, hr,
209 "failed to get component info %d/%d of %S",
210 j, cComponents, bstrWriterName);
211 goto out;
212 }
213
214 if (info->bSelectable) {
215 hr = vss_ctx.pVssbc->AddComponent(idInstance, idWriter,
216 info->type,
217 info->bstrLogicalPath,
218 info->bstrComponentName);
219 if (FAILED(hr)) {
220 err_set(errset, hr, "failed to add component %S(%S)",
221 info->bstrComponentName, bstrWriterName);
222 goto out;
223 }
224 }
225 SysFreeString(bstrWriterName);
226 bstrWriterName = NULL;
227 pComponent->FreeComponentInfo(info);
228 info = NULL;
229 }
230 }
231 out:
232 if (bstrWriterName) {
233 SysFreeString(bstrWriterName);
234 }
235 if (pComponent && info) {
236 pComponent->FreeComponentInfo(info);
237 }
238 }
239
240 DWORD get_reg_dword_value(HKEY baseKey, LPCSTR subKey, LPCSTR valueName,
241 DWORD defaultData)
242 {
243 DWORD regGetValueError;
244 DWORD dwordData;
245 DWORD dataSize = sizeof(DWORD);
246
247 regGetValueError = RegGetValue(baseKey, subKey, valueName, RRF_RT_DWORD,
248 NULL, &dwordData, &dataSize);
249 if (regGetValueError != ERROR_SUCCESS) {
250 return defaultData;
251 }
252 return dwordData;
253 }
254
255 bool is_valid_vss_backup_type(VSS_BACKUP_TYPE vssBT)
256 {
257 return (vssBT > VSS_BT_UNDEFINED && vssBT < VSS_BT_OTHER);
258 }
259
260 VSS_BACKUP_TYPE get_vss_backup_type(
261 VSS_BACKUP_TYPE defaultVssBT = DEFAULT_VSS_BACKUP_TYPE)
262 {
263 VSS_BACKUP_TYPE vssBackupType;
264
265 vssBackupType = static_cast<VSS_BACKUP_TYPE>(
266 get_reg_dword_value(HKEY_LOCAL_MACHINE,
267 QGA_PROVIDER_REGISTRY_ADDRESS,
268 "VssOption",
269 defaultVssBT));
270 if (!is_valid_vss_backup_type(vssBackupType)) {
271 return defaultVssBT;
272 }
273 return vssBackupType;
274 }
275
276 void requester_freeze(int *num_vols, void *mountpoints, ErrorSet *errset)
277 {
278 COMPointer<IVssAsync> pAsync;
279 HANDLE volume;
280 HRESULT hr;
281 LONG ctx;
282 GUID guidSnapshotSet = GUID_NULL;
283 SECURITY_DESCRIPTOR sd;
284 SECURITY_ATTRIBUTES sa;
285 WCHAR short_volume_name[64], *display_name = short_volume_name;
286 DWORD wait_status;
287 int num_fixed_drives = 0, i;
288 int num_mount_points = 0;
289 VSS_BACKUP_TYPE vss_bt = get_vss_backup_type();
290
291 if (vss_ctx.pVssbc) { /* already frozen */
292 *num_vols = 0;
293 return;
294 }
295
296 CoInitialize(NULL);
297
298 /* Allow unrestricted access to events */
299 InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION);
300 SetSecurityDescriptorDacl(&sd, TRUE, NULL, FALSE);
301 sa.nLength = sizeof(sa);
302 sa.lpSecurityDescriptor = &sd;
303 sa.bInheritHandle = FALSE;
304
305 vss_ctx.hEventFrozen = CreateEvent(&sa, TRUE, FALSE, EVENT_NAME_FROZEN);
306 if (!vss_ctx.hEventFrozen) {
307 err_set(errset, GetLastError(), "failed to create event %s",
308 EVENT_NAME_FROZEN);
309 goto out;
310 }
311 vss_ctx.hEventThaw = CreateEvent(&sa, TRUE, FALSE, EVENT_NAME_THAW);
312 if (!vss_ctx.hEventThaw) {
313 err_set(errset, GetLastError(), "failed to create event %s",
314 EVENT_NAME_THAW);
315 goto out;
316 }
317 vss_ctx.hEventTimeout = CreateEvent(&sa, TRUE, FALSE, EVENT_NAME_TIMEOUT);
318 if (!vss_ctx.hEventTimeout) {
319 err_set(errset, GetLastError(), "failed to create event %s",
320 EVENT_NAME_TIMEOUT);
321 goto out;
322 }
323
324 assert(pCreateVssBackupComponents != NULL);
325 hr = pCreateVssBackupComponents(&vss_ctx.pVssbc);
326 if (FAILED(hr)) {
327 err_set(errset, hr, "failed to create VSS backup components");
328 goto out;
329 }
330
331 hr = vss_ctx.pVssbc->InitializeForBackup();
332 if (FAILED(hr)) {
333 err_set(errset, hr, "failed to initialize for backup");
334 goto out;
335 }
336
337 hr = vss_ctx.pVssbc->SetBackupState(true, true, vss_bt, false);
338 if (FAILED(hr)) {
339 err_set(errset, hr, "failed to set backup state");
340 goto out;
341 }
342
343 /*
344 * Currently writable snapshots are not supported.
345 * To prevent the final commit (which requires to write to snapshots),
346 * ATTR_NO_AUTORECOVERY and ATTR_TRANSPORTABLE are specified here.
347 */
348 ctx = VSS_CTX_APP_ROLLBACK | VSS_VOLSNAP_ATTR_TRANSPORTABLE |
349 VSS_VOLSNAP_ATTR_NO_AUTORECOVERY | VSS_VOLSNAP_ATTR_TXF_RECOVERY;
350 hr = vss_ctx.pVssbc->SetContext(ctx);
351 if (hr == (HRESULT)VSS_E_UNSUPPORTED_CONTEXT) {
352 /* Non-server version of Windows doesn't support ATTR_TRANSPORTABLE */
353 ctx &= ~VSS_VOLSNAP_ATTR_TRANSPORTABLE;
354 hr = vss_ctx.pVssbc->SetContext(ctx);
355 }
356 if (FAILED(hr)) {
357 err_set(errset, hr, "failed to set backup context");
358 goto out;
359 }
360
361 hr = vss_ctx.pVssbc->GatherWriterMetadata(pAsync.replace());
362 if (SUCCEEDED(hr)) {
363 hr = WaitForAsync(pAsync);
364 }
365 if (FAILED(hr)) {
366 err_set(errset, hr, "failed to gather writer metadata");
367 goto out;
368 }
369
370 AddComponents(errset);
371 if (err_is_set(errset)) {
372 goto out;
373 }
374
375 hr = vss_ctx.pVssbc->StartSnapshotSet(&guidSnapshotSet);
376 if (FAILED(hr)) {
377 err_set(errset, hr, "failed to start snapshot set");
378 goto out;
379 }
380
381 if (mountpoints) {
382 PWCHAR volume_name_wchar;
383 for (volList *list = (volList *)mountpoints; list; list = list->next) {
384 size_t len = strlen(list->value) + 1;
385 size_t converted = 0;
386 VSS_ID pid;
387
388 volume_name_wchar = new wchar_t[len];
389 mbstowcs_s(&converted, volume_name_wchar, len,
390 list->value, _TRUNCATE);
391
392 hr = vss_ctx.pVssbc->AddToSnapshotSet(volume_name_wchar,
393 g_gProviderId, &pid);
394 if (FAILED(hr)) {
395 err_set(errset, hr, "failed to add %S to snapshot set",
396 volume_name_wchar);
397 delete[] volume_name_wchar;
398 goto out;
399 }
400 num_mount_points++;
401
402 delete[] volume_name_wchar;
403 }
404
405 if (num_mount_points == 0) {
406 /* If there is no valid mount points, just exit. */
407 goto out;
408 }
409 }
410
411 if (!mountpoints) {
412 volume = FindFirstVolumeW(short_volume_name, sizeof(short_volume_name));
413 if (volume == INVALID_HANDLE_VALUE) {
414 err_set(errset, hr, "failed to find first volume");
415 goto out;
416 }
417
418 for (;;) {
419 if (GetDriveTypeW(short_volume_name) == DRIVE_FIXED) {
420 VSS_ID pid;
421 hr = vss_ctx.pVssbc->AddToSnapshotSet(short_volume_name,
422 g_gProviderId, &pid);
423 if (FAILED(hr)) {
424 WCHAR volume_path_name[PATH_MAX];
425 if (GetVolumePathNamesForVolumeNameW(
426 short_volume_name, volume_path_name,
427 sizeof(volume_path_name), NULL) &&
428 *volume_path_name) {
429 display_name = volume_path_name;
430 }
431 err_set(errset, hr, "failed to add %S to snapshot set",
432 display_name);
433 FindVolumeClose(volume);
434 goto out;
435 }
436 num_fixed_drives++;
437 }
438 if (!FindNextVolumeW(volume, short_volume_name,
439 sizeof(short_volume_name))) {
440 FindVolumeClose(volume);
441 break;
442 }
443 }
444
445 if (num_fixed_drives == 0) {
446 goto out; /* If there is no fixed drive, just exit. */
447 }
448 }
449
450 hr = vss_ctx.pVssbc->PrepareForBackup(pAsync.replace());
451 if (SUCCEEDED(hr)) {
452 hr = WaitForAsync(pAsync);
453 }
454 if (FAILED(hr)) {
455 err_set(errset, hr, "failed to prepare for backup");
456 goto out;
457 }
458
459 hr = vss_ctx.pVssbc->GatherWriterStatus(pAsync.replace());
460 if (SUCCEEDED(hr)) {
461 hr = WaitForAsync(pAsync);
462 }
463 if (FAILED(hr)) {
464 err_set(errset, hr, "failed to gather writer status");
465 goto out;
466 }
467
468 /*
469 * Start VSS quiescing operations.
470 * CQGAVssProvider::CommitSnapshots will kick vss_ctx.hEventFrozen
471 * after the applications and filesystems are frozen.
472 */
473 hr = vss_ctx.pVssbc->DoSnapshotSet(&vss_ctx.pAsyncSnapshot);
474 if (FAILED(hr)) {
475 err_set(errset, hr, "failed to do snapshot set");
476 goto out;
477 }
478
479 /* Need to call QueryStatus several times to make VSS provider progress */
480 for (i = 0; i < VSS_TIMEOUT_FREEZE_MSEC/VSS_TIMEOUT_EVENT_MSEC; i++) {
481 HRESULT hr2 = vss_ctx.pAsyncSnapshot->QueryStatus(&hr, NULL);
482 if (FAILED(hr2)) {
483 err_set(errset, hr, "failed to do snapshot set");
484 goto out;
485 }
486 if (hr != VSS_S_ASYNC_PENDING) {
487 err_set(errset, E_FAIL,
488 "DoSnapshotSet exited without Frozen event");
489 goto out;
490 }
491 wait_status = WaitForSingleObject(vss_ctx.hEventFrozen,
492 VSS_TIMEOUT_EVENT_MSEC);
493 if (wait_status != WAIT_TIMEOUT) {
494 break;
495 }
496 }
497
498 if (wait_status == WAIT_TIMEOUT) {
499 err_set(errset, E_FAIL,
500 "timeout when try to receive Frozen event from VSS provider");
501 /* If we are here, VSS had timeout.
502 * Don't call AbortBackup, just return directly.
503 */
504 goto out1;
505 }
506
507 if (wait_status != WAIT_OBJECT_0) {
508 err_set(errset, E_FAIL,
509 "couldn't receive Frozen event from VSS provider");
510 goto out;
511 }
512
513 if (mountpoints) {
514 *num_vols = vss_ctx.cFrozenVols = num_mount_points;
515 } else {
516 *num_vols = vss_ctx.cFrozenVols = num_fixed_drives;
517 }
518
519 return;
520
521 out:
522 if (vss_ctx.pVssbc) {
523 vss_ctx.pVssbc->AbortBackup();
524 }
525
526 out1:
527 requester_cleanup();
528 CoUninitialize();
529 }
530
531
532 void requester_thaw(int *num_vols, void *mountpints, ErrorSet *errset)
533 {
534 COMPointer<IVssAsync> pAsync;
535
536 if (!vss_ctx.hEventThaw) {
537 /*
538 * In this case, DoSnapshotSet is aborted or not started,
539 * and no volumes must be frozen. We return without an error.
540 */
541 *num_vols = 0;
542 return;
543 }
544
545 /* Tell the provider that the snapshot is finished. */
546 SetEvent(vss_ctx.hEventThaw);
547
548 assert(vss_ctx.pVssbc);
549 assert(vss_ctx.pAsyncSnapshot);
550
551 HRESULT hr = WaitForAsync(vss_ctx.pAsyncSnapshot);
552 switch (hr) {
553 case VSS_S_ASYNC_FINISHED:
554 hr = vss_ctx.pVssbc->BackupComplete(pAsync.replace());
555 if (SUCCEEDED(hr)) {
556 hr = WaitForAsync(pAsync);
557 }
558 if (FAILED(hr)) {
559 err_set(errset, hr, "failed to complete backup");
560 }
561 break;
562
563 case (HRESULT)VSS_E_OBJECT_NOT_FOUND:
564 /*
565 * On Windows earlier than 2008 SP2 which does not support
566 * VSS_VOLSNAP_ATTR_NO_AUTORECOVERY context, the final commit is not
567 * skipped and VSS is aborted by VSS_E_OBJECT_NOT_FOUND. However, as
568 * the system had been frozen until fsfreeze-thaw command was issued,
569 * we ignore this error.
570 */
571 vss_ctx.pVssbc->AbortBackup();
572 break;
573
574 case VSS_E_UNEXPECTED_PROVIDER_ERROR:
575 if (WaitForSingleObject(vss_ctx.hEventTimeout, 0) != WAIT_OBJECT_0) {
576 err_set(errset, hr, "unexpected error in VSS provider");
577 break;
578 }
579 /* fall through if hEventTimeout is signaled */
580
581 case (HRESULT)VSS_E_HOLD_WRITES_TIMEOUT:
582 err_set(errset, hr, "couldn't hold writes: "
583 "fsfreeze is limited up to 10 seconds");
584 break;
585
586 default:
587 err_set(errset, hr, "failed to do snapshot set");
588 }
589
590 if (err_is_set(errset)) {
591 vss_ctx.pVssbc->AbortBackup();
592 }
593 *num_vols = vss_ctx.cFrozenVols;
594 requester_cleanup();
595
596 CoUninitialize();
597 StopService();
598 }