mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2025-02-02 01:45:21 +00:00
virtio-devices: balloon: Implement free page reporting
Implement the VIRTIO_BALLOON_F_REPORTING feature, indicating to the guest it can report set of free pages. A new virtqueue dedicated for receiving the information about the free pages is created. The VMM releases the memory by punching holes with fallocate() if the guest memory is backed by a file, and madvise() the host about the ranges of memory that shouldn't be needed anymore. Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
This commit is contained in:
parent
052f38fa96
commit
384752647a
@ -41,8 +41,8 @@ use vm_migration::{
|
|||||||
use vmm_sys_util::eventfd::EventFd;
|
use vmm_sys_util::eventfd::EventFd;
|
||||||
|
|
||||||
const QUEUE_SIZE: u16 = 128;
|
const QUEUE_SIZE: u16 = 128;
|
||||||
const NUM_QUEUES: usize = 2;
|
const REPORTING_QUEUE_SIZE: u16 = 32;
|
||||||
const QUEUE_SIZES: &[u16] = &[QUEUE_SIZE; NUM_QUEUES];
|
const MIN_NUM_QUEUES: usize = 2;
|
||||||
|
|
||||||
// Resize event.
|
// Resize event.
|
||||||
const RESIZE_EVENT: u16 = EPOLL_HELPER_EVENT_LAST + 1;
|
const RESIZE_EVENT: u16 = EPOLL_HELPER_EVENT_LAST + 1;
|
||||||
@ -50,12 +50,17 @@ const RESIZE_EVENT: u16 = EPOLL_HELPER_EVENT_LAST + 1;
|
|||||||
const INFLATE_QUEUE_EVENT: u16 = EPOLL_HELPER_EVENT_LAST + 2;
|
const INFLATE_QUEUE_EVENT: u16 = EPOLL_HELPER_EVENT_LAST + 2;
|
||||||
// Deflate virtio queue event.
|
// Deflate virtio queue event.
|
||||||
const DEFLATE_QUEUE_EVENT: u16 = EPOLL_HELPER_EVENT_LAST + 3;
|
const DEFLATE_QUEUE_EVENT: u16 = EPOLL_HELPER_EVENT_LAST + 3;
|
||||||
|
// Reporting virtio queue event.
|
||||||
|
const REPORTING_QUEUE_EVENT: u16 = EPOLL_HELPER_EVENT_LAST + 4;
|
||||||
|
|
||||||
// Size of a PFN in the balloon interface.
|
// Size of a PFN in the balloon interface.
|
||||||
const VIRTIO_BALLOON_PFN_SHIFT: u64 = 12;
|
const VIRTIO_BALLOON_PFN_SHIFT: u64 = 12;
|
||||||
|
|
||||||
// Deflate balloon on OOM
|
// Deflate balloon on OOM
|
||||||
const VIRTIO_BALLOON_F_DEFLATE_ON_OOM: u64 = 2;
|
const VIRTIO_BALLOON_F_DEFLATE_ON_OOM: u64 = 2;
|
||||||
|
// Enable an additional virtqueue to let the guest notify the host about free
|
||||||
|
// pages.
|
||||||
|
const VIRTIO_BALLOON_F_REPORTING: u64 = 5;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
@ -162,6 +167,7 @@ struct BalloonEpollHandler {
|
|||||||
interrupt_cb: Arc<dyn VirtioInterrupt>,
|
interrupt_cb: Arc<dyn VirtioInterrupt>,
|
||||||
inflate_queue_evt: EventFd,
|
inflate_queue_evt: EventFd,
|
||||||
deflate_queue_evt: EventFd,
|
deflate_queue_evt: EventFd,
|
||||||
|
reporting_queue_evt: Option<EventFd>,
|
||||||
kill_evt: EventFd,
|
kill_evt: EventFd,
|
||||||
pause_evt: EventFd,
|
pause_evt: EventFd,
|
||||||
}
|
}
|
||||||
@ -291,6 +297,25 @@ impl BalloonEpollHandler {
|
|||||||
self.notify_queue(queue_index, used_descs)
|
self.notify_queue(queue_index, used_descs)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn process_reporting_queue(&mut self, queue_index: usize) -> result::Result<(), Error> {
|
||||||
|
let mut used_descs = Vec::new();
|
||||||
|
|
||||||
|
for mut desc_chain in self.queues[queue_index]
|
||||||
|
.iter()
|
||||||
|
.map_err(Error::QueueIterator)?
|
||||||
|
{
|
||||||
|
let mut descs_len = 0;
|
||||||
|
while let Some(desc) = desc_chain.next() {
|
||||||
|
descs_len += desc.len();
|
||||||
|
Self::release_memory_range(desc_chain.memory(), desc.addr(), desc.len() as usize)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
used_descs.push((desc_chain.head_index(), descs_len));
|
||||||
|
}
|
||||||
|
|
||||||
|
self.notify_queue(queue_index, used_descs)
|
||||||
|
}
|
||||||
|
|
||||||
fn run(
|
fn run(
|
||||||
&mut self,
|
&mut self,
|
||||||
paused: Arc<AtomicBool>,
|
paused: Arc<AtomicBool>,
|
||||||
@ -300,6 +325,9 @@ impl BalloonEpollHandler {
|
|||||||
helper.add_event(self.resize_receiver.evt.as_raw_fd(), RESIZE_EVENT)?;
|
helper.add_event(self.resize_receiver.evt.as_raw_fd(), RESIZE_EVENT)?;
|
||||||
helper.add_event(self.inflate_queue_evt.as_raw_fd(), INFLATE_QUEUE_EVENT)?;
|
helper.add_event(self.inflate_queue_evt.as_raw_fd(), INFLATE_QUEUE_EVENT)?;
|
||||||
helper.add_event(self.deflate_queue_evt.as_raw_fd(), DEFLATE_QUEUE_EVENT)?;
|
helper.add_event(self.deflate_queue_evt.as_raw_fd(), DEFLATE_QUEUE_EVENT)?;
|
||||||
|
if let Some(reporting_queue_evt) = self.reporting_queue_evt.as_ref() {
|
||||||
|
helper.add_event(reporting_queue_evt.as_raw_fd(), REPORTING_QUEUE_EVENT)?;
|
||||||
|
}
|
||||||
helper.run(paused, paused_sync, self)?;
|
helper.run(paused, paused_sync, self)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -357,6 +385,20 @@ impl EpollHelperHandler for BalloonEpollHandler {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
REPORTING_QUEUE_EVENT => {
|
||||||
|
if let Some(reporting_queue_evt) = self.reporting_queue_evt.as_ref() {
|
||||||
|
if let Err(e) = reporting_queue_evt.read() {
|
||||||
|
error!("Failed to get reporting queue event: {:?}", e);
|
||||||
|
return true;
|
||||||
|
} else if let Err(e) = self.process_reporting_queue(2) {
|
||||||
|
error!("Failed to signal used inflate queue: {:?}", e);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
error!("Invalid reporting queue event as no eventfd registered");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
_ => {
|
_ => {
|
||||||
error!("Unknown event for virtio-balloon");
|
error!("Unknown event for virtio-balloon");
|
||||||
return true;
|
return true;
|
||||||
@ -392,14 +434,19 @@ impl Balloon {
|
|||||||
id: String,
|
id: String,
|
||||||
size: u64,
|
size: u64,
|
||||||
deflate_on_oom: bool,
|
deflate_on_oom: bool,
|
||||||
_free_page_reporting: bool,
|
free_page_reporting: bool,
|
||||||
seccomp_action: SeccompAction,
|
seccomp_action: SeccompAction,
|
||||||
exit_evt: EventFd,
|
exit_evt: EventFd,
|
||||||
) -> io::Result<Self> {
|
) -> io::Result<Self> {
|
||||||
|
let mut queue_sizes = vec![QUEUE_SIZE; MIN_NUM_QUEUES];
|
||||||
let mut avail_features = 1u64 << VIRTIO_F_VERSION_1;
|
let mut avail_features = 1u64 << VIRTIO_F_VERSION_1;
|
||||||
if deflate_on_oom {
|
if deflate_on_oom {
|
||||||
avail_features |= 1u64 << VIRTIO_BALLOON_F_DEFLATE_ON_OOM;
|
avail_features |= 1u64 << VIRTIO_BALLOON_F_DEFLATE_ON_OOM;
|
||||||
}
|
}
|
||||||
|
if free_page_reporting {
|
||||||
|
avail_features |= 1u64 << VIRTIO_BALLOON_F_REPORTING;
|
||||||
|
queue_sizes.push(REPORTING_QUEUE_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
let config = VirtioBalloonConfig {
|
let config = VirtioBalloonConfig {
|
||||||
num_pages: (size >> VIRTIO_BALLOON_PFN_SHIFT) as u32,
|
num_pages: (size >> VIRTIO_BALLOON_PFN_SHIFT) as u32,
|
||||||
@ -411,8 +458,8 @@ impl Balloon {
|
|||||||
device_type: VirtioDeviceType::Balloon as u32,
|
device_type: VirtioDeviceType::Balloon as u32,
|
||||||
avail_features,
|
avail_features,
|
||||||
paused_sync: Some(Arc::new(Barrier::new(2))),
|
paused_sync: Some(Arc::new(Barrier::new(2))),
|
||||||
queue_sizes: QUEUE_SIZES.to_vec(),
|
queue_sizes,
|
||||||
min_queues: NUM_QUEUES as u16,
|
min_queues: MIN_NUM_QUEUES as u16,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
id,
|
id,
|
||||||
@ -503,6 +550,12 @@ impl VirtioDevice for Balloon {
|
|||||||
|
|
||||||
let inflate_queue_evt = queue_evts.remove(0);
|
let inflate_queue_evt = queue_evts.remove(0);
|
||||||
let deflate_queue_evt = queue_evts.remove(0);
|
let deflate_queue_evt = queue_evts.remove(0);
|
||||||
|
let reporting_queue_evt =
|
||||||
|
if self.common.feature_acked(VIRTIO_BALLOON_F_REPORTING) && !queue_evts.is_empty() {
|
||||||
|
Some(queue_evts.remove(0))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
let mut handler = BalloonEpollHandler {
|
let mut handler = BalloonEpollHandler {
|
||||||
config: self.config.clone(),
|
config: self.config.clone(),
|
||||||
@ -514,6 +567,7 @@ impl VirtioDevice for Balloon {
|
|||||||
interrupt_cb,
|
interrupt_cb,
|
||||||
inflate_queue_evt,
|
inflate_queue_evt,
|
||||||
deflate_queue_evt,
|
deflate_queue_evt,
|
||||||
|
reporting_queue_evt,
|
||||||
kill_evt,
|
kill_evt,
|
||||||
pause_evt,
|
pause_evt,
|
||||||
};
|
};
|
||||||
|
Loading…
x
Reference in New Issue
Block a user