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