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