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