Skip to content

Commit 84c87c3

Browse files
committed
feat(balloon): enable memory reclaiming
1 parent bb077cb commit 84c87c3

File tree

3 files changed

+87
-9
lines changed

3 files changed

+87
-9
lines changed

src/devices/src/virtio/balloon/device.rs

+65-6
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,13 @@ use vm_memory::{Address, ByteValued, Bytes, GuestAddress, GuestMemoryMmap};
1818
use super::super::{ActivateResult, DeviceState, Queue, VirtioDevice, TYPE_BALLOON};
1919
use super::utils::{compact_page_frame_numbers, remove_range};
2020
use super::{
21-
BALLOON_DEV_ID, DEFLATE_INDEX, INFLATE_INDEX, MAX_PAGES_IN_DESC, MAX_PAGE_COMPACT_BUFFER,
22-
MIB_TO_4K_PAGES, NUM_QUEUES, QUEUE_SIZES, STATS_INDEX, VIRTIO_BALLOON_F_DEFLATE_ON_OOM,
23-
VIRTIO_BALLOON_F_STATS_VQ, VIRTIO_BALLOON_PFN_SHIFT, VIRTIO_BALLOON_S_AVAIL,
24-
VIRTIO_BALLOON_S_CACHES, VIRTIO_BALLOON_S_HTLB_PGALLOC, VIRTIO_BALLOON_S_HTLB_PGFAIL,
25-
VIRTIO_BALLOON_S_MAJFLT, VIRTIO_BALLOON_S_MEMFREE, VIRTIO_BALLOON_S_MEMTOT,
26-
VIRTIO_BALLOON_S_MINFLT, VIRTIO_BALLOON_S_SWAP_IN, VIRTIO_BALLOON_S_SWAP_OUT,
21+
BALLOON_DEV_ID, DEFLATE_INDEX, FREE_PAGE_REPORTING_INDEX, INFLATE_INDEX, MAX_PAGES_IN_DESC,
22+
MAX_PAGE_COMPACT_BUFFER, MIB_TO_4K_PAGES, NUM_QUEUES, QUEUE_SIZES, STATS_INDEX,
23+
VIRTIO_BALLOON_F_DEFLATE_ON_OOM, VIRTIO_BALLOON_F_REPORTING, VIRTIO_BALLOON_F_STATS_VQ,
24+
VIRTIO_BALLOON_PFN_SHIFT, VIRTIO_BALLOON_S_AVAIL, VIRTIO_BALLOON_S_CACHES,
25+
VIRTIO_BALLOON_S_HTLB_PGALLOC, VIRTIO_BALLOON_S_HTLB_PGFAIL, VIRTIO_BALLOON_S_MAJFLT,
26+
VIRTIO_BALLOON_S_MEMFREE, VIRTIO_BALLOON_S_MEMTOT, VIRTIO_BALLOON_S_MINFLT,
27+
VIRTIO_BALLOON_S_SWAP_IN, VIRTIO_BALLOON_S_SWAP_OUT,
2728
};
2829
use crate::virtio::balloon::Error as BalloonError;
2930
use crate::virtio::{IrqTrigger, IrqType};
@@ -167,10 +168,15 @@ impl Balloon {
167168
avail_features |= 1u64 << VIRTIO_BALLOON_F_STATS_VQ;
168169
}
169170

171+
avail_features |= 1u64 << VIRTIO_BALLOON_F_REPORTING;
172+
173+
logger::debug!("balloon: registering balloon device");
174+
170175
let queue_evts = [
171176
EventFd::new(libc::EFD_NONBLOCK).map_err(BalloonError::EventFd)?,
172177
EventFd::new(libc::EFD_NONBLOCK).map_err(BalloonError::EventFd)?,
173178
EventFd::new(libc::EFD_NONBLOCK).map_err(BalloonError::EventFd)?,
179+
EventFd::new(libc::EFD_NONBLOCK).map_err(BalloonError::EventFd)?,
174180
];
175181

176182
let mut queues: Vec<Queue> = QUEUE_SIZES.iter().map(|&s| Queue::new(s)).collect();
@@ -231,6 +237,14 @@ impl Balloon {
231237
self.trigger_stats_update()
232238
}
233239

240+
pub(crate) fn process_free_page_report_event(&mut self) -> Result<(), BalloonError> {
241+
logger::debug!("balloon: received free page report event");
242+
self.queue_evts[FREE_PAGE_REPORTING_INDEX]
243+
.read()
244+
.map_err(BalloonError::EventFd)?;
245+
self.process_free_page_reporting_queue()
246+
}
247+
234248
pub(crate) fn process_inflate(&mut self) -> Result<(), BalloonError> {
235249
// This is safe since we checked in the event handler that the device is activated.
236250
let mem = self.device_state.mem().unwrap();
@@ -382,6 +396,50 @@ impl Balloon {
382396
Ok(())
383397
}
384398

399+
pub(crate) fn process_free_page_reporting_queue(
400+
&mut self,
401+
) -> std::result::Result<(), BalloonError> {
402+
logger::debug!("balloon: processing free page reporting queue");
403+
let mem = self.device_state.mem().unwrap();
404+
405+
let mut total_removed = 0;
406+
let queue = &mut self.queues[FREE_PAGE_REPORTING_INDEX];
407+
let mut needs_interrupt = false;
408+
409+
while let Some(head) = queue.pop(mem) {
410+
let head_index = head.index;
411+
let head_mem = head.mem;
412+
413+
let mut last_desc = Some(head);
414+
while let Some(desc) = last_desc {
415+
total_removed += desc.len;
416+
if let Err(err) =
417+
remove_range(desc.mem, (desc.addr, desc.len as u64), self.restored)
418+
{
419+
error!("balloon: failed to remove range: {:?}", err);
420+
};
421+
last_desc = desc.next_descriptor();
422+
}
423+
424+
// Acknowledge the receipt of the descriptor.
425+
queue
426+
.add_used(head_mem, head_index, 0)
427+
.map_err(BalloonError::Queue)?;
428+
429+
logger::debug!("balloon: adding to the queue");
430+
431+
needs_interrupt = true;
432+
}
433+
434+
logger::debug!("balloon: total removed: {}MiB", total_removed >> 20);
435+
436+
if needs_interrupt {
437+
self.signal_used_queue()?;
438+
}
439+
440+
Ok(())
441+
}
442+
385443
pub(crate) fn signal_used_queue(&self) -> Result<(), BalloonError> {
386444
self.irq_trigger.trigger_irq(IrqType::Vring).map_err(|err| {
387445
METRICS.balloon.event_fails.inc();
@@ -393,6 +451,7 @@ impl Balloon {
393451
pub fn process_virtio_queues(&mut self) {
394452
let _ = self.process_inflate();
395453
let _ = self.process_deflate_queue();
454+
let _ = self.process_free_page_reporting_queue();
396455
}
397456

398457
pub fn id(&self) -> &str {

src/devices/src/virtio/balloon/event_handler.rs

+16-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,9 @@ use utils::epoll::EventSet;
99

1010
use crate::report_balloon_event_fail;
1111
use crate::virtio::balloon::device::Balloon;
12-
use crate::virtio::{VirtioDevice, DEFLATE_INDEX, INFLATE_INDEX, STATS_INDEX};
12+
use crate::virtio::{
13+
VirtioDevice, DEFLATE_INDEX, FREE_PAGE_REPORTING_INDEX, INFLATE_INDEX, STATS_INDEX,
14+
};
1315

1416
impl Balloon {
1517
fn register_runtime_events(&self, ops: &mut EventOps) {
@@ -27,6 +29,15 @@ impl Balloon {
2729
error!("Failed to register stats timerfd event: {}", err);
2830
}
2931
}
32+
if let Err(err) = ops.add(Events::new(
33+
&self.queue_evts[FREE_PAGE_REPORTING_INDEX],
34+
EventSet::IN,
35+
)) {
36+
error!(
37+
"Failed to register free page reporting queue event: {}",
38+
err
39+
);
40+
}
3041
}
3142

3243
fn register_activate_event(&self, ops: &mut EventOps) {
@@ -65,6 +76,7 @@ impl MutEventSubscriber for Balloon {
6576
let virtq_inflate_ev_fd = self.queue_evts[INFLATE_INDEX].as_raw_fd();
6677
let virtq_deflate_ev_fd = self.queue_evts[DEFLATE_INDEX].as_raw_fd();
6778
let virtq_stats_ev_fd = self.queue_evts[STATS_INDEX].as_raw_fd();
79+
let free_page_report_ev_fd = self.queue_evts[FREE_PAGE_REPORTING_INDEX].as_raw_fd();
6880
let stats_timer_fd = self.stats_timer.as_raw_fd();
6981
let activate_fd = self.activate_evt.as_raw_fd();
7082

@@ -82,6 +94,9 @@ impl MutEventSubscriber for Balloon {
8294
_ if source == stats_timer_fd => self
8395
.process_stats_timer_event()
8496
.unwrap_or_else(report_balloon_event_fail),
97+
_ if source == free_page_report_ev_fd => self
98+
.process_free_page_report_event()
99+
.unwrap_or_else(report_balloon_event_fail),
85100
_ if activate_fd == source => self.process_activate_event(ops),
86101
_ => {
87102
warn!("Balloon: Spurious event received: {:?}", source);

src/devices/src/virtio/balloon/mod.rs

+6-2
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,9 @@ pub use self::event_handler::*;
1717
pub const BALLOON_DEV_ID: &str = "balloon";
1818
pub const CONFIG_SPACE_SIZE: usize = 8;
1919
pub const QUEUE_SIZE: u16 = 256;
20-
pub const NUM_QUEUES: usize = 3;
21-
pub const QUEUE_SIZES: &[u16] = &[QUEUE_SIZE, QUEUE_SIZE, QUEUE_SIZE];
20+
pub const REPORTING_QUEUE_SIZE: u16 = 32;
21+
pub const NUM_QUEUES: usize = 4;
22+
pub const QUEUE_SIZES: &[u16] = &[QUEUE_SIZE, QUEUE_SIZE, QUEUE_SIZE, QUEUE_SIZE];
2223
// Number of 4K pages in a MiB.
2324
pub const MIB_TO_4K_PAGES: u32 = 256;
2425
// The maximum number of pages that can be received in a single descriptor.
@@ -34,10 +35,13 @@ pub const INFLATE_INDEX: usize = 0;
3435
pub const DEFLATE_INDEX: usize = 1;
3536
// The index of the deflate queue from Balloon device queues/queues_evts vector.
3637
pub const STATS_INDEX: usize = 2;
38+
// The index of the free page reporting from Balloon device queues/queues_evts vector.
39+
pub const FREE_PAGE_REPORTING_INDEX: usize = 3;
3740

3841
// The feature bitmap for virtio balloon.
3942
const VIRTIO_BALLOON_F_STATS_VQ: u32 = 1; // Enable statistics.
4043
const VIRTIO_BALLOON_F_DEFLATE_ON_OOM: u32 = 2; // Deflate balloon on OOM.
44+
const VIRTIO_BALLOON_F_REPORTING: u32 = 5; // Page reporting virtqueue
4145

4246
// The statistics tags.
4347
const VIRTIO_BALLOON_S_SWAP_IN: u16 = 0;

0 commit comments

Comments
 (0)