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