megasas: add MegaRAID SAS 2108 emulation
[qemu/ar7.git] / qga / vss-win32 / requester.cpp
blob922e74ddfcb9b3fc119b90a5409321f727fb72e2
1 /*
2 * QEMU Guest Agent win32 VSS Requester implementations
4 * Copyright Hitachi Data Systems Corp. 2013
6 * Authors:
7 * Tomoki Sekiyama <tomoki.sekiyama@hds.com>
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.
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"
20 /* Max wait time for frozen event (VSS can only hold writes for 10 seconds) */
21 #define VSS_TIMEOUT_FREEZE_MSEC 10000
23 /* Call QueryStatus every 10 ms while waiting for frozen event */
24 #define VSS_TIMEOUT_EVENT_MSEC 10
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)
31 /* Handle to VSSAPI.DLL */
32 static HMODULE hLib;
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;
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;
51 STDAPI requester_init(void)
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;
62 hLib = LoadLibraryA("VSSAPI.DLL");
63 if (!hLib) {
64 fprintf(stderr, "failed to load VSSAPI.DLL\n");
65 return HRESULT_FROM_WIN32(GetLastError());
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
76 if (!pCreateVssBackupComponents) {
77 fprintf(stderr, "failed to get proc address from VSSAPI.DLL\n");
78 return HRESULT_FROM_WIN32(GetLastError());
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());
88 return S_OK;
91 static void requester_cleanup(void)
93 if (vss_ctx.hEventFrozen) {
94 CloseHandle(vss_ctx.hEventFrozen);
95 vss_ctx.hEventFrozen = NULL;
97 if (vss_ctx.hEventThaw) {
98 CloseHandle(vss_ctx.hEventThaw);
99 vss_ctx.hEventThaw = NULL;
101 if (vss_ctx.hEventTimeout) {
102 CloseHandle(vss_ctx.hEventTimeout);
103 vss_ctx.hEventTimeout = NULL;
105 if (vss_ctx.pAsyncSnapshot) {
106 vss_ctx.pAsyncSnapshot->Release();
107 vss_ctx.pAsyncSnapshot = NULL;
109 if (vss_ctx.pVssbc) {
110 vss_ctx.pVssbc->Release();
111 vss_ctx.pVssbc = NULL;
113 vss_ctx.cFrozenVols = 0;
116 STDAPI requester_deinit(void)
118 requester_cleanup();
120 pCreateVssBackupComponents = NULL;
121 pVssFreeSnapshotProperties = NULL;
122 if (hLib) {
123 FreeLibrary(hLib);
124 hLib = NULL;
127 return S_OK;
130 static HRESULT WaitForAsync(IVssAsync *pAsync)
132 HRESULT ret, hr;
134 do {
135 hr = pAsync->Wait();
136 if (FAILED(hr)) {
137 ret = hr;
138 break;
140 hr = pAsync->QueryStatus(&ret, NULL);
141 if (FAILED(hr)) {
142 ret = hr;
143 break;
145 } while (ret == VSS_S_ASYNC_PENDING);
147 return ret;
150 static void AddComponents(ErrorSet *errset)
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;
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;
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;
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;
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;
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;
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;
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;
220 SysFreeString(bstrWriterName);
221 bstrWriterName = NULL;
222 pComponent->FreeComponentInfo(info);
223 info = NULL;
226 out:
227 if (bstrWriterName) {
228 SysFreeString(bstrWriterName);
230 if (pComponent && info) {
231 pComponent->FreeComponentInfo(info);
235 void requester_freeze(int *num_vols, ErrorSet *errset)
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;
248 if (vss_ctx.pVssbc) { /* already frozen */
249 *num_vols = 0;
250 return;
253 CoInitialize(NULL);
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;
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;
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;
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;
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;
288 hr = vss_ctx.pVssbc->InitializeForBackup();
289 if (FAILED(hr)) {
290 err_set(errset, hr, "failed to initialize for backup");
291 goto out;
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;
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.
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);
313 if (FAILED(hr)) {
314 err_set(errset, hr, "failed to set backup context");
315 goto out;
318 hr = vss_ctx.pVssbc->GatherWriterMetadata(pAsync.replace());
319 if (SUCCEEDED(hr)) {
320 hr = WaitForAsync(pAsync);
322 if (FAILED(hr)) {
323 err_set(errset, hr, "failed to gather writer metadata");
324 goto out;
327 AddComponents(errset);
328 if (err_is_set(errset)) {
329 goto out;
332 hr = vss_ctx.pVssbc->StartSnapshotSet(&guidSnapshotSet);
333 if (FAILED(hr)) {
334 err_set(errset, hr, "failed to start snapshot set");
335 goto out;
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;
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;
355 err_set(errset, hr, "failed to add %S to snapshot set",
356 display_name);
357 FindVolumeClose(volume);
358 goto out;
360 num_fixed_drives++;
362 if (!FindNextVolumeW(volume, short_volume_name,
363 sizeof(short_volume_name))) {
364 FindVolumeClose(volume);
365 break;
369 if (num_fixed_drives == 0) {
370 goto out; /* If there is no fixed drive, just exit. */
373 hr = vss_ctx.pVssbc->PrepareForBackup(pAsync.replace());
374 if (SUCCEEDED(hr)) {
375 hr = WaitForAsync(pAsync);
377 if (FAILED(hr)) {
378 err_set(errset, hr, "failed to prepare for backup");
379 goto out;
382 hr = vss_ctx.pVssbc->GatherWriterStatus(pAsync.replace());
383 if (SUCCEEDED(hr)) {
384 hr = WaitForAsync(pAsync);
386 if (FAILED(hr)) {
387 err_set(errset, hr, "failed to gather writer status");
388 goto out;
392 * Start VSS quiescing operations.
393 * CQGAVssProvider::CommitSnapshots will kick vss_ctx.hEventFrozen
394 * after the applications and filesystems are frozen.
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;
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;
409 if (hr != VSS_S_ASYNC_PENDING) {
410 err_set(errset, E_FAIL,
411 "DoSnapshotSet exited without Frozen event");
412 goto out;
414 wait_status = WaitForSingleObject(vss_ctx.hEventFrozen,
415 VSS_TIMEOUT_EVENT_MSEC);
416 if (wait_status != WAIT_TIMEOUT) {
417 break;
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;
426 *num_vols = vss_ctx.cFrozenVols = num_fixed_drives;
427 return;
429 out:
430 if (vss_ctx.pVssbc) {
431 vss_ctx.pVssbc->AbortBackup();
433 requester_cleanup();
434 CoUninitialize();
438 void requester_thaw(int *num_vols, ErrorSet *errset)
440 COMPointer<IVssAsync> pAsync;
442 if (!vss_ctx.hEventThaw) {
444 * In this case, DoSnapshotSet is aborted or not started,
445 * and no volumes must be frozen. We return without an error.
447 *num_vols = 0;
448 return;
451 /* Tell the provider that the snapshot is finished. */
452 SetEvent(vss_ctx.hEventThaw);
454 assert(vss_ctx.pVssbc);
455 assert(vss_ctx.pAsyncSnapshot);
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);
464 if (FAILED(hr)) {
465 err_set(errset, hr, "failed to complete backup");
467 break;
469 case (HRESULT)VSS_E_OBJECT_NOT_FOUND:
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.
477 vss_ctx.pVssbc->AbortBackup();
478 break;
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;
485 /* fall through if hEventTimeout is signaled */
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;
492 default:
493 err_set(errset, hr, "failed to do snapshot set");
496 if (err_is_set(errset)) {
497 vss_ctx.pVssbc->AbortBackup();
499 *num_vols = vss_ctx.cFrozenVols;
500 requester_cleanup();
502 CoUninitialize();