RCT implementation query

balu T 41 Reputation points
2020-08-11T13:18:10.54+00:00

Hi, we are trying to use the RCT . Few questions related to it:

the query WMI GetVirtualDiskChanges or VHD QueryChangesVirtualDisk returns access_denied error while getting the disk changes for full. Any idea on what is best to perform full backup ?

We tried the below procedure and found to get the corrupted disk.

  1. Create production snapshot using WMI
  2. then we manually copied the base read-only vhdx file to some other directory (say c:\temp\vm1)
  3. Created reference point (say, RCT_id1).
  4. Created snapshot again
  5. Run in GetVirtualDiskChanges query to get changed blocks since RCT_id1
  6. Read the blocks (offset/length) - (seek and read) to get the data to buffer.
  7. Write the buffer to c:\temp\vm1\ (saved in step 2) - overwrite
  8. Open/attach the c:\temp\vm1\vm1.vhdx =====> This is corrupted.

Any help here is appreciated

Windows development | Windows API - Win32
{count} votes

7 answers

Sort by: Most helpful
  1. balu T 41 Reputation points
    2020-08-25T11:57:03.307+00:00
    HANDLE vhdHandle;
    _VIRTUAL_STORAGE_TYPE storageType;
    storageType.DeviceId = VIRTUAL_STORAGE_TYPE_DEVICE_UNKNOWN;
    storageType.VendorId = VIRTUAL_STORAGE_TYPE_VENDOR_UNKNOWN;
    wchar_t path[] = L"C:\\Hyper-V\\Virtual Hard Disks\\L\\Windows2016.vhdx";
    VIRTUAL_DISK_ACCESS_MASK mask = VIRTUAL_DISK_ACCESS_GET_INFO;
    
    PGET_VIRTUAL_DISK_INFO diskInfo;
    ULONG diskInfoSize = sizeof(GET_VIRTUAL_DISK_INFO) + sizeof(changeTrackingInfo);
    std::wcout << "size of diskinfo structure " << diskInfoSize << std::endl;
    diskInfo = (PGET_VIRTUAL_DISK_INFO)malloc(diskInfoSize);
    

    ...

    OPEN_VIRTUAL_DISK_PARAMETERS *openParameters = NULL;
    
      DWORD res = OpenVirtualDisk(&storageType, path,
        VIRTUAL_DISK_ACCESS_GET_INFO | VIRTUAL_DISK_ACCESS_DETACH | VIRTUAL_DISK_ACCESS_ATTACH_RO,
        OPEN_VIRTUAL_DISK_FLAG_NONE,
        openParameters,
        &vhdHandle);
    
    diskInfo->Version = GET_VIRTUAL_DISK_INFO_SIZE;
    
    res = GetVirtualDiskInformation(vhdHandle, &diskInfoSize, diskInfo, &szUsed);
    
    ULONGLONG physicalSize = diskInfo->Size.PhysicalSize;
    ULONGLONG virtualSize = diskInfo->Size.VirtualSize;
    ULONG sectorSize = diskInfo->Size.SectorSize;
    ULONG blockSize = diskInfo->Size.BlockSize;
    
    
    diskInfo->Version = (GET_VIRTUAL_DISK_INFO_VERSION)GET_VIRTUAL_DISK_INFO_CHANGE_TRACKING_STATE;
    szUsed = NULL;
    res = GetVirtualDiskInformation(vhdHandle, &diskInfoSize, diskInfo, &szUsed);
    if (res != ERROR_SUCCESS)
    {
        std::cout << "Failed to GET_VIRTUAL_DISK_INFO_CHANGE_TRACKING_STATE, ret=" << res << std::endl;
    }
    std::wcout << "\nrct id:" << diskInfo->ChangeTrackingState.MostRecentId << std::endl;
    std::wcout << "\change tracking enabled: " << diskInfo->ChangeTrackingState.Enabled << std::endl;
    WCHAR* rctId = diskInfo->ChangeTrackingState.MostRecentId;
    
    
    //to get incr changes we used rct id like this L"rctX:c2eb01d9:ccb1:405d:acb6:f0e76d055906:00000001";
    //to get allocated blocks for full backup we used rct is as "*", "0", etc.
    std::wcout << "\nQuerying for changed disk areas..." << rctId << std::endl;
    
    ULONG64   byteOffset = 0;
    ULONG64   byteLength = 19327352832; //set disk max internal size.
    QUERY_CHANGES_VIRTUAL_DISK_RANGE* changedAreas = NULL;
    ULONG     rangeCount = 0;
    ULONG64   processedLength = 0;
    res = QueryChangesVirtualDisk(vhdHandle, rctId, byteOffset, byteLength,
        QUERY_CHANGES_VIRTUAL_DISK_FLAG_NONE,
        changedAreas, &rangeCount, &processedLength);
    
    if (res != ERROR_SUCCESS)
    {
        std::cout << "Failed to get changed areas, ret=" << res << std::endl;
    

    ;
    }
    ....


  2. Rita Han - MSFT 2,171 Reputation points
    2020-09-09T02:17:21.073+00:00

    Hello @balu T ,

    Sharing the instructions for getting the detailed tracing here:

    In short these are the steps that need to be performed (More detailed information please refer to here.) :

    • Open Event Viewer. On the View menu, click Show Analytic and Debug Logs. Locate the Trace channel log for WMI under Applications and Service Logs | Microsoft | Windows | WMI Activity.
    • Right-click the Trace log and select Log Properties. Click the Enable Logging check box to start the WMI event tracing. For more information about channels, see Event Logs and Channels in Windows Event Log.
    • Save the log – Action -> Save all events as VMMS and vhdmp.sys.

    Captures via batch file:

    @echo off  
    ECHO These commands will enable tracing:  
    @echo on  
    logman create trace "vm_manifests" -ow -o c:\vm_manifests.etl -p "Microsoft-Windows-Hyper-V-VMMS" 0xffffffffffffffff 0xff -nb 16 16 -bs 1024 -mode Circular -f bincirc -max 4096 -ets  
    logman update trace "vm_manifests" -p {4DDF50D0-75DE-4FBE-8F08-F8936638E7A1} 0xffffffffffffffff 0xff -ets  
    logman update trace "vm_manifests" -p "Microsoft-Windows-VHDMP" 0xffffffffffffffff 0xff -ets  
    logman update trace "vm_manifests" -p "Microsoft-Windows-Hyper-V-VHDMP" 0xffffffffffffffff 0xff -ets  
    @echo off  
    echo  
    ECHO Reproduce your issue and enter any key to stop tracing  
    @echo on  
    pause  
    logman stop "vm_manifests" -ets  
    @echo off  
    echo Tracing has been captured and saved successfully at c:\vm_manifests.etl  
    pause  
    

    Enable additional VMMS event logs via the Event Viewer:

    A. Open EventVwr and in the main menu select View and ensure "Show Analytic and Debug logs" is checked

    B. Under Applications and Services Logs -> Microsoft -> Windows -> Hyper-V-VMMS, select each item (Admin, etc.) and ensure that you "Enable Log" in the Actions pane on the right. Analytic is disabled by default.

    So when you upload the vm_manifests.etl file, include the EventVwr log via Main Menu -> Action -> Save All Events as, and include everything.

    This will help us in determining the reason for this behavior.

    Thank you!

    0 comments No comments

  3. Neelabh Mam 1 Reputation point
    2020-12-13T03:55:57.617+00:00

    Do we have a resolution here ? I am facing the exact same access denied and then (with VIRTUAL_DISK_ACCESS_ALL) the zero range count issue...

    0 comments No comments

  4. Neelabh Mam 1 Reputation point
    2020-12-13T09:08:26.453+00:00

    Figured out the zero range count issue.. working sample here:

    https://stackoverflow.com/questions/63358492/querychangesvirtualdisk-is-returning-error-invalid-handle6-even-though-openvir/65273895#65273895

    The only blocker now is how to get this working with a live checkpointed VM...

    also how do we query CBT data from WMI as the OP has done in the above post (image reproduced below)

    47588-image.png

    0 comments No comments

  5. Neelabh Mam 1 Reputation point
    2020-12-13T11:04:43.06+00:00

    Both issues fixed. Please see the below git repo. Thanks to alexpilotti the dev for this repo

    https://github.com/cloudbase/rct-service/issues/1

    Maybe the docs should highlight the correct OpenVirtualDisk API usage.

    47681-image.png

    0 comments No comments

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.