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