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 COMInitializer initializer; /* to call CoInitializeSecurity */ 54 HRESULT hr = CoInitializeSecurity( 55 NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_PKT_PRIVACY, 56 RPC_C_IMP_LEVEL_IDENTIFY, NULL, EOAC_NONE, NULL); 57 if (FAILED(hr)) { 58 fprintf(stderr, "failed to CoInitializeSecurity (error %lx)\n", hr); 59 return hr; 60 } 61 62 hLib = LoadLibraryA("VSSAPI.DLL"); 63 if (!hLib) { 64 fprintf(stderr, "failed to load VSSAPI.DLL\n"); 65 return HRESULT_FROM_WIN32(GetLastError()); 66 } 67 68 pCreateVssBackupComponents = (t_CreateVssBackupComponents) 69 GetProcAddress(hLib, 70 #ifdef _WIN64 /* 64bit environment */ 71 "?CreateVssBackupComponents@@YAJPEAPEAVIVssBackupComponents@@@Z" 72 #else /* 32bit environment */ 73 "?CreateVssBackupComponents@@YGJPAPAVIVssBackupComponents@@@Z" 74 #endif 75 ); 76 if (!pCreateVssBackupComponents) { 77 fprintf(stderr, "failed to get proc address from VSSAPI.DLL\n"); 78 return HRESULT_FROM_WIN32(GetLastError()); 79 } 80 81 pVssFreeSnapshotProperties = (t_VssFreeSnapshotProperties) 82 GetProcAddress(hLib, "VssFreeSnapshotProperties"); 83 if (!pVssFreeSnapshotProperties) { 84 fprintf(stderr, "failed to get proc address from VSSAPI.DLL\n"); 85 return HRESULT_FROM_WIN32(GetLastError()); 86 } 87 88 return S_OK; 89 } 90 91 static void requester_cleanup(void) 92 { 93 if (vss_ctx.hEventFrozen) { 94 CloseHandle(vss_ctx.hEventFrozen); 95 vss_ctx.hEventFrozen = NULL; 96 } 97 if (vss_ctx.hEventThaw) { 98 CloseHandle(vss_ctx.hEventThaw); 99 vss_ctx.hEventThaw = NULL; 100 } 101 if (vss_ctx.hEventTimeout) { 102 CloseHandle(vss_ctx.hEventTimeout); 103 vss_ctx.hEventTimeout = NULL; 104 } 105 if (vss_ctx.pAsyncSnapshot) { 106 vss_ctx.pAsyncSnapshot->Release(); 107 vss_ctx.pAsyncSnapshot = NULL; 108 } 109 if (vss_ctx.pVssbc) { 110 vss_ctx.pVssbc->Release(); 111 vss_ctx.pVssbc = NULL; 112 } 113 vss_ctx.cFrozenVols = 0; 114 } 115 116 STDAPI requester_deinit(void) 117 { 118 requester_cleanup(); 119 120 pCreateVssBackupComponents = NULL; 121 pVssFreeSnapshotProperties = NULL; 122 if (hLib) { 123 FreeLibrary(hLib); 124 hLib = NULL; 125 } 126 127 return S_OK; 128 } 129 130 static HRESULT WaitForAsync(IVssAsync *pAsync) 131 { 132 HRESULT ret, hr; 133 134 do { 135 hr = pAsync->Wait(); 136 if (FAILED(hr)) { 137 ret = hr; 138 break; 139 } 140 hr = pAsync->QueryStatus(&ret, NULL); 141 if (FAILED(hr)) { 142 ret = hr; 143 break; 144 } 145 } while (ret == VSS_S_ASYNC_PENDING); 146 147 return ret; 148 } 149 150 static void AddComponents(ErrorSet *errset) 151 { 152 unsigned int cWriters, i; 153 VSS_ID id, idInstance, idWriter; 154 BSTR bstrWriterName = NULL; 155 VSS_USAGE_TYPE usage; 156 VSS_SOURCE_TYPE source; 157 unsigned int cComponents, c1, c2, j; 158 COMPointer<IVssExamineWriterMetadata> pMetadata; 159 COMPointer<IVssWMComponent> pComponent; 160 PVSSCOMPONENTINFO info; 161 HRESULT hr; 162 163 hr = vss_ctx.pVssbc->GetWriterMetadataCount(&cWriters); 164 if (FAILED(hr)) { 165 err_set(errset, hr, "failed to get writer metadata count"); 166 goto out; 167 } 168 169 for (i = 0; i < cWriters; i++) { 170 hr = vss_ctx.pVssbc->GetWriterMetadata(i, &id, pMetadata.replace()); 171 if (FAILED(hr)) { 172 err_set(errset, hr, "failed to get writer metadata of %d/%d", 173 i, cWriters); 174 goto out; 175 } 176 177 hr = pMetadata->GetIdentity(&idInstance, &idWriter, 178 &bstrWriterName, &usage, &source); 179 if (FAILED(hr)) { 180 err_set(errset, hr, "failed to get identity of writer %d/%d", 181 i, cWriters); 182 goto out; 183 } 184 185 hr = pMetadata->GetFileCounts(&c1, &c2, &cComponents); 186 if (FAILED(hr)) { 187 err_set(errset, hr, "failed to get file counts of %S", 188 bstrWriterName); 189 goto out; 190 } 191 192 for (j = 0; j < cComponents; j++) { 193 hr = pMetadata->GetComponent(j, pComponent.replace()); 194 if (FAILED(hr)) { 195 err_set(errset, hr, 196 "failed to get component %d/%d of %S", 197 j, cComponents, bstrWriterName); 198 goto out; 199 } 200 201 hr = pComponent->GetComponentInfo(&info); 202 if (FAILED(hr)) { 203 err_set(errset, hr, 204 "failed to get component info %d/%d of %S", 205 j, cComponents, bstrWriterName); 206 goto out; 207 } 208 209 if (info->bSelectable) { 210 hr = vss_ctx.pVssbc->AddComponent(idInstance, idWriter, 211 info->type, 212 info->bstrLogicalPath, 213 info->bstrComponentName); 214 if (FAILED(hr)) { 215 err_set(errset, hr, "failed to add component %S(%S)", 216 info->bstrComponentName, bstrWriterName); 217 goto out; 218 } 219 } 220 SysFreeString(bstrWriterName); 221 bstrWriterName = NULL; 222 pComponent->FreeComponentInfo(info); 223 info = NULL; 224 } 225 } 226 out: 227 if (bstrWriterName) { 228 SysFreeString(bstrWriterName); 229 } 230 if (pComponent && info) { 231 pComponent->FreeComponentInfo(info); 232 } 233 } 234 235 void requester_freeze(int *num_vols, ErrorSet *errset) 236 { 237 COMPointer<IVssAsync> pAsync; 238 HANDLE volume; 239 HRESULT hr; 240 LONG ctx; 241 GUID guidSnapshotSet = GUID_NULL; 242 SECURITY_DESCRIPTOR sd; 243 SECURITY_ATTRIBUTES sa; 244 WCHAR short_volume_name[64], *display_name = short_volume_name; 245 DWORD wait_status; 246 int num_fixed_drives = 0, i; 247 248 if (vss_ctx.pVssbc) { /* already frozen */ 249 *num_vols = 0; 250 return; 251 } 252 253 CoInitialize(NULL); 254 255 /* Allow unrestricted access to events */ 256 InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION); 257 SetSecurityDescriptorDacl(&sd, TRUE, NULL, FALSE); 258 sa.nLength = sizeof(sa); 259 sa.lpSecurityDescriptor = &sd; 260 sa.bInheritHandle = FALSE; 261 262 vss_ctx.hEventFrozen = CreateEvent(&sa, TRUE, FALSE, EVENT_NAME_FROZEN); 263 if (!vss_ctx.hEventFrozen) { 264 err_set(errset, GetLastError(), "failed to create event %s", 265 EVENT_NAME_FROZEN); 266 goto out; 267 } 268 vss_ctx.hEventThaw = CreateEvent(&sa, TRUE, FALSE, EVENT_NAME_THAW); 269 if (!vss_ctx.hEventThaw) { 270 err_set(errset, GetLastError(), "failed to create event %s", 271 EVENT_NAME_THAW); 272 goto out; 273 } 274 vss_ctx.hEventTimeout = CreateEvent(&sa, TRUE, FALSE, EVENT_NAME_TIMEOUT); 275 if (!vss_ctx.hEventTimeout) { 276 err_set(errset, GetLastError(), "failed to create event %s", 277 EVENT_NAME_TIMEOUT); 278 goto out; 279 } 280 281 assert(pCreateVssBackupComponents != NULL); 282 hr = pCreateVssBackupComponents(&vss_ctx.pVssbc); 283 if (FAILED(hr)) { 284 err_set(errset, hr, "failed to create VSS backup components"); 285 goto out; 286 } 287 288 hr = vss_ctx.pVssbc->InitializeForBackup(); 289 if (FAILED(hr)) { 290 err_set(errset, hr, "failed to initialize for backup"); 291 goto out; 292 } 293 294 hr = vss_ctx.pVssbc->SetBackupState(true, true, VSS_BT_FULL, false); 295 if (FAILED(hr)) { 296 err_set(errset, hr, "failed to set backup state"); 297 goto out; 298 } 299 300 /* 301 * Currently writable snapshots are not supported. 302 * To prevent the final commit (which requires to write to snapshots), 303 * ATTR_NO_AUTORECOVERY and ATTR_TRANSPORTABLE are specified here. 304 */ 305 ctx = VSS_CTX_APP_ROLLBACK | VSS_VOLSNAP_ATTR_TRANSPORTABLE | 306 VSS_VOLSNAP_ATTR_NO_AUTORECOVERY | VSS_VOLSNAP_ATTR_TXF_RECOVERY; 307 hr = vss_ctx.pVssbc->SetContext(ctx); 308 if (hr == (HRESULT)VSS_E_UNSUPPORTED_CONTEXT) { 309 /* Non-server version of Windows doesn't support ATTR_TRANSPORTABLE */ 310 ctx &= ~VSS_VOLSNAP_ATTR_TRANSPORTABLE; 311 hr = vss_ctx.pVssbc->SetContext(ctx); 312 } 313 if (FAILED(hr)) { 314 err_set(errset, hr, "failed to set backup context"); 315 goto out; 316 } 317 318 hr = vss_ctx.pVssbc->GatherWriterMetadata(pAsync.replace()); 319 if (SUCCEEDED(hr)) { 320 hr = WaitForAsync(pAsync); 321 } 322 if (FAILED(hr)) { 323 err_set(errset, hr, "failed to gather writer metadata"); 324 goto out; 325 } 326 327 AddComponents(errset); 328 if (err_is_set(errset)) { 329 goto out; 330 } 331 332 hr = vss_ctx.pVssbc->StartSnapshotSet(&guidSnapshotSet); 333 if (FAILED(hr)) { 334 err_set(errset, hr, "failed to start snapshot set"); 335 goto out; 336 } 337 338 volume = FindFirstVolumeW(short_volume_name, sizeof(short_volume_name)); 339 if (volume == INVALID_HANDLE_VALUE) { 340 err_set(errset, hr, "failed to find first volume"); 341 goto out; 342 } 343 for (;;) { 344 if (GetDriveTypeW(short_volume_name) == DRIVE_FIXED) { 345 VSS_ID pid; 346 hr = vss_ctx.pVssbc->AddToSnapshotSet(short_volume_name, 347 g_gProviderId, &pid); 348 if (FAILED(hr)) { 349 WCHAR volume_path_name[PATH_MAX]; 350 if (GetVolumePathNamesForVolumeNameW( 351 short_volume_name, volume_path_name, 352 sizeof(volume_path_name), NULL) && *volume_path_name) { 353 display_name = volume_path_name; 354 } 355 err_set(errset, hr, "failed to add %S to snapshot set", 356 display_name); 357 FindVolumeClose(volume); 358 goto out; 359 } 360 num_fixed_drives++; 361 } 362 if (!FindNextVolumeW(volume, short_volume_name, 363 sizeof(short_volume_name))) { 364 FindVolumeClose(volume); 365 break; 366 } 367 } 368 369 if (num_fixed_drives == 0) { 370 goto out; /* If there is no fixed drive, just exit. */ 371 } 372 373 hr = vss_ctx.pVssbc->PrepareForBackup(pAsync.replace()); 374 if (SUCCEEDED(hr)) { 375 hr = WaitForAsync(pAsync); 376 } 377 if (FAILED(hr)) { 378 err_set(errset, hr, "failed to prepare for backup"); 379 goto out; 380 } 381 382 hr = vss_ctx.pVssbc->GatherWriterStatus(pAsync.replace()); 383 if (SUCCEEDED(hr)) { 384 hr = WaitForAsync(pAsync); 385 } 386 if (FAILED(hr)) { 387 err_set(errset, hr, "failed to gather writer status"); 388 goto out; 389 } 390 391 /* 392 * Start VSS quiescing operations. 393 * CQGAVssProvider::CommitSnapshots will kick vss_ctx.hEventFrozen 394 * after the applications and filesystems are frozen. 395 */ 396 hr = vss_ctx.pVssbc->DoSnapshotSet(&vss_ctx.pAsyncSnapshot); 397 if (FAILED(hr)) { 398 err_set(errset, hr, "failed to do snapshot set"); 399 goto out; 400 } 401 402 /* Need to call QueryStatus several times to make VSS provider progress */ 403 for (i = 0; i < VSS_TIMEOUT_FREEZE_MSEC/VSS_TIMEOUT_EVENT_MSEC; i++) { 404 HRESULT hr2 = vss_ctx.pAsyncSnapshot->QueryStatus(&hr, NULL); 405 if (FAILED(hr2)) { 406 err_set(errset, hr, "failed to do snapshot set"); 407 goto out; 408 } 409 if (hr != VSS_S_ASYNC_PENDING) { 410 err_set(errset, E_FAIL, 411 "DoSnapshotSet exited without Frozen event"); 412 goto out; 413 } 414 wait_status = WaitForSingleObject(vss_ctx.hEventFrozen, 415 VSS_TIMEOUT_EVENT_MSEC); 416 if (wait_status != WAIT_TIMEOUT) { 417 break; 418 } 419 } 420 if (wait_status != WAIT_OBJECT_0) { 421 err_set(errset, E_FAIL, 422 "couldn't receive Frozen event from VSS provider"); 423 goto out; 424 } 425 426 *num_vols = vss_ctx.cFrozenVols = num_fixed_drives; 427 return; 428 429 out: 430 if (vss_ctx.pVssbc) { 431 vss_ctx.pVssbc->AbortBackup(); 432 } 433 requester_cleanup(); 434 CoUninitialize(); 435 } 436 437 438 void requester_thaw(int *num_vols, ErrorSet *errset) 439 { 440 COMPointer<IVssAsync> pAsync; 441 442 if (!vss_ctx.hEventThaw) { 443 /* 444 * In this case, DoSnapshotSet is aborted or not started, 445 * and no volumes must be frozen. We return without an error. 446 */ 447 *num_vols = 0; 448 return; 449 } 450 451 /* Tell the provider that the snapshot is finished. */ 452 SetEvent(vss_ctx.hEventThaw); 453 454 assert(vss_ctx.pVssbc); 455 assert(vss_ctx.pAsyncSnapshot); 456 457 HRESULT hr = WaitForAsync(vss_ctx.pAsyncSnapshot); 458 switch (hr) { 459 case VSS_S_ASYNC_FINISHED: 460 hr = vss_ctx.pVssbc->BackupComplete(pAsync.replace()); 461 if (SUCCEEDED(hr)) { 462 hr = WaitForAsync(pAsync); 463 } 464 if (FAILED(hr)) { 465 err_set(errset, hr, "failed to complete backup"); 466 } 467 break; 468 469 case (HRESULT)VSS_E_OBJECT_NOT_FOUND: 470 /* 471 * On Windows earlier than 2008 SP2 which does not support 472 * VSS_VOLSNAP_ATTR_NO_AUTORECOVERY context, the final commit is not 473 * skipped and VSS is aborted by VSS_E_OBJECT_NOT_FOUND. However, as 474 * the system had been frozen until fsfreeze-thaw command was issued, 475 * we ignore this error. 476 */ 477 vss_ctx.pVssbc->AbortBackup(); 478 break; 479 480 case VSS_E_UNEXPECTED_PROVIDER_ERROR: 481 if (WaitForSingleObject(vss_ctx.hEventTimeout, 0) != WAIT_OBJECT_0) { 482 err_set(errset, hr, "unexpected error in VSS provider"); 483 break; 484 } 485 /* fall through if hEventTimeout is signaled */ 486 487 case (HRESULT)VSS_E_HOLD_WRITES_TIMEOUT: 488 err_set(errset, hr, "couldn't hold writes: " 489 "fsfreeze is limited up to 10 seconds"); 490 break; 491 492 default: 493 err_set(errset, hr, "failed to do snapshot set"); 494 } 495 496 if (err_is_set(errset)) { 497 vss_ctx.pVssbc->AbortBackup(); 498 } 499 *num_vols = vss_ctx.cFrozenVols; 500 requester_cleanup(); 501 502 CoUninitialize(); 503 } 504