virtio: add driver for the virtio balloon device
* how-to for qemu: command line option: -balloon virtio * in the monitor view - to switch the vm size to 500MB: balloon 500 - to display balloon info: info balloon
This commit is contained in:
parent
2284eb4875
commit
fe11711026
@ -7,4 +7,6 @@ KernelAddon virtio :
|
||||
VirtioDevice.cpp
|
||||
VirtioModule.cpp
|
||||
VirtioQueue.cpp
|
||||
VirtioBalloonDevice.cpp
|
||||
virtio_balloon.cpp
|
||||
;
|
||||
|
258
src/add-ons/kernel/bus_managers/virtio/VirtioBalloonDevice.cpp
Normal file
258
src/add-ons/kernel/bus_managers/virtio/VirtioBalloonDevice.cpp
Normal file
@ -0,0 +1,258 @@
|
||||
/*
|
||||
* Copyright 2018, Jérôme Duval, jerome.duval@gmail.com.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
|
||||
#include "VirtioBalloonPrivate.h"
|
||||
|
||||
#include <new>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <util/AutoLock.h>
|
||||
|
||||
#include "virtio_balloon.h"
|
||||
|
||||
|
||||
const char*
|
||||
get_feature_name(uint32 feature)
|
||||
{
|
||||
switch (feature) {
|
||||
case VIRTIO_BALLOON_F_MUST_TELL_HOST:
|
||||
return "must tell host";
|
||||
case VIRTIO_BALLOON_F_STATS_VQ:
|
||||
return "stats vq";
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
VirtioBalloonDevice::VirtioBalloonDevice(device_node* node)
|
||||
:
|
||||
fNode(node),
|
||||
fVirtio(NULL),
|
||||
fVirtioDevice(NULL),
|
||||
fStatus(B_NO_INIT),
|
||||
fDesiredSize(0),
|
||||
fActualSize(0)
|
||||
{
|
||||
CALLED();
|
||||
|
||||
B_INITIALIZE_SPINLOCK(&fInterruptLock);
|
||||
fQueueCondition.Init(this, "virtio balloon transfer");
|
||||
fConfigCondition.Init(this, "virtio balloon config");
|
||||
|
||||
get_memory_map(fBuffer, sizeof(fBuffer), &fEntry, 1);
|
||||
|
||||
// get the Virtio device from our parent's parent
|
||||
device_node* parent = gDeviceManager->get_parent_node(node);
|
||||
device_node* virtioParent = gDeviceManager->get_parent_node(parent);
|
||||
gDeviceManager->put_node(parent);
|
||||
|
||||
gDeviceManager->get_driver(virtioParent, (driver_module_info**)&fVirtio,
|
||||
(void**)&fVirtioDevice);
|
||||
gDeviceManager->put_node(virtioParent);
|
||||
|
||||
fVirtio->negotiate_features(fVirtioDevice,
|
||||
0, &fFeatures, &get_feature_name);
|
||||
|
||||
fStatus = fVirtio->alloc_queues(fVirtioDevice, 2, fVirtioQueues);
|
||||
if (fStatus != B_OK) {
|
||||
ERROR("queue allocation failed (%s)\n", strerror(fStatus));
|
||||
return;
|
||||
}
|
||||
|
||||
fStatus = fVirtio->setup_interrupt(fVirtioDevice, _ConfigCallback, this);
|
||||
if (fStatus != B_OK) {
|
||||
ERROR("interrupt setup failed (%s)\n", strerror(fStatus));
|
||||
return;
|
||||
}
|
||||
|
||||
fStatus = fVirtio->queue_setup_interrupt(fVirtioQueues[0],
|
||||
_QueueCallback, fVirtioQueues[0]);
|
||||
if (fStatus != B_OK) {
|
||||
ERROR("queue interrupt setup failed (%s)\n", strerror(fStatus));
|
||||
return;
|
||||
}
|
||||
|
||||
fStatus = fVirtio->queue_setup_interrupt(fVirtioQueues[1],
|
||||
_QueueCallback, fVirtioQueues[1]);
|
||||
if (fStatus != B_OK) {
|
||||
ERROR("queue interrupt setup failed (%s)\n", strerror(fStatus));
|
||||
return;
|
||||
}
|
||||
|
||||
fThread = spawn_kernel_thread(&_ThreadEntry, "virtio balloon thread",
|
||||
B_NORMAL_PRIORITY, this);
|
||||
if (fThread < 0) {
|
||||
fStatus = fThread;
|
||||
return;
|
||||
}
|
||||
resume_thread(fThread);
|
||||
}
|
||||
|
||||
|
||||
VirtioBalloonDevice::~VirtioBalloonDevice()
|
||||
{
|
||||
fRunning = false;
|
||||
if (fThread >= 0) {
|
||||
int32 result;
|
||||
wait_for_thread(fThread, &result);
|
||||
fThread = -1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
VirtioBalloonDevice::InitCheck()
|
||||
{
|
||||
return fStatus;
|
||||
}
|
||||
|
||||
|
||||
int32
|
||||
VirtioBalloonDevice::_ThreadEntry(void* data)
|
||||
{
|
||||
VirtioBalloonDevice* device = (VirtioBalloonDevice*)data;
|
||||
return device->_Thread();
|
||||
}
|
||||
|
||||
|
||||
int32
|
||||
VirtioBalloonDevice::_Thread()
|
||||
{
|
||||
CALLED();
|
||||
|
||||
while (fRunning) {
|
||||
if (fDesiredSize == fActualSize) {
|
||||
TRACE("waiting for a config change\n");
|
||||
ConditionVariableEntry configConditionEntry;
|
||||
fConfigCondition.Add(&configConditionEntry);
|
||||
status_t result = configConditionEntry.Wait(B_CAN_INTERRUPT);
|
||||
if (result != B_OK)
|
||||
continue;
|
||||
|
||||
fDesiredSize = _DesiredSize();
|
||||
TRACE("finished waiting: requested %" B_PRIu32 " instead of %" B_PRIu32
|
||||
"\n", fDesiredSize, fActualSize);
|
||||
}
|
||||
::virtio_queue queue;
|
||||
if (fDesiredSize > fActualSize) {
|
||||
int32 count = min_c(PAGES_COUNT, fDesiredSize - fActualSize);
|
||||
TRACE("allocating %" B_PRIu32 " pages\n", count);
|
||||
queue = fVirtioQueues[0];
|
||||
|
||||
vm_page_reservation reservation;
|
||||
vm_page_reserve_pages(&reservation, count, VM_PRIORITY_SYSTEM);
|
||||
for (int i = 0; i < count; i++) {
|
||||
//TRACE("allocating page %" B_PRIu32 " pages\n", i);
|
||||
vm_page* page = vm_page_allocate_page(&reservation,
|
||||
PAGE_STATE_WIRED);
|
||||
if (page == NULL) {
|
||||
TRACE("allocating failed\n");
|
||||
count = i;
|
||||
break;
|
||||
}
|
||||
PageInfo* info = new PageInfo;
|
||||
info->page = page;
|
||||
fBuffer[i] = (phys_addr_t)page->physical_page_number
|
||||
>> (PAGE_SHIFT - VIRTIO_BALLOON_PFN_SHIFT);
|
||||
fPages.Add(info);
|
||||
}
|
||||
fEntry.size = count * sizeof(uint32);
|
||||
fActualSize += count;
|
||||
} else {
|
||||
int32 count = min_c(PAGES_COUNT, fActualSize - fDesiredSize);
|
||||
TRACE("freeing %" B_PRIu32 " pages\n", count);
|
||||
queue = fVirtioQueues[1];
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
PageInfo* info = fPages.RemoveHead();
|
||||
if (info == NULL) {
|
||||
TRACE("remove failed\n");
|
||||
count = i;
|
||||
break;
|
||||
}
|
||||
vm_page* page = info->page;
|
||||
fBuffer[i] = (phys_addr_t)page->physical_page_number
|
||||
>> (PAGE_SHIFT - VIRTIO_BALLOON_PFN_SHIFT);
|
||||
vm_page_free(NULL, page);
|
||||
}
|
||||
fEntry.size = count * sizeof(uint32);
|
||||
fActualSize -= count;
|
||||
}
|
||||
|
||||
ConditionVariableEntry queueConditionEntry;
|
||||
fQueueCondition.Add(&queueConditionEntry);
|
||||
|
||||
// alloc or release
|
||||
TRACE("queue request\n");
|
||||
status_t result = fVirtio->queue_request(queue, &fEntry, NULL,
|
||||
queue);
|
||||
if (result != B_OK) {
|
||||
ERROR("queueing failed (%s)\n", strerror(result));
|
||||
return result;
|
||||
}
|
||||
|
||||
while (fVirtio->queue_dequeue(queue, NULL) == NULL) {
|
||||
TRACE("wait for response\n");
|
||||
queueConditionEntry.Wait(B_CAN_INTERRUPT);
|
||||
}
|
||||
|
||||
TRACE("update size\n");
|
||||
_UpdateSize();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
VirtioBalloonDevice::_ConfigCallback(void* driverCookie)
|
||||
{
|
||||
CALLED();
|
||||
VirtioBalloonDevice* device = (VirtioBalloonDevice*)driverCookie;
|
||||
|
||||
SpinLocker locker(device->fInterruptLock);
|
||||
device->fConfigCondition.NotifyAll();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
VirtioBalloonDevice::_QueueCallback(void* driverCookie, void* cookie)
|
||||
{
|
||||
CALLED();
|
||||
VirtioBalloonDevice* device = (VirtioBalloonDevice*)driverCookie;
|
||||
|
||||
SpinLocker locker(device->fInterruptLock);
|
||||
device->fQueueCondition.NotifyAll();
|
||||
}
|
||||
|
||||
|
||||
uint32
|
||||
VirtioBalloonDevice::_DesiredSize()
|
||||
{
|
||||
CALLED();
|
||||
uint32 desiredSize;
|
||||
|
||||
status_t status = fVirtio->read_device_config(fVirtioDevice,
|
||||
offsetof(struct virtio_balloon_config, num_pages),
|
||||
&desiredSize, sizeof(desiredSize));
|
||||
if (status != B_OK)
|
||||
return 0;
|
||||
|
||||
return B_LENDIAN_TO_HOST_INT32(desiredSize);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
VirtioBalloonDevice::_UpdateSize()
|
||||
{
|
||||
CALLED();
|
||||
TRACE("_UpdateSize %u\n", fActualSize);
|
||||
uint32 actualSize = B_HOST_TO_LENDIAN_INT32(fActualSize);
|
||||
return fVirtio->write_device_config(fVirtioDevice,
|
||||
offsetof(struct virtio_balloon_config, actual),
|
||||
&actualSize, sizeof(actualSize));
|
||||
}
|
@ -0,0 +1,83 @@
|
||||
/*
|
||||
* Copyright 2018, Jérôme Duval, jerome.duval@gmail.com.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef VIRTIO_BALLOON_PRIVATE_H
|
||||
#define VIRTIO_BALLOON_PRIVATE_H
|
||||
|
||||
|
||||
#include <condition_variable.h>
|
||||
#include <lock.h>
|
||||
#include <virtio.h>
|
||||
#include <vm/vm_page.h>
|
||||
|
||||
|
||||
//#define TRACE_VIRTIO_BALLOON
|
||||
#ifdef TRACE_VIRTIO_BALLOON
|
||||
# define TRACE(x...) dprintf("virtio_balloon: " x)
|
||||
#else
|
||||
# define TRACE(x...) ;
|
||||
#endif
|
||||
#define ERROR(x...) dprintf("\33[33mvirtio_rng:\33[0m " x)
|
||||
#define CALLED() TRACE("CALLED %s\n", __PRETTY_FUNCTION__)
|
||||
|
||||
|
||||
extern device_manager_info* gDeviceManager;
|
||||
|
||||
|
||||
#define PAGES_COUNT 256
|
||||
|
||||
|
||||
struct PageInfo : DoublyLinkedListLinkImpl<PageInfo> {
|
||||
vm_page *page;
|
||||
};
|
||||
|
||||
|
||||
typedef DoublyLinkedList<PageInfo> PageInfoList;
|
||||
|
||||
|
||||
|
||||
class VirtioBalloonDevice {
|
||||
public:
|
||||
VirtioBalloonDevice(device_node* node);
|
||||
~VirtioBalloonDevice();
|
||||
|
||||
status_t InitCheck();
|
||||
|
||||
private:
|
||||
static void _ConfigCallback(void* driverCookie);
|
||||
static void _QueueCallback(void* driverCookie,
|
||||
void *cookie);
|
||||
|
||||
static int32 _ThreadEntry(void *data);
|
||||
int32 _Thread();
|
||||
|
||||
uint32 _DesiredSize();
|
||||
status_t _UpdateSize();
|
||||
|
||||
device_node* fNode;
|
||||
|
||||
virtio_device_interface* fVirtio;
|
||||
virtio_device* fVirtioDevice;
|
||||
|
||||
status_t fStatus;
|
||||
uint32 fFeatures;
|
||||
::virtio_queue fVirtioQueues[2];
|
||||
|
||||
physical_entry fEntry;
|
||||
uint32 fBuffer[PAGES_COUNT];
|
||||
|
||||
thread_id fThread;
|
||||
uint32 fDesiredSize;
|
||||
uint32 fActualSize;
|
||||
|
||||
spinlock fInterruptLock;
|
||||
ConditionVariable fQueueCondition;
|
||||
ConditionVariable fConfigCondition;
|
||||
bool fRunning;
|
||||
|
||||
PageInfoList fPages;
|
||||
};
|
||||
|
||||
|
||||
#endif // VIRTIO_BALLOON_PRIVATE_H
|
@ -315,9 +315,16 @@ module_dependency module_dependencies[] = {
|
||||
{}
|
||||
};
|
||||
|
||||
|
||||
extern struct driver_module_info sVirtioBalloonDriver;
|
||||
extern struct driver_module_info sVirtioBalloonDeviceInterface;
|
||||
|
||||
|
||||
module_info *modules[] = {
|
||||
(module_info *)&virtio_for_controller_module,
|
||||
(module_info *)&virtio_device_module,
|
||||
(module_info *)&sVirtioBalloonDriver,
|
||||
(module_info *)&sVirtioBalloonDeviceInterface,
|
||||
NULL
|
||||
};
|
||||
|
||||
|
167
src/add-ons/kernel/bus_managers/virtio/virtio_balloon.cpp
Normal file
167
src/add-ons/kernel/bus_managers/virtio/virtio_balloon.cpp
Normal file
@ -0,0 +1,167 @@
|
||||
/*
|
||||
* Copyright 2018, Jérôme Duval, jerome.duval@gmail.com.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
|
||||
#include "VirtioBalloonPrivate.h"
|
||||
|
||||
#include <new>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
#define VIRTIO_BALLOON_CONTROLLER_PRETTY_NAME "Virtio Balloon Device"
|
||||
|
||||
#define VIRTIO_BALLOON_DRIVER_MODULE_NAME "drivers/misc/virtio_balloon/driver_v1"
|
||||
#define VIRTIO_BALLOON_DEVICE_MODULE_NAME "drivers/misc/virtio_balloon/device_v1"
|
||||
|
||||
|
||||
extern device_manager_info *gDeviceManager;
|
||||
|
||||
|
||||
// #pragma mark - Device module interface
|
||||
|
||||
|
||||
static status_t
|
||||
virtio_balloon_init_device(device_node *node, void **_cookie)
|
||||
{
|
||||
CALLED();
|
||||
|
||||
VirtioBalloonDevice *device = new(std::nothrow)
|
||||
VirtioBalloonDevice(node);
|
||||
if (device == NULL)
|
||||
return B_NO_MEMORY;
|
||||
status_t status = device->InitCheck();
|
||||
if (status < B_OK) {
|
||||
delete device;
|
||||
return status;
|
||||
}
|
||||
|
||||
*_cookie = device;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
virtio_balloon_uninit_device(void *cookie)
|
||||
{
|
||||
CALLED();
|
||||
VirtioBalloonDevice *device = (VirtioBalloonDevice*)cookie;
|
||||
|
||||
delete device;
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - Driver module interface
|
||||
|
||||
|
||||
static float
|
||||
virtio_balloon_supports_device(device_node *parent)
|
||||
{
|
||||
const char *bus;
|
||||
uint16 deviceType;
|
||||
|
||||
// make sure parent is really the Virtio bus manager
|
||||
if (gDeviceManager->get_attr_string(parent, B_DEVICE_BUS, &bus, false))
|
||||
return -1;
|
||||
|
||||
if (strcmp(bus, "virtio"))
|
||||
return 0.0;
|
||||
|
||||
// check whether it's really a Virtio Entropy Device
|
||||
if (gDeviceManager->get_attr_uint16(parent, VIRTIO_DEVICE_TYPE_ITEM,
|
||||
&deviceType, true) != B_OK || deviceType != VIRTIO_DEVICE_ID_BALLOON)
|
||||
return 0.0;
|
||||
|
||||
TRACE("Virtio Balloon device found!\n");
|
||||
|
||||
return 0.6f;
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
virtio_balloon_register_device(device_node *parent)
|
||||
{
|
||||
CALLED();
|
||||
|
||||
device_attr attrs[] = {
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
return gDeviceManager->register_node(parent, VIRTIO_BALLOON_DRIVER_MODULE_NAME,
|
||||
attrs, NULL, NULL);
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
virtio_balloon_init_driver(device_node *node, void **_cookie)
|
||||
{
|
||||
CALLED();
|
||||
*_cookie = node;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
virtio_balloon_register_child_devices(void *cookie)
|
||||
{
|
||||
CALLED();
|
||||
device_node *node = (device_node *)cookie;
|
||||
|
||||
device_attr attrs[] = {
|
||||
{ B_DEVICE_PRETTY_NAME, B_STRING_TYPE,
|
||||
{ string: VIRTIO_BALLOON_CONTROLLER_PRETTY_NAME }},
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
return gDeviceManager->register_node(node,
|
||||
VIRTIO_BALLOON_DEVICE_MODULE_NAME, attrs, NULL, NULL);
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
std_ops(int32 op, ...)
|
||||
{
|
||||
switch (op) {
|
||||
case B_MODULE_INIT:
|
||||
case B_MODULE_UNINIT:
|
||||
return B_OK;
|
||||
|
||||
default:
|
||||
return B_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
driver_module_info sVirtioBalloonDeviceInterface = {
|
||||
{
|
||||
VIRTIO_BALLOON_DEVICE_MODULE_NAME,
|
||||
0,
|
||||
std_ops
|
||||
},
|
||||
NULL, // supported devices
|
||||
NULL, // register node
|
||||
virtio_balloon_init_device,
|
||||
virtio_balloon_uninit_device,
|
||||
NULL, // register child devices
|
||||
NULL, // rescan
|
||||
NULL // bus_removed
|
||||
};
|
||||
|
||||
|
||||
driver_module_info sVirtioBalloonDriver = {
|
||||
{
|
||||
VIRTIO_BALLOON_DRIVER_MODULE_NAME,
|
||||
0,
|
||||
std_ops
|
||||
},
|
||||
virtio_balloon_supports_device,
|
||||
virtio_balloon_register_device,
|
||||
virtio_balloon_init_driver,
|
||||
NULL, // uninit_driver,
|
||||
virtio_balloon_register_child_devices,
|
||||
NULL, // rescan
|
||||
NULL, // device_removed
|
||||
};
|
||||
|
64
src/add-ons/kernel/bus_managers/virtio/virtio_balloon.h
Normal file
64
src/add-ons/kernel/bus_managers/virtio/virtio_balloon.h
Normal file
@ -0,0 +1,64 @@
|
||||
/*-
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*
|
||||
* This header is BSD licensed so anyone can use the definitions to implement
|
||||
* compatible drivers/servers.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of IBM nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL IBM OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#ifndef _VIRTIO_BALLOON_H
|
||||
#define _VIRTIO_BALLOON_H
|
||||
|
||||
/* Feature bits. */
|
||||
#define VIRTIO_BALLOON_F_MUST_TELL_HOST 0x1 /* Tell before reclaiming pages */
|
||||
#define VIRTIO_BALLOON_F_STATS_VQ 0x2 /* Memory stats virtqueue */
|
||||
|
||||
/* Size of a PFN in the balloon interface. */
|
||||
#define VIRTIO_BALLOON_PFN_SHIFT 12
|
||||
|
||||
struct virtio_balloon_config {
|
||||
/* Number of pages host wants Guest to give up. */
|
||||
uint32_t num_pages;
|
||||
|
||||
/* Number of pages we've actually got in balloon. */
|
||||
uint32_t actual;
|
||||
};
|
||||
|
||||
#define VIRTIO_BALLOON_S_SWAP_IN 0 /* Amount of memory swapped in */
|
||||
#define VIRTIO_BALLOON_S_SWAP_OUT 1 /* Amount of memory swapped out */
|
||||
#define VIRTIO_BALLOON_S_MAJFLT 2 /* Number of major faults */
|
||||
#define VIRTIO_BALLOON_S_MINFLT 3 /* Number of minor faults */
|
||||
#define VIRTIO_BALLOON_S_MEMFREE 4 /* Total amount of free memory */
|
||||
#define VIRTIO_BALLOON_S_MEMTOT 5 /* Total amount of memory */
|
||||
#define VIRTIO_BALLOON_S_NR 6
|
||||
|
||||
struct virtio_balloon_stat {
|
||||
uint16_t tag;
|
||||
uint64_t val;
|
||||
} __packed;
|
||||
|
||||
#endif /* _VIRTIO_BALLOON_H */
|
Loading…
Reference in New Issue
Block a user