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