diff options
Diffstat (limited to 'qemu/qga/vss-win32/requester.cpp')
-rw-r--r-- | qemu/qga/vss-win32/requester.cpp | 504 |
1 files changed, 0 insertions, 504 deletions
diff --git a/qemu/qga/vss-win32/requester.cpp b/qemu/qga/vss-win32/requester.cpp deleted file mode 100644 index 889052ded..000000000 --- a/qemu/qga/vss-win32/requester.cpp +++ /dev/null @@ -1,504 +0,0 @@ -/* - * QEMU Guest Agent win32 VSS Requester implementations - * - * Copyright Hitachi Data Systems Corp. 2013 - * - * Authors: - * Tomoki Sekiyama <tomoki.sekiyama@hds.com> - * - * This work is licensed under the terms of the GNU GPL, version 2 or later. - * See the COPYING file in the top-level directory. - */ - -#include "qemu/osdep.h" -#include "vss-common.h" -#include "requester.h" -#include "inc/win2003/vswriter.h" -#include "inc/win2003/vsbackup.h" - -/* Max wait time for frozen event (VSS can only hold writes for 10 seconds) */ -#define VSS_TIMEOUT_FREEZE_MSEC 10000 - -/* Call QueryStatus every 10 ms while waiting for frozen event */ -#define VSS_TIMEOUT_EVENT_MSEC 10 - -#define err_set(e, err, fmt, ...) \ - ((e)->error_setg_win32_wrapper((e)->errp, __FILE__, __LINE__, __func__, \ - err, fmt, ## __VA_ARGS__)) -/* Bad idea, works only when (e)->errp != NULL: */ -#define err_is_set(e) ((e)->errp && *(e)->errp) -/* To lift this restriction, error_propagate(), like we do in QEMU code */ - -/* Handle to VSSAPI.DLL */ -static HMODULE hLib; - -/* Functions in VSSAPI.DLL */ -typedef HRESULT(STDAPICALLTYPE * t_CreateVssBackupComponents)( - OUT IVssBackupComponents**); -typedef void(APIENTRY * t_VssFreeSnapshotProperties)(IN VSS_SNAPSHOT_PROP*); -static t_CreateVssBackupComponents pCreateVssBackupComponents; -static t_VssFreeSnapshotProperties pVssFreeSnapshotProperties; - -/* Variables used while applications and filesystes are frozen by VSS */ -static struct QGAVSSContext { - IVssBackupComponents *pVssbc; /* VSS requester interface */ - IVssAsync *pAsyncSnapshot; /* async info of VSS snapshot operation */ - HANDLE hEventFrozen; /* notify fs/writer freeze from provider */ - HANDLE hEventThaw; /* request provider to thaw */ - HANDLE hEventTimeout; /* notify timeout in provider */ - int cFrozenVols; /* number of frozen volumes */ -} vss_ctx; - -STDAPI requester_init(void) -{ - COMInitializer initializer; /* to call CoInitializeSecurity */ - HRESULT hr = CoInitializeSecurity( - NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_PKT_PRIVACY, - RPC_C_IMP_LEVEL_IDENTIFY, NULL, EOAC_NONE, NULL); - if (FAILED(hr)) { - fprintf(stderr, "failed to CoInitializeSecurity (error %lx)\n", hr); - return hr; - } - - hLib = LoadLibraryA("VSSAPI.DLL"); - if (!hLib) { - fprintf(stderr, "failed to load VSSAPI.DLL\n"); - return HRESULT_FROM_WIN32(GetLastError()); - } - - pCreateVssBackupComponents = (t_CreateVssBackupComponents) - GetProcAddress(hLib, -#ifdef _WIN64 /* 64bit environment */ - "?CreateVssBackupComponents@@YAJPEAPEAVIVssBackupComponents@@@Z" -#else /* 32bit environment */ - "?CreateVssBackupComponents@@YGJPAPAVIVssBackupComponents@@@Z" -#endif - ); - if (!pCreateVssBackupComponents) { - fprintf(stderr, "failed to get proc address from VSSAPI.DLL\n"); - return HRESULT_FROM_WIN32(GetLastError()); - } - - pVssFreeSnapshotProperties = (t_VssFreeSnapshotProperties) - GetProcAddress(hLib, "VssFreeSnapshotProperties"); - if (!pVssFreeSnapshotProperties) { - fprintf(stderr, "failed to get proc address from VSSAPI.DLL\n"); - return HRESULT_FROM_WIN32(GetLastError()); - } - - return S_OK; -} - -static void requester_cleanup(void) -{ - if (vss_ctx.hEventFrozen) { - CloseHandle(vss_ctx.hEventFrozen); - vss_ctx.hEventFrozen = NULL; - } - if (vss_ctx.hEventThaw) { - CloseHandle(vss_ctx.hEventThaw); - vss_ctx.hEventThaw = NULL; - } - if (vss_ctx.hEventTimeout) { - CloseHandle(vss_ctx.hEventTimeout); - vss_ctx.hEventTimeout = NULL; - } - if (vss_ctx.pAsyncSnapshot) { - vss_ctx.pAsyncSnapshot->Release(); - vss_ctx.pAsyncSnapshot = NULL; - } - if (vss_ctx.pVssbc) { - vss_ctx.pVssbc->Release(); - vss_ctx.pVssbc = NULL; - } - vss_ctx.cFrozenVols = 0; -} - -STDAPI requester_deinit(void) -{ - requester_cleanup(); - - pCreateVssBackupComponents = NULL; - pVssFreeSnapshotProperties = NULL; - if (hLib) { - FreeLibrary(hLib); - hLib = NULL; - } - - return S_OK; -} - -static HRESULT WaitForAsync(IVssAsync *pAsync) -{ - HRESULT ret, hr; - - do { - hr = pAsync->Wait(); - if (FAILED(hr)) { - ret = hr; - break; - } - hr = pAsync->QueryStatus(&ret, NULL); - if (FAILED(hr)) { - ret = hr; - break; - } - } while (ret == VSS_S_ASYNC_PENDING); - - return ret; -} - -static void AddComponents(ErrorSet *errset) -{ - unsigned int cWriters, i; - VSS_ID id, idInstance, idWriter; - BSTR bstrWriterName = NULL; - VSS_USAGE_TYPE usage; - VSS_SOURCE_TYPE source; - unsigned int cComponents, c1, c2, j; - COMPointer<IVssExamineWriterMetadata> pMetadata; - COMPointer<IVssWMComponent> pComponent; - PVSSCOMPONENTINFO info; - HRESULT hr; - - hr = vss_ctx.pVssbc->GetWriterMetadataCount(&cWriters); - if (FAILED(hr)) { - err_set(errset, hr, "failed to get writer metadata count"); - goto out; - } - - for (i = 0; i < cWriters; i++) { - hr = vss_ctx.pVssbc->GetWriterMetadata(i, &id, pMetadata.replace()); - if (FAILED(hr)) { - err_set(errset, hr, "failed to get writer metadata of %d/%d", - i, cWriters); - goto out; - } - - hr = pMetadata->GetIdentity(&idInstance, &idWriter, - &bstrWriterName, &usage, &source); - if (FAILED(hr)) { - err_set(errset, hr, "failed to get identity of writer %d/%d", - i, cWriters); - goto out; - } - - hr = pMetadata->GetFileCounts(&c1, &c2, &cComponents); - if (FAILED(hr)) { - err_set(errset, hr, "failed to get file counts of %S", - bstrWriterName); - goto out; - } - - for (j = 0; j < cComponents; j++) { - hr = pMetadata->GetComponent(j, pComponent.replace()); - if (FAILED(hr)) { - err_set(errset, hr, - "failed to get component %d/%d of %S", - j, cComponents, bstrWriterName); - goto out; - } - - hr = pComponent->GetComponentInfo(&info); - if (FAILED(hr)) { - err_set(errset, hr, - "failed to get component info %d/%d of %S", - j, cComponents, bstrWriterName); - goto out; - } - - if (info->bSelectable) { - hr = vss_ctx.pVssbc->AddComponent(idInstance, idWriter, - info->type, - info->bstrLogicalPath, - info->bstrComponentName); - if (FAILED(hr)) { - err_set(errset, hr, "failed to add component %S(%S)", - info->bstrComponentName, bstrWriterName); - goto out; - } - } - SysFreeString(bstrWriterName); - bstrWriterName = NULL; - pComponent->FreeComponentInfo(info); - info = NULL; - } - } -out: - if (bstrWriterName) { - SysFreeString(bstrWriterName); - } - if (pComponent && info) { - pComponent->FreeComponentInfo(info); - } -} - -void requester_freeze(int *num_vols, ErrorSet *errset) -{ - COMPointer<IVssAsync> pAsync; - HANDLE volume; - HRESULT hr; - LONG ctx; - GUID guidSnapshotSet = GUID_NULL; - SECURITY_DESCRIPTOR sd; - SECURITY_ATTRIBUTES sa; - WCHAR short_volume_name[64], *display_name = short_volume_name; - DWORD wait_status; - int num_fixed_drives = 0, i; - - if (vss_ctx.pVssbc) { /* already frozen */ - *num_vols = 0; - return; - } - - CoInitialize(NULL); - - /* Allow unrestricted access to events */ - InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION); - SetSecurityDescriptorDacl(&sd, TRUE, NULL, FALSE); - sa.nLength = sizeof(sa); - sa.lpSecurityDescriptor = &sd; - sa.bInheritHandle = FALSE; - - vss_ctx.hEventFrozen = CreateEvent(&sa, TRUE, FALSE, EVENT_NAME_FROZEN); - if (!vss_ctx.hEventFrozen) { - err_set(errset, GetLastError(), "failed to create event %s", - EVENT_NAME_FROZEN); - goto out; - } - vss_ctx.hEventThaw = CreateEvent(&sa, TRUE, FALSE, EVENT_NAME_THAW); - if (!vss_ctx.hEventThaw) { - err_set(errset, GetLastError(), "failed to create event %s", - EVENT_NAME_THAW); - goto out; - } - vss_ctx.hEventTimeout = CreateEvent(&sa, TRUE, FALSE, EVENT_NAME_TIMEOUT); - if (!vss_ctx.hEventTimeout) { - err_set(errset, GetLastError(), "failed to create event %s", - EVENT_NAME_TIMEOUT); - goto out; - } - - assert(pCreateVssBackupComponents != NULL); - hr = pCreateVssBackupComponents(&vss_ctx.pVssbc); - if (FAILED(hr)) { - err_set(errset, hr, "failed to create VSS backup components"); - goto out; - } - - hr = vss_ctx.pVssbc->InitializeForBackup(); - if (FAILED(hr)) { - err_set(errset, hr, "failed to initialize for backup"); - goto out; - } - - hr = vss_ctx.pVssbc->SetBackupState(true, true, VSS_BT_FULL, false); - if (FAILED(hr)) { - err_set(errset, hr, "failed to set backup state"); - goto out; - } - - /* - * Currently writable snapshots are not supported. - * To prevent the final commit (which requires to write to snapshots), - * ATTR_NO_AUTORECOVERY and ATTR_TRANSPORTABLE are specified here. - */ - ctx = VSS_CTX_APP_ROLLBACK | VSS_VOLSNAP_ATTR_TRANSPORTABLE | - VSS_VOLSNAP_ATTR_NO_AUTORECOVERY | VSS_VOLSNAP_ATTR_TXF_RECOVERY; - hr = vss_ctx.pVssbc->SetContext(ctx); - if (hr == (HRESULT)VSS_E_UNSUPPORTED_CONTEXT) { - /* Non-server version of Windows doesn't support ATTR_TRANSPORTABLE */ - ctx &= ~VSS_VOLSNAP_ATTR_TRANSPORTABLE; - hr = vss_ctx.pVssbc->SetContext(ctx); - } - if (FAILED(hr)) { - err_set(errset, hr, "failed to set backup context"); - goto out; - } - - hr = vss_ctx.pVssbc->GatherWriterMetadata(pAsync.replace()); - if (SUCCEEDED(hr)) { - hr = WaitForAsync(pAsync); - } - if (FAILED(hr)) { - err_set(errset, hr, "failed to gather writer metadata"); - goto out; - } - - AddComponents(errset); - if (err_is_set(errset)) { - goto out; - } - - hr = vss_ctx.pVssbc->StartSnapshotSet(&guidSnapshotSet); - if (FAILED(hr)) { - err_set(errset, hr, "failed to start snapshot set"); - goto out; - } - - volume = FindFirstVolumeW(short_volume_name, sizeof(short_volume_name)); - if (volume == INVALID_HANDLE_VALUE) { - err_set(errset, hr, "failed to find first volume"); - goto out; - } - for (;;) { - if (GetDriveTypeW(short_volume_name) == DRIVE_FIXED) { - VSS_ID pid; - hr = vss_ctx.pVssbc->AddToSnapshotSet(short_volume_name, - g_gProviderId, &pid); - if (FAILED(hr)) { - WCHAR volume_path_name[PATH_MAX]; - if (GetVolumePathNamesForVolumeNameW( - short_volume_name, volume_path_name, - sizeof(volume_path_name), NULL) && *volume_path_name) { - display_name = volume_path_name; - } - err_set(errset, hr, "failed to add %S to snapshot set", - display_name); - FindVolumeClose(volume); - goto out; - } - num_fixed_drives++; - } - if (!FindNextVolumeW(volume, short_volume_name, - sizeof(short_volume_name))) { - FindVolumeClose(volume); - break; - } - } - - if (num_fixed_drives == 0) { - goto out; /* If there is no fixed drive, just exit. */ - } - - hr = vss_ctx.pVssbc->PrepareForBackup(pAsync.replace()); - if (SUCCEEDED(hr)) { - hr = WaitForAsync(pAsync); - } - if (FAILED(hr)) { - err_set(errset, hr, "failed to prepare for backup"); - goto out; - } - - hr = vss_ctx.pVssbc->GatherWriterStatus(pAsync.replace()); - if (SUCCEEDED(hr)) { - hr = WaitForAsync(pAsync); - } - if (FAILED(hr)) { - err_set(errset, hr, "failed to gather writer status"); - goto out; - } - - /* - * Start VSS quiescing operations. - * CQGAVssProvider::CommitSnapshots will kick vss_ctx.hEventFrozen - * after the applications and filesystems are frozen. - */ - hr = vss_ctx.pVssbc->DoSnapshotSet(&vss_ctx.pAsyncSnapshot); - if (FAILED(hr)) { - err_set(errset, hr, "failed to do snapshot set"); - goto out; - } - - /* Need to call QueryStatus several times to make VSS provider progress */ - for (i = 0; i < VSS_TIMEOUT_FREEZE_MSEC/VSS_TIMEOUT_EVENT_MSEC; i++) { - HRESULT hr2 = vss_ctx.pAsyncSnapshot->QueryStatus(&hr, NULL); - if (FAILED(hr2)) { - err_set(errset, hr, "failed to do snapshot set"); - goto out; - } - if (hr != VSS_S_ASYNC_PENDING) { - err_set(errset, E_FAIL, - "DoSnapshotSet exited without Frozen event"); - goto out; - } - wait_status = WaitForSingleObject(vss_ctx.hEventFrozen, - VSS_TIMEOUT_EVENT_MSEC); - if (wait_status != WAIT_TIMEOUT) { - break; - } - } - if (wait_status != WAIT_OBJECT_0) { - err_set(errset, E_FAIL, - "couldn't receive Frozen event from VSS provider"); - goto out; - } - - *num_vols = vss_ctx.cFrozenVols = num_fixed_drives; - return; - -out: - if (vss_ctx.pVssbc) { - vss_ctx.pVssbc->AbortBackup(); - } - requester_cleanup(); - CoUninitialize(); -} - - -void requester_thaw(int *num_vols, ErrorSet *errset) -{ - COMPointer<IVssAsync> pAsync; - - if (!vss_ctx.hEventThaw) { - /* - * In this case, DoSnapshotSet is aborted or not started, - * and no volumes must be frozen. We return without an error. - */ - *num_vols = 0; - return; - } - - /* Tell the provider that the snapshot is finished. */ - SetEvent(vss_ctx.hEventThaw); - - assert(vss_ctx.pVssbc); - assert(vss_ctx.pAsyncSnapshot); - - HRESULT hr = WaitForAsync(vss_ctx.pAsyncSnapshot); - switch (hr) { - case VSS_S_ASYNC_FINISHED: - hr = vss_ctx.pVssbc->BackupComplete(pAsync.replace()); - if (SUCCEEDED(hr)) { - hr = WaitForAsync(pAsync); - } - if (FAILED(hr)) { - err_set(errset, hr, "failed to complete backup"); - } - break; - - case (HRESULT)VSS_E_OBJECT_NOT_FOUND: - /* - * On Windows earlier than 2008 SP2 which does not support - * VSS_VOLSNAP_ATTR_NO_AUTORECOVERY context, the final commit is not - * skipped and VSS is aborted by VSS_E_OBJECT_NOT_FOUND. However, as - * the system had been frozen until fsfreeze-thaw command was issued, - * we ignore this error. - */ - vss_ctx.pVssbc->AbortBackup(); - break; - - case VSS_E_UNEXPECTED_PROVIDER_ERROR: - if (WaitForSingleObject(vss_ctx.hEventTimeout, 0) != WAIT_OBJECT_0) { - err_set(errset, hr, "unexpected error in VSS provider"); - break; - } - /* fall through if hEventTimeout is signaled */ - - case (HRESULT)VSS_E_HOLD_WRITES_TIMEOUT: - err_set(errset, hr, "couldn't hold writes: " - "fsfreeze is limited up to 10 seconds"); - break; - - default: - err_set(errset, hr, "failed to do snapshot set"); - } - - if (err_is_set(errset)) { - vss_ctx.pVssbc->AbortBackup(); - } - *num_vols = vss_ctx.cFrozenVols; - requester_cleanup(); - - CoUninitialize(); -} |