qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

requester.cpp (17653B)


      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 "install.h"
     17 #include <vswriter.h>
     18 #include <vsbackup.h>
     19 
     20 /* Max wait time for frozen event (VSS can only hold writes for 10 seconds) */
     21 #define VSS_TIMEOUT_FREEZE_MSEC 60000
     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_wrapper((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, void *mountpoints, 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     int num_mount_points = 0;
    250 
    251     if (vss_ctx.pVssbc) { /* already frozen */
    252         *num_vols = 0;
    253         return;
    254     }
    255 
    256     CoInitialize(NULL);
    257 
    258     /* Allow unrestricted access to events */
    259     InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION);
    260     SetSecurityDescriptorDacl(&sd, TRUE, NULL, FALSE);
    261     sa.nLength = sizeof(sa);
    262     sa.lpSecurityDescriptor = &sd;
    263     sa.bInheritHandle = FALSE;
    264 
    265     vss_ctx.hEventFrozen = CreateEvent(&sa, TRUE, FALSE, EVENT_NAME_FROZEN);
    266     if (!vss_ctx.hEventFrozen) {
    267         err_set(errset, GetLastError(), "failed to create event %s",
    268                 EVENT_NAME_FROZEN);
    269         goto out;
    270     }
    271     vss_ctx.hEventThaw = CreateEvent(&sa, TRUE, FALSE, EVENT_NAME_THAW);
    272     if (!vss_ctx.hEventThaw) {
    273         err_set(errset, GetLastError(), "failed to create event %s",
    274                 EVENT_NAME_THAW);
    275         goto out;
    276     }
    277     vss_ctx.hEventTimeout = CreateEvent(&sa, TRUE, FALSE, EVENT_NAME_TIMEOUT);
    278     if (!vss_ctx.hEventTimeout) {
    279         err_set(errset, GetLastError(), "failed to create event %s",
    280                 EVENT_NAME_TIMEOUT);
    281         goto out;
    282     }
    283 
    284     assert(pCreateVssBackupComponents != NULL);
    285     hr = pCreateVssBackupComponents(&vss_ctx.pVssbc);
    286     if (FAILED(hr)) {
    287         err_set(errset, hr, "failed to create VSS backup components");
    288         goto out;
    289     }
    290 
    291     hr = vss_ctx.pVssbc->InitializeForBackup();
    292     if (FAILED(hr)) {
    293         err_set(errset, hr, "failed to initialize for backup");
    294         goto out;
    295     }
    296 
    297     hr = vss_ctx.pVssbc->SetBackupState(true, true, VSS_BT_FULL, false);
    298     if (FAILED(hr)) {
    299         err_set(errset, hr, "failed to set backup state");
    300         goto out;
    301     }
    302 
    303     /*
    304      * Currently writable snapshots are not supported.
    305      * To prevent the final commit (which requires to write to snapshots),
    306      * ATTR_NO_AUTORECOVERY and ATTR_TRANSPORTABLE are specified here.
    307      */
    308     ctx = VSS_CTX_APP_ROLLBACK | VSS_VOLSNAP_ATTR_TRANSPORTABLE |
    309         VSS_VOLSNAP_ATTR_NO_AUTORECOVERY | VSS_VOLSNAP_ATTR_TXF_RECOVERY;
    310     hr = vss_ctx.pVssbc->SetContext(ctx);
    311     if (hr == (HRESULT)VSS_E_UNSUPPORTED_CONTEXT) {
    312         /* Non-server version of Windows doesn't support ATTR_TRANSPORTABLE */
    313         ctx &= ~VSS_VOLSNAP_ATTR_TRANSPORTABLE;
    314         hr = vss_ctx.pVssbc->SetContext(ctx);
    315     }
    316     if (FAILED(hr)) {
    317         err_set(errset, hr, "failed to set backup context");
    318         goto out;
    319     }
    320 
    321     hr = vss_ctx.pVssbc->GatherWriterMetadata(pAsync.replace());
    322     if (SUCCEEDED(hr)) {
    323         hr = WaitForAsync(pAsync);
    324     }
    325     if (FAILED(hr)) {
    326         err_set(errset, hr, "failed to gather writer metadata");
    327         goto out;
    328     }
    329 
    330     AddComponents(errset);
    331     if (err_is_set(errset)) {
    332         goto out;
    333     }
    334 
    335     hr = vss_ctx.pVssbc->StartSnapshotSet(&guidSnapshotSet);
    336     if (FAILED(hr)) {
    337         err_set(errset, hr, "failed to start snapshot set");
    338         goto out;
    339     }
    340 
    341     if (mountpoints) {
    342         PWCHAR volume_name_wchar;
    343         for (volList *list = (volList *)mountpoints; list; list = list->next) {
    344             size_t len = strlen(list->value) + 1;
    345             size_t converted = 0;
    346             VSS_ID pid;
    347 
    348             volume_name_wchar = new wchar_t[len];
    349             mbstowcs_s(&converted, volume_name_wchar, len,
    350                        list->value, _TRUNCATE);
    351 
    352             hr = vss_ctx.pVssbc->AddToSnapshotSet(volume_name_wchar,
    353                                                   g_gProviderId, &pid);
    354             if (FAILED(hr)) {
    355                 err_set(errset, hr, "failed to add %S to snapshot set",
    356                         volume_name_wchar);
    357                 delete[] volume_name_wchar;
    358                 goto out;
    359             }
    360             num_mount_points++;
    361 
    362             delete[] volume_name_wchar;
    363         }
    364 
    365         if (num_mount_points == 0) {
    366             /* If there is no valid mount points, just exit. */
    367             goto out;
    368         }
    369     }
    370 
    371     if (!mountpoints) {
    372         volume = FindFirstVolumeW(short_volume_name, sizeof(short_volume_name));
    373         if (volume == INVALID_HANDLE_VALUE) {
    374             err_set(errset, hr, "failed to find first volume");
    375             goto out;
    376         }
    377 
    378         for (;;) {
    379             if (GetDriveTypeW(short_volume_name) == DRIVE_FIXED) {
    380                 VSS_ID pid;
    381                 hr = vss_ctx.pVssbc->AddToSnapshotSet(short_volume_name,
    382                                                       g_gProviderId, &pid);
    383                 if (FAILED(hr)) {
    384                     WCHAR volume_path_name[PATH_MAX];
    385                     if (GetVolumePathNamesForVolumeNameW(
    386                             short_volume_name, volume_path_name,
    387                             sizeof(volume_path_name), NULL) &&
    388                             *volume_path_name) {
    389                         display_name = volume_path_name;
    390                     }
    391                     err_set(errset, hr, "failed to add %S to snapshot set",
    392                             display_name);
    393                     FindVolumeClose(volume);
    394                     goto out;
    395                 }
    396                 num_fixed_drives++;
    397             }
    398             if (!FindNextVolumeW(volume, short_volume_name,
    399                                  sizeof(short_volume_name))) {
    400                 FindVolumeClose(volume);
    401                 break;
    402             }
    403         }
    404 
    405         if (num_fixed_drives == 0) {
    406             goto out; /* If there is no fixed drive, just exit. */
    407         }
    408     }
    409 
    410     hr = vss_ctx.pVssbc->PrepareForBackup(pAsync.replace());
    411     if (SUCCEEDED(hr)) {
    412         hr = WaitForAsync(pAsync);
    413     }
    414     if (FAILED(hr)) {
    415         err_set(errset, hr, "failed to prepare for backup");
    416         goto out;
    417     }
    418 
    419     hr = vss_ctx.pVssbc->GatherWriterStatus(pAsync.replace());
    420     if (SUCCEEDED(hr)) {
    421         hr = WaitForAsync(pAsync);
    422     }
    423     if (FAILED(hr)) {
    424         err_set(errset, hr, "failed to gather writer status");
    425         goto out;
    426     }
    427 
    428     /*
    429      * Start VSS quiescing operations.
    430      * CQGAVssProvider::CommitSnapshots will kick vss_ctx.hEventFrozen
    431      * after the applications and filesystems are frozen.
    432      */
    433     hr = vss_ctx.pVssbc->DoSnapshotSet(&vss_ctx.pAsyncSnapshot);
    434     if (FAILED(hr)) {
    435         err_set(errset, hr, "failed to do snapshot set");
    436         goto out;
    437     }
    438 
    439     /* Need to call QueryStatus several times to make VSS provider progress */
    440     for (i = 0; i < VSS_TIMEOUT_FREEZE_MSEC/VSS_TIMEOUT_EVENT_MSEC; i++) {
    441         HRESULT hr2 = vss_ctx.pAsyncSnapshot->QueryStatus(&hr, NULL);
    442         if (FAILED(hr2)) {
    443             err_set(errset, hr, "failed to do snapshot set");
    444             goto out;
    445         }
    446         if (hr != VSS_S_ASYNC_PENDING) {
    447             err_set(errset, E_FAIL,
    448                     "DoSnapshotSet exited without Frozen event");
    449             goto out;
    450         }
    451         wait_status = WaitForSingleObject(vss_ctx.hEventFrozen,
    452                                           VSS_TIMEOUT_EVENT_MSEC);
    453         if (wait_status != WAIT_TIMEOUT) {
    454             break;
    455         }
    456     }
    457 
    458     if (wait_status == WAIT_TIMEOUT) {
    459         err_set(errset, E_FAIL,
    460                 "timeout when try to receive Frozen event from VSS provider");
    461         /* If we are here, VSS had timeout.
    462          * Don't call AbortBackup, just return directly.
    463          */
    464         goto out1;
    465     }
    466 
    467     if (wait_status != WAIT_OBJECT_0) {
    468         err_set(errset, E_FAIL,
    469                 "couldn't receive Frozen event from VSS provider");
    470         goto out;
    471     }
    472 
    473     if (mountpoints) {
    474         *num_vols = vss_ctx.cFrozenVols = num_mount_points;
    475     } else {
    476         *num_vols = vss_ctx.cFrozenVols = num_fixed_drives;
    477     }
    478 
    479     return;
    480 
    481 out:
    482     if (vss_ctx.pVssbc) {
    483         vss_ctx.pVssbc->AbortBackup();
    484     }
    485 
    486 out1:
    487     requester_cleanup();
    488     CoUninitialize();
    489 }
    490 
    491 
    492 void requester_thaw(int *num_vols, void *mountpints, ErrorSet *errset)
    493 {
    494     COMPointer<IVssAsync> pAsync;
    495 
    496     if (!vss_ctx.hEventThaw) {
    497         /*
    498          * In this case, DoSnapshotSet is aborted or not started,
    499          * and no volumes must be frozen. We return without an error.
    500          */
    501         *num_vols = 0;
    502         return;
    503     }
    504 
    505     /* Tell the provider that the snapshot is finished. */
    506     SetEvent(vss_ctx.hEventThaw);
    507 
    508     assert(vss_ctx.pVssbc);
    509     assert(vss_ctx.pAsyncSnapshot);
    510 
    511     HRESULT hr = WaitForAsync(vss_ctx.pAsyncSnapshot);
    512     switch (hr) {
    513     case VSS_S_ASYNC_FINISHED:
    514         hr = vss_ctx.pVssbc->BackupComplete(pAsync.replace());
    515         if (SUCCEEDED(hr)) {
    516             hr = WaitForAsync(pAsync);
    517         }
    518         if (FAILED(hr)) {
    519             err_set(errset, hr, "failed to complete backup");
    520         }
    521         break;
    522 
    523     case (HRESULT)VSS_E_OBJECT_NOT_FOUND:
    524         /*
    525          * On Windows earlier than 2008 SP2 which does not support
    526          * VSS_VOLSNAP_ATTR_NO_AUTORECOVERY context, the final commit is not
    527          * skipped and VSS is aborted by VSS_E_OBJECT_NOT_FOUND. However, as
    528          * the system had been frozen until fsfreeze-thaw command was issued,
    529          * we ignore this error.
    530          */
    531         vss_ctx.pVssbc->AbortBackup();
    532         break;
    533 
    534     case VSS_E_UNEXPECTED_PROVIDER_ERROR:
    535         if (WaitForSingleObject(vss_ctx.hEventTimeout, 0) != WAIT_OBJECT_0) {
    536             err_set(errset, hr, "unexpected error in VSS provider");
    537             break;
    538         }
    539         /* fall through if hEventTimeout is signaled */
    540 
    541     case (HRESULT)VSS_E_HOLD_WRITES_TIMEOUT:
    542         err_set(errset, hr, "couldn't hold writes: "
    543                 "fsfreeze is limited up to 10 seconds");
    544         break;
    545 
    546     default:
    547         err_set(errset, hr, "failed to do snapshot set");
    548     }
    549 
    550     if (err_is_set(errset)) {
    551         vss_ctx.pVssbc->AbortBackup();
    552     }
    553     *num_vols = vss_ctx.cFrozenVols;
    554     requester_cleanup();
    555 
    556     CoUninitialize();
    557     StopService();
    558 }