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 <stdio.h> 14 #include "vss-common.h" 15 #include "requester.h" 16 #include "assert.h" 17 #include "inc/win2003/vswriter.h" 18 #include "inc/win2003/vsbackup.h" 19 20 /* Max wait time for frozen event (VSS can only hold writes for 10 seconds) */ 21 #define VSS_TIMEOUT_FREEZE_MSEC 10000 22 23 /* Call QueryStatus every 10 ms while waiting for frozen event */ 24 #define VSS_TIMEOUT_EVENT_MSEC 10 25 26 #define err_set(e, err, fmt, ...) \ 27 ((e)->error_set((e)->errp, err, (e)->err_class, fmt, ## __VA_ARGS__)) 28 #define err_is_set(e) ((e)->errp && *(e)->errp) 29 30 31 /* Handle to VSSAPI.DLL */ 32 static HMODULE hLib; 33 34 /* Functions in VSSAPI.DLL */ 35 typedef HRESULT(STDAPICALLTYPE * t_CreateVssBackupComponents)( 36 OUT IVssBackupComponents**); 37 typedef void(APIENTRY * t_VssFreeSnapshotProperties)(IN VSS_SNAPSHOT_PROP*); 38 static t_CreateVssBackupComponents pCreateVssBackupComponents; 39 static t_VssFreeSnapshotProperties pVssFreeSnapshotProperties; 40 41 /* Variables used while applications and filesystes are frozen by VSS */ 42 static struct QGAVSSContext { 43 IVssBackupComponents *pVssbc; /* VSS requester interface */ 44 IVssAsync *pAsyncSnapshot; /* async info of VSS snapshot operation */ 45 HANDLE hEventFrozen; /* notify fs/writer freeze from provider */ 46 HANDLE hEventThaw; /* request provider to thaw */ 47 HANDLE hEventTimeout; /* notify timeout in provider */ 48 int cFrozenVols; /* number of frozen volumes */ 49 } vss_ctx; 50 51 STDAPI requester_init(void) 52 { 53 vss_ctx.hEventFrozen = INVALID_HANDLE_VALUE; 54 vss_ctx.hEventThaw = INVALID_HANDLE_VALUE; 55 vss_ctx.hEventTimeout = INVALID_HANDLE_VALUE; 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 != INVALID_HANDLE_VALUE) { 98 CloseHandle(vss_ctx.hEventFrozen); 99 vss_ctx.hEventFrozen = INVALID_HANDLE_VALUE; 100 } 101 if (vss_ctx.hEventThaw != INVALID_HANDLE_VALUE) { 102 CloseHandle(vss_ctx.hEventThaw); 103 vss_ctx.hEventThaw = INVALID_HANDLE_VALUE; 104 } 105 if (vss_ctx.hEventTimeout != INVALID_HANDLE_VALUE) { 106 CloseHandle(vss_ctx.hEventTimeout); 107 vss_ctx.hEventTimeout = INVALID_HANDLE_VALUE; 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 void requester_freeze(int *num_vols, ErrorSet *errset) 240 { 241 COMPointer<IVssAsync> pAsync; 242 HANDLE volume; 243 HRESULT hr; 244 LONG ctx; 245 GUID guidSnapshotSet = GUID_NULL; 246 SECURITY_DESCRIPTOR sd; 247 SECURITY_ATTRIBUTES sa; 248 WCHAR short_volume_name[64], *display_name = short_volume_name; 249 DWORD wait_status; 250 int num_fixed_drives = 0, i; 251 252 if (vss_ctx.pVssbc) { /* already frozen */ 253 *num_vols = 0; 254 return; 255 } 256 257 CoInitialize(NULL); 258 259 assert(pCreateVssBackupComponents != NULL); 260 hr = pCreateVssBackupComponents(&vss_ctx.pVssbc); 261 if (FAILED(hr)) { 262 err_set(errset, hr, "failed to create VSS backup components"); 263 goto out; 264 } 265 266 hr = vss_ctx.pVssbc->InitializeForBackup(); 267 if (FAILED(hr)) { 268 err_set(errset, hr, "failed to initialize for backup"); 269 goto out; 270 } 271 272 hr = vss_ctx.pVssbc->SetBackupState(true, true, VSS_BT_FULL, false); 273 if (FAILED(hr)) { 274 err_set(errset, hr, "failed to set backup state"); 275 goto out; 276 } 277 278 /* 279 * Currently writable snapshots are not supported. 280 * To prevent the final commit (which requires to write to snapshots), 281 * ATTR_NO_AUTORECOVERY and ATTR_TRANSPORTABLE are specified here. 282 */ 283 ctx = VSS_CTX_APP_ROLLBACK | VSS_VOLSNAP_ATTR_TRANSPORTABLE | 284 VSS_VOLSNAP_ATTR_NO_AUTORECOVERY | VSS_VOLSNAP_ATTR_TXF_RECOVERY; 285 hr = vss_ctx.pVssbc->SetContext(ctx); 286 if (hr == (HRESULT)VSS_E_UNSUPPORTED_CONTEXT) { 287 /* Non-server version of Windows doesn't support ATTR_TRANSPORTABLE */ 288 ctx &= ~VSS_VOLSNAP_ATTR_TRANSPORTABLE; 289 hr = vss_ctx.pVssbc->SetContext(ctx); 290 } 291 if (FAILED(hr)) { 292 err_set(errset, hr, "failed to set backup context"); 293 goto out; 294 } 295 296 hr = vss_ctx.pVssbc->GatherWriterMetadata(pAsync.replace()); 297 if (SUCCEEDED(hr)) { 298 hr = WaitForAsync(pAsync); 299 } 300 if (FAILED(hr)) { 301 err_set(errset, hr, "failed to gather writer metadata"); 302 goto out; 303 } 304 305 AddComponents(errset); 306 if (err_is_set(errset)) { 307 goto out; 308 } 309 310 hr = vss_ctx.pVssbc->StartSnapshotSet(&guidSnapshotSet); 311 if (FAILED(hr)) { 312 err_set(errset, hr, "failed to start snapshot set"); 313 goto out; 314 } 315 316 volume = FindFirstVolumeW(short_volume_name, sizeof(short_volume_name)); 317 if (volume == INVALID_HANDLE_VALUE) { 318 err_set(errset, hr, "failed to find first volume"); 319 goto out; 320 } 321 for (;;) { 322 if (GetDriveTypeW(short_volume_name) == DRIVE_FIXED) { 323 VSS_ID pid; 324 hr = vss_ctx.pVssbc->AddToSnapshotSet(short_volume_name, 325 g_gProviderId, &pid); 326 if (FAILED(hr)) { 327 WCHAR volume_path_name[PATH_MAX]; 328 if (GetVolumePathNamesForVolumeNameW( 329 short_volume_name, volume_path_name, 330 sizeof(volume_path_name), NULL) && *volume_path_name) { 331 display_name = volume_path_name; 332 } 333 err_set(errset, hr, "failed to add %S to snapshot set", 334 display_name); 335 FindVolumeClose(volume); 336 goto out; 337 } 338 num_fixed_drives++; 339 } 340 if (!FindNextVolumeW(volume, short_volume_name, 341 sizeof(short_volume_name))) { 342 FindVolumeClose(volume); 343 break; 344 } 345 } 346 347 if (num_fixed_drives == 0) { 348 goto out; /* If there is no fixed drive, just exit. */ 349 } 350 351 hr = vss_ctx.pVssbc->PrepareForBackup(pAsync.replace()); 352 if (SUCCEEDED(hr)) { 353 hr = WaitForAsync(pAsync); 354 } 355 if (FAILED(hr)) { 356 err_set(errset, hr, "failed to prepare for backup"); 357 goto out; 358 } 359 360 hr = vss_ctx.pVssbc->GatherWriterStatus(pAsync.replace()); 361 if (SUCCEEDED(hr)) { 362 hr = WaitForAsync(pAsync); 363 } 364 if (FAILED(hr)) { 365 err_set(errset, hr, "failed to gather writer status"); 366 goto out; 367 } 368 369 /* Allow unrestricted access to events */ 370 InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION); 371 SetSecurityDescriptorDacl(&sd, TRUE, NULL, FALSE); 372 sa.nLength = sizeof(sa); 373 sa.lpSecurityDescriptor = &sd; 374 sa.bInheritHandle = FALSE; 375 376 vss_ctx.hEventFrozen = CreateEvent(&sa, TRUE, FALSE, EVENT_NAME_FROZEN); 377 if (vss_ctx.hEventFrozen == INVALID_HANDLE_VALUE) { 378 err_set(errset, GetLastError(), "failed to create event %s", 379 EVENT_NAME_FROZEN); 380 goto out; 381 } 382 vss_ctx.hEventThaw = CreateEvent(&sa, TRUE, FALSE, EVENT_NAME_THAW); 383 if (vss_ctx.hEventThaw == INVALID_HANDLE_VALUE) { 384 err_set(errset, GetLastError(), "failed to create event %s", 385 EVENT_NAME_THAW); 386 goto out; 387 } 388 vss_ctx.hEventTimeout = CreateEvent(&sa, TRUE, FALSE, EVENT_NAME_TIMEOUT); 389 if (vss_ctx.hEventTimeout == INVALID_HANDLE_VALUE) { 390 err_set(errset, GetLastError(), "failed to create event %s", 391 EVENT_NAME_TIMEOUT); 392 goto out; 393 } 394 395 /* 396 * Start VSS quiescing operations. 397 * CQGAVssProvider::CommitSnapshots will kick vss_ctx.hEventFrozen 398 * after the applications and filesystems are frozen. 399 */ 400 hr = vss_ctx.pVssbc->DoSnapshotSet(&vss_ctx.pAsyncSnapshot); 401 if (FAILED(hr)) { 402 err_set(errset, hr, "failed to do snapshot set"); 403 goto out; 404 } 405 406 /* Need to call QueryStatus several times to make VSS provider progress */ 407 for (i = 0; i < VSS_TIMEOUT_FREEZE_MSEC/VSS_TIMEOUT_EVENT_MSEC; i++) { 408 HRESULT hr2 = vss_ctx.pAsyncSnapshot->QueryStatus(&hr, NULL); 409 if (FAILED(hr2)) { 410 err_set(errset, hr, "failed to do snapshot set"); 411 goto out; 412 } 413 if (hr != VSS_S_ASYNC_PENDING) { 414 err_set(errset, E_FAIL, 415 "DoSnapshotSet exited without Frozen event"); 416 goto out; 417 } 418 wait_status = WaitForSingleObject(vss_ctx.hEventFrozen, 419 VSS_TIMEOUT_EVENT_MSEC); 420 if (wait_status != WAIT_TIMEOUT) { 421 break; 422 } 423 } 424 if (wait_status != WAIT_OBJECT_0) { 425 err_set(errset, E_FAIL, 426 "couldn't receive Frozen event from VSS provider"); 427 goto out; 428 } 429 430 *num_vols = vss_ctx.cFrozenVols = num_fixed_drives; 431 return; 432 433 out: 434 if (vss_ctx.pVssbc) { 435 vss_ctx.pVssbc->AbortBackup(); 436 } 437 requester_cleanup(); 438 CoUninitialize(); 439 } 440 441 442 void requester_thaw(int *num_vols, ErrorSet *errset) 443 { 444 COMPointer<IVssAsync> pAsync; 445 446 if (vss_ctx.hEventThaw == INVALID_HANDLE_VALUE) { 447 /* 448 * In this case, DoSnapshotSet is aborted or not started, 449 * and no volumes must be frozen. We return without an error. 450 */ 451 *num_vols = 0; 452 return; 453 } 454 455 /* Tell the provider that the snapshot is finished. */ 456 SetEvent(vss_ctx.hEventThaw); 457 458 assert(vss_ctx.pVssbc); 459 assert(vss_ctx.pAsyncSnapshot); 460 461 HRESULT hr = WaitForAsync(vss_ctx.pAsyncSnapshot); 462 switch (hr) { 463 case VSS_S_ASYNC_FINISHED: 464 hr = vss_ctx.pVssbc->BackupComplete(pAsync.replace()); 465 if (SUCCEEDED(hr)) { 466 hr = WaitForAsync(pAsync); 467 } 468 if (FAILED(hr)) { 469 err_set(errset, hr, "failed to complete backup"); 470 } 471 break; 472 473 case (HRESULT)VSS_E_OBJECT_NOT_FOUND: 474 /* 475 * On Windows earlier than 2008 SP2 which does not support 476 * VSS_VOLSNAP_ATTR_NO_AUTORECOVERY context, the final commit is not 477 * skipped and VSS is aborted by VSS_E_OBJECT_NOT_FOUND. However, as 478 * the system had been frozen until fsfreeze-thaw command was issued, 479 * we ignore this error. 480 */ 481 vss_ctx.pVssbc->AbortBackup(); 482 break; 483 484 case VSS_E_UNEXPECTED_PROVIDER_ERROR: 485 if (WaitForSingleObject(vss_ctx.hEventTimeout, 0) != WAIT_OBJECT_0) { 486 err_set(errset, hr, "unexpected error in VSS provider"); 487 break; 488 } 489 /* fall through if hEventTimeout is signaled */ 490 491 case (HRESULT)VSS_E_HOLD_WRITES_TIMEOUT: 492 err_set(errset, hr, "couldn't hold writes: " 493 "fsfreeze is limited up to 10 seconds"); 494 break; 495 496 default: 497 err_set(errset, hr, "failed to do snapshot set"); 498 } 499 500 if (err_is_set(errset)) { 501 vss_ctx.pVssbc->AbortBackup(); 502 } 503 *num_vols = vss_ctx.cFrozenVols; 504 requester_cleanup(); 505 506 CoUninitialize(); 507 } 508