/*
 * Still use devCtx->MemStats cause it points to non-paged pool,
 * for virtio/host that access stats via physical memory.
 */
VOID
StatWorkItemWorker(
    IN WDFWORKITEM  WorkItem
    )
{
    WDFDEVICE       Device = WdfWorkItemGetParentObject(WorkItem);
    PDEVICE_CONTEXT devCtx = GetDeviceContext(Device);
    NTSTATUS        status = STATUS_SUCCESS;

    do
    {
        TraceEvents(TRACE_LEVEL_INFORMATION, DBG_HW_ACCESS,
            "StatWorkItemWorker Called! \n");
        status = GatherKernelStats(devCtx->MemStats);
        if (NT_SUCCESS(status))
        {
#if 0
            size_t i;
            for (i = 0; i < VIRTIO_BALLOON_S_NR; ++i)
            {
                TraceEvents(TRACE_LEVEL_INFORMATION, DBG_HW_ACCESS,
                    "st=%x tag = %d, value = %08I64X \n\n", status,
                    devCtx->MemStats[i].tag, devCtx->MemStats[i].val);
            }
#endif
        } else {
            RtlFillMemory (devCtx->MemStats, sizeof (BALLOON_STAT) * VIRTIO_BALLOON_S_NR, -1);
        }
        BalloonMemStats(Device);
    } while(InterlockedDecrement(&devCtx->WorkCount));
    return;
}
VOID
BalloonEvtDeviceContextCleanup(
    IN WDFOBJECT  Device
    )
{
    PDEVICE_CONTEXT     devCtx = GetDeviceContext((WDFDEVICE)Device);

    PAGED_CODE();

    TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "--> %s\n", __FUNCTION__);

    if(devCtx->bListInitialized)
    {
        ExDeleteNPagedLookasideList(&devCtx->LookAsideList);
        devCtx->bListInitialized = FALSE;
    }
    if(devCtx->pfns_table)
    {
        ExFreePoolWithTag(
                   devCtx->pfns_table,
                   BALLOON_MGMT_POOL_TAG
                   );
        devCtx->pfns_table = NULL;
    }

    RtlFillMemory(devCtx->MemStats,
        sizeof(BALLOON_STAT) * VIRTIO_BALLOON_S_NR, -1);
    if (devCtx->StatVirtQueue)
    {
        BalloonMemStats(Device);
    }

    if(devCtx->MemStats)
    {
        ExFreePoolWithTag(
                   devCtx->MemStats,
                   BALLOON_MGMT_POOL_TAG
                   );
        devCtx->MemStats = NULL;
    }
    TraceEvents(TRACE_LEVEL_INFORMATION, DBG_INIT, "<-- %s\n", __FUNCTION__);
}
VOID
BalloonEvtFileClose (
    IN WDFFILEOBJECT    FileObject
    )
{
    PDEVICE_CONTEXT devCtx = GetDeviceContext(
        WdfFileObjectGetDevice(FileObject));

    PAGED_CODE();

    TraceEvents(TRACE_LEVEL_INFORMATION, DBG_PNP, "<-> %s\n", __FUNCTION__);

    RtlFillMemory(devCtx->MemStats,
        sizeof(BALLOON_STAT) * VIRTIO_BALLOON_S_NR, -1);

    if (devCtx->StatVirtQueue)
    {
        BalloonMemStats(WdfFileObjectGetDevice(FileObject));
    }
}