1use std::collections::BTreeMap;
6use std::collections::VecDeque;
7use std::io::Write;
8use std::sync::Arc;
9
10use anyhow::anyhow;
11use anyhow::Context;
12use balloon_control::BalloonStats;
13use balloon_control::BalloonTubeCommand;
14use balloon_control::BalloonTubeResult;
15use balloon_control::BalloonWS;
16use balloon_control::WSBucket;
17use balloon_control::VIRTIO_BALLOON_WS_MAX_NUM_BINS;
18use balloon_control::VIRTIO_BALLOON_WS_MIN_NUM_BINS;
19use base::debug;
20use base::error;
21use base::warn;
22use base::AsRawDescriptor;
23use base::Event;
24use base::RawDescriptor;
25#[cfg(feature = "registered_events")]
26use base::SendTube;
27use base::Tube;
28use base::WorkerThread;
29use cros_async::block_on;
30use cros_async::sync::RwLock as AsyncRwLock;
31use cros_async::AsyncTube;
32use cros_async::EventAsync;
33use cros_async::Executor;
34#[cfg(feature = "registered_events")]
35use cros_async::SendTubeAsync;
36use data_model::Le16;
37use data_model::Le32;
38use data_model::Le64;
39use futures::channel::mpsc;
40use futures::channel::oneshot;
41use futures::pin_mut;
42use futures::select;
43use futures::select_biased;
44use futures::FutureExt;
45use futures::StreamExt;
46use remain::sorted;
47use serde::Deserialize;
48use serde::Serialize;
49use snapshot::AnySnapshot;
50use thiserror::Error as ThisError;
51use vm_control::api::VmMemoryClient;
52#[cfg(feature = "registered_events")]
53use vm_control::RegisteredEventWithData;
54use vm_memory::GuestAddress;
55use vm_memory::GuestMemory;
56use zerocopy::FromBytes;
57use zerocopy::Immutable;
58use zerocopy::IntoBytes;
59use zerocopy::KnownLayout;
60
61use super::async_utils;
62use super::copy_config;
63use super::create_stop_oneshot;
64use super::DescriptorChain;
65use super::DeviceType;
66use super::Interrupt;
67use super::Queue;
68use super::Reader;
69use super::StoppedWorker;
70use super::VirtioDevice;
71use crate::UnpinRequest;
72use crate::UnpinResponse;
73
74#[sorted]
75#[derive(ThisError, Debug)]
76pub enum BalloonError {
77 #[error("failed async await: {0}")]
79 AsyncAwait(cros_async::AsyncError),
80 #[error("failed async await: {0}")]
82 AsyncAwaitAnyhow(anyhow::Error),
83 #[error("failed to create event: {0}")]
85 CreatingEvent(base::Error),
86 #[error("failed to create async message receiver: {0}")]
88 CreatingMessageReceiver(base::TubeError),
89 #[error("failed to receive command message: {0}")]
91 ReceivingCommand(base::TubeError),
92 #[error("failed to send command response: {0}")]
94 SendResponse(base::TubeError),
95 #[error("failed to write to virtqueue: {0}")]
97 WriteQueue(std::io::Error),
98 #[error("failed to write config event: {0}")]
100 WritingConfigEvent(base::Error),
101}
102pub type Result<T> = std::result::Result<T, BalloonError>;
103
104const QUEUE_SIZE: u16 = 128;
105
106const INFLATEQ: usize = 0;
108const DEFLATEQ: usize = 1;
109
110const VIRTIO_BALLOON_PFN_SHIFT: u32 = 12;
111const VIRTIO_BALLOON_PF_SIZE: u64 = 1 << VIRTIO_BALLOON_PFN_SHIFT;
112
113const VIRTIO_BALLOON_F_MUST_TELL_HOST: u32 = 0; const VIRTIO_BALLOON_F_STATS_VQ: u32 = 1; const VIRTIO_BALLOON_F_DEFLATE_ON_OOM: u32 = 2; const VIRTIO_BALLOON_F_PAGE_REPORTING: u32 = 5; const VIRTIO_BALLOON_F_WS_REPORTING: u32 = 8; #[derive(Copy, Clone)]
123#[repr(u32)]
124pub enum BalloonFeatures {
126 PageReporting = VIRTIO_BALLOON_F_PAGE_REPORTING,
128 WSReporting = VIRTIO_BALLOON_F_WS_REPORTING,
130}
131
132#[derive(Copy, Clone, Debug, Default, FromBytes, Immutable, IntoBytes, KnownLayout)]
134#[repr(C)]
135struct virtio_balloon_config {
136 num_pages: Le32,
137 actual: Le32,
138 free_page_hint_cmd_id: Le32,
139 poison_val: Le32,
140 ws_num_bins: u8,
142 _reserved: [u8; 3],
143}
144
145#[derive(Clone, Default, Serialize, Deserialize)]
147struct BalloonState {
148 num_pages: u32,
149 actual_pages: u32,
150 expecting_ws: bool,
151 failable_update: bool,
155 pending_adjusted_responses: VecDeque<u32>,
156}
157
158const VIRTIO_BALLOON_S_SWAP_IN: u16 = 0;
160const VIRTIO_BALLOON_S_SWAP_OUT: u16 = 1;
161const VIRTIO_BALLOON_S_MAJFLT: u16 = 2;
162const VIRTIO_BALLOON_S_MINFLT: u16 = 3;
163const VIRTIO_BALLOON_S_MEMFREE: u16 = 4;
164const VIRTIO_BALLOON_S_MEMTOT: u16 = 5;
165const VIRTIO_BALLOON_S_AVAIL: u16 = 6;
166const VIRTIO_BALLOON_S_CACHES: u16 = 7;
167const VIRTIO_BALLOON_S_HTLB_PGALLOC: u16 = 8;
168const VIRTIO_BALLOON_S_HTLB_PGFAIL: u16 = 9;
169const VIRTIO_BALLOON_S_NONSTANDARD_SHMEM: u16 = 65534;
170const VIRTIO_BALLOON_S_NONSTANDARD_UNEVICTABLE: u16 = 65535;
171
172#[derive(Copy, Clone, FromBytes, Immutable, IntoBytes, KnownLayout)]
174#[repr(C, packed)]
175struct BalloonStat {
176 tag: Le16,
177 val: Le64,
178}
179
180impl BalloonStat {
181 fn update_stats(&self, stats: &mut BalloonStats) {
182 let val = Some(self.val.to_native());
183 match self.tag.to_native() {
184 VIRTIO_BALLOON_S_SWAP_IN => stats.swap_in = val,
185 VIRTIO_BALLOON_S_SWAP_OUT => stats.swap_out = val,
186 VIRTIO_BALLOON_S_MAJFLT => stats.major_faults = val,
187 VIRTIO_BALLOON_S_MINFLT => stats.minor_faults = val,
188 VIRTIO_BALLOON_S_MEMFREE => stats.free_memory = val,
189 VIRTIO_BALLOON_S_MEMTOT => stats.total_memory = val,
190 VIRTIO_BALLOON_S_AVAIL => stats.available_memory = val,
191 VIRTIO_BALLOON_S_CACHES => stats.disk_caches = val,
192 VIRTIO_BALLOON_S_HTLB_PGALLOC => stats.hugetlb_allocations = val,
193 VIRTIO_BALLOON_S_HTLB_PGFAIL => stats.hugetlb_failures = val,
194 VIRTIO_BALLOON_S_NONSTANDARD_SHMEM => stats.shared_memory = val,
195 VIRTIO_BALLOON_S_NONSTANDARD_UNEVICTABLE => stats.unevictable_memory = val,
196 _ => (),
197 }
198 }
199}
200
201#[repr(C)]
203#[derive(Copy, Clone, Debug, Default, FromBytes, Immutable, IntoBytes, KnownLayout)]
204struct virtio_balloon_ws {
205 tag: Le16,
206 node_id: Le16,
207 _reserved: [u8; 4],
210 idle_age_ms: Le64,
211 memory_size_bytes: [Le64; 2],
213}
214
215impl virtio_balloon_ws {
216 fn update_ws(&self, ws: &mut BalloonWS) {
217 let bucket = WSBucket {
218 age: self.idle_age_ms.to_native(),
219 bytes: [
220 self.memory_size_bytes[0].to_native(),
221 self.memory_size_bytes[1].to_native(),
222 ],
223 };
224 ws.ws.push(bucket);
225 }
226}
227
228const _VIRTIO_BALLOON_WS_OP_INVALID: u16 = 0;
229const VIRTIO_BALLOON_WS_OP_REQUEST: u16 = 1;
230const VIRTIO_BALLOON_WS_OP_CONFIG: u16 = 2;
231const _VIRTIO_BALLOON_WS_OP_DISCARD: u16 = 3;
232
233#[repr(C, packed)]
235#[derive(Copy, Clone, Debug, Default, FromBytes, Immutable, IntoBytes, KnownLayout)]
236struct virtio_balloon_op {
237 type_: Le16,
238}
239
240fn invoke_desc_handler<F>(ranges: Vec<(u64, u64)>, desc_handler: &mut F)
241where
242 F: FnMut(Vec<(GuestAddress, u64)>),
243{
244 desc_handler(
245 ranges
246 .into_iter()
247 .map(|range| (GuestAddress(range.0), range.1))
248 .collect(),
249 );
250}
251
252fn release_ranges<F>(
256 release_memory_tube: Option<&Tube>,
257 inflate_ranges: Vec<(u64, u64)>,
258 desc_handler: &mut F,
259) -> anyhow::Result<()>
260where
261 F: FnMut(Vec<(GuestAddress, u64)>),
262{
263 if let Some(tube) = release_memory_tube {
264 let unpin_ranges = inflate_ranges
265 .iter()
266 .map(|v| {
267 (
268 v.0 >> VIRTIO_BALLOON_PFN_SHIFT,
269 v.1 / VIRTIO_BALLOON_PF_SIZE,
270 )
271 })
272 .collect();
273 let req = UnpinRequest {
274 ranges: unpin_ranges,
275 };
276 if let Err(e) = tube.send(&req) {
277 error!("failed to send unpin request: {}", e);
278 } else {
279 match tube.recv() {
280 Ok(resp) => match resp {
281 UnpinResponse::Success => invoke_desc_handler(inflate_ranges, desc_handler),
282 UnpinResponse::Failed => error!("failed to handle unpin request"),
283 },
284 Err(e) => error!("failed to handle get unpin response: {}", e),
285 }
286 }
287 } else {
288 invoke_desc_handler(inflate_ranges, desc_handler);
289 }
290
291 Ok(())
292}
293
294fn handle_address_chain<F>(
296 release_memory_tube: Option<&Tube>,
297 avail_desc: &mut DescriptorChain,
298 desc_handler: &mut F,
299) -> anyhow::Result<()>
300where
301 F: FnMut(Vec<(GuestAddress, u64)>),
302{
303 let mut range_start = 0;
308 let mut range_size = 0;
309 let mut inflate_ranges: Vec<(u64, u64)> = Vec::new();
310 for res in avail_desc.reader.iter::<Le32>() {
311 let pfn = match res {
312 Ok(pfn) => pfn,
313 Err(e) => {
314 error!("error while reading unused pages: {}", e);
315 break;
316 }
317 };
318 let guest_address = (u64::from(pfn.to_native())) << VIRTIO_BALLOON_PFN_SHIFT;
319 if range_start + range_size == guest_address {
320 range_size += VIRTIO_BALLOON_PF_SIZE;
321 } else if range_start == guest_address + VIRTIO_BALLOON_PF_SIZE {
322 range_start = guest_address;
323 range_size += VIRTIO_BALLOON_PF_SIZE;
324 } else {
325 if range_size != 0 {
328 inflate_ranges.push((range_start, range_size));
329 }
330 range_start = guest_address;
331 range_size = VIRTIO_BALLOON_PF_SIZE;
332 }
333 }
334 if range_size != 0 {
335 inflate_ranges.push((range_start, range_size));
336 }
337
338 release_ranges(release_memory_tube, inflate_ranges, desc_handler)
339}
340
341async fn handle_queue<F>(
343 mut queue: Queue,
344 mut queue_event: EventAsync,
345 release_memory_tube: Option<&Tube>,
346 mut desc_handler: F,
347 mut stop_rx: oneshot::Receiver<()>,
348) -> Queue
349where
350 F: FnMut(Vec<(GuestAddress, u64)>),
351{
352 loop {
353 let mut avail_desc = match queue
354 .next_async_interruptable(&mut queue_event, &mut stop_rx)
355 .await
356 {
357 Ok(Some(res)) => res,
358 Ok(None) => return queue,
359 Err(e) => {
360 error!("Failed to read descriptor {}", e);
361 return queue;
362 }
363 };
364 if let Err(e) =
365 handle_address_chain(release_memory_tube, &mut avail_desc, &mut desc_handler)
366 {
367 error!("balloon: failed to process inflate addresses: {}", e);
368 }
369 queue.add_used(avail_desc);
370 queue.trigger_interrupt();
371 }
372}
373
374fn handle_reported_buffer<F>(
376 release_memory_tube: Option<&Tube>,
377 avail_desc: &DescriptorChain,
378 desc_handler: &mut F,
379) -> anyhow::Result<()>
380where
381 F: FnMut(Vec<(GuestAddress, u64)>),
382{
383 let reported_ranges: Vec<(u64, u64)> = avail_desc
384 .reader
385 .get_remaining_regions()
386 .chain(avail_desc.writer.get_remaining_regions())
387 .map(|r| (r.offset, r.len as u64))
388 .collect();
389
390 release_ranges(release_memory_tube, reported_ranges, desc_handler)
391}
392
393async fn handle_reporting_queue<F>(
395 mut queue: Queue,
396 mut queue_event: EventAsync,
397 release_memory_tube: Option<&Tube>,
398 mut desc_handler: F,
399 mut stop_rx: oneshot::Receiver<()>,
400) -> Queue
401where
402 F: FnMut(Vec<(GuestAddress, u64)>),
403{
404 loop {
405 let avail_desc = match queue
406 .next_async_interruptable(&mut queue_event, &mut stop_rx)
407 .await
408 {
409 Ok(Some(res)) => res,
410 Ok(None) => return queue,
411 Err(e) => {
412 error!("Failed to read descriptor {}", e);
413 return queue;
414 }
415 };
416 if let Err(e) = handle_reported_buffer(release_memory_tube, &avail_desc, &mut desc_handler)
417 {
418 error!("balloon: failed to process reported buffer: {}", e);
419 }
420 queue.add_used(avail_desc);
421 queue.trigger_interrupt();
422 }
423}
424
425fn parse_balloon_stats(reader: &mut Reader) -> BalloonStats {
426 let mut stats: BalloonStats = Default::default();
427 for res in reader.iter::<BalloonStat>() {
428 match res {
429 Ok(stat) => stat.update_stats(&mut stats),
430 Err(e) => {
431 error!("error while reading stats: {}", e);
432 break;
433 }
434 };
435 }
436 stats
437}
438
439async fn handle_stats_queue(
444 mut queue: Queue,
445 mut queue_event: EventAsync,
446 mut stats_rx: mpsc::Receiver<()>,
447 command_tube: &AsyncTube,
448 #[cfg(feature = "registered_events")] registered_evt_q: Option<&SendTubeAsync>,
449 state: Arc<AsyncRwLock<BalloonState>>,
450 mut stop_rx: oneshot::Receiver<()>,
451) -> Queue {
452 let mut avail_desc = match queue
453 .next_async_interruptable(&mut queue_event, &mut stop_rx)
454 .await
455 {
456 Ok(Some(res)) => res,
459 Ok(None) => return queue,
460 Err(e) => {
461 error!("Failed to read descriptor {}", e);
462 return queue;
463 }
464 };
465
466 loop {
467 select_biased! {
468 msg = stats_rx.next() => {
469 match msg {
471 Some(()) => (),
472 None => {
473 error!("stats signal channel was closed");
474 return queue;
475 }
476 }
477 }
478 _ = stop_rx => return queue,
479 };
480
481 queue.add_used(avail_desc);
483 queue.trigger_interrupt();
484
485 avail_desc = match queue.next_async(&mut queue_event).await {
486 Err(e) => {
487 error!("Failed to read descriptor {}", e);
488 return queue;
489 }
490 Ok(d) => d,
491 };
492 let stats = parse_balloon_stats(&mut avail_desc.reader);
493
494 let actual_pages = state.lock().await.actual_pages as u64;
495 let result = BalloonTubeResult::Stats {
496 balloon_actual: actual_pages << VIRTIO_BALLOON_PFN_SHIFT,
497 stats,
498 };
499 let send_result = command_tube.send(result).await;
500 if let Err(e) = send_result {
501 error!("failed to send stats result: {}", e);
502 }
503
504 #[cfg(feature = "registered_events")]
505 if let Some(registered_evt_q) = registered_evt_q {
506 if let Err(e) = registered_evt_q
507 .send(&RegisteredEventWithData::VirtioBalloonResize)
508 .await
509 {
510 error!("failed to send VirtioBalloonResize event: {}", e);
511 }
512 }
513 }
514}
515
516async fn send_adjusted_response(
517 tube: &AsyncTube,
518 num_pages: u32,
519) -> std::result::Result<(), base::TubeError> {
520 let num_bytes = (num_pages as u64) << VIRTIO_BALLOON_PFN_SHIFT;
521 let result = BalloonTubeResult::Adjusted { num_bytes };
522 tube.send(result).await
523}
524
525enum WSOp {
526 WSReport,
527 WSConfig {
528 bins: Vec<u32>,
529 refresh_threshold: u32,
530 report_threshold: u32,
531 },
532}
533
534async fn handle_ws_op_queue(
535 mut queue: Queue,
536 mut queue_event: EventAsync,
537 mut ws_op_rx: mpsc::Receiver<WSOp>,
538 state: Arc<AsyncRwLock<BalloonState>>,
539 mut stop_rx: oneshot::Receiver<()>,
540) -> Result<Queue> {
541 loop {
542 let op = select_biased! {
543 next_op = ws_op_rx.next().fuse() => {
544 match next_op {
545 Some(op) => op,
546 None => {
547 error!("ws op tube was closed");
548 break;
549 }
550 }
551 }
552 _ = stop_rx => {
553 break;
554 }
555 };
556 let mut avail_desc = queue
557 .next_async(&mut queue_event)
558 .await
559 .map_err(BalloonError::AsyncAwait)?;
560 let writer = &mut avail_desc.writer;
561
562 match op {
563 WSOp::WSReport => {
564 {
565 let mut state = state.lock().await;
566 state.expecting_ws = true;
567 }
568
569 let ws_r = virtio_balloon_op {
570 type_: VIRTIO_BALLOON_WS_OP_REQUEST.into(),
571 };
572
573 writer.write_obj(ws_r).map_err(BalloonError::WriteQueue)?;
574 }
575 WSOp::WSConfig {
576 bins,
577 refresh_threshold,
578 report_threshold,
579 } => {
580 let cmd = virtio_balloon_op {
581 type_: VIRTIO_BALLOON_WS_OP_CONFIG.into(),
582 };
583
584 writer.write_obj(cmd).map_err(BalloonError::WriteQueue)?;
585 writer
586 .write_all(bins.as_bytes())
587 .map_err(BalloonError::WriteQueue)?;
588 writer
589 .write_obj(refresh_threshold)
590 .map_err(BalloonError::WriteQueue)?;
591 writer
592 .write_obj(report_threshold)
593 .map_err(BalloonError::WriteQueue)?;
594 }
595 }
596
597 queue.add_used(avail_desc);
598 queue.trigger_interrupt();
599 }
600
601 Ok(queue)
602}
603
604fn parse_balloon_ws(reader: &mut Reader) -> BalloonWS {
605 let mut ws = BalloonWS::new();
606 for res in reader.iter::<virtio_balloon_ws>() {
607 match res {
608 Ok(ws_msg) => {
609 ws_msg.update_ws(&mut ws);
610 }
611 Err(e) => {
612 error!("error while reading ws: {}", e);
613 break;
614 }
615 }
616 }
617 if ws.ws.len() < VIRTIO_BALLOON_WS_MIN_NUM_BINS || ws.ws.len() > VIRTIO_BALLOON_WS_MAX_NUM_BINS
618 {
619 error!("unexpected number of WS buckets: {}", ws.ws.len());
620 }
621 ws
622}
623
624async fn handle_ws_data_queue(
630 mut queue: Queue,
631 mut queue_event: EventAsync,
632 command_tube: &AsyncTube,
633 #[cfg(feature = "registered_events")] registered_evt_q: Option<&SendTubeAsync>,
634 state: Arc<AsyncRwLock<BalloonState>>,
635 mut stop_rx: oneshot::Receiver<()>,
636) -> Result<Queue> {
637 loop {
638 let mut avail_desc = match queue
639 .next_async_interruptable(&mut queue_event, &mut stop_rx)
640 .await
641 .map_err(BalloonError::AsyncAwait)?
642 {
643 Some(res) => res,
644 None => return Ok(queue),
645 };
646
647 let ws = parse_balloon_ws(&mut avail_desc.reader);
648
649 let mut state = state.lock().await;
650
651 let balloon_actual = (state.actual_pages as u64) << VIRTIO_BALLOON_PFN_SHIFT;
653
654 if state.expecting_ws {
655 let result = BalloonTubeResult::WorkingSet { ws, balloon_actual };
656 let send_result = command_tube.send(result).await;
657 if let Err(e) = send_result {
658 error!("failed to send ws result: {}", e);
659 }
660
661 state.expecting_ws = false;
662 } else {
663 #[cfg(feature = "registered_events")]
664 if let Some(registered_evt_q) = registered_evt_q {
665 if let Err(e) = registered_evt_q
666 .send(RegisteredEventWithData::from_ws(&ws, balloon_actual))
667 .await
668 {
669 error!("failed to send VirtioBalloonWSReport event: {}", e);
670 }
671 }
672 }
673
674 queue.add_used(avail_desc);
675 queue.trigger_interrupt();
676 }
677}
678
679async fn handle_command_tube(
682 command_tube: &AsyncTube,
683 interrupt: Interrupt,
684 state: Arc<AsyncRwLock<BalloonState>>,
685 mut stats_tx: mpsc::Sender<()>,
686 mut ws_op_tx: mpsc::Sender<WSOp>,
687 mut stop_rx: oneshot::Receiver<()>,
688) -> Result<()> {
689 loop {
690 let cmd_res = select_biased! {
691 res = command_tube.next().fuse() => res,
692 _ = stop_rx => return Ok(())
693 };
694 match cmd_res {
695 Ok(command) => match command {
696 BalloonTubeCommand::Adjust {
697 num_bytes,
698 allow_failure,
699 } => {
700 let num_pages = (num_bytes >> VIRTIO_BALLOON_PFN_SHIFT) as u32;
701 let mut state = state.lock().await;
702
703 state.num_pages = num_pages;
704 interrupt.signal_config_changed();
705
706 if allow_failure {
707 if num_pages == state.actual_pages {
708 send_adjusted_response(command_tube, num_pages)
709 .await
710 .map_err(BalloonError::SendResponse)?;
711 } else {
712 state.failable_update = true;
713 }
714 }
715 }
716 BalloonTubeCommand::WorkingSetConfig {
717 bins,
718 refresh_threshold,
719 report_threshold,
720 } => {
721 if let Err(e) = ws_op_tx.try_send(WSOp::WSConfig {
722 bins,
723 refresh_threshold,
724 report_threshold,
725 }) {
726 error!("failed to send config to ws handler: {}", e);
727 }
728 }
729 BalloonTubeCommand::Stats => {
730 if let Err(e) = stats_tx.try_send(()) {
731 error!("failed to signal the stat handler: {}", e);
732 }
733 }
734 BalloonTubeCommand::WorkingSet => {
735 if let Err(e) = ws_op_tx.try_send(WSOp::WSReport) {
736 error!("failed to send report request to ws handler: {}", e);
737 }
738 }
739 },
740 #[cfg(windows)]
741 Err(base::TubeError::Recv(e)) if e.kind() == std::io::ErrorKind::TimedOut => {
742 let _ = stop_rx.await;
749 return Ok(());
750 }
751 Err(e) => {
752 return Err(BalloonError::ReceivingCommand(e));
753 }
754 }
755 }
756}
757
758async fn handle_pending_adjusted_responses(
759 pending_adjusted_response_event: EventAsync,
760 command_tube: &AsyncTube,
761 state: Arc<AsyncRwLock<BalloonState>>,
762) -> Result<()> {
763 loop {
764 pending_adjusted_response_event
765 .next_val()
766 .await
767 .map_err(BalloonError::AsyncAwait)?;
768 while let Some(num_pages) = state.lock().await.pending_adjusted_responses.pop_front() {
769 send_adjusted_response(command_tube, num_pages)
770 .await
771 .map_err(BalloonError::SendResponse)?;
772 }
773 }
774}
775
776struct BalloonQueues {
778 inflate: Queue,
779 deflate: Queue,
780 stats: Option<Queue>,
781 reporting: Option<Queue>,
782 ws_data: Option<Queue>,
783 ws_op: Option<Queue>,
784}
785
786impl BalloonQueues {
787 fn new(inflate: Queue, deflate: Queue) -> Self {
788 BalloonQueues {
789 inflate,
790 deflate,
791 stats: None,
792 reporting: None,
793 ws_data: None,
794 ws_op: None,
795 }
796 }
797}
798
799struct PausedQueues {
801 inflate: Queue,
802 deflate: Queue,
803 stats: Option<Queue>,
804 reporting: Option<Queue>,
805 ws_data: Option<Queue>,
806 ws_op: Option<Queue>,
807}
808
809impl PausedQueues {
810 fn new(inflate: Queue, deflate: Queue) -> Self {
811 PausedQueues {
812 inflate,
813 deflate,
814 stats: None,
815 reporting: None,
816 ws_data: None,
817 ws_op: None,
818 }
819 }
820}
821
822fn apply_if_some<F, R>(queue_opt: Option<Queue>, mut func: F)
823where
824 F: FnMut(Queue) -> R,
825{
826 if let Some(queue) = queue_opt {
827 func(queue);
828 }
829}
830
831impl From<Box<PausedQueues>> for BTreeMap<usize, Queue> {
832 fn from(queues: Box<PausedQueues>) -> BTreeMap<usize, Queue> {
833 let mut ret = Vec::new();
834 ret.push(queues.inflate);
835 ret.push(queues.deflate);
836 apply_if_some(queues.stats, |stats| ret.push(stats));
837 apply_if_some(queues.reporting, |reporting| ret.push(reporting));
838 apply_if_some(queues.ws_data, |ws_data| ret.push(ws_data));
839 apply_if_some(queues.ws_op, |ws_op| ret.push(ws_op));
840 ret.into_iter().enumerate().collect()
843 }
844}
845
846fn free_memory(
847 vm_memory_client: &VmMemoryClient,
848 mem: &GuestMemory,
849 ranges: Vec<(GuestAddress, u64)>,
850) {
851 #[cfg(any(target_os = "android", target_os = "linux"))]
860 if mem.locked() && !mem.use_punchhole_locked() {
861 for (guest_address, len) in ranges {
862 if let Err(e) = mem.remove_range(guest_address, len) {
863 warn!("Marking pages unused failed: {}, addr={}", e, guest_address);
864 }
865 }
866 return;
867 }
868 if let Err(e) = vm_memory_client.dynamically_free_memory_ranges(ranges) {
869 warn!("Failed to dynamically free memory ranges: {e:#}");
870 }
871}
872
873fn reclaim_memory(vm_memory_client: &VmMemoryClient, ranges: Vec<(GuestAddress, u64)>) {
874 if let Err(e) = vm_memory_client.dynamically_reclaim_memory_ranges(ranges) {
875 warn!("Failed to dynamically reclaim memory range: {e:#}");
876 }
877}
878
879struct WorkerReturn {
882 release_memory_tube: Option<Tube>,
883 command_tube: Tube,
884 #[cfg(feature = "registered_events")]
885 registered_evt_q: Option<SendTube>,
886 paused_queues: Option<PausedQueues>,
887 vm_memory_client: VmMemoryClient,
888}
889
890fn run_worker(
893 inflate_queue: Queue,
894 deflate_queue: Queue,
895 stats_queue: Option<Queue>,
896 reporting_queue: Option<Queue>,
897 ws_data_queue: Option<Queue>,
898 ws_op_queue: Option<Queue>,
899 command_tube: Tube,
900 vm_memory_client: VmMemoryClient,
901 mem: GuestMemory,
902 release_memory_tube: Option<Tube>,
903 interrupt: Interrupt,
904 kill_evt: Event,
905 target_reached_evt: Event,
906 pending_adjusted_response_event: Event,
907 state: Arc<AsyncRwLock<BalloonState>>,
908 #[cfg(feature = "registered_events")] registered_evt_q: Option<SendTube>,
909) -> WorkerReturn {
910 let ex = Executor::new().unwrap();
911 if let Err(e) = command_tube.send(&BalloonTubeResult::Ready) {
912 error!("failed to send balloon ready result: {}", e);
913 }
914 let command_tube = AsyncTube::new(&ex, command_tube).unwrap();
915 #[cfg(feature = "registered_events")]
916 let registered_evt_q_async = registered_evt_q
917 .as_ref()
918 .map(|q| SendTubeAsync::new(q.try_clone().unwrap(), &ex).unwrap());
919
920 let mut stop_queue_oneshots = Vec::new();
921
922 let paused_queues = {
924 let stop_rx = create_stop_oneshot(&mut stop_queue_oneshots);
926 let inflate_queue_evt = inflate_queue
927 .event()
928 .try_clone()
929 .expect("failed to clone queue event");
930 let inflate = handle_queue(
931 inflate_queue,
932 EventAsync::new(inflate_queue_evt, &ex).expect("failed to create async event"),
933 release_memory_tube.as_ref(),
934 |ranges| free_memory(&vm_memory_client, &mem, ranges),
935 stop_rx,
936 );
937 let inflate = inflate.fuse();
938 pin_mut!(inflate);
939
940 let stop_rx = create_stop_oneshot(&mut stop_queue_oneshots);
942 let deflate_queue_evt = deflate_queue
943 .event()
944 .try_clone()
945 .expect("failed to clone queue event");
946 let deflate = handle_queue(
947 deflate_queue,
948 EventAsync::new(deflate_queue_evt, &ex).expect("failed to create async event"),
949 None,
950 |ranges| reclaim_memory(&vm_memory_client, ranges),
951 stop_rx,
952 );
953 let deflate = deflate.fuse();
954 pin_mut!(deflate);
955
956 let (stats_tx, stats_rx) = mpsc::channel::<()>(1);
958 let has_stats_queue = stats_queue.is_some();
959 let stats = if let Some(stats_queue) = stats_queue {
960 let stop_rx = create_stop_oneshot(&mut stop_queue_oneshots);
961 let stats_queue_evt = stats_queue
962 .event()
963 .try_clone()
964 .expect("failed to clone queue event");
965 handle_stats_queue(
966 stats_queue,
967 EventAsync::new(stats_queue_evt, &ex).expect("failed to create async event"),
968 stats_rx,
969 &command_tube,
970 #[cfg(feature = "registered_events")]
971 registered_evt_q_async.as_ref(),
972 state.clone(),
973 stop_rx,
974 )
975 .left_future()
976 } else {
977 std::future::pending().right_future()
978 };
979 let stats = stats.fuse();
980 pin_mut!(stats);
981
982 let has_reporting_queue = reporting_queue.is_some();
984 let reporting = if let Some(reporting_queue) = reporting_queue {
985 let stop_rx = create_stop_oneshot(&mut stop_queue_oneshots);
986 let reporting_queue_evt = reporting_queue
987 .event()
988 .try_clone()
989 .expect("failed to clone queue event");
990 handle_reporting_queue(
991 reporting_queue,
992 EventAsync::new(reporting_queue_evt, &ex).expect("failed to create async event"),
993 release_memory_tube.as_ref(),
994 |ranges| free_memory(&vm_memory_client, &mem, ranges),
995 stop_rx,
996 )
997 .left_future()
998 } else {
999 std::future::pending().right_future()
1000 };
1001 let reporting = reporting.fuse();
1002 pin_mut!(reporting);
1003
1004 let has_ws_data_queue = ws_data_queue.is_some();
1007 let ws_data = if let Some(ws_data_queue) = ws_data_queue {
1008 let stop_rx = create_stop_oneshot(&mut stop_queue_oneshots);
1009 let ws_data_queue_evt = ws_data_queue
1010 .event()
1011 .try_clone()
1012 .expect("failed to clone queue event");
1013 handle_ws_data_queue(
1014 ws_data_queue,
1015 EventAsync::new(ws_data_queue_evt, &ex).expect("failed to create async event"),
1016 &command_tube,
1017 #[cfg(feature = "registered_events")]
1018 registered_evt_q_async.as_ref(),
1019 state.clone(),
1020 stop_rx,
1021 )
1022 .left_future()
1023 } else {
1024 std::future::pending().right_future()
1025 };
1026 let ws_data = ws_data.fuse();
1027 pin_mut!(ws_data);
1028
1029 let (ws_op_tx, ws_op_rx) = mpsc::channel::<WSOp>(1);
1030 let has_ws_op_queue = ws_op_queue.is_some();
1031 let ws_op = if let Some(ws_op_queue) = ws_op_queue {
1032 let stop_rx = create_stop_oneshot(&mut stop_queue_oneshots);
1033 let ws_op_queue_evt = ws_op_queue
1034 .event()
1035 .try_clone()
1036 .expect("failed to clone queue event");
1037 handle_ws_op_queue(
1038 ws_op_queue,
1039 EventAsync::new(ws_op_queue_evt, &ex).expect("failed to create async event"),
1040 ws_op_rx,
1041 state.clone(),
1042 stop_rx,
1043 )
1044 .left_future()
1045 } else {
1046 std::future::pending().right_future()
1047 };
1048 let ws_op = ws_op.fuse();
1049 pin_mut!(ws_op);
1050
1051 let stop_rx = create_stop_oneshot(&mut stop_queue_oneshots);
1053 let command = handle_command_tube(
1054 &command_tube,
1055 interrupt.clone(),
1056 state.clone(),
1057 stats_tx,
1058 ws_op_tx,
1059 stop_rx,
1060 );
1061 pin_mut!(command);
1062
1063 let target_reached = handle_target_reached(&ex, target_reached_evt, &vm_memory_client);
1065 pin_mut!(target_reached);
1066
1067 let kill = async_utils::await_and_exit(&ex, kill_evt);
1069 pin_mut!(kill);
1070
1071 let pending_adjusted = handle_pending_adjusted_responses(
1072 EventAsync::new(pending_adjusted_response_event, &ex)
1073 .expect("failed to create async event"),
1074 &command_tube,
1075 state,
1076 );
1077 pin_mut!(pending_adjusted);
1078
1079 let res = ex.run_until(async {
1080 select! {
1081 _ = kill.fuse() => (),
1082 _ = inflate => return Err(anyhow!("inflate stopped unexpectedly")),
1083 _ = deflate => return Err(anyhow!("deflate stopped unexpectedly")),
1084 _ = stats => return Err(anyhow!("stats stopped unexpectedly")),
1085 _ = reporting => return Err(anyhow!("reporting stopped unexpectedly")),
1086 _ = command.fuse() => return Err(anyhow!("command stopped unexpectedly")),
1087 _ = ws_op => return Err(anyhow!("ws_op stopped unexpectedly")),
1088 _ = pending_adjusted.fuse() => return Err(anyhow!("pending_adjusted stopped unexpectedly")),
1089 _ = ws_data => return Err(anyhow!("ws_data stopped unexpectedly")),
1090 _ = target_reached.fuse() => return Err(anyhow!("target_reached stopped unexpectedly")),
1091 }
1092
1093 for stop_tx in stop_queue_oneshots {
1096 if stop_tx.send(()).is_err() {
1097 return Err(anyhow!("failed to request stop for queue future"));
1098 }
1099 }
1100
1101 let mut paused_queues = PausedQueues::new(
1104 inflate.await,
1105 deflate.await,
1106 );
1107 if has_reporting_queue {
1108 paused_queues.reporting = Some(reporting.await);
1109 }
1110 if has_stats_queue {
1111 paused_queues.stats = Some(stats.await);
1112 }
1113 if has_ws_data_queue {
1114 paused_queues.ws_data = Some(ws_data.await.context("failed to stop ws_data queue")?);
1115 }
1116 if has_ws_op_queue {
1117 paused_queues.ws_op = Some(ws_op.await.context("failed to stop ws_op queue")?);
1118 }
1119 Ok(paused_queues)
1120 });
1121
1122 match res {
1123 Err(e) => {
1124 error!("error happened in executor: {}", e);
1125 None
1126 }
1127 Ok(main_future_res) => match main_future_res {
1128 Ok(paused_queues) => Some(paused_queues),
1129 Err(e) => {
1130 error!("error happened in main balloon future: {}", e);
1131 None
1132 }
1133 },
1134 }
1135 };
1136
1137 WorkerReturn {
1138 command_tube: command_tube.into(),
1139 paused_queues,
1140 release_memory_tube,
1141 #[cfg(feature = "registered_events")]
1142 registered_evt_q,
1143 vm_memory_client,
1144 }
1145}
1146
1147async fn handle_target_reached(
1148 ex: &Executor,
1149 target_reached_evt: Event,
1150 vm_memory_client: &VmMemoryClient,
1151) -> anyhow::Result<()> {
1152 let event_async =
1153 EventAsync::new(target_reached_evt, ex).context("failed to create EventAsync")?;
1154 loop {
1155 let _ = event_async.next_val().await;
1157 if let Err(e) = vm_memory_client.balloon_target_reached(0) {
1160 warn!("Failed to send or receive allocation complete request: {e:#}");
1161 }
1162 }
1163 #[allow(unreachable_code)]
1167 Ok(())
1168}
1169
1170pub struct Balloon {
1172 command_tube: Option<Tube>,
1173 vm_memory_client: Option<VmMemoryClient>,
1174 release_memory_tube: Option<Tube>,
1175 pending_adjusted_response_event: Event,
1176 state: Arc<AsyncRwLock<BalloonState>>,
1177 features: u64,
1178 acked_features: u64,
1179 worker_thread: Option<WorkerThread<WorkerReturn>>,
1180 #[cfg(feature = "registered_events")]
1181 registered_evt_q: Option<SendTube>,
1182 ws_num_bins: u8,
1183 target_reached_evt: Option<Event>,
1184 queue_sizes: Vec<u16>,
1185}
1186
1187#[derive(Serialize, Deserialize)]
1189struct BalloonSnapshot {
1190 state: BalloonState,
1191 features: u64,
1192 acked_features: u64,
1193 ws_num_bins: u8,
1194}
1195
1196impl Balloon {
1197 pub fn new(
1203 base_features: u64,
1204 command_tube: Tube,
1205 vm_memory_client: VmMemoryClient,
1206 release_memory_tube: Option<Tube>,
1207 init_balloon_size: u64,
1208 enabled_features: u64,
1209 #[cfg(feature = "registered_events")] registered_evt_q: Option<SendTube>,
1210 ws_num_bins: u8,
1211 ) -> Result<Balloon> {
1212 let features = base_features
1213 | 1 << VIRTIO_BALLOON_F_MUST_TELL_HOST
1214 | 1 << VIRTIO_BALLOON_F_STATS_VQ
1215 | 1 << VIRTIO_BALLOON_F_DEFLATE_ON_OOM
1216 | enabled_features;
1217
1218 let mut queue_sizes = Vec::new();
1219 queue_sizes.push(QUEUE_SIZE); queue_sizes.push(QUEUE_SIZE); if features & (1 << VIRTIO_BALLOON_F_STATS_VQ) != 0 {
1222 queue_sizes.push(QUEUE_SIZE); }
1224 if features & (1 << VIRTIO_BALLOON_F_PAGE_REPORTING) != 0 {
1225 queue_sizes.push(QUEUE_SIZE); }
1227 if features & (1 << VIRTIO_BALLOON_F_WS_REPORTING) != 0 {
1228 queue_sizes.push(QUEUE_SIZE); queue_sizes.push(QUEUE_SIZE); }
1231
1232 Ok(Balloon {
1233 command_tube: Some(command_tube),
1234 vm_memory_client: Some(vm_memory_client),
1235 release_memory_tube,
1236 pending_adjusted_response_event: Event::new().map_err(BalloonError::CreatingEvent)?,
1237 state: Arc::new(AsyncRwLock::new(BalloonState {
1238 num_pages: (init_balloon_size >> VIRTIO_BALLOON_PFN_SHIFT) as u32,
1239 actual_pages: 0,
1240 failable_update: false,
1241 pending_adjusted_responses: VecDeque::new(),
1242 expecting_ws: false,
1243 })),
1244 worker_thread: None,
1245 features,
1246 acked_features: 0,
1247 #[cfg(feature = "registered_events")]
1248 registered_evt_q,
1249 ws_num_bins,
1250 target_reached_evt: None,
1251 queue_sizes,
1252 })
1253 }
1254
1255 fn get_config(&self) -> virtio_balloon_config {
1256 let state = block_on(self.state.lock());
1257 virtio_balloon_config {
1258 num_pages: state.num_pages.into(),
1259 actual: state.actual_pages.into(),
1260 free_page_hint_cmd_id: 0.into(),
1265 poison_val: 0.into(),
1266 ws_num_bins: self.ws_num_bins,
1267 _reserved: [0, 0, 0],
1268 }
1269 }
1270
1271 fn stop_worker(&mut self) -> StoppedWorker<PausedQueues> {
1272 if let Some(worker_thread) = self.worker_thread.take() {
1273 let worker_ret = worker_thread.stop();
1274 self.release_memory_tube = worker_ret.release_memory_tube;
1275 self.command_tube = Some(worker_ret.command_tube);
1276 #[cfg(feature = "registered_events")]
1277 {
1278 self.registered_evt_q = worker_ret.registered_evt_q;
1279 }
1280 self.vm_memory_client = Some(worker_ret.vm_memory_client);
1281
1282 if let Some(queues) = worker_ret.paused_queues {
1283 StoppedWorker::WithQueues(Box::new(queues))
1284 } else {
1285 StoppedWorker::MissingQueues
1286 }
1287 } else {
1288 StoppedWorker::AlreadyStopped
1289 }
1290 }
1291
1292 fn get_queues_from_map(
1296 &self,
1297 mut queues: BTreeMap<usize, Queue>,
1298 ) -> anyhow::Result<BalloonQueues> {
1299 let inflate_queue = queues.remove(&INFLATEQ).context("missing inflateq")?;
1300 let deflate_queue = queues.remove(&DEFLATEQ).context("missing deflateq")?;
1301 let mut queue_struct = BalloonQueues::new(inflate_queue, deflate_queue);
1302
1303 let mut next_queue_index = 2;
1305 let mut next_queue = || {
1306 let idx = next_queue_index;
1307 next_queue_index += 1;
1308 idx
1309 };
1310
1311 if self.features & (1 << VIRTIO_BALLOON_F_STATS_VQ) != 0 {
1312 let statsq = next_queue();
1313 if self.acked_features & (1 << VIRTIO_BALLOON_F_STATS_VQ) != 0 {
1314 queue_struct.stats = Some(queues.remove(&statsq).context("missing statsq")?);
1315 }
1316 }
1317
1318 if self.features & (1 << VIRTIO_BALLOON_F_PAGE_REPORTING) != 0 {
1319 let reporting_vq = next_queue();
1320 if self.acked_features & (1 << VIRTIO_BALLOON_F_PAGE_REPORTING) != 0 {
1321 queue_struct.reporting = Some(
1322 queues
1323 .remove(&reporting_vq)
1324 .context("missing reporting_vq")?,
1325 );
1326 }
1327 }
1328
1329 if self.features & (1 << VIRTIO_BALLOON_F_WS_REPORTING) != 0 {
1330 let ws_data_vq = next_queue();
1331 let ws_op_vq = next_queue();
1332 if self.acked_features & (1 << VIRTIO_BALLOON_F_WS_REPORTING) != 0 {
1333 queue_struct.ws_data =
1334 Some(queues.remove(&ws_data_vq).context("missing ws_data_vq")?);
1335 queue_struct.ws_op = Some(queues.remove(&ws_op_vq).context("missing ws_op_vq")?);
1336 }
1337 }
1338
1339 if !queues.is_empty() {
1340 return Err(anyhow!("unexpected queues {:?}", queues.into_keys()));
1341 }
1342
1343 Ok(queue_struct)
1344 }
1345
1346 fn start_worker(
1347 &mut self,
1348 mem: GuestMemory,
1349 interrupt: Interrupt,
1350 queues: BalloonQueues,
1351 ) -> anyhow::Result<()> {
1352 let (self_target_reached_evt, target_reached_evt) = Event::new()
1353 .and_then(|e| Ok((e.try_clone()?, e)))
1354 .context("failed to create target_reached Event pair: {}")?;
1355 self.target_reached_evt = Some(self_target_reached_evt);
1356
1357 let state = self.state.clone();
1358
1359 let command_tube = self.command_tube.take().unwrap();
1360
1361 let vm_memory_client = self.vm_memory_client.take().unwrap();
1362 let release_memory_tube = self.release_memory_tube.take();
1363 #[cfg(feature = "registered_events")]
1364 let registered_evt_q = self.registered_evt_q.take();
1365 let pending_adjusted_response_event = self
1366 .pending_adjusted_response_event
1367 .try_clone()
1368 .context("failed to clone Event")?;
1369
1370 self.worker_thread = Some(WorkerThread::start("v_balloon", move |kill_evt| {
1371 run_worker(
1372 queues.inflate,
1373 queues.deflate,
1374 queues.stats,
1375 queues.reporting,
1376 queues.ws_data,
1377 queues.ws_op,
1378 command_tube,
1379 vm_memory_client,
1380 mem,
1381 release_memory_tube,
1382 interrupt,
1383 kill_evt,
1384 target_reached_evt,
1385 pending_adjusted_response_event,
1386 state,
1387 #[cfg(feature = "registered_events")]
1388 registered_evt_q,
1389 )
1390 }));
1391
1392 Ok(())
1393 }
1394}
1395
1396impl VirtioDevice for Balloon {
1397 fn keep_rds(&self) -> Vec<RawDescriptor> {
1398 let mut rds = Vec::new();
1399 if let Some(command_tube) = &self.command_tube {
1400 rds.push(command_tube.as_raw_descriptor());
1401 }
1402 if let Some(vm_memory_client) = &self.vm_memory_client {
1403 rds.push(vm_memory_client.as_raw_descriptor());
1404 }
1405 if let Some(release_memory_tube) = &self.release_memory_tube {
1406 rds.push(release_memory_tube.as_raw_descriptor());
1407 }
1408 #[cfg(feature = "registered_events")]
1409 if let Some(registered_evt_q) = &self.registered_evt_q {
1410 rds.push(registered_evt_q.as_raw_descriptor());
1411 }
1412 rds.push(self.pending_adjusted_response_event.as_raw_descriptor());
1413 rds
1414 }
1415
1416 fn device_type(&self) -> DeviceType {
1417 DeviceType::Balloon
1418 }
1419
1420 fn queue_max_sizes(&self) -> &[u16] {
1421 &self.queue_sizes
1422 }
1423
1424 fn read_config(&self, offset: u64, data: &mut [u8]) {
1425 copy_config(data, 0, self.get_config().as_bytes(), offset);
1426 }
1427
1428 fn write_config(&mut self, offset: u64, data: &[u8]) {
1429 let mut config = self.get_config();
1430 copy_config(config.as_mut_bytes(), offset, data, 0);
1431 let mut state = block_on(self.state.lock());
1432 state.actual_pages = config.actual.to_native();
1433
1434 if config.num_pages == config.actual {
1436 debug!(
1437 "sending target reached event at {}",
1438 u32::from(config.num_pages)
1439 );
1440 self.target_reached_evt.as_ref().map(|e| e.signal());
1441 }
1442 if state.failable_update && state.actual_pages == state.num_pages {
1443 state.failable_update = false;
1444 let num_pages = state.num_pages;
1445 state.pending_adjusted_responses.push_back(num_pages);
1446 let _ = self.pending_adjusted_response_event.signal();
1447 }
1448 }
1449
1450 fn features(&self) -> u64 {
1451 self.features
1452 }
1453
1454 fn ack_features(&mut self, mut value: u64) {
1455 if value & !self.features != 0 {
1456 warn!("virtio_balloon got unknown feature ack {:x}", value);
1457 value &= self.features;
1458 }
1459 self.acked_features |= value;
1460 }
1461
1462 fn activate(
1463 &mut self,
1464 mem: GuestMemory,
1465 interrupt: Interrupt,
1466 queues: BTreeMap<usize, Queue>,
1467 ) -> anyhow::Result<()> {
1468 let queues = self.get_queues_from_map(queues)?;
1469 self.start_worker(mem, interrupt, queues)
1470 }
1471
1472 fn reset(&mut self) -> anyhow::Result<()> {
1473 let _worker = self.stop_worker();
1474 if let Some(tube) = &self.command_tube {
1475 if let Err(e) = tube.send(&BalloonTubeResult::NotReady) {
1476 error!("failed to send balloon not ready result: {}", e);
1477 }
1478 }
1479 Ok(())
1480 }
1481
1482 fn virtio_sleep(&mut self) -> anyhow::Result<Option<BTreeMap<usize, Queue>>> {
1483 match self.stop_worker() {
1484 StoppedWorker::WithQueues(paused_queues) => Ok(Some(paused_queues.into())),
1485 StoppedWorker::MissingQueues => {
1486 anyhow::bail!("balloon queue workers did not stop cleanly.")
1487 }
1488 StoppedWorker::AlreadyStopped => {
1489 Ok(None)
1491 }
1492 }
1493 }
1494
1495 fn virtio_wake(
1496 &mut self,
1497 queues_state: Option<(GuestMemory, Interrupt, BTreeMap<usize, Queue>)>,
1498 ) -> anyhow::Result<()> {
1499 if let Some((mem, interrupt, queues)) = queues_state {
1500 if queues.len() < 2 {
1501 anyhow::bail!("{} queues were found, but an activated balloon must have at least 2 active queues.", queues.len());
1502 }
1503
1504 let balloon_queues = self.get_queues_from_map(queues)?;
1505 self.start_worker(mem, interrupt, balloon_queues)?;
1506 }
1507 Ok(())
1508 }
1509
1510 fn virtio_snapshot(&mut self) -> anyhow::Result<AnySnapshot> {
1511 let state = self
1512 .state
1513 .lock()
1514 .now_or_never()
1515 .context("failed to acquire balloon lock")?;
1516 AnySnapshot::to_any(BalloonSnapshot {
1517 features: self.features,
1518 acked_features: self.acked_features,
1519 state: state.clone(),
1520 ws_num_bins: self.ws_num_bins,
1521 })
1522 .context("failed to serialize balloon state")
1523 }
1524
1525 fn virtio_restore(&mut self, data: AnySnapshot) -> anyhow::Result<()> {
1526 let snap: BalloonSnapshot = AnySnapshot::from_any(data).context("error deserializing")?;
1527 if snap.features != self.features {
1528 anyhow::bail!(
1529 "balloon: expected features to match, but they did not. Live: {:?}, snapshot {:?}",
1530 self.features,
1531 snap.features,
1532 );
1533 }
1534
1535 let mut state = self
1536 .state
1537 .lock()
1538 .now_or_never()
1539 .context("failed to acquire balloon lock")?;
1540 *state = snap.state;
1541 self.ws_num_bins = snap.ws_num_bins;
1542 self.acked_features = snap.acked_features;
1543 Ok(())
1544 }
1545}
1546
1547#[cfg(test)]
1548mod tests {
1549 use super::*;
1550 use crate::suspendable_virtio_tests;
1551 use crate::virtio::descriptor_utils::create_descriptor_chain;
1552 use crate::virtio::descriptor_utils::DescriptorType;
1553
1554 #[test]
1555 fn desc_parsing_inflate() {
1556 let memory_start_addr = GuestAddress(0x0);
1559 let memory = GuestMemory::new(&[(memory_start_addr, 0x10000)]).unwrap();
1560 memory
1561 .write_obj_at_addr(0x10u32, GuestAddress(0x100))
1562 .unwrap();
1563 memory
1564 .write_obj_at_addr(0xaa55aa55u32, GuestAddress(0x104))
1565 .unwrap();
1566
1567 let mut chain = create_descriptor_chain(
1568 &memory,
1569 GuestAddress(0x0),
1570 GuestAddress(0x100),
1571 vec![(DescriptorType::Readable, 8)],
1572 0,
1573 )
1574 .expect("create_descriptor_chain failed");
1575
1576 let mut addrs = Vec::new();
1577 let res = handle_address_chain(None, &mut chain, &mut |mut ranges| {
1578 addrs.append(&mut ranges)
1579 });
1580 assert!(res.is_ok());
1581 assert_eq!(addrs.len(), 2);
1582 assert_eq!(
1583 addrs[0].0,
1584 GuestAddress(0x10u64 << VIRTIO_BALLOON_PFN_SHIFT)
1585 );
1586 assert_eq!(
1587 addrs[1].0,
1588 GuestAddress(0xaa55aa55u64 << VIRTIO_BALLOON_PFN_SHIFT)
1589 );
1590 }
1591
1592 struct BalloonContext {
1593 _ctrl_tube: Tube,
1594 _mem_client_tube: Tube,
1595 }
1596
1597 fn modify_device(_balloon_context: &mut BalloonContext, balloon: &mut Balloon) {
1598 balloon.ws_num_bins = !balloon.ws_num_bins;
1599 }
1600
1601 fn create_device() -> (BalloonContext, Balloon) {
1602 let (_ctrl_tube, ctrl_tube_device) = Tube::pair().unwrap();
1603 let (_mem_client_tube, mem_client_tube_device) = Tube::pair().unwrap();
1604 (
1605 BalloonContext {
1606 _ctrl_tube,
1607 _mem_client_tube,
1608 },
1609 Balloon::new(
1610 0,
1611 ctrl_tube_device,
1612 VmMemoryClient::new(mem_client_tube_device),
1613 None,
1614 1024,
1615 0,
1616 #[cfg(feature = "registered_events")]
1617 None,
1618 0,
1619 )
1620 .unwrap(),
1621 )
1622 }
1623
1624 suspendable_virtio_tests!(balloon, create_device, 2, modify_device);
1625}