@@ -18,12 +18,13 @@ use vm_memory::{Address, ByteValued, Bytes, GuestAddress, GuestMemoryMmap};
18
18
use super :: super :: { ActivateResult , DeviceState , Queue , VirtioDevice , TYPE_BALLOON } ;
19
19
use super :: utils:: { compact_page_frame_numbers, remove_range} ;
20
20
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 ,
27
28
} ;
28
29
use crate :: virtio:: balloon:: Error as BalloonError ;
29
30
use crate :: virtio:: { IrqTrigger , IrqType } ;
@@ -167,10 +168,15 @@ impl Balloon {
167
168
avail_features |= 1u64 << VIRTIO_BALLOON_F_STATS_VQ ;
168
169
}
169
170
171
+ avail_features |= 1u64 << VIRTIO_BALLOON_F_REPORTING ;
172
+
173
+ logger:: debug!( "balloon: registering balloon device" ) ;
174
+
170
175
let queue_evts = [
171
176
EventFd :: new ( libc:: EFD_NONBLOCK ) . map_err ( BalloonError :: EventFd ) ?,
172
177
EventFd :: new ( libc:: EFD_NONBLOCK ) . map_err ( BalloonError :: EventFd ) ?,
173
178
EventFd :: new ( libc:: EFD_NONBLOCK ) . map_err ( BalloonError :: EventFd ) ?,
179
+ EventFd :: new ( libc:: EFD_NONBLOCK ) . map_err ( BalloonError :: EventFd ) ?,
174
180
] ;
175
181
176
182
let mut queues: Vec < Queue > = QUEUE_SIZES . iter ( ) . map ( |& s| Queue :: new ( s) ) . collect ( ) ;
@@ -231,6 +237,14 @@ impl Balloon {
231
237
self . trigger_stats_update ( )
232
238
}
233
239
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
+
234
248
pub ( crate ) fn process_inflate ( & mut self ) -> Result < ( ) , BalloonError > {
235
249
// This is safe since we checked in the event handler that the device is activated.
236
250
let mem = self . device_state . mem ( ) . unwrap ( ) ;
@@ -382,6 +396,50 @@ impl Balloon {
382
396
Ok ( ( ) )
383
397
}
384
398
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
+
385
443
pub ( crate ) fn signal_used_queue ( & self ) -> Result < ( ) , BalloonError > {
386
444
self . irq_trigger . trigger_irq ( IrqType :: Vring ) . map_err ( |err| {
387
445
METRICS . balloon . event_fails . inc ( ) ;
@@ -393,6 +451,7 @@ impl Balloon {
393
451
pub fn process_virtio_queues ( & mut self ) {
394
452
let _ = self . process_inflate ( ) ;
395
453
let _ = self . process_deflate_queue ( ) ;
454
+ let _ = self . process_free_page_reporting_queue ( ) ;
396
455
}
397
456
398
457
pub fn id ( & self ) -> & str {
0 commit comments