xref: /aosp_15_r20/external/crosvm/devices/src/virtio/balloon.rs (revision bb4ee6a4ae7042d18b07a98463b9c8b875e44b39)
1*bb4ee6a4SAndroid Build Coastguard Worker // Copyright 2017 The ChromiumOS Authors
2*bb4ee6a4SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*bb4ee6a4SAndroid Build Coastguard Worker // found in the LICENSE file.
4*bb4ee6a4SAndroid Build Coastguard Worker 
5*bb4ee6a4SAndroid Build Coastguard Worker mod sys;
6*bb4ee6a4SAndroid Build Coastguard Worker 
7*bb4ee6a4SAndroid Build Coastguard Worker use std::collections::BTreeMap;
8*bb4ee6a4SAndroid Build Coastguard Worker use std::collections::VecDeque;
9*bb4ee6a4SAndroid Build Coastguard Worker use std::io::Write;
10*bb4ee6a4SAndroid Build Coastguard Worker use std::sync::Arc;
11*bb4ee6a4SAndroid Build Coastguard Worker 
12*bb4ee6a4SAndroid Build Coastguard Worker use anyhow::anyhow;
13*bb4ee6a4SAndroid Build Coastguard Worker use anyhow::Context;
14*bb4ee6a4SAndroid Build Coastguard Worker use balloon_control::BalloonStats;
15*bb4ee6a4SAndroid Build Coastguard Worker use balloon_control::BalloonTubeCommand;
16*bb4ee6a4SAndroid Build Coastguard Worker use balloon_control::BalloonTubeResult;
17*bb4ee6a4SAndroid Build Coastguard Worker use balloon_control::BalloonWS;
18*bb4ee6a4SAndroid Build Coastguard Worker use balloon_control::WSBucket;
19*bb4ee6a4SAndroid Build Coastguard Worker use balloon_control::VIRTIO_BALLOON_WS_MAX_NUM_BINS;
20*bb4ee6a4SAndroid Build Coastguard Worker use balloon_control::VIRTIO_BALLOON_WS_MIN_NUM_BINS;
21*bb4ee6a4SAndroid Build Coastguard Worker use base::debug;
22*bb4ee6a4SAndroid Build Coastguard Worker use base::error;
23*bb4ee6a4SAndroid Build Coastguard Worker use base::warn;
24*bb4ee6a4SAndroid Build Coastguard Worker use base::AsRawDescriptor;
25*bb4ee6a4SAndroid Build Coastguard Worker use base::Event;
26*bb4ee6a4SAndroid Build Coastguard Worker use base::RawDescriptor;
27*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "registered_events")]
28*bb4ee6a4SAndroid Build Coastguard Worker use base::SendTube;
29*bb4ee6a4SAndroid Build Coastguard Worker use base::Tube;
30*bb4ee6a4SAndroid Build Coastguard Worker use base::WorkerThread;
31*bb4ee6a4SAndroid Build Coastguard Worker use cros_async::block_on;
32*bb4ee6a4SAndroid Build Coastguard Worker use cros_async::sync::RwLock as AsyncRwLock;
33*bb4ee6a4SAndroid Build Coastguard Worker use cros_async::AsyncTube;
34*bb4ee6a4SAndroid Build Coastguard Worker use cros_async::EventAsync;
35*bb4ee6a4SAndroid Build Coastguard Worker use cros_async::Executor;
36*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "registered_events")]
37*bb4ee6a4SAndroid Build Coastguard Worker use cros_async::SendTubeAsync;
38*bb4ee6a4SAndroid Build Coastguard Worker use data_model::Le16;
39*bb4ee6a4SAndroid Build Coastguard Worker use data_model::Le32;
40*bb4ee6a4SAndroid Build Coastguard Worker use data_model::Le64;
41*bb4ee6a4SAndroid Build Coastguard Worker use futures::channel::mpsc;
42*bb4ee6a4SAndroid Build Coastguard Worker use futures::channel::oneshot;
43*bb4ee6a4SAndroid Build Coastguard Worker use futures::pin_mut;
44*bb4ee6a4SAndroid Build Coastguard Worker use futures::select;
45*bb4ee6a4SAndroid Build Coastguard Worker use futures::select_biased;
46*bb4ee6a4SAndroid Build Coastguard Worker use futures::FutureExt;
47*bb4ee6a4SAndroid Build Coastguard Worker use futures::StreamExt;
48*bb4ee6a4SAndroid Build Coastguard Worker use remain::sorted;
49*bb4ee6a4SAndroid Build Coastguard Worker use serde::Deserialize;
50*bb4ee6a4SAndroid Build Coastguard Worker use serde::Serialize;
51*bb4ee6a4SAndroid Build Coastguard Worker use thiserror::Error as ThisError;
52*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(windows)]
53*bb4ee6a4SAndroid Build Coastguard Worker use vm_control::api::VmMemoryClient;
54*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "registered_events")]
55*bb4ee6a4SAndroid Build Coastguard Worker use vm_control::RegisteredEventWithData;
56*bb4ee6a4SAndroid Build Coastguard Worker use vm_memory::GuestAddress;
57*bb4ee6a4SAndroid Build Coastguard Worker use vm_memory::GuestMemory;
58*bb4ee6a4SAndroid Build Coastguard Worker use zerocopy::AsBytes;
59*bb4ee6a4SAndroid Build Coastguard Worker use zerocopy::FromBytes;
60*bb4ee6a4SAndroid Build Coastguard Worker use zerocopy::FromZeroes;
61*bb4ee6a4SAndroid Build Coastguard Worker 
62*bb4ee6a4SAndroid Build Coastguard Worker use super::async_utils;
63*bb4ee6a4SAndroid Build Coastguard Worker use super::copy_config;
64*bb4ee6a4SAndroid Build Coastguard Worker use super::create_stop_oneshot;
65*bb4ee6a4SAndroid Build Coastguard Worker use super::DescriptorChain;
66*bb4ee6a4SAndroid Build Coastguard Worker use super::DeviceType;
67*bb4ee6a4SAndroid Build Coastguard Worker use super::Interrupt;
68*bb4ee6a4SAndroid Build Coastguard Worker use super::Queue;
69*bb4ee6a4SAndroid Build Coastguard Worker use super::Reader;
70*bb4ee6a4SAndroid Build Coastguard Worker use super::StoppedWorker;
71*bb4ee6a4SAndroid Build Coastguard Worker use super::VirtioDevice;
72*bb4ee6a4SAndroid Build Coastguard Worker use crate::UnpinRequest;
73*bb4ee6a4SAndroid Build Coastguard Worker use crate::UnpinResponse;
74*bb4ee6a4SAndroid Build Coastguard Worker 
75*bb4ee6a4SAndroid Build Coastguard Worker #[sorted]
76*bb4ee6a4SAndroid Build Coastguard Worker #[derive(ThisError, Debug)]
77*bb4ee6a4SAndroid Build Coastguard Worker pub enum BalloonError {
78*bb4ee6a4SAndroid Build Coastguard Worker     /// Failed an async await
79*bb4ee6a4SAndroid Build Coastguard Worker     #[error("failed async await: {0}")]
80*bb4ee6a4SAndroid Build Coastguard Worker     AsyncAwait(cros_async::AsyncError),
81*bb4ee6a4SAndroid Build Coastguard Worker     /// Failed an async await
82*bb4ee6a4SAndroid Build Coastguard Worker     #[error("failed async await: {0}")]
83*bb4ee6a4SAndroid Build Coastguard Worker     AsyncAwaitAnyhow(anyhow::Error),
84*bb4ee6a4SAndroid Build Coastguard Worker     /// Failed to create event.
85*bb4ee6a4SAndroid Build Coastguard Worker     #[error("failed to create event: {0}")]
86*bb4ee6a4SAndroid Build Coastguard Worker     CreatingEvent(base::Error),
87*bb4ee6a4SAndroid Build Coastguard Worker     /// Failed to create async message receiver.
88*bb4ee6a4SAndroid Build Coastguard Worker     #[error("failed to create async message receiver: {0}")]
89*bb4ee6a4SAndroid Build Coastguard Worker     CreatingMessageReceiver(base::TubeError),
90*bb4ee6a4SAndroid Build Coastguard Worker     /// Failed to receive command message.
91*bb4ee6a4SAndroid Build Coastguard Worker     #[error("failed to receive command message: {0}")]
92*bb4ee6a4SAndroid Build Coastguard Worker     ReceivingCommand(base::TubeError),
93*bb4ee6a4SAndroid Build Coastguard Worker     /// Failed to send command response.
94*bb4ee6a4SAndroid Build Coastguard Worker     #[error("failed to send command response: {0}")]
95*bb4ee6a4SAndroid Build Coastguard Worker     SendResponse(base::TubeError),
96*bb4ee6a4SAndroid Build Coastguard Worker     /// Error while writing to virtqueue
97*bb4ee6a4SAndroid Build Coastguard Worker     #[error("failed to write to virtqueue: {0}")]
98*bb4ee6a4SAndroid Build Coastguard Worker     WriteQueue(std::io::Error),
99*bb4ee6a4SAndroid Build Coastguard Worker     /// Failed to write config event.
100*bb4ee6a4SAndroid Build Coastguard Worker     #[error("failed to write config event: {0}")]
101*bb4ee6a4SAndroid Build Coastguard Worker     WritingConfigEvent(base::Error),
102*bb4ee6a4SAndroid Build Coastguard Worker }
103*bb4ee6a4SAndroid Build Coastguard Worker pub type Result<T> = std::result::Result<T, BalloonError>;
104*bb4ee6a4SAndroid Build Coastguard Worker 
105*bb4ee6a4SAndroid Build Coastguard Worker // Balloon implements five virt IO queues: Inflate, Deflate, Stats, WsData, WsCmd.
106*bb4ee6a4SAndroid Build Coastguard Worker const QUEUE_SIZE: u16 = 128;
107*bb4ee6a4SAndroid Build Coastguard Worker const QUEUE_SIZES: &[u16] = &[QUEUE_SIZE, QUEUE_SIZE, QUEUE_SIZE, QUEUE_SIZE, QUEUE_SIZE];
108*bb4ee6a4SAndroid Build Coastguard Worker 
109*bb4ee6a4SAndroid Build Coastguard Worker // Virtqueue indexes
110*bb4ee6a4SAndroid Build Coastguard Worker const INFLATEQ: usize = 0;
111*bb4ee6a4SAndroid Build Coastguard Worker const DEFLATEQ: usize = 1;
112*bb4ee6a4SAndroid Build Coastguard Worker const STATSQ: usize = 2;
113*bb4ee6a4SAndroid Build Coastguard Worker const _FREE_PAGE_VQ: usize = 3;
114*bb4ee6a4SAndroid Build Coastguard Worker const REPORTING_VQ: usize = 4;
115*bb4ee6a4SAndroid Build Coastguard Worker const WS_DATA_VQ: usize = 5;
116*bb4ee6a4SAndroid Build Coastguard Worker const WS_OP_VQ: usize = 6;
117*bb4ee6a4SAndroid Build Coastguard Worker 
118*bb4ee6a4SAndroid Build Coastguard Worker const VIRTIO_BALLOON_PFN_SHIFT: u32 = 12;
119*bb4ee6a4SAndroid Build Coastguard Worker const VIRTIO_BALLOON_PF_SIZE: u64 = 1 << VIRTIO_BALLOON_PFN_SHIFT;
120*bb4ee6a4SAndroid Build Coastguard Worker 
121*bb4ee6a4SAndroid Build Coastguard Worker // The feature bitmap for virtio balloon
122*bb4ee6a4SAndroid Build Coastguard Worker const VIRTIO_BALLOON_F_MUST_TELL_HOST: u32 = 0; // Tell before reclaiming pages
123*bb4ee6a4SAndroid Build Coastguard Worker const VIRTIO_BALLOON_F_STATS_VQ: u32 = 1; // Stats reporting enabled
124*bb4ee6a4SAndroid Build Coastguard Worker const VIRTIO_BALLOON_F_DEFLATE_ON_OOM: u32 = 2; // Deflate balloon on OOM
125*bb4ee6a4SAndroid Build Coastguard Worker const VIRTIO_BALLOON_F_PAGE_REPORTING: u32 = 5; // Page reporting virtqueue
126*bb4ee6a4SAndroid Build Coastguard Worker                                                 // TODO(b/273973298): this should maybe be bit 6? to be changed later
127*bb4ee6a4SAndroid Build Coastguard Worker const VIRTIO_BALLOON_F_WS_REPORTING: u32 = 8; // Working Set Reporting virtqueues
128*bb4ee6a4SAndroid Build Coastguard Worker 
129*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Copy, Clone)]
130*bb4ee6a4SAndroid Build Coastguard Worker #[repr(u32)]
131*bb4ee6a4SAndroid Build Coastguard Worker // Balloon virtqueues
132*bb4ee6a4SAndroid Build Coastguard Worker pub enum BalloonFeatures {
133*bb4ee6a4SAndroid Build Coastguard Worker     // Page Reporting enabled
134*bb4ee6a4SAndroid Build Coastguard Worker     PageReporting = VIRTIO_BALLOON_F_PAGE_REPORTING,
135*bb4ee6a4SAndroid Build Coastguard Worker     // WS Reporting enabled
136*bb4ee6a4SAndroid Build Coastguard Worker     WSReporting = VIRTIO_BALLOON_F_WS_REPORTING,
137*bb4ee6a4SAndroid Build Coastguard Worker }
138*bb4ee6a4SAndroid Build Coastguard Worker 
139*bb4ee6a4SAndroid Build Coastguard Worker // virtio_balloon_config is the balloon device configuration space defined by the virtio spec.
140*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Copy, Clone, Debug, Default, AsBytes, FromZeroes, FromBytes)]
141*bb4ee6a4SAndroid Build Coastguard Worker #[repr(C)]
142*bb4ee6a4SAndroid Build Coastguard Worker struct virtio_balloon_config {
143*bb4ee6a4SAndroid Build Coastguard Worker     num_pages: Le32,
144*bb4ee6a4SAndroid Build Coastguard Worker     actual: Le32,
145*bb4ee6a4SAndroid Build Coastguard Worker     free_page_hint_cmd_id: Le32,
146*bb4ee6a4SAndroid Build Coastguard Worker     poison_val: Le32,
147*bb4ee6a4SAndroid Build Coastguard Worker     // WS field is part of proposed spec extension (b/273973298).
148*bb4ee6a4SAndroid Build Coastguard Worker     ws_num_bins: u8,
149*bb4ee6a4SAndroid Build Coastguard Worker     _reserved: [u8; 3],
150*bb4ee6a4SAndroid Build Coastguard Worker }
151*bb4ee6a4SAndroid Build Coastguard Worker 
152*bb4ee6a4SAndroid Build Coastguard Worker // BalloonState is shared by the worker and device thread.
153*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Clone, Default, Serialize, Deserialize)]
154*bb4ee6a4SAndroid Build Coastguard Worker struct BalloonState {
155*bb4ee6a4SAndroid Build Coastguard Worker     num_pages: u32,
156*bb4ee6a4SAndroid Build Coastguard Worker     actual_pages: u32,
157*bb4ee6a4SAndroid Build Coastguard Worker     expecting_ws: bool,
158*bb4ee6a4SAndroid Build Coastguard Worker     // Flag indicating that the balloon is in the process of a failable update. This
159*bb4ee6a4SAndroid Build Coastguard Worker     // is set by an Adjust command that has allow_failure set, and is cleared when the
160*bb4ee6a4SAndroid Build Coastguard Worker     // Adjusted success/failure response is sent.
161*bb4ee6a4SAndroid Build Coastguard Worker     failable_update: bool,
162*bb4ee6a4SAndroid Build Coastguard Worker     pending_adjusted_responses: VecDeque<u32>,
163*bb4ee6a4SAndroid Build Coastguard Worker }
164*bb4ee6a4SAndroid Build Coastguard Worker 
165*bb4ee6a4SAndroid Build Coastguard Worker // The constants defining stats types in virtio_baloon_stat
166*bb4ee6a4SAndroid Build Coastguard Worker const VIRTIO_BALLOON_S_SWAP_IN: u16 = 0;
167*bb4ee6a4SAndroid Build Coastguard Worker const VIRTIO_BALLOON_S_SWAP_OUT: u16 = 1;
168*bb4ee6a4SAndroid Build Coastguard Worker const VIRTIO_BALLOON_S_MAJFLT: u16 = 2;
169*bb4ee6a4SAndroid Build Coastguard Worker const VIRTIO_BALLOON_S_MINFLT: u16 = 3;
170*bb4ee6a4SAndroid Build Coastguard Worker const VIRTIO_BALLOON_S_MEMFREE: u16 = 4;
171*bb4ee6a4SAndroid Build Coastguard Worker const VIRTIO_BALLOON_S_MEMTOT: u16 = 5;
172*bb4ee6a4SAndroid Build Coastguard Worker const VIRTIO_BALLOON_S_AVAIL: u16 = 6;
173*bb4ee6a4SAndroid Build Coastguard Worker const VIRTIO_BALLOON_S_CACHES: u16 = 7;
174*bb4ee6a4SAndroid Build Coastguard Worker const VIRTIO_BALLOON_S_HTLB_PGALLOC: u16 = 8;
175*bb4ee6a4SAndroid Build Coastguard Worker const VIRTIO_BALLOON_S_HTLB_PGFAIL: u16 = 9;
176*bb4ee6a4SAndroid Build Coastguard Worker const VIRTIO_BALLOON_S_NONSTANDARD_SHMEM: u16 = 65534;
177*bb4ee6a4SAndroid Build Coastguard Worker const VIRTIO_BALLOON_S_NONSTANDARD_UNEVICTABLE: u16 = 65535;
178*bb4ee6a4SAndroid Build Coastguard Worker 
179*bb4ee6a4SAndroid Build Coastguard Worker // BalloonStat is used to deserialize stats from the stats_queue.
180*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Copy, Clone, FromZeroes, FromBytes, AsBytes)]
181*bb4ee6a4SAndroid Build Coastguard Worker #[repr(C, packed)]
182*bb4ee6a4SAndroid Build Coastguard Worker struct BalloonStat {
183*bb4ee6a4SAndroid Build Coastguard Worker     tag: Le16,
184*bb4ee6a4SAndroid Build Coastguard Worker     val: Le64,
185*bb4ee6a4SAndroid Build Coastguard Worker }
186*bb4ee6a4SAndroid Build Coastguard Worker 
187*bb4ee6a4SAndroid Build Coastguard Worker impl BalloonStat {
update_stats(&self, stats: &mut BalloonStats)188*bb4ee6a4SAndroid Build Coastguard Worker     fn update_stats(&self, stats: &mut BalloonStats) {
189*bb4ee6a4SAndroid Build Coastguard Worker         let val = Some(self.val.to_native());
190*bb4ee6a4SAndroid Build Coastguard Worker         match self.tag.to_native() {
191*bb4ee6a4SAndroid Build Coastguard Worker             VIRTIO_BALLOON_S_SWAP_IN => stats.swap_in = val,
192*bb4ee6a4SAndroid Build Coastguard Worker             VIRTIO_BALLOON_S_SWAP_OUT => stats.swap_out = val,
193*bb4ee6a4SAndroid Build Coastguard Worker             VIRTIO_BALLOON_S_MAJFLT => stats.major_faults = val,
194*bb4ee6a4SAndroid Build Coastguard Worker             VIRTIO_BALLOON_S_MINFLT => stats.minor_faults = val,
195*bb4ee6a4SAndroid Build Coastguard Worker             VIRTIO_BALLOON_S_MEMFREE => stats.free_memory = val,
196*bb4ee6a4SAndroid Build Coastguard Worker             VIRTIO_BALLOON_S_MEMTOT => stats.total_memory = val,
197*bb4ee6a4SAndroid Build Coastguard Worker             VIRTIO_BALLOON_S_AVAIL => stats.available_memory = val,
198*bb4ee6a4SAndroid Build Coastguard Worker             VIRTIO_BALLOON_S_CACHES => stats.disk_caches = val,
199*bb4ee6a4SAndroid Build Coastguard Worker             VIRTIO_BALLOON_S_HTLB_PGALLOC => stats.hugetlb_allocations = val,
200*bb4ee6a4SAndroid Build Coastguard Worker             VIRTIO_BALLOON_S_HTLB_PGFAIL => stats.hugetlb_failures = val,
201*bb4ee6a4SAndroid Build Coastguard Worker             VIRTIO_BALLOON_S_NONSTANDARD_SHMEM => stats.shared_memory = val,
202*bb4ee6a4SAndroid Build Coastguard Worker             VIRTIO_BALLOON_S_NONSTANDARD_UNEVICTABLE => stats.unevictable_memory = val,
203*bb4ee6a4SAndroid Build Coastguard Worker             _ => (),
204*bb4ee6a4SAndroid Build Coastguard Worker         }
205*bb4ee6a4SAndroid Build Coastguard Worker     }
206*bb4ee6a4SAndroid Build Coastguard Worker }
207*bb4ee6a4SAndroid Build Coastguard Worker 
208*bb4ee6a4SAndroid Build Coastguard Worker // virtio_balloon_ws is used to deserialize from the ws data vq.
209*bb4ee6a4SAndroid Build Coastguard Worker #[repr(C)]
210*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Copy, Clone, Debug, Default, AsBytes, FromZeroes, FromBytes)]
211*bb4ee6a4SAndroid Build Coastguard Worker struct virtio_balloon_ws {
212*bb4ee6a4SAndroid Build Coastguard Worker     tag: Le16,
213*bb4ee6a4SAndroid Build Coastguard Worker     node_id: Le16,
214*bb4ee6a4SAndroid Build Coastguard Worker     // virtio prefers field members to align on a word boundary so we must pad. see:
215*bb4ee6a4SAndroid Build Coastguard Worker     // https://crsrc.org/o/src/third_party/kernel/v5.15/include/uapi/linux/virtio_balloon.h;l=105
216*bb4ee6a4SAndroid Build Coastguard Worker     _reserved: [u8; 4],
217*bb4ee6a4SAndroid Build Coastguard Worker     idle_age_ms: Le64,
218*bb4ee6a4SAndroid Build Coastguard Worker     // TODO(b/273973298): these should become separate fields - bytes for ANON and FILE
219*bb4ee6a4SAndroid Build Coastguard Worker     memory_size_bytes: [Le64; 2],
220*bb4ee6a4SAndroid Build Coastguard Worker }
221*bb4ee6a4SAndroid Build Coastguard Worker 
222*bb4ee6a4SAndroid Build Coastguard Worker impl virtio_balloon_ws {
update_ws(&self, ws: &mut BalloonWS)223*bb4ee6a4SAndroid Build Coastguard Worker     fn update_ws(&self, ws: &mut BalloonWS) {
224*bb4ee6a4SAndroid Build Coastguard Worker         let bucket = WSBucket {
225*bb4ee6a4SAndroid Build Coastguard Worker             age: self.idle_age_ms.to_native(),
226*bb4ee6a4SAndroid Build Coastguard Worker             bytes: [
227*bb4ee6a4SAndroid Build Coastguard Worker                 self.memory_size_bytes[0].to_native(),
228*bb4ee6a4SAndroid Build Coastguard Worker                 self.memory_size_bytes[1].to_native(),
229*bb4ee6a4SAndroid Build Coastguard Worker             ],
230*bb4ee6a4SAndroid Build Coastguard Worker         };
231*bb4ee6a4SAndroid Build Coastguard Worker         ws.ws.push(bucket);
232*bb4ee6a4SAndroid Build Coastguard Worker     }
233*bb4ee6a4SAndroid Build Coastguard Worker }
234*bb4ee6a4SAndroid Build Coastguard Worker 
235*bb4ee6a4SAndroid Build Coastguard Worker const _VIRTIO_BALLOON_WS_OP_INVALID: u16 = 0;
236*bb4ee6a4SAndroid Build Coastguard Worker const VIRTIO_BALLOON_WS_OP_REQUEST: u16 = 1;
237*bb4ee6a4SAndroid Build Coastguard Worker const VIRTIO_BALLOON_WS_OP_CONFIG: u16 = 2;
238*bb4ee6a4SAndroid Build Coastguard Worker const _VIRTIO_BALLOON_WS_OP_DISCARD: u16 = 3;
239*bb4ee6a4SAndroid Build Coastguard Worker 
240*bb4ee6a4SAndroid Build Coastguard Worker // virtio_balloon_op is used to serialize to the ws cmd vq.
241*bb4ee6a4SAndroid Build Coastguard Worker #[repr(C, packed)]
242*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Copy, Clone, Debug, Default, AsBytes, FromZeroes, FromBytes)]
243*bb4ee6a4SAndroid Build Coastguard Worker struct virtio_balloon_op {
244*bb4ee6a4SAndroid Build Coastguard Worker     type_: Le16,
245*bb4ee6a4SAndroid Build Coastguard Worker }
246*bb4ee6a4SAndroid Build Coastguard Worker 
invoke_desc_handler<F>(ranges: Vec<(u64, u64)>, desc_handler: &mut F) where F: FnMut(GuestAddress, u64),247*bb4ee6a4SAndroid Build Coastguard Worker fn invoke_desc_handler<F>(ranges: Vec<(u64, u64)>, desc_handler: &mut F)
248*bb4ee6a4SAndroid Build Coastguard Worker where
249*bb4ee6a4SAndroid Build Coastguard Worker     F: FnMut(GuestAddress, u64),
250*bb4ee6a4SAndroid Build Coastguard Worker {
251*bb4ee6a4SAndroid Build Coastguard Worker     for range in ranges {
252*bb4ee6a4SAndroid Build Coastguard Worker         desc_handler(GuestAddress(range.0), range.1);
253*bb4ee6a4SAndroid Build Coastguard Worker     }
254*bb4ee6a4SAndroid Build Coastguard Worker }
255*bb4ee6a4SAndroid Build Coastguard Worker 
256*bb4ee6a4SAndroid Build Coastguard Worker // Release a list of guest memory ranges back to the host system.
257*bb4ee6a4SAndroid Build Coastguard Worker // Unpin requests for each inflate range will be sent via `release_memory_tube`
258*bb4ee6a4SAndroid Build Coastguard Worker // if provided, and then `desc_handler` will be called for each inflate range.
release_ranges<F>( release_memory_tube: Option<&Tube>, inflate_ranges: Vec<(u64, u64)>, desc_handler: &mut F, ) -> anyhow::Result<()> where F: FnMut(GuestAddress, u64),259*bb4ee6a4SAndroid Build Coastguard Worker fn release_ranges<F>(
260*bb4ee6a4SAndroid Build Coastguard Worker     release_memory_tube: Option<&Tube>,
261*bb4ee6a4SAndroid Build Coastguard Worker     inflate_ranges: Vec<(u64, u64)>,
262*bb4ee6a4SAndroid Build Coastguard Worker     desc_handler: &mut F,
263*bb4ee6a4SAndroid Build Coastguard Worker ) -> anyhow::Result<()>
264*bb4ee6a4SAndroid Build Coastguard Worker where
265*bb4ee6a4SAndroid Build Coastguard Worker     F: FnMut(GuestAddress, u64),
266*bb4ee6a4SAndroid Build Coastguard Worker {
267*bb4ee6a4SAndroid Build Coastguard Worker     if let Some(tube) = release_memory_tube {
268*bb4ee6a4SAndroid Build Coastguard Worker         let unpin_ranges = inflate_ranges
269*bb4ee6a4SAndroid Build Coastguard Worker             .iter()
270*bb4ee6a4SAndroid Build Coastguard Worker             .map(|v| {
271*bb4ee6a4SAndroid Build Coastguard Worker                 (
272*bb4ee6a4SAndroid Build Coastguard Worker                     v.0 >> VIRTIO_BALLOON_PFN_SHIFT,
273*bb4ee6a4SAndroid Build Coastguard Worker                     v.1 / VIRTIO_BALLOON_PF_SIZE,
274*bb4ee6a4SAndroid Build Coastguard Worker                 )
275*bb4ee6a4SAndroid Build Coastguard Worker             })
276*bb4ee6a4SAndroid Build Coastguard Worker             .collect();
277*bb4ee6a4SAndroid Build Coastguard Worker         let req = UnpinRequest {
278*bb4ee6a4SAndroid Build Coastguard Worker             ranges: unpin_ranges,
279*bb4ee6a4SAndroid Build Coastguard Worker         };
280*bb4ee6a4SAndroid Build Coastguard Worker         if let Err(e) = tube.send(&req) {
281*bb4ee6a4SAndroid Build Coastguard Worker             error!("failed to send unpin request: {}", e);
282*bb4ee6a4SAndroid Build Coastguard Worker         } else {
283*bb4ee6a4SAndroid Build Coastguard Worker             match tube.recv() {
284*bb4ee6a4SAndroid Build Coastguard Worker                 Ok(resp) => match resp {
285*bb4ee6a4SAndroid Build Coastguard Worker                     UnpinResponse::Success => invoke_desc_handler(inflate_ranges, desc_handler),
286*bb4ee6a4SAndroid Build Coastguard Worker                     UnpinResponse::Failed => error!("failed to handle unpin request"),
287*bb4ee6a4SAndroid Build Coastguard Worker                 },
288*bb4ee6a4SAndroid Build Coastguard Worker                 Err(e) => error!("failed to handle get unpin response: {}", e),
289*bb4ee6a4SAndroid Build Coastguard Worker             }
290*bb4ee6a4SAndroid Build Coastguard Worker         }
291*bb4ee6a4SAndroid Build Coastguard Worker     } else {
292*bb4ee6a4SAndroid Build Coastguard Worker         invoke_desc_handler(inflate_ranges, desc_handler);
293*bb4ee6a4SAndroid Build Coastguard Worker     }
294*bb4ee6a4SAndroid Build Coastguard Worker 
295*bb4ee6a4SAndroid Build Coastguard Worker     Ok(())
296*bb4ee6a4SAndroid Build Coastguard Worker }
297*bb4ee6a4SAndroid Build Coastguard Worker 
298*bb4ee6a4SAndroid Build Coastguard Worker // Processes one message's list of addresses.
handle_address_chain<F>( release_memory_tube: Option<&Tube>, avail_desc: &mut DescriptorChain, desc_handler: &mut F, ) -> anyhow::Result<()> where F: FnMut(GuestAddress, u64),299*bb4ee6a4SAndroid Build Coastguard Worker fn handle_address_chain<F>(
300*bb4ee6a4SAndroid Build Coastguard Worker     release_memory_tube: Option<&Tube>,
301*bb4ee6a4SAndroid Build Coastguard Worker     avail_desc: &mut DescriptorChain,
302*bb4ee6a4SAndroid Build Coastguard Worker     desc_handler: &mut F,
303*bb4ee6a4SAndroid Build Coastguard Worker ) -> anyhow::Result<()>
304*bb4ee6a4SAndroid Build Coastguard Worker where
305*bb4ee6a4SAndroid Build Coastguard Worker     F: FnMut(GuestAddress, u64),
306*bb4ee6a4SAndroid Build Coastguard Worker {
307*bb4ee6a4SAndroid Build Coastguard Worker     // In a long-running system, there is no reason to expect that
308*bb4ee6a4SAndroid Build Coastguard Worker     // a significant number of freed pages are consecutive. However,
309*bb4ee6a4SAndroid Build Coastguard Worker     // batching is relatively simple and can result in significant
310*bb4ee6a4SAndroid Build Coastguard Worker     // gains in a newly booted system, so it's worth attempting.
311*bb4ee6a4SAndroid Build Coastguard Worker     let mut range_start = 0;
312*bb4ee6a4SAndroid Build Coastguard Worker     let mut range_size = 0;
313*bb4ee6a4SAndroid Build Coastguard Worker     let mut inflate_ranges: Vec<(u64, u64)> = Vec::new();
314*bb4ee6a4SAndroid Build Coastguard Worker     for res in avail_desc.reader.iter::<Le32>() {
315*bb4ee6a4SAndroid Build Coastguard Worker         let pfn = match res {
316*bb4ee6a4SAndroid Build Coastguard Worker             Ok(pfn) => pfn,
317*bb4ee6a4SAndroid Build Coastguard Worker             Err(e) => {
318*bb4ee6a4SAndroid Build Coastguard Worker                 error!("error while reading unused pages: {}", e);
319*bb4ee6a4SAndroid Build Coastguard Worker                 break;
320*bb4ee6a4SAndroid Build Coastguard Worker             }
321*bb4ee6a4SAndroid Build Coastguard Worker         };
322*bb4ee6a4SAndroid Build Coastguard Worker         let guest_address = (u64::from(pfn.to_native())) << VIRTIO_BALLOON_PFN_SHIFT;
323*bb4ee6a4SAndroid Build Coastguard Worker         if range_start + range_size == guest_address {
324*bb4ee6a4SAndroid Build Coastguard Worker             range_size += VIRTIO_BALLOON_PF_SIZE;
325*bb4ee6a4SAndroid Build Coastguard Worker         } else if range_start == guest_address + VIRTIO_BALLOON_PF_SIZE {
326*bb4ee6a4SAndroid Build Coastguard Worker             range_start = guest_address;
327*bb4ee6a4SAndroid Build Coastguard Worker             range_size += VIRTIO_BALLOON_PF_SIZE;
328*bb4ee6a4SAndroid Build Coastguard Worker         } else {
329*bb4ee6a4SAndroid Build Coastguard Worker             // Discontinuity, so flush the previous range. Note range_size
330*bb4ee6a4SAndroid Build Coastguard Worker             // will be 0 on the first iteration, so skip that.
331*bb4ee6a4SAndroid Build Coastguard Worker             if range_size != 0 {
332*bb4ee6a4SAndroid Build Coastguard Worker                 inflate_ranges.push((range_start, range_size));
333*bb4ee6a4SAndroid Build Coastguard Worker             }
334*bb4ee6a4SAndroid Build Coastguard Worker             range_start = guest_address;
335*bb4ee6a4SAndroid Build Coastguard Worker             range_size = VIRTIO_BALLOON_PF_SIZE;
336*bb4ee6a4SAndroid Build Coastguard Worker         }
337*bb4ee6a4SAndroid Build Coastguard Worker     }
338*bb4ee6a4SAndroid Build Coastguard Worker     if range_size != 0 {
339*bb4ee6a4SAndroid Build Coastguard Worker         inflate_ranges.push((range_start, range_size));
340*bb4ee6a4SAndroid Build Coastguard Worker     }
341*bb4ee6a4SAndroid Build Coastguard Worker 
342*bb4ee6a4SAndroid Build Coastguard Worker     release_ranges(release_memory_tube, inflate_ranges, desc_handler)
343*bb4ee6a4SAndroid Build Coastguard Worker }
344*bb4ee6a4SAndroid Build Coastguard Worker 
345*bb4ee6a4SAndroid Build Coastguard Worker // Async task that handles the main balloon inflate and deflate queues.
handle_queue<F>( mut queue: Queue, mut queue_event: EventAsync, release_memory_tube: Option<&Tube>, mut desc_handler: F, mut stop_rx: oneshot::Receiver<()>, ) -> Queue where F: FnMut(GuestAddress, u64),346*bb4ee6a4SAndroid Build Coastguard Worker async fn handle_queue<F>(
347*bb4ee6a4SAndroid Build Coastguard Worker     mut queue: Queue,
348*bb4ee6a4SAndroid Build Coastguard Worker     mut queue_event: EventAsync,
349*bb4ee6a4SAndroid Build Coastguard Worker     release_memory_tube: Option<&Tube>,
350*bb4ee6a4SAndroid Build Coastguard Worker     mut desc_handler: F,
351*bb4ee6a4SAndroid Build Coastguard Worker     mut stop_rx: oneshot::Receiver<()>,
352*bb4ee6a4SAndroid Build Coastguard Worker ) -> Queue
353*bb4ee6a4SAndroid Build Coastguard Worker where
354*bb4ee6a4SAndroid Build Coastguard Worker     F: FnMut(GuestAddress, u64),
355*bb4ee6a4SAndroid Build Coastguard Worker {
356*bb4ee6a4SAndroid Build Coastguard Worker     loop {
357*bb4ee6a4SAndroid Build Coastguard Worker         let mut avail_desc = match queue
358*bb4ee6a4SAndroid Build Coastguard Worker             .next_async_interruptable(&mut queue_event, &mut stop_rx)
359*bb4ee6a4SAndroid Build Coastguard Worker             .await
360*bb4ee6a4SAndroid Build Coastguard Worker         {
361*bb4ee6a4SAndroid Build Coastguard Worker             Ok(Some(res)) => res,
362*bb4ee6a4SAndroid Build Coastguard Worker             Ok(None) => return queue,
363*bb4ee6a4SAndroid Build Coastguard Worker             Err(e) => {
364*bb4ee6a4SAndroid Build Coastguard Worker                 error!("Failed to read descriptor {}", e);
365*bb4ee6a4SAndroid Build Coastguard Worker                 return queue;
366*bb4ee6a4SAndroid Build Coastguard Worker             }
367*bb4ee6a4SAndroid Build Coastguard Worker         };
368*bb4ee6a4SAndroid Build Coastguard Worker         if let Err(e) =
369*bb4ee6a4SAndroid Build Coastguard Worker             handle_address_chain(release_memory_tube, &mut avail_desc, &mut desc_handler)
370*bb4ee6a4SAndroid Build Coastguard Worker         {
371*bb4ee6a4SAndroid Build Coastguard Worker             error!("balloon: failed to process inflate addresses: {}", e);
372*bb4ee6a4SAndroid Build Coastguard Worker         }
373*bb4ee6a4SAndroid Build Coastguard Worker         queue.add_used(avail_desc, 0);
374*bb4ee6a4SAndroid Build Coastguard Worker         queue.trigger_interrupt();
375*bb4ee6a4SAndroid Build Coastguard Worker     }
376*bb4ee6a4SAndroid Build Coastguard Worker }
377*bb4ee6a4SAndroid Build Coastguard Worker 
378*bb4ee6a4SAndroid Build Coastguard Worker // Processes one page-reporting descriptor.
handle_reported_buffer<F>( release_memory_tube: Option<&Tube>, avail_desc: &DescriptorChain, desc_handler: &mut F, ) -> anyhow::Result<()> where F: FnMut(GuestAddress, u64),379*bb4ee6a4SAndroid Build Coastguard Worker fn handle_reported_buffer<F>(
380*bb4ee6a4SAndroid Build Coastguard Worker     release_memory_tube: Option<&Tube>,
381*bb4ee6a4SAndroid Build Coastguard Worker     avail_desc: &DescriptorChain,
382*bb4ee6a4SAndroid Build Coastguard Worker     desc_handler: &mut F,
383*bb4ee6a4SAndroid Build Coastguard Worker ) -> anyhow::Result<()>
384*bb4ee6a4SAndroid Build Coastguard Worker where
385*bb4ee6a4SAndroid Build Coastguard Worker     F: FnMut(GuestAddress, u64),
386*bb4ee6a4SAndroid Build Coastguard Worker {
387*bb4ee6a4SAndroid Build Coastguard Worker     let reported_ranges: Vec<(u64, u64)> = avail_desc
388*bb4ee6a4SAndroid Build Coastguard Worker         .reader
389*bb4ee6a4SAndroid Build Coastguard Worker         .get_remaining_regions()
390*bb4ee6a4SAndroid Build Coastguard Worker         .chain(avail_desc.writer.get_remaining_regions())
391*bb4ee6a4SAndroid Build Coastguard Worker         .map(|r| (r.offset, r.len as u64))
392*bb4ee6a4SAndroid Build Coastguard Worker         .collect();
393*bb4ee6a4SAndroid Build Coastguard Worker 
394*bb4ee6a4SAndroid Build Coastguard Worker     release_ranges(release_memory_tube, reported_ranges, desc_handler)
395*bb4ee6a4SAndroid Build Coastguard Worker }
396*bb4ee6a4SAndroid Build Coastguard Worker 
397*bb4ee6a4SAndroid Build Coastguard Worker // Async task that handles the page reporting queue.
handle_reporting_queue<F>( mut queue: Queue, mut queue_event: EventAsync, release_memory_tube: Option<&Tube>, mut desc_handler: F, mut stop_rx: oneshot::Receiver<()>, ) -> Queue where F: FnMut(GuestAddress, u64),398*bb4ee6a4SAndroid Build Coastguard Worker async fn handle_reporting_queue<F>(
399*bb4ee6a4SAndroid Build Coastguard Worker     mut queue: Queue,
400*bb4ee6a4SAndroid Build Coastguard Worker     mut queue_event: EventAsync,
401*bb4ee6a4SAndroid Build Coastguard Worker     release_memory_tube: Option<&Tube>,
402*bb4ee6a4SAndroid Build Coastguard Worker     mut desc_handler: F,
403*bb4ee6a4SAndroid Build Coastguard Worker     mut stop_rx: oneshot::Receiver<()>,
404*bb4ee6a4SAndroid Build Coastguard Worker ) -> Queue
405*bb4ee6a4SAndroid Build Coastguard Worker where
406*bb4ee6a4SAndroid Build Coastguard Worker     F: FnMut(GuestAddress, u64),
407*bb4ee6a4SAndroid Build Coastguard Worker {
408*bb4ee6a4SAndroid Build Coastguard Worker     loop {
409*bb4ee6a4SAndroid Build Coastguard Worker         let avail_desc = match queue
410*bb4ee6a4SAndroid Build Coastguard Worker             .next_async_interruptable(&mut queue_event, &mut stop_rx)
411*bb4ee6a4SAndroid Build Coastguard Worker             .await
412*bb4ee6a4SAndroid Build Coastguard Worker         {
413*bb4ee6a4SAndroid Build Coastguard Worker             Ok(Some(res)) => res,
414*bb4ee6a4SAndroid Build Coastguard Worker             Ok(None) => return queue,
415*bb4ee6a4SAndroid Build Coastguard Worker             Err(e) => {
416*bb4ee6a4SAndroid Build Coastguard Worker                 error!("Failed to read descriptor {}", e);
417*bb4ee6a4SAndroid Build Coastguard Worker                 return queue;
418*bb4ee6a4SAndroid Build Coastguard Worker             }
419*bb4ee6a4SAndroid Build Coastguard Worker         };
420*bb4ee6a4SAndroid Build Coastguard Worker         if let Err(e) = handle_reported_buffer(release_memory_tube, &avail_desc, &mut desc_handler)
421*bb4ee6a4SAndroid Build Coastguard Worker         {
422*bb4ee6a4SAndroid Build Coastguard Worker             error!("balloon: failed to process reported buffer: {}", e);
423*bb4ee6a4SAndroid Build Coastguard Worker         }
424*bb4ee6a4SAndroid Build Coastguard Worker         queue.add_used(avail_desc, 0);
425*bb4ee6a4SAndroid Build Coastguard Worker         queue.trigger_interrupt();
426*bb4ee6a4SAndroid Build Coastguard Worker     }
427*bb4ee6a4SAndroid Build Coastguard Worker }
428*bb4ee6a4SAndroid Build Coastguard Worker 
parse_balloon_stats(reader: &mut Reader) -> BalloonStats429*bb4ee6a4SAndroid Build Coastguard Worker fn parse_balloon_stats(reader: &mut Reader) -> BalloonStats {
430*bb4ee6a4SAndroid Build Coastguard Worker     let mut stats: BalloonStats = Default::default();
431*bb4ee6a4SAndroid Build Coastguard Worker     for res in reader.iter::<BalloonStat>() {
432*bb4ee6a4SAndroid Build Coastguard Worker         match res {
433*bb4ee6a4SAndroid Build Coastguard Worker             Ok(stat) => stat.update_stats(&mut stats),
434*bb4ee6a4SAndroid Build Coastguard Worker             Err(e) => {
435*bb4ee6a4SAndroid Build Coastguard Worker                 error!("error while reading stats: {}", e);
436*bb4ee6a4SAndroid Build Coastguard Worker                 break;
437*bb4ee6a4SAndroid Build Coastguard Worker             }
438*bb4ee6a4SAndroid Build Coastguard Worker         };
439*bb4ee6a4SAndroid Build Coastguard Worker     }
440*bb4ee6a4SAndroid Build Coastguard Worker     stats
441*bb4ee6a4SAndroid Build Coastguard Worker }
442*bb4ee6a4SAndroid Build Coastguard Worker 
443*bb4ee6a4SAndroid Build Coastguard Worker // Async task that handles the stats queue. Note that the cadence of this is driven by requests for
444*bb4ee6a4SAndroid Build Coastguard Worker // balloon stats from the control pipe.
445*bb4ee6a4SAndroid Build Coastguard Worker // The guests queues an initial buffer on boot, which is read and then this future will block until
446*bb4ee6a4SAndroid Build Coastguard Worker // signaled from the command socket that stats should be collected again.
handle_stats_queue( mut queue: Queue, mut queue_event: EventAsync, mut stats_rx: mpsc::Receiver<()>, command_tube: &AsyncTube, #[cfg(feature = "registered_events")] registered_evt_q: Option<&SendTubeAsync>, state: Arc<AsyncRwLock<BalloonState>>, mut stop_rx: oneshot::Receiver<()>, ) -> Queue447*bb4ee6a4SAndroid Build Coastguard Worker async fn handle_stats_queue(
448*bb4ee6a4SAndroid Build Coastguard Worker     mut queue: Queue,
449*bb4ee6a4SAndroid Build Coastguard Worker     mut queue_event: EventAsync,
450*bb4ee6a4SAndroid Build Coastguard Worker     mut stats_rx: mpsc::Receiver<()>,
451*bb4ee6a4SAndroid Build Coastguard Worker     command_tube: &AsyncTube,
452*bb4ee6a4SAndroid Build Coastguard Worker     #[cfg(feature = "registered_events")] registered_evt_q: Option<&SendTubeAsync>,
453*bb4ee6a4SAndroid Build Coastguard Worker     state: Arc<AsyncRwLock<BalloonState>>,
454*bb4ee6a4SAndroid Build Coastguard Worker     mut stop_rx: oneshot::Receiver<()>,
455*bb4ee6a4SAndroid Build Coastguard Worker ) -> Queue {
456*bb4ee6a4SAndroid Build Coastguard Worker     let mut avail_desc = match queue
457*bb4ee6a4SAndroid Build Coastguard Worker         .next_async_interruptable(&mut queue_event, &mut stop_rx)
458*bb4ee6a4SAndroid Build Coastguard Worker         .await
459*bb4ee6a4SAndroid Build Coastguard Worker     {
460*bb4ee6a4SAndroid Build Coastguard Worker         // Consume the first stats buffer sent from the guest at startup. It was not
461*bb4ee6a4SAndroid Build Coastguard Worker         // requested by anyone, and the stats are stale.
462*bb4ee6a4SAndroid Build Coastguard Worker         Ok(Some(res)) => res,
463*bb4ee6a4SAndroid Build Coastguard Worker         Ok(None) => return queue,
464*bb4ee6a4SAndroid Build Coastguard Worker         Err(e) => {
465*bb4ee6a4SAndroid Build Coastguard Worker             error!("Failed to read descriptor {}", e);
466*bb4ee6a4SAndroid Build Coastguard Worker             return queue;
467*bb4ee6a4SAndroid Build Coastguard Worker         }
468*bb4ee6a4SAndroid Build Coastguard Worker     };
469*bb4ee6a4SAndroid Build Coastguard Worker 
470*bb4ee6a4SAndroid Build Coastguard Worker     loop {
471*bb4ee6a4SAndroid Build Coastguard Worker         select_biased! {
472*bb4ee6a4SAndroid Build Coastguard Worker             msg = stats_rx.next() => {
473*bb4ee6a4SAndroid Build Coastguard Worker                 // Wait for a request to read the stats.
474*bb4ee6a4SAndroid Build Coastguard Worker                 match msg {
475*bb4ee6a4SAndroid Build Coastguard Worker                     Some(()) => (),
476*bb4ee6a4SAndroid Build Coastguard Worker                     None => {
477*bb4ee6a4SAndroid Build Coastguard Worker                         error!("stats signal channel was closed");
478*bb4ee6a4SAndroid Build Coastguard Worker                         return queue;
479*bb4ee6a4SAndroid Build Coastguard Worker                     }
480*bb4ee6a4SAndroid Build Coastguard Worker                 }
481*bb4ee6a4SAndroid Build Coastguard Worker             }
482*bb4ee6a4SAndroid Build Coastguard Worker             _ = stop_rx => return queue,
483*bb4ee6a4SAndroid Build Coastguard Worker         };
484*bb4ee6a4SAndroid Build Coastguard Worker 
485*bb4ee6a4SAndroid Build Coastguard Worker         // Request a new stats_desc to the guest.
486*bb4ee6a4SAndroid Build Coastguard Worker         queue.add_used(avail_desc, 0);
487*bb4ee6a4SAndroid Build Coastguard Worker         queue.trigger_interrupt();
488*bb4ee6a4SAndroid Build Coastguard Worker 
489*bb4ee6a4SAndroid Build Coastguard Worker         avail_desc = match queue.next_async(&mut queue_event).await {
490*bb4ee6a4SAndroid Build Coastguard Worker             Err(e) => {
491*bb4ee6a4SAndroid Build Coastguard Worker                 error!("Failed to read descriptor {}", e);
492*bb4ee6a4SAndroid Build Coastguard Worker                 return queue;
493*bb4ee6a4SAndroid Build Coastguard Worker             }
494*bb4ee6a4SAndroid Build Coastguard Worker             Ok(d) => d,
495*bb4ee6a4SAndroid Build Coastguard Worker         };
496*bb4ee6a4SAndroid Build Coastguard Worker         let stats = parse_balloon_stats(&mut avail_desc.reader);
497*bb4ee6a4SAndroid Build Coastguard Worker 
498*bb4ee6a4SAndroid Build Coastguard Worker         let actual_pages = state.lock().await.actual_pages as u64;
499*bb4ee6a4SAndroid Build Coastguard Worker         let result = BalloonTubeResult::Stats {
500*bb4ee6a4SAndroid Build Coastguard Worker             balloon_actual: actual_pages << VIRTIO_BALLOON_PFN_SHIFT,
501*bb4ee6a4SAndroid Build Coastguard Worker             stats,
502*bb4ee6a4SAndroid Build Coastguard Worker         };
503*bb4ee6a4SAndroid Build Coastguard Worker         let send_result = command_tube.send(result).await;
504*bb4ee6a4SAndroid Build Coastguard Worker         if let Err(e) = send_result {
505*bb4ee6a4SAndroid Build Coastguard Worker             error!("failed to send stats result: {}", e);
506*bb4ee6a4SAndroid Build Coastguard Worker         }
507*bb4ee6a4SAndroid Build Coastguard Worker 
508*bb4ee6a4SAndroid Build Coastguard Worker         #[cfg(feature = "registered_events")]
509*bb4ee6a4SAndroid Build Coastguard Worker         if let Some(registered_evt_q) = registered_evt_q {
510*bb4ee6a4SAndroid Build Coastguard Worker             if let Err(e) = registered_evt_q
511*bb4ee6a4SAndroid Build Coastguard Worker                 .send(&RegisteredEventWithData::VirtioBalloonResize)
512*bb4ee6a4SAndroid Build Coastguard Worker                 .await
513*bb4ee6a4SAndroid Build Coastguard Worker             {
514*bb4ee6a4SAndroid Build Coastguard Worker                 error!("failed to send VirtioBalloonResize event: {}", e);
515*bb4ee6a4SAndroid Build Coastguard Worker             }
516*bb4ee6a4SAndroid Build Coastguard Worker         }
517*bb4ee6a4SAndroid Build Coastguard Worker     }
518*bb4ee6a4SAndroid Build Coastguard Worker }
519*bb4ee6a4SAndroid Build Coastguard Worker 
send_adjusted_response( tube: &AsyncTube, num_pages: u32, ) -> std::result::Result<(), base::TubeError>520*bb4ee6a4SAndroid Build Coastguard Worker async fn send_adjusted_response(
521*bb4ee6a4SAndroid Build Coastguard Worker     tube: &AsyncTube,
522*bb4ee6a4SAndroid Build Coastguard Worker     num_pages: u32,
523*bb4ee6a4SAndroid Build Coastguard Worker ) -> std::result::Result<(), base::TubeError> {
524*bb4ee6a4SAndroid Build Coastguard Worker     let num_bytes = (num_pages as u64) << VIRTIO_BALLOON_PFN_SHIFT;
525*bb4ee6a4SAndroid Build Coastguard Worker     let result = BalloonTubeResult::Adjusted { num_bytes };
526*bb4ee6a4SAndroid Build Coastguard Worker     tube.send(result).await
527*bb4ee6a4SAndroid Build Coastguard Worker }
528*bb4ee6a4SAndroid Build Coastguard Worker 
529*bb4ee6a4SAndroid Build Coastguard Worker enum WSOp {
530*bb4ee6a4SAndroid Build Coastguard Worker     WSReport,
531*bb4ee6a4SAndroid Build Coastguard Worker     WSConfig {
532*bb4ee6a4SAndroid Build Coastguard Worker         bins: Vec<u32>,
533*bb4ee6a4SAndroid Build Coastguard Worker         refresh_threshold: u32,
534*bb4ee6a4SAndroid Build Coastguard Worker         report_threshold: u32,
535*bb4ee6a4SAndroid Build Coastguard Worker     },
536*bb4ee6a4SAndroid Build Coastguard Worker }
537*bb4ee6a4SAndroid Build Coastguard Worker 
handle_ws_op_queue( mut queue: Queue, mut queue_event: EventAsync, mut ws_op_rx: mpsc::Receiver<WSOp>, state: Arc<AsyncRwLock<BalloonState>>, mut stop_rx: oneshot::Receiver<()>, ) -> Result<Queue>538*bb4ee6a4SAndroid Build Coastguard Worker async fn handle_ws_op_queue(
539*bb4ee6a4SAndroid Build Coastguard Worker     mut queue: Queue,
540*bb4ee6a4SAndroid Build Coastguard Worker     mut queue_event: EventAsync,
541*bb4ee6a4SAndroid Build Coastguard Worker     mut ws_op_rx: mpsc::Receiver<WSOp>,
542*bb4ee6a4SAndroid Build Coastguard Worker     state: Arc<AsyncRwLock<BalloonState>>,
543*bb4ee6a4SAndroid Build Coastguard Worker     mut stop_rx: oneshot::Receiver<()>,
544*bb4ee6a4SAndroid Build Coastguard Worker ) -> Result<Queue> {
545*bb4ee6a4SAndroid Build Coastguard Worker     loop {
546*bb4ee6a4SAndroid Build Coastguard Worker         let op = select_biased! {
547*bb4ee6a4SAndroid Build Coastguard Worker             next_op = ws_op_rx.next().fuse() => {
548*bb4ee6a4SAndroid Build Coastguard Worker                 match next_op {
549*bb4ee6a4SAndroid Build Coastguard Worker                     Some(op) => op,
550*bb4ee6a4SAndroid Build Coastguard Worker                     None => {
551*bb4ee6a4SAndroid Build Coastguard Worker                         error!("ws op tube was closed");
552*bb4ee6a4SAndroid Build Coastguard Worker                         break;
553*bb4ee6a4SAndroid Build Coastguard Worker                     }
554*bb4ee6a4SAndroid Build Coastguard Worker                 }
555*bb4ee6a4SAndroid Build Coastguard Worker             }
556*bb4ee6a4SAndroid Build Coastguard Worker             _ = stop_rx => {
557*bb4ee6a4SAndroid Build Coastguard Worker                 break;
558*bb4ee6a4SAndroid Build Coastguard Worker             }
559*bb4ee6a4SAndroid Build Coastguard Worker         };
560*bb4ee6a4SAndroid Build Coastguard Worker         let mut avail_desc = queue
561*bb4ee6a4SAndroid Build Coastguard Worker             .next_async(&mut queue_event)
562*bb4ee6a4SAndroid Build Coastguard Worker             .await
563*bb4ee6a4SAndroid Build Coastguard Worker             .map_err(BalloonError::AsyncAwait)?;
564*bb4ee6a4SAndroid Build Coastguard Worker         let writer = &mut avail_desc.writer;
565*bb4ee6a4SAndroid Build Coastguard Worker 
566*bb4ee6a4SAndroid Build Coastguard Worker         match op {
567*bb4ee6a4SAndroid Build Coastguard Worker             WSOp::WSReport => {
568*bb4ee6a4SAndroid Build Coastguard Worker                 {
569*bb4ee6a4SAndroid Build Coastguard Worker                     let mut state = state.lock().await;
570*bb4ee6a4SAndroid Build Coastguard Worker                     state.expecting_ws = true;
571*bb4ee6a4SAndroid Build Coastguard Worker                 }
572*bb4ee6a4SAndroid Build Coastguard Worker 
573*bb4ee6a4SAndroid Build Coastguard Worker                 let ws_r = virtio_balloon_op {
574*bb4ee6a4SAndroid Build Coastguard Worker                     type_: VIRTIO_BALLOON_WS_OP_REQUEST.into(),
575*bb4ee6a4SAndroid Build Coastguard Worker                 };
576*bb4ee6a4SAndroid Build Coastguard Worker 
577*bb4ee6a4SAndroid Build Coastguard Worker                 writer.write_obj(ws_r).map_err(BalloonError::WriteQueue)?;
578*bb4ee6a4SAndroid Build Coastguard Worker             }
579*bb4ee6a4SAndroid Build Coastguard Worker             WSOp::WSConfig {
580*bb4ee6a4SAndroid Build Coastguard Worker                 bins,
581*bb4ee6a4SAndroid Build Coastguard Worker                 refresh_threshold,
582*bb4ee6a4SAndroid Build Coastguard Worker                 report_threshold,
583*bb4ee6a4SAndroid Build Coastguard Worker             } => {
584*bb4ee6a4SAndroid Build Coastguard Worker                 let cmd = virtio_balloon_op {
585*bb4ee6a4SAndroid Build Coastguard Worker                     type_: VIRTIO_BALLOON_WS_OP_CONFIG.into(),
586*bb4ee6a4SAndroid Build Coastguard Worker                 };
587*bb4ee6a4SAndroid Build Coastguard Worker 
588*bb4ee6a4SAndroid Build Coastguard Worker                 writer.write_obj(cmd).map_err(BalloonError::WriteQueue)?;
589*bb4ee6a4SAndroid Build Coastguard Worker                 writer
590*bb4ee6a4SAndroid Build Coastguard Worker                     .write_all(bins.as_bytes())
591*bb4ee6a4SAndroid Build Coastguard Worker                     .map_err(BalloonError::WriteQueue)?;
592*bb4ee6a4SAndroid Build Coastguard Worker                 writer
593*bb4ee6a4SAndroid Build Coastguard Worker                     .write_obj(refresh_threshold)
594*bb4ee6a4SAndroid Build Coastguard Worker                     .map_err(BalloonError::WriteQueue)?;
595*bb4ee6a4SAndroid Build Coastguard Worker                 writer
596*bb4ee6a4SAndroid Build Coastguard Worker                     .write_obj(report_threshold)
597*bb4ee6a4SAndroid Build Coastguard Worker                     .map_err(BalloonError::WriteQueue)?;
598*bb4ee6a4SAndroid Build Coastguard Worker             }
599*bb4ee6a4SAndroid Build Coastguard Worker         }
600*bb4ee6a4SAndroid Build Coastguard Worker 
601*bb4ee6a4SAndroid Build Coastguard Worker         let len = writer.bytes_written() as u32;
602*bb4ee6a4SAndroid Build Coastguard Worker         queue.add_used(avail_desc, len);
603*bb4ee6a4SAndroid Build Coastguard Worker         queue.trigger_interrupt();
604*bb4ee6a4SAndroid Build Coastguard Worker     }
605*bb4ee6a4SAndroid Build Coastguard Worker 
606*bb4ee6a4SAndroid Build Coastguard Worker     Ok(queue)
607*bb4ee6a4SAndroid Build Coastguard Worker }
608*bb4ee6a4SAndroid Build Coastguard Worker 
parse_balloon_ws(reader: &mut Reader) -> BalloonWS609*bb4ee6a4SAndroid Build Coastguard Worker fn parse_balloon_ws(reader: &mut Reader) -> BalloonWS {
610*bb4ee6a4SAndroid Build Coastguard Worker     let mut ws = BalloonWS::new();
611*bb4ee6a4SAndroid Build Coastguard Worker     for res in reader.iter::<virtio_balloon_ws>() {
612*bb4ee6a4SAndroid Build Coastguard Worker         match res {
613*bb4ee6a4SAndroid Build Coastguard Worker             Ok(ws_msg) => {
614*bb4ee6a4SAndroid Build Coastguard Worker                 ws_msg.update_ws(&mut ws);
615*bb4ee6a4SAndroid Build Coastguard Worker             }
616*bb4ee6a4SAndroid Build Coastguard Worker             Err(e) => {
617*bb4ee6a4SAndroid Build Coastguard Worker                 error!("error while reading ws: {}", e);
618*bb4ee6a4SAndroid Build Coastguard Worker                 break;
619*bb4ee6a4SAndroid Build Coastguard Worker             }
620*bb4ee6a4SAndroid Build Coastguard Worker         }
621*bb4ee6a4SAndroid Build Coastguard Worker     }
622*bb4ee6a4SAndroid Build Coastguard Worker     if ws.ws.len() < VIRTIO_BALLOON_WS_MIN_NUM_BINS || ws.ws.len() > VIRTIO_BALLOON_WS_MAX_NUM_BINS
623*bb4ee6a4SAndroid Build Coastguard Worker     {
624*bb4ee6a4SAndroid Build Coastguard Worker         error!("unexpected number of WS buckets: {}", ws.ws.len());
625*bb4ee6a4SAndroid Build Coastguard Worker     }
626*bb4ee6a4SAndroid Build Coastguard Worker     ws
627*bb4ee6a4SAndroid Build Coastguard Worker }
628*bb4ee6a4SAndroid Build Coastguard Worker 
629*bb4ee6a4SAndroid Build Coastguard Worker // Async task that handles the stats queue. Note that the arrival of events on
630*bb4ee6a4SAndroid Build Coastguard Worker // the WS vq may be the result of either a WS request (WS-R) command having
631*bb4ee6a4SAndroid Build Coastguard Worker // been sent to the guest, or an unprompted send due to memory pressue in the
632*bb4ee6a4SAndroid Build Coastguard Worker // guest. If the data was requested, we should also send that back on the
633*bb4ee6a4SAndroid Build Coastguard Worker // command tube.
handle_ws_data_queue( mut queue: Queue, mut queue_event: EventAsync, command_tube: &AsyncTube, #[cfg(feature = "registered_events")] registered_evt_q: Option<&SendTubeAsync>, state: Arc<AsyncRwLock<BalloonState>>, mut stop_rx: oneshot::Receiver<()>, ) -> Result<Queue>634*bb4ee6a4SAndroid Build Coastguard Worker async fn handle_ws_data_queue(
635*bb4ee6a4SAndroid Build Coastguard Worker     mut queue: Queue,
636*bb4ee6a4SAndroid Build Coastguard Worker     mut queue_event: EventAsync,
637*bb4ee6a4SAndroid Build Coastguard Worker     command_tube: &AsyncTube,
638*bb4ee6a4SAndroid Build Coastguard Worker     #[cfg(feature = "registered_events")] registered_evt_q: Option<&SendTubeAsync>,
639*bb4ee6a4SAndroid Build Coastguard Worker     state: Arc<AsyncRwLock<BalloonState>>,
640*bb4ee6a4SAndroid Build Coastguard Worker     mut stop_rx: oneshot::Receiver<()>,
641*bb4ee6a4SAndroid Build Coastguard Worker ) -> Result<Queue> {
642*bb4ee6a4SAndroid Build Coastguard Worker     loop {
643*bb4ee6a4SAndroid Build Coastguard Worker         let mut avail_desc = match queue
644*bb4ee6a4SAndroid Build Coastguard Worker             .next_async_interruptable(&mut queue_event, &mut stop_rx)
645*bb4ee6a4SAndroid Build Coastguard Worker             .await
646*bb4ee6a4SAndroid Build Coastguard Worker             .map_err(BalloonError::AsyncAwait)?
647*bb4ee6a4SAndroid Build Coastguard Worker         {
648*bb4ee6a4SAndroid Build Coastguard Worker             Some(res) => res,
649*bb4ee6a4SAndroid Build Coastguard Worker             None => return Ok(queue),
650*bb4ee6a4SAndroid Build Coastguard Worker         };
651*bb4ee6a4SAndroid Build Coastguard Worker 
652*bb4ee6a4SAndroid Build Coastguard Worker         let ws = parse_balloon_ws(&mut avail_desc.reader);
653*bb4ee6a4SAndroid Build Coastguard Worker 
654*bb4ee6a4SAndroid Build Coastguard Worker         let mut state = state.lock().await;
655*bb4ee6a4SAndroid Build Coastguard Worker 
656*bb4ee6a4SAndroid Build Coastguard Worker         // update ws report with balloon pages now that we have a lock on state
657*bb4ee6a4SAndroid Build Coastguard Worker         let balloon_actual = (state.actual_pages as u64) << VIRTIO_BALLOON_PFN_SHIFT;
658*bb4ee6a4SAndroid Build Coastguard Worker 
659*bb4ee6a4SAndroid Build Coastguard Worker         if state.expecting_ws {
660*bb4ee6a4SAndroid Build Coastguard Worker             let result = BalloonTubeResult::WorkingSet { ws, balloon_actual };
661*bb4ee6a4SAndroid Build Coastguard Worker             let send_result = command_tube.send(result).await;
662*bb4ee6a4SAndroid Build Coastguard Worker             if let Err(e) = send_result {
663*bb4ee6a4SAndroid Build Coastguard Worker                 error!("failed to send ws result: {}", e);
664*bb4ee6a4SAndroid Build Coastguard Worker             }
665*bb4ee6a4SAndroid Build Coastguard Worker 
666*bb4ee6a4SAndroid Build Coastguard Worker             state.expecting_ws = false;
667*bb4ee6a4SAndroid Build Coastguard Worker         } else {
668*bb4ee6a4SAndroid Build Coastguard Worker             #[cfg(feature = "registered_events")]
669*bb4ee6a4SAndroid Build Coastguard Worker             if let Some(registered_evt_q) = registered_evt_q {
670*bb4ee6a4SAndroid Build Coastguard Worker                 if let Err(e) = registered_evt_q
671*bb4ee6a4SAndroid Build Coastguard Worker                     .send(RegisteredEventWithData::from_ws(&ws, balloon_actual))
672*bb4ee6a4SAndroid Build Coastguard Worker                     .await
673*bb4ee6a4SAndroid Build Coastguard Worker                 {
674*bb4ee6a4SAndroid Build Coastguard Worker                     error!("failed to send VirtioBalloonWSReport event: {}", e);
675*bb4ee6a4SAndroid Build Coastguard Worker                 }
676*bb4ee6a4SAndroid Build Coastguard Worker             }
677*bb4ee6a4SAndroid Build Coastguard Worker         }
678*bb4ee6a4SAndroid Build Coastguard Worker 
679*bb4ee6a4SAndroid Build Coastguard Worker         queue.add_used(avail_desc, 0);
680*bb4ee6a4SAndroid Build Coastguard Worker         queue.trigger_interrupt();
681*bb4ee6a4SAndroid Build Coastguard Worker     }
682*bb4ee6a4SAndroid Build Coastguard Worker }
683*bb4ee6a4SAndroid Build Coastguard Worker 
684*bb4ee6a4SAndroid Build Coastguard Worker // Async task that handles the command socket. The command socket handles messages from the host
685*bb4ee6a4SAndroid Build Coastguard Worker // requesting that the guest balloon be adjusted or to report guest memory statistics.
handle_command_tube( command_tube: &AsyncTube, interrupt: Interrupt, state: Arc<AsyncRwLock<BalloonState>>, mut stats_tx: mpsc::Sender<()>, mut ws_op_tx: mpsc::Sender<WSOp>, mut stop_rx: oneshot::Receiver<()>, ) -> Result<()>686*bb4ee6a4SAndroid Build Coastguard Worker async fn handle_command_tube(
687*bb4ee6a4SAndroid Build Coastguard Worker     command_tube: &AsyncTube,
688*bb4ee6a4SAndroid Build Coastguard Worker     interrupt: Interrupt,
689*bb4ee6a4SAndroid Build Coastguard Worker     state: Arc<AsyncRwLock<BalloonState>>,
690*bb4ee6a4SAndroid Build Coastguard Worker     mut stats_tx: mpsc::Sender<()>,
691*bb4ee6a4SAndroid Build Coastguard Worker     mut ws_op_tx: mpsc::Sender<WSOp>,
692*bb4ee6a4SAndroid Build Coastguard Worker     mut stop_rx: oneshot::Receiver<()>,
693*bb4ee6a4SAndroid Build Coastguard Worker ) -> Result<()> {
694*bb4ee6a4SAndroid Build Coastguard Worker     loop {
695*bb4ee6a4SAndroid Build Coastguard Worker         let cmd_res = select_biased! {
696*bb4ee6a4SAndroid Build Coastguard Worker             res = command_tube.next().fuse() => res,
697*bb4ee6a4SAndroid Build Coastguard Worker             _ = stop_rx => return Ok(())
698*bb4ee6a4SAndroid Build Coastguard Worker         };
699*bb4ee6a4SAndroid Build Coastguard Worker         match cmd_res {
700*bb4ee6a4SAndroid Build Coastguard Worker             Ok(command) => match command {
701*bb4ee6a4SAndroid Build Coastguard Worker                 BalloonTubeCommand::Adjust {
702*bb4ee6a4SAndroid Build Coastguard Worker                     num_bytes,
703*bb4ee6a4SAndroid Build Coastguard Worker                     allow_failure,
704*bb4ee6a4SAndroid Build Coastguard Worker                 } => {
705*bb4ee6a4SAndroid Build Coastguard Worker                     let num_pages = (num_bytes >> VIRTIO_BALLOON_PFN_SHIFT) as u32;
706*bb4ee6a4SAndroid Build Coastguard Worker                     let mut state = state.lock().await;
707*bb4ee6a4SAndroid Build Coastguard Worker 
708*bb4ee6a4SAndroid Build Coastguard Worker                     state.num_pages = num_pages;
709*bb4ee6a4SAndroid Build Coastguard Worker                     interrupt.signal_config_changed();
710*bb4ee6a4SAndroid Build Coastguard Worker 
711*bb4ee6a4SAndroid Build Coastguard Worker                     if allow_failure {
712*bb4ee6a4SAndroid Build Coastguard Worker                         if num_pages == state.actual_pages {
713*bb4ee6a4SAndroid Build Coastguard Worker                             send_adjusted_response(command_tube, num_pages)
714*bb4ee6a4SAndroid Build Coastguard Worker                                 .await
715*bb4ee6a4SAndroid Build Coastguard Worker                                 .map_err(BalloonError::SendResponse)?;
716*bb4ee6a4SAndroid Build Coastguard Worker                         } else {
717*bb4ee6a4SAndroid Build Coastguard Worker                             state.failable_update = true;
718*bb4ee6a4SAndroid Build Coastguard Worker                         }
719*bb4ee6a4SAndroid Build Coastguard Worker                     }
720*bb4ee6a4SAndroid Build Coastguard Worker                 }
721*bb4ee6a4SAndroid Build Coastguard Worker                 BalloonTubeCommand::WorkingSetConfig {
722*bb4ee6a4SAndroid Build Coastguard Worker                     bins,
723*bb4ee6a4SAndroid Build Coastguard Worker                     refresh_threshold,
724*bb4ee6a4SAndroid Build Coastguard Worker                     report_threshold,
725*bb4ee6a4SAndroid Build Coastguard Worker                 } => {
726*bb4ee6a4SAndroid Build Coastguard Worker                     if let Err(e) = ws_op_tx.try_send(WSOp::WSConfig {
727*bb4ee6a4SAndroid Build Coastguard Worker                         bins,
728*bb4ee6a4SAndroid Build Coastguard Worker                         refresh_threshold,
729*bb4ee6a4SAndroid Build Coastguard Worker                         report_threshold,
730*bb4ee6a4SAndroid Build Coastguard Worker                     }) {
731*bb4ee6a4SAndroid Build Coastguard Worker                         error!("failed to send config to ws handler: {}", e);
732*bb4ee6a4SAndroid Build Coastguard Worker                     }
733*bb4ee6a4SAndroid Build Coastguard Worker                 }
734*bb4ee6a4SAndroid Build Coastguard Worker                 BalloonTubeCommand::Stats => {
735*bb4ee6a4SAndroid Build Coastguard Worker                     if let Err(e) = stats_tx.try_send(()) {
736*bb4ee6a4SAndroid Build Coastguard Worker                         error!("failed to signal the stat handler: {}", e);
737*bb4ee6a4SAndroid Build Coastguard Worker                     }
738*bb4ee6a4SAndroid Build Coastguard Worker                 }
739*bb4ee6a4SAndroid Build Coastguard Worker                 BalloonTubeCommand::WorkingSet => {
740*bb4ee6a4SAndroid Build Coastguard Worker                     if let Err(e) = ws_op_tx.try_send(WSOp::WSReport) {
741*bb4ee6a4SAndroid Build Coastguard Worker                         error!("failed to send report request to ws handler: {}", e);
742*bb4ee6a4SAndroid Build Coastguard Worker                     }
743*bb4ee6a4SAndroid Build Coastguard Worker                 }
744*bb4ee6a4SAndroid Build Coastguard Worker             },
745*bb4ee6a4SAndroid Build Coastguard Worker             #[cfg(windows)]
746*bb4ee6a4SAndroid Build Coastguard Worker             Err(base::TubeError::Recv(e)) if e.kind() == std::io::ErrorKind::TimedOut => {
747*bb4ee6a4SAndroid Build Coastguard Worker                 // On Windows, async IO tasks like the next/recv above are cancelled as the VM is
748*bb4ee6a4SAndroid Build Coastguard Worker                 // shutting down. For the sake of consistency with unix, we can't *just* return
749*bb4ee6a4SAndroid Build Coastguard Worker                 // here; instead, we wait for the stop request to arrive, *and then* return.
750*bb4ee6a4SAndroid Build Coastguard Worker                 //
751*bb4ee6a4SAndroid Build Coastguard Worker                 // The real fix is to get rid of the global unblock pool, since then we won't
752*bb4ee6a4SAndroid Build Coastguard Worker                 // cancel the tasks early (b/196911556).
753*bb4ee6a4SAndroid Build Coastguard Worker                 let _ = stop_rx.await;
754*bb4ee6a4SAndroid Build Coastguard Worker                 return Ok(());
755*bb4ee6a4SAndroid Build Coastguard Worker             }
756*bb4ee6a4SAndroid Build Coastguard Worker             Err(e) => {
757*bb4ee6a4SAndroid Build Coastguard Worker                 return Err(BalloonError::ReceivingCommand(e));
758*bb4ee6a4SAndroid Build Coastguard Worker             }
759*bb4ee6a4SAndroid Build Coastguard Worker         }
760*bb4ee6a4SAndroid Build Coastguard Worker     }
761*bb4ee6a4SAndroid Build Coastguard Worker }
762*bb4ee6a4SAndroid Build Coastguard Worker 
handle_pending_adjusted_responses( pending_adjusted_response_event: EventAsync, command_tube: &AsyncTube, state: Arc<AsyncRwLock<BalloonState>>, ) -> Result<()>763*bb4ee6a4SAndroid Build Coastguard Worker async fn handle_pending_adjusted_responses(
764*bb4ee6a4SAndroid Build Coastguard Worker     pending_adjusted_response_event: EventAsync,
765*bb4ee6a4SAndroid Build Coastguard Worker     command_tube: &AsyncTube,
766*bb4ee6a4SAndroid Build Coastguard Worker     state: Arc<AsyncRwLock<BalloonState>>,
767*bb4ee6a4SAndroid Build Coastguard Worker ) -> Result<()> {
768*bb4ee6a4SAndroid Build Coastguard Worker     loop {
769*bb4ee6a4SAndroid Build Coastguard Worker         pending_adjusted_response_event
770*bb4ee6a4SAndroid Build Coastguard Worker             .next_val()
771*bb4ee6a4SAndroid Build Coastguard Worker             .await
772*bb4ee6a4SAndroid Build Coastguard Worker             .map_err(BalloonError::AsyncAwait)?;
773*bb4ee6a4SAndroid Build Coastguard Worker         while let Some(num_pages) = state.lock().await.pending_adjusted_responses.pop_front() {
774*bb4ee6a4SAndroid Build Coastguard Worker             send_adjusted_response(command_tube, num_pages)
775*bb4ee6a4SAndroid Build Coastguard Worker                 .await
776*bb4ee6a4SAndroid Build Coastguard Worker                 .map_err(BalloonError::SendResponse)?;
777*bb4ee6a4SAndroid Build Coastguard Worker         }
778*bb4ee6a4SAndroid Build Coastguard Worker     }
779*bb4ee6a4SAndroid Build Coastguard Worker }
780*bb4ee6a4SAndroid Build Coastguard Worker 
781*bb4ee6a4SAndroid Build Coastguard Worker /// Represents queues & events for the balloon device.
782*bb4ee6a4SAndroid Build Coastguard Worker struct BalloonQueues {
783*bb4ee6a4SAndroid Build Coastguard Worker     inflate: Queue,
784*bb4ee6a4SAndroid Build Coastguard Worker     deflate: Queue,
785*bb4ee6a4SAndroid Build Coastguard Worker     stats: Option<Queue>,
786*bb4ee6a4SAndroid Build Coastguard Worker     reporting: Option<Queue>,
787*bb4ee6a4SAndroid Build Coastguard Worker     ws_data: Option<Queue>,
788*bb4ee6a4SAndroid Build Coastguard Worker     ws_op: Option<Queue>,
789*bb4ee6a4SAndroid Build Coastguard Worker }
790*bb4ee6a4SAndroid Build Coastguard Worker 
791*bb4ee6a4SAndroid Build Coastguard Worker impl BalloonQueues {
new(inflate: Queue, deflate: Queue) -> Self792*bb4ee6a4SAndroid Build Coastguard Worker     fn new(inflate: Queue, deflate: Queue) -> Self {
793*bb4ee6a4SAndroid Build Coastguard Worker         BalloonQueues {
794*bb4ee6a4SAndroid Build Coastguard Worker             inflate,
795*bb4ee6a4SAndroid Build Coastguard Worker             deflate,
796*bb4ee6a4SAndroid Build Coastguard Worker             stats: None,
797*bb4ee6a4SAndroid Build Coastguard Worker             reporting: None,
798*bb4ee6a4SAndroid Build Coastguard Worker             ws_data: None,
799*bb4ee6a4SAndroid Build Coastguard Worker             ws_op: None,
800*bb4ee6a4SAndroid Build Coastguard Worker         }
801*bb4ee6a4SAndroid Build Coastguard Worker     }
802*bb4ee6a4SAndroid Build Coastguard Worker }
803*bb4ee6a4SAndroid Build Coastguard Worker 
804*bb4ee6a4SAndroid Build Coastguard Worker /// When the worker is stopped, the queues are preserved here.
805*bb4ee6a4SAndroid Build Coastguard Worker struct PausedQueues {
806*bb4ee6a4SAndroid Build Coastguard Worker     inflate: Queue,
807*bb4ee6a4SAndroid Build Coastguard Worker     deflate: Queue,
808*bb4ee6a4SAndroid Build Coastguard Worker     stats: Option<Queue>,
809*bb4ee6a4SAndroid Build Coastguard Worker     reporting: Option<Queue>,
810*bb4ee6a4SAndroid Build Coastguard Worker     ws_data: Option<Queue>,
811*bb4ee6a4SAndroid Build Coastguard Worker     ws_op: Option<Queue>,
812*bb4ee6a4SAndroid Build Coastguard Worker }
813*bb4ee6a4SAndroid Build Coastguard Worker 
814*bb4ee6a4SAndroid Build Coastguard Worker impl PausedQueues {
new(inflate: Queue, deflate: Queue) -> Self815*bb4ee6a4SAndroid Build Coastguard Worker     fn new(inflate: Queue, deflate: Queue) -> Self {
816*bb4ee6a4SAndroid Build Coastguard Worker         PausedQueues {
817*bb4ee6a4SAndroid Build Coastguard Worker             inflate,
818*bb4ee6a4SAndroid Build Coastguard Worker             deflate,
819*bb4ee6a4SAndroid Build Coastguard Worker             stats: None,
820*bb4ee6a4SAndroid Build Coastguard Worker             reporting: None,
821*bb4ee6a4SAndroid Build Coastguard Worker             ws_data: None,
822*bb4ee6a4SAndroid Build Coastguard Worker             ws_op: None,
823*bb4ee6a4SAndroid Build Coastguard Worker         }
824*bb4ee6a4SAndroid Build Coastguard Worker     }
825*bb4ee6a4SAndroid Build Coastguard Worker }
826*bb4ee6a4SAndroid Build Coastguard Worker 
apply_if_some<F, R>(queue_opt: Option<Queue>, mut func: F) where F: FnMut(Queue) -> R,827*bb4ee6a4SAndroid Build Coastguard Worker fn apply_if_some<F, R>(queue_opt: Option<Queue>, mut func: F)
828*bb4ee6a4SAndroid Build Coastguard Worker where
829*bb4ee6a4SAndroid Build Coastguard Worker     F: FnMut(Queue) -> R,
830*bb4ee6a4SAndroid Build Coastguard Worker {
831*bb4ee6a4SAndroid Build Coastguard Worker     if let Some(queue) = queue_opt {
832*bb4ee6a4SAndroid Build Coastguard Worker         func(queue);
833*bb4ee6a4SAndroid Build Coastguard Worker     }
834*bb4ee6a4SAndroid Build Coastguard Worker }
835*bb4ee6a4SAndroid Build Coastguard Worker 
836*bb4ee6a4SAndroid Build Coastguard Worker impl From<Box<PausedQueues>> for BTreeMap<usize, Queue> {
from(queues: Box<PausedQueues>) -> BTreeMap<usize, Queue>837*bb4ee6a4SAndroid Build Coastguard Worker     fn from(queues: Box<PausedQueues>) -> BTreeMap<usize, Queue> {
838*bb4ee6a4SAndroid Build Coastguard Worker         let mut ret = Vec::new();
839*bb4ee6a4SAndroid Build Coastguard Worker         ret.push(queues.inflate);
840*bb4ee6a4SAndroid Build Coastguard Worker         ret.push(queues.deflate);
841*bb4ee6a4SAndroid Build Coastguard Worker         apply_if_some(queues.stats, |stats| ret.push(stats));
842*bb4ee6a4SAndroid Build Coastguard Worker         apply_if_some(queues.reporting, |reporting| ret.push(reporting));
843*bb4ee6a4SAndroid Build Coastguard Worker         apply_if_some(queues.ws_data, |ws_data| ret.push(ws_data));
844*bb4ee6a4SAndroid Build Coastguard Worker         apply_if_some(queues.ws_op, |ws_op| ret.push(ws_op));
845*bb4ee6a4SAndroid Build Coastguard Worker         // WARNING: We don't use the indices from the virito spec on purpose, see comment in
846*bb4ee6a4SAndroid Build Coastguard Worker         // get_queues_from_map for the rationale.
847*bb4ee6a4SAndroid Build Coastguard Worker         ret.into_iter().enumerate().collect()
848*bb4ee6a4SAndroid Build Coastguard Worker     }
849*bb4ee6a4SAndroid Build Coastguard Worker }
850*bb4ee6a4SAndroid Build Coastguard Worker 
851*bb4ee6a4SAndroid Build Coastguard Worker /// Stores data from the worker when it stops so that data can be re-used when
852*bb4ee6a4SAndroid Build Coastguard Worker /// the worker is restarted.
853*bb4ee6a4SAndroid Build Coastguard Worker struct WorkerReturn {
854*bb4ee6a4SAndroid Build Coastguard Worker     release_memory_tube: Option<Tube>,
855*bb4ee6a4SAndroid Build Coastguard Worker     command_tube: Tube,
856*bb4ee6a4SAndroid Build Coastguard Worker     #[cfg(feature = "registered_events")]
857*bb4ee6a4SAndroid Build Coastguard Worker     registered_evt_q: Option<SendTube>,
858*bb4ee6a4SAndroid Build Coastguard Worker     paused_queues: Option<PausedQueues>,
859*bb4ee6a4SAndroid Build Coastguard Worker     #[cfg(windows)]
860*bb4ee6a4SAndroid Build Coastguard Worker     vm_memory_client: VmMemoryClient,
861*bb4ee6a4SAndroid Build Coastguard Worker }
862*bb4ee6a4SAndroid Build Coastguard Worker 
863*bb4ee6a4SAndroid Build Coastguard Worker // The main worker thread. Initialized the asynchronous worker tasks and passes them to the executor
864*bb4ee6a4SAndroid Build Coastguard Worker // to be processed.
run_worker( inflate_queue: Queue, deflate_queue: Queue, stats_queue: Option<Queue>, reporting_queue: Option<Queue>, ws_data_queue: Option<Queue>, ws_op_queue: Option<Queue>, command_tube: Tube, #[cfg(windows)] vm_memory_client: VmMemoryClient, release_memory_tube: Option<Tube>, interrupt: Interrupt, kill_evt: Event, target_reached_evt: Event, pending_adjusted_response_event: Event, mem: GuestMemory, state: Arc<AsyncRwLock<BalloonState>>, #[cfg(feature = "registered_events")] registered_evt_q: Option<SendTube>, ) -> WorkerReturn865*bb4ee6a4SAndroid Build Coastguard Worker fn run_worker(
866*bb4ee6a4SAndroid Build Coastguard Worker     inflate_queue: Queue,
867*bb4ee6a4SAndroid Build Coastguard Worker     deflate_queue: Queue,
868*bb4ee6a4SAndroid Build Coastguard Worker     stats_queue: Option<Queue>,
869*bb4ee6a4SAndroid Build Coastguard Worker     reporting_queue: Option<Queue>,
870*bb4ee6a4SAndroid Build Coastguard Worker     ws_data_queue: Option<Queue>,
871*bb4ee6a4SAndroid Build Coastguard Worker     ws_op_queue: Option<Queue>,
872*bb4ee6a4SAndroid Build Coastguard Worker     command_tube: Tube,
873*bb4ee6a4SAndroid Build Coastguard Worker     #[cfg(windows)] vm_memory_client: VmMemoryClient,
874*bb4ee6a4SAndroid Build Coastguard Worker     release_memory_tube: Option<Tube>,
875*bb4ee6a4SAndroid Build Coastguard Worker     interrupt: Interrupt,
876*bb4ee6a4SAndroid Build Coastguard Worker     kill_evt: Event,
877*bb4ee6a4SAndroid Build Coastguard Worker     target_reached_evt: Event,
878*bb4ee6a4SAndroid Build Coastguard Worker     pending_adjusted_response_event: Event,
879*bb4ee6a4SAndroid Build Coastguard Worker     mem: GuestMemory,
880*bb4ee6a4SAndroid Build Coastguard Worker     state: Arc<AsyncRwLock<BalloonState>>,
881*bb4ee6a4SAndroid Build Coastguard Worker     #[cfg(feature = "registered_events")] registered_evt_q: Option<SendTube>,
882*bb4ee6a4SAndroid Build Coastguard Worker ) -> WorkerReturn {
883*bb4ee6a4SAndroid Build Coastguard Worker     let ex = Executor::new().unwrap();
884*bb4ee6a4SAndroid Build Coastguard Worker     let command_tube = AsyncTube::new(&ex, command_tube).unwrap();
885*bb4ee6a4SAndroid Build Coastguard Worker     #[cfg(feature = "registered_events")]
886*bb4ee6a4SAndroid Build Coastguard Worker     let registered_evt_q_async = registered_evt_q
887*bb4ee6a4SAndroid Build Coastguard Worker         .as_ref()
888*bb4ee6a4SAndroid Build Coastguard Worker         .map(|q| SendTubeAsync::new(q.try_clone().unwrap(), &ex).unwrap());
889*bb4ee6a4SAndroid Build Coastguard Worker 
890*bb4ee6a4SAndroid Build Coastguard Worker     let mut stop_queue_oneshots = Vec::new();
891*bb4ee6a4SAndroid Build Coastguard Worker 
892*bb4ee6a4SAndroid Build Coastguard Worker     // We need a block to release all references to command_tube at the end before returning it.
893*bb4ee6a4SAndroid Build Coastguard Worker     let paused_queues = {
894*bb4ee6a4SAndroid Build Coastguard Worker         // The first queue is used for inflate messages
895*bb4ee6a4SAndroid Build Coastguard Worker         let stop_rx = create_stop_oneshot(&mut stop_queue_oneshots);
896*bb4ee6a4SAndroid Build Coastguard Worker         let inflate_queue_evt = inflate_queue
897*bb4ee6a4SAndroid Build Coastguard Worker             .event()
898*bb4ee6a4SAndroid Build Coastguard Worker             .try_clone()
899*bb4ee6a4SAndroid Build Coastguard Worker             .expect("failed to clone queue event");
900*bb4ee6a4SAndroid Build Coastguard Worker         let inflate = handle_queue(
901*bb4ee6a4SAndroid Build Coastguard Worker             inflate_queue,
902*bb4ee6a4SAndroid Build Coastguard Worker             EventAsync::new(inflate_queue_evt, &ex).expect("failed to create async event"),
903*bb4ee6a4SAndroid Build Coastguard Worker             release_memory_tube.as_ref(),
904*bb4ee6a4SAndroid Build Coastguard Worker             |guest_address, len| {
905*bb4ee6a4SAndroid Build Coastguard Worker                 sys::free_memory(
906*bb4ee6a4SAndroid Build Coastguard Worker                     &guest_address,
907*bb4ee6a4SAndroid Build Coastguard Worker                     len,
908*bb4ee6a4SAndroid Build Coastguard Worker                     #[cfg(windows)]
909*bb4ee6a4SAndroid Build Coastguard Worker                     &vm_memory_client,
910*bb4ee6a4SAndroid Build Coastguard Worker                     #[cfg(any(target_os = "android", target_os = "linux"))]
911*bb4ee6a4SAndroid Build Coastguard Worker                     &mem,
912*bb4ee6a4SAndroid Build Coastguard Worker                 )
913*bb4ee6a4SAndroid Build Coastguard Worker             },
914*bb4ee6a4SAndroid Build Coastguard Worker             stop_rx,
915*bb4ee6a4SAndroid Build Coastguard Worker         );
916*bb4ee6a4SAndroid Build Coastguard Worker         let inflate = inflate.fuse();
917*bb4ee6a4SAndroid Build Coastguard Worker         pin_mut!(inflate);
918*bb4ee6a4SAndroid Build Coastguard Worker 
919*bb4ee6a4SAndroid Build Coastguard Worker         // The second queue is used for deflate messages
920*bb4ee6a4SAndroid Build Coastguard Worker         let stop_rx = create_stop_oneshot(&mut stop_queue_oneshots);
921*bb4ee6a4SAndroid Build Coastguard Worker         let deflate_queue_evt = deflate_queue
922*bb4ee6a4SAndroid Build Coastguard Worker             .event()
923*bb4ee6a4SAndroid Build Coastguard Worker             .try_clone()
924*bb4ee6a4SAndroid Build Coastguard Worker             .expect("failed to clone queue event");
925*bb4ee6a4SAndroid Build Coastguard Worker         let deflate = handle_queue(
926*bb4ee6a4SAndroid Build Coastguard Worker             deflate_queue,
927*bb4ee6a4SAndroid Build Coastguard Worker             EventAsync::new(deflate_queue_evt, &ex).expect("failed to create async event"),
928*bb4ee6a4SAndroid Build Coastguard Worker             None,
929*bb4ee6a4SAndroid Build Coastguard Worker             |guest_address, len| {
930*bb4ee6a4SAndroid Build Coastguard Worker                 sys::reclaim_memory(
931*bb4ee6a4SAndroid Build Coastguard Worker                     &guest_address,
932*bb4ee6a4SAndroid Build Coastguard Worker                     len,
933*bb4ee6a4SAndroid Build Coastguard Worker                     #[cfg(windows)]
934*bb4ee6a4SAndroid Build Coastguard Worker                     &vm_memory_client,
935*bb4ee6a4SAndroid Build Coastguard Worker                 )
936*bb4ee6a4SAndroid Build Coastguard Worker             },
937*bb4ee6a4SAndroid Build Coastguard Worker             stop_rx,
938*bb4ee6a4SAndroid Build Coastguard Worker         );
939*bb4ee6a4SAndroid Build Coastguard Worker         let deflate = deflate.fuse();
940*bb4ee6a4SAndroid Build Coastguard Worker         pin_mut!(deflate);
941*bb4ee6a4SAndroid Build Coastguard Worker 
942*bb4ee6a4SAndroid Build Coastguard Worker         // The next queue is used for stats messages if VIRTIO_BALLOON_F_STATS_VQ is negotiated.
943*bb4ee6a4SAndroid Build Coastguard Worker         let (stats_tx, stats_rx) = mpsc::channel::<()>(1);
944*bb4ee6a4SAndroid Build Coastguard Worker         let has_stats_queue = stats_queue.is_some();
945*bb4ee6a4SAndroid Build Coastguard Worker         let stats = if let Some(stats_queue) = stats_queue {
946*bb4ee6a4SAndroid Build Coastguard Worker             let stop_rx = create_stop_oneshot(&mut stop_queue_oneshots);
947*bb4ee6a4SAndroid Build Coastguard Worker             let stats_queue_evt = stats_queue
948*bb4ee6a4SAndroid Build Coastguard Worker                 .event()
949*bb4ee6a4SAndroid Build Coastguard Worker                 .try_clone()
950*bb4ee6a4SAndroid Build Coastguard Worker                 .expect("failed to clone queue event");
951*bb4ee6a4SAndroid Build Coastguard Worker             handle_stats_queue(
952*bb4ee6a4SAndroid Build Coastguard Worker                 stats_queue,
953*bb4ee6a4SAndroid Build Coastguard Worker                 EventAsync::new(stats_queue_evt, &ex).expect("failed to create async event"),
954*bb4ee6a4SAndroid Build Coastguard Worker                 stats_rx,
955*bb4ee6a4SAndroid Build Coastguard Worker                 &command_tube,
956*bb4ee6a4SAndroid Build Coastguard Worker                 #[cfg(feature = "registered_events")]
957*bb4ee6a4SAndroid Build Coastguard Worker                 registered_evt_q_async.as_ref(),
958*bb4ee6a4SAndroid Build Coastguard Worker                 state.clone(),
959*bb4ee6a4SAndroid Build Coastguard Worker                 stop_rx,
960*bb4ee6a4SAndroid Build Coastguard Worker             )
961*bb4ee6a4SAndroid Build Coastguard Worker             .left_future()
962*bb4ee6a4SAndroid Build Coastguard Worker         } else {
963*bb4ee6a4SAndroid Build Coastguard Worker             std::future::pending().right_future()
964*bb4ee6a4SAndroid Build Coastguard Worker         };
965*bb4ee6a4SAndroid Build Coastguard Worker         let stats = stats.fuse();
966*bb4ee6a4SAndroid Build Coastguard Worker         pin_mut!(stats);
967*bb4ee6a4SAndroid Build Coastguard Worker 
968*bb4ee6a4SAndroid Build Coastguard Worker         // The next queue is used for reporting messages
969*bb4ee6a4SAndroid Build Coastguard Worker         let has_reporting_queue = reporting_queue.is_some();
970*bb4ee6a4SAndroid Build Coastguard Worker         let reporting = if let Some(reporting_queue) = reporting_queue {
971*bb4ee6a4SAndroid Build Coastguard Worker             let stop_rx = create_stop_oneshot(&mut stop_queue_oneshots);
972*bb4ee6a4SAndroid Build Coastguard Worker             let reporting_queue_evt = reporting_queue
973*bb4ee6a4SAndroid Build Coastguard Worker                 .event()
974*bb4ee6a4SAndroid Build Coastguard Worker                 .try_clone()
975*bb4ee6a4SAndroid Build Coastguard Worker                 .expect("failed to clone queue event");
976*bb4ee6a4SAndroid Build Coastguard Worker             handle_reporting_queue(
977*bb4ee6a4SAndroid Build Coastguard Worker                 reporting_queue,
978*bb4ee6a4SAndroid Build Coastguard Worker                 EventAsync::new(reporting_queue_evt, &ex).expect("failed to create async event"),
979*bb4ee6a4SAndroid Build Coastguard Worker                 release_memory_tube.as_ref(),
980*bb4ee6a4SAndroid Build Coastguard Worker                 |guest_address, len| {
981*bb4ee6a4SAndroid Build Coastguard Worker                     sys::free_memory(
982*bb4ee6a4SAndroid Build Coastguard Worker                         &guest_address,
983*bb4ee6a4SAndroid Build Coastguard Worker                         len,
984*bb4ee6a4SAndroid Build Coastguard Worker                         #[cfg(windows)]
985*bb4ee6a4SAndroid Build Coastguard Worker                         &vm_memory_client,
986*bb4ee6a4SAndroid Build Coastguard Worker                         #[cfg(any(target_os = "android", target_os = "linux"))]
987*bb4ee6a4SAndroid Build Coastguard Worker                         &mem,
988*bb4ee6a4SAndroid Build Coastguard Worker                     )
989*bb4ee6a4SAndroid Build Coastguard Worker                 },
990*bb4ee6a4SAndroid Build Coastguard Worker                 stop_rx,
991*bb4ee6a4SAndroid Build Coastguard Worker             )
992*bb4ee6a4SAndroid Build Coastguard Worker             .left_future()
993*bb4ee6a4SAndroid Build Coastguard Worker         } else {
994*bb4ee6a4SAndroid Build Coastguard Worker             std::future::pending().right_future()
995*bb4ee6a4SAndroid Build Coastguard Worker         };
996*bb4ee6a4SAndroid Build Coastguard Worker         let reporting = reporting.fuse();
997*bb4ee6a4SAndroid Build Coastguard Worker         pin_mut!(reporting);
998*bb4ee6a4SAndroid Build Coastguard Worker 
999*bb4ee6a4SAndroid Build Coastguard Worker         // If VIRTIO_BALLOON_F_WS_REPORTING is set 2 queues must handled - one for WS data and one
1000*bb4ee6a4SAndroid Build Coastguard Worker         // for WS notifications.
1001*bb4ee6a4SAndroid Build Coastguard Worker         let has_ws_data_queue = ws_data_queue.is_some();
1002*bb4ee6a4SAndroid Build Coastguard Worker         let ws_data = if let Some(ws_data_queue) = ws_data_queue {
1003*bb4ee6a4SAndroid Build Coastguard Worker             let stop_rx = create_stop_oneshot(&mut stop_queue_oneshots);
1004*bb4ee6a4SAndroid Build Coastguard Worker             let ws_data_queue_evt = ws_data_queue
1005*bb4ee6a4SAndroid Build Coastguard Worker                 .event()
1006*bb4ee6a4SAndroid Build Coastguard Worker                 .try_clone()
1007*bb4ee6a4SAndroid Build Coastguard Worker                 .expect("failed to clone queue event");
1008*bb4ee6a4SAndroid Build Coastguard Worker             handle_ws_data_queue(
1009*bb4ee6a4SAndroid Build Coastguard Worker                 ws_data_queue,
1010*bb4ee6a4SAndroid Build Coastguard Worker                 EventAsync::new(ws_data_queue_evt, &ex).expect("failed to create async event"),
1011*bb4ee6a4SAndroid Build Coastguard Worker                 &command_tube,
1012*bb4ee6a4SAndroid Build Coastguard Worker                 #[cfg(feature = "registered_events")]
1013*bb4ee6a4SAndroid Build Coastguard Worker                 registered_evt_q_async.as_ref(),
1014*bb4ee6a4SAndroid Build Coastguard Worker                 state.clone(),
1015*bb4ee6a4SAndroid Build Coastguard Worker                 stop_rx,
1016*bb4ee6a4SAndroid Build Coastguard Worker             )
1017*bb4ee6a4SAndroid Build Coastguard Worker             .left_future()
1018*bb4ee6a4SAndroid Build Coastguard Worker         } else {
1019*bb4ee6a4SAndroid Build Coastguard Worker             std::future::pending().right_future()
1020*bb4ee6a4SAndroid Build Coastguard Worker         };
1021*bb4ee6a4SAndroid Build Coastguard Worker         let ws_data = ws_data.fuse();
1022*bb4ee6a4SAndroid Build Coastguard Worker         pin_mut!(ws_data);
1023*bb4ee6a4SAndroid Build Coastguard Worker 
1024*bb4ee6a4SAndroid Build Coastguard Worker         let (ws_op_tx, ws_op_rx) = mpsc::channel::<WSOp>(1);
1025*bb4ee6a4SAndroid Build Coastguard Worker         let has_ws_op_queue = ws_op_queue.is_some();
1026*bb4ee6a4SAndroid Build Coastguard Worker         let ws_op = if let Some(ws_op_queue) = ws_op_queue {
1027*bb4ee6a4SAndroid Build Coastguard Worker             let stop_rx = create_stop_oneshot(&mut stop_queue_oneshots);
1028*bb4ee6a4SAndroid Build Coastguard Worker             let ws_op_queue_evt = ws_op_queue
1029*bb4ee6a4SAndroid Build Coastguard Worker                 .event()
1030*bb4ee6a4SAndroid Build Coastguard Worker                 .try_clone()
1031*bb4ee6a4SAndroid Build Coastguard Worker                 .expect("failed to clone queue event");
1032*bb4ee6a4SAndroid Build Coastguard Worker             handle_ws_op_queue(
1033*bb4ee6a4SAndroid Build Coastguard Worker                 ws_op_queue,
1034*bb4ee6a4SAndroid Build Coastguard Worker                 EventAsync::new(ws_op_queue_evt, &ex).expect("failed to create async event"),
1035*bb4ee6a4SAndroid Build Coastguard Worker                 ws_op_rx,
1036*bb4ee6a4SAndroid Build Coastguard Worker                 state.clone(),
1037*bb4ee6a4SAndroid Build Coastguard Worker                 stop_rx,
1038*bb4ee6a4SAndroid Build Coastguard Worker             )
1039*bb4ee6a4SAndroid Build Coastguard Worker             .left_future()
1040*bb4ee6a4SAndroid Build Coastguard Worker         } else {
1041*bb4ee6a4SAndroid Build Coastguard Worker             std::future::pending().right_future()
1042*bb4ee6a4SAndroid Build Coastguard Worker         };
1043*bb4ee6a4SAndroid Build Coastguard Worker         let ws_op = ws_op.fuse();
1044*bb4ee6a4SAndroid Build Coastguard Worker         pin_mut!(ws_op);
1045*bb4ee6a4SAndroid Build Coastguard Worker 
1046*bb4ee6a4SAndroid Build Coastguard Worker         // Future to handle command messages that resize the balloon.
1047*bb4ee6a4SAndroid Build Coastguard Worker         let stop_rx = create_stop_oneshot(&mut stop_queue_oneshots);
1048*bb4ee6a4SAndroid Build Coastguard Worker         let command = handle_command_tube(
1049*bb4ee6a4SAndroid Build Coastguard Worker             &command_tube,
1050*bb4ee6a4SAndroid Build Coastguard Worker             interrupt.clone(),
1051*bb4ee6a4SAndroid Build Coastguard Worker             state.clone(),
1052*bb4ee6a4SAndroid Build Coastguard Worker             stats_tx,
1053*bb4ee6a4SAndroid Build Coastguard Worker             ws_op_tx,
1054*bb4ee6a4SAndroid Build Coastguard Worker             stop_rx,
1055*bb4ee6a4SAndroid Build Coastguard Worker         );
1056*bb4ee6a4SAndroid Build Coastguard Worker         pin_mut!(command);
1057*bb4ee6a4SAndroid Build Coastguard Worker 
1058*bb4ee6a4SAndroid Build Coastguard Worker         // Process any requests to resample the irq value.
1059*bb4ee6a4SAndroid Build Coastguard Worker         let resample = async_utils::handle_irq_resample(&ex, interrupt.clone());
1060*bb4ee6a4SAndroid Build Coastguard Worker         pin_mut!(resample);
1061*bb4ee6a4SAndroid Build Coastguard Worker 
1062*bb4ee6a4SAndroid Build Coastguard Worker         // Send a message if balloon target reached event is triggered.
1063*bb4ee6a4SAndroid Build Coastguard Worker         let target_reached = handle_target_reached(
1064*bb4ee6a4SAndroid Build Coastguard Worker             &ex,
1065*bb4ee6a4SAndroid Build Coastguard Worker             target_reached_evt,
1066*bb4ee6a4SAndroid Build Coastguard Worker             #[cfg(windows)]
1067*bb4ee6a4SAndroid Build Coastguard Worker             &vm_memory_client,
1068*bb4ee6a4SAndroid Build Coastguard Worker         );
1069*bb4ee6a4SAndroid Build Coastguard Worker         pin_mut!(target_reached);
1070*bb4ee6a4SAndroid Build Coastguard Worker 
1071*bb4ee6a4SAndroid Build Coastguard Worker         // Exit if the kill event is triggered.
1072*bb4ee6a4SAndroid Build Coastguard Worker         let kill = async_utils::await_and_exit(&ex, kill_evt);
1073*bb4ee6a4SAndroid Build Coastguard Worker         pin_mut!(kill);
1074*bb4ee6a4SAndroid Build Coastguard Worker 
1075*bb4ee6a4SAndroid Build Coastguard Worker         let pending_adjusted = handle_pending_adjusted_responses(
1076*bb4ee6a4SAndroid Build Coastguard Worker             EventAsync::new(pending_adjusted_response_event, &ex)
1077*bb4ee6a4SAndroid Build Coastguard Worker                 .expect("failed to create async event"),
1078*bb4ee6a4SAndroid Build Coastguard Worker             &command_tube,
1079*bb4ee6a4SAndroid Build Coastguard Worker             state,
1080*bb4ee6a4SAndroid Build Coastguard Worker         );
1081*bb4ee6a4SAndroid Build Coastguard Worker         pin_mut!(pending_adjusted);
1082*bb4ee6a4SAndroid Build Coastguard Worker 
1083*bb4ee6a4SAndroid Build Coastguard Worker         let res = ex.run_until(async {
1084*bb4ee6a4SAndroid Build Coastguard Worker             select! {
1085*bb4ee6a4SAndroid Build Coastguard Worker                 _ = kill.fuse() => (),
1086*bb4ee6a4SAndroid Build Coastguard Worker                 _ = inflate => return Err(anyhow!("inflate stopped unexpectedly")),
1087*bb4ee6a4SAndroid Build Coastguard Worker                 _ = deflate => return Err(anyhow!("deflate stopped unexpectedly")),
1088*bb4ee6a4SAndroid Build Coastguard Worker                 _ = stats => return Err(anyhow!("stats stopped unexpectedly")),
1089*bb4ee6a4SAndroid Build Coastguard Worker                 _ = reporting => return Err(anyhow!("reporting stopped unexpectedly")),
1090*bb4ee6a4SAndroid Build Coastguard Worker                 _ = command.fuse() => return Err(anyhow!("command stopped unexpectedly")),
1091*bb4ee6a4SAndroid Build Coastguard Worker                 _ = ws_op => return Err(anyhow!("ws_op stopped unexpectedly")),
1092*bb4ee6a4SAndroid Build Coastguard Worker                 _ = resample.fuse() => return Err(anyhow!("resample stopped unexpectedly")),
1093*bb4ee6a4SAndroid Build Coastguard Worker                 _ = pending_adjusted.fuse() => return Err(anyhow!("pending_adjusted stopped unexpectedly")),
1094*bb4ee6a4SAndroid Build Coastguard Worker                 _ = ws_data => return Err(anyhow!("ws_data stopped unexpectedly")),
1095*bb4ee6a4SAndroid Build Coastguard Worker                 _ = target_reached.fuse() => return Err(anyhow!("target_reached stopped unexpectedly")),
1096*bb4ee6a4SAndroid Build Coastguard Worker             }
1097*bb4ee6a4SAndroid Build Coastguard Worker 
1098*bb4ee6a4SAndroid Build Coastguard Worker             // Worker is shutting down. To recover the queues, we have to signal
1099*bb4ee6a4SAndroid Build Coastguard Worker             // all the queue futures to exit.
1100*bb4ee6a4SAndroid Build Coastguard Worker             for stop_tx in stop_queue_oneshots {
1101*bb4ee6a4SAndroid Build Coastguard Worker                 if stop_tx.send(()).is_err() {
1102*bb4ee6a4SAndroid Build Coastguard Worker                     return Err(anyhow!("failed to request stop for queue future"));
1103*bb4ee6a4SAndroid Build Coastguard Worker                 }
1104*bb4ee6a4SAndroid Build Coastguard Worker             }
1105*bb4ee6a4SAndroid Build Coastguard Worker 
1106*bb4ee6a4SAndroid Build Coastguard Worker             // Collect all the queues (awaiting any queue future should now
1107*bb4ee6a4SAndroid Build Coastguard Worker             // return its Queue immediately).
1108*bb4ee6a4SAndroid Build Coastguard Worker             let mut paused_queues = PausedQueues::new(
1109*bb4ee6a4SAndroid Build Coastguard Worker                 inflate.await,
1110*bb4ee6a4SAndroid Build Coastguard Worker                 deflate.await,
1111*bb4ee6a4SAndroid Build Coastguard Worker             );
1112*bb4ee6a4SAndroid Build Coastguard Worker             if has_reporting_queue {
1113*bb4ee6a4SAndroid Build Coastguard Worker                 paused_queues.reporting = Some(reporting.await);
1114*bb4ee6a4SAndroid Build Coastguard Worker             }
1115*bb4ee6a4SAndroid Build Coastguard Worker             if has_stats_queue {
1116*bb4ee6a4SAndroid Build Coastguard Worker                 paused_queues.stats = Some(stats.await);
1117*bb4ee6a4SAndroid Build Coastguard Worker             }
1118*bb4ee6a4SAndroid Build Coastguard Worker             if has_ws_data_queue {
1119*bb4ee6a4SAndroid Build Coastguard Worker                 paused_queues.ws_data = Some(ws_data.await.context("failed to stop ws_data queue")?);
1120*bb4ee6a4SAndroid Build Coastguard Worker             }
1121*bb4ee6a4SAndroid Build Coastguard Worker             if has_ws_op_queue {
1122*bb4ee6a4SAndroid Build Coastguard Worker                 paused_queues.ws_op = Some(ws_op.await.context("failed to stop ws_op queue")?);
1123*bb4ee6a4SAndroid Build Coastguard Worker             }
1124*bb4ee6a4SAndroid Build Coastguard Worker             Ok(paused_queues)
1125*bb4ee6a4SAndroid Build Coastguard Worker         });
1126*bb4ee6a4SAndroid Build Coastguard Worker 
1127*bb4ee6a4SAndroid Build Coastguard Worker         match res {
1128*bb4ee6a4SAndroid Build Coastguard Worker             Err(e) => {
1129*bb4ee6a4SAndroid Build Coastguard Worker                 error!("error happened in executor: {}", e);
1130*bb4ee6a4SAndroid Build Coastguard Worker                 None
1131*bb4ee6a4SAndroid Build Coastguard Worker             }
1132*bb4ee6a4SAndroid Build Coastguard Worker             Ok(main_future_res) => match main_future_res {
1133*bb4ee6a4SAndroid Build Coastguard Worker                 Ok(paused_queues) => Some(paused_queues),
1134*bb4ee6a4SAndroid Build Coastguard Worker                 Err(e) => {
1135*bb4ee6a4SAndroid Build Coastguard Worker                     error!("error happened in main balloon future: {}", e);
1136*bb4ee6a4SAndroid Build Coastguard Worker                     None
1137*bb4ee6a4SAndroid Build Coastguard Worker                 }
1138*bb4ee6a4SAndroid Build Coastguard Worker             },
1139*bb4ee6a4SAndroid Build Coastguard Worker         }
1140*bb4ee6a4SAndroid Build Coastguard Worker     };
1141*bb4ee6a4SAndroid Build Coastguard Worker 
1142*bb4ee6a4SAndroid Build Coastguard Worker     WorkerReturn {
1143*bb4ee6a4SAndroid Build Coastguard Worker         command_tube: command_tube.into(),
1144*bb4ee6a4SAndroid Build Coastguard Worker         paused_queues,
1145*bb4ee6a4SAndroid Build Coastguard Worker         release_memory_tube,
1146*bb4ee6a4SAndroid Build Coastguard Worker         #[cfg(feature = "registered_events")]
1147*bb4ee6a4SAndroid Build Coastguard Worker         registered_evt_q,
1148*bb4ee6a4SAndroid Build Coastguard Worker         #[cfg(windows)]
1149*bb4ee6a4SAndroid Build Coastguard Worker         vm_memory_client,
1150*bb4ee6a4SAndroid Build Coastguard Worker     }
1151*bb4ee6a4SAndroid Build Coastguard Worker }
1152*bb4ee6a4SAndroid Build Coastguard Worker 
handle_target_reached( ex: &Executor, target_reached_evt: Event, #[cfg(windows)] vm_memory_client: &VmMemoryClient, ) -> anyhow::Result<()>1153*bb4ee6a4SAndroid Build Coastguard Worker async fn handle_target_reached(
1154*bb4ee6a4SAndroid Build Coastguard Worker     ex: &Executor,
1155*bb4ee6a4SAndroid Build Coastguard Worker     target_reached_evt: Event,
1156*bb4ee6a4SAndroid Build Coastguard Worker     #[cfg(windows)] vm_memory_client: &VmMemoryClient,
1157*bb4ee6a4SAndroid Build Coastguard Worker ) -> anyhow::Result<()> {
1158*bb4ee6a4SAndroid Build Coastguard Worker     let event_async =
1159*bb4ee6a4SAndroid Build Coastguard Worker         EventAsync::new(target_reached_evt, ex).context("failed to create EventAsync")?;
1160*bb4ee6a4SAndroid Build Coastguard Worker     loop {
1161*bb4ee6a4SAndroid Build Coastguard Worker         // Wait for target reached trigger.
1162*bb4ee6a4SAndroid Build Coastguard Worker         let _ = event_async.next_val().await;
1163*bb4ee6a4SAndroid Build Coastguard Worker         // Send the message to vm_control on the event. We don't have to read the current
1164*bb4ee6a4SAndroid Build Coastguard Worker         // size yet.
1165*bb4ee6a4SAndroid Build Coastguard Worker         sys::balloon_target_reached(
1166*bb4ee6a4SAndroid Build Coastguard Worker             0,
1167*bb4ee6a4SAndroid Build Coastguard Worker             #[cfg(windows)]
1168*bb4ee6a4SAndroid Build Coastguard Worker             vm_memory_client,
1169*bb4ee6a4SAndroid Build Coastguard Worker         );
1170*bb4ee6a4SAndroid Build Coastguard Worker     }
1171*bb4ee6a4SAndroid Build Coastguard Worker     // The above loop will never terminate and there is no reason to terminate it either. However,
1172*bb4ee6a4SAndroid Build Coastguard Worker     // the function is used in an executor that expects a Result<> return. Make sure that clippy
1173*bb4ee6a4SAndroid Build Coastguard Worker     // doesn't enforce the unreachable_code condition.
1174*bb4ee6a4SAndroid Build Coastguard Worker     #[allow(unreachable_code)]
1175*bb4ee6a4SAndroid Build Coastguard Worker     Ok(())
1176*bb4ee6a4SAndroid Build Coastguard Worker }
1177*bb4ee6a4SAndroid Build Coastguard Worker 
1178*bb4ee6a4SAndroid Build Coastguard Worker /// Virtio device for memory balloon inflation/deflation.
1179*bb4ee6a4SAndroid Build Coastguard Worker pub struct Balloon {
1180*bb4ee6a4SAndroid Build Coastguard Worker     command_tube: Option<Tube>,
1181*bb4ee6a4SAndroid Build Coastguard Worker     #[cfg(windows)]
1182*bb4ee6a4SAndroid Build Coastguard Worker     vm_memory_client: Option<VmMemoryClient>,
1183*bb4ee6a4SAndroid Build Coastguard Worker     release_memory_tube: Option<Tube>,
1184*bb4ee6a4SAndroid Build Coastguard Worker     pending_adjusted_response_event: Event,
1185*bb4ee6a4SAndroid Build Coastguard Worker     state: Arc<AsyncRwLock<BalloonState>>,
1186*bb4ee6a4SAndroid Build Coastguard Worker     features: u64,
1187*bb4ee6a4SAndroid Build Coastguard Worker     acked_features: u64,
1188*bb4ee6a4SAndroid Build Coastguard Worker     worker_thread: Option<WorkerThread<WorkerReturn>>,
1189*bb4ee6a4SAndroid Build Coastguard Worker     #[cfg(feature = "registered_events")]
1190*bb4ee6a4SAndroid Build Coastguard Worker     registered_evt_q: Option<SendTube>,
1191*bb4ee6a4SAndroid Build Coastguard Worker     ws_num_bins: u8,
1192*bb4ee6a4SAndroid Build Coastguard Worker     target_reached_evt: Option<Event>,
1193*bb4ee6a4SAndroid Build Coastguard Worker }
1194*bb4ee6a4SAndroid Build Coastguard Worker 
1195*bb4ee6a4SAndroid Build Coastguard Worker /// Snapshot of the [Balloon] state.
1196*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Serialize, Deserialize)]
1197*bb4ee6a4SAndroid Build Coastguard Worker struct BalloonSnapshot {
1198*bb4ee6a4SAndroid Build Coastguard Worker     state: BalloonState,
1199*bb4ee6a4SAndroid Build Coastguard Worker     features: u64,
1200*bb4ee6a4SAndroid Build Coastguard Worker     acked_features: u64,
1201*bb4ee6a4SAndroid Build Coastguard Worker     ws_num_bins: u8,
1202*bb4ee6a4SAndroid Build Coastguard Worker }
1203*bb4ee6a4SAndroid Build Coastguard Worker 
1204*bb4ee6a4SAndroid Build Coastguard Worker impl Balloon {
1205*bb4ee6a4SAndroid Build Coastguard Worker     /// Creates a new virtio balloon device.
1206*bb4ee6a4SAndroid Build Coastguard Worker     /// To let Balloon able to successfully release the memory which are pinned
1207*bb4ee6a4SAndroid Build Coastguard Worker     /// by CoIOMMU to host, the release_memory_tube will be used to send the inflate
1208*bb4ee6a4SAndroid Build Coastguard Worker     /// ranges to CoIOMMU with UnpinRequest/UnpinResponse messages, so that The
1209*bb4ee6a4SAndroid Build Coastguard Worker     /// memory in the inflate range can be unpinned first.
new( base_features: u64, command_tube: Tube, #[cfg(windows)] vm_memory_client: VmMemoryClient, release_memory_tube: Option<Tube>, init_balloon_size: u64, enabled_features: u64, #[cfg(feature = "registered_events")] registered_evt_q: Option<SendTube>, ws_num_bins: u8, ) -> Result<Balloon>1210*bb4ee6a4SAndroid Build Coastguard Worker     pub fn new(
1211*bb4ee6a4SAndroid Build Coastguard Worker         base_features: u64,
1212*bb4ee6a4SAndroid Build Coastguard Worker         command_tube: Tube,
1213*bb4ee6a4SAndroid Build Coastguard Worker         #[cfg(windows)] vm_memory_client: VmMemoryClient,
1214*bb4ee6a4SAndroid Build Coastguard Worker         release_memory_tube: Option<Tube>,
1215*bb4ee6a4SAndroid Build Coastguard Worker         init_balloon_size: u64,
1216*bb4ee6a4SAndroid Build Coastguard Worker         enabled_features: u64,
1217*bb4ee6a4SAndroid Build Coastguard Worker         #[cfg(feature = "registered_events")] registered_evt_q: Option<SendTube>,
1218*bb4ee6a4SAndroid Build Coastguard Worker         ws_num_bins: u8,
1219*bb4ee6a4SAndroid Build Coastguard Worker     ) -> Result<Balloon> {
1220*bb4ee6a4SAndroid Build Coastguard Worker         let features = base_features
1221*bb4ee6a4SAndroid Build Coastguard Worker             | 1 << VIRTIO_BALLOON_F_MUST_TELL_HOST
1222*bb4ee6a4SAndroid Build Coastguard Worker             | 1 << VIRTIO_BALLOON_F_STATS_VQ
1223*bb4ee6a4SAndroid Build Coastguard Worker             | 1 << VIRTIO_BALLOON_F_DEFLATE_ON_OOM
1224*bb4ee6a4SAndroid Build Coastguard Worker             | enabled_features;
1225*bb4ee6a4SAndroid Build Coastguard Worker 
1226*bb4ee6a4SAndroid Build Coastguard Worker         Ok(Balloon {
1227*bb4ee6a4SAndroid Build Coastguard Worker             command_tube: Some(command_tube),
1228*bb4ee6a4SAndroid Build Coastguard Worker             #[cfg(windows)]
1229*bb4ee6a4SAndroid Build Coastguard Worker             vm_memory_client: Some(vm_memory_client),
1230*bb4ee6a4SAndroid Build Coastguard Worker             release_memory_tube,
1231*bb4ee6a4SAndroid Build Coastguard Worker             pending_adjusted_response_event: Event::new().map_err(BalloonError::CreatingEvent)?,
1232*bb4ee6a4SAndroid Build Coastguard Worker             state: Arc::new(AsyncRwLock::new(BalloonState {
1233*bb4ee6a4SAndroid Build Coastguard Worker                 num_pages: (init_balloon_size >> VIRTIO_BALLOON_PFN_SHIFT) as u32,
1234*bb4ee6a4SAndroid Build Coastguard Worker                 actual_pages: 0,
1235*bb4ee6a4SAndroid Build Coastguard Worker                 failable_update: false,
1236*bb4ee6a4SAndroid Build Coastguard Worker                 pending_adjusted_responses: VecDeque::new(),
1237*bb4ee6a4SAndroid Build Coastguard Worker                 expecting_ws: false,
1238*bb4ee6a4SAndroid Build Coastguard Worker             })),
1239*bb4ee6a4SAndroid Build Coastguard Worker             worker_thread: None,
1240*bb4ee6a4SAndroid Build Coastguard Worker             features,
1241*bb4ee6a4SAndroid Build Coastguard Worker             acked_features: 0,
1242*bb4ee6a4SAndroid Build Coastguard Worker             #[cfg(feature = "registered_events")]
1243*bb4ee6a4SAndroid Build Coastguard Worker             registered_evt_q,
1244*bb4ee6a4SAndroid Build Coastguard Worker             ws_num_bins,
1245*bb4ee6a4SAndroid Build Coastguard Worker             target_reached_evt: None,
1246*bb4ee6a4SAndroid Build Coastguard Worker         })
1247*bb4ee6a4SAndroid Build Coastguard Worker     }
1248*bb4ee6a4SAndroid Build Coastguard Worker 
get_config(&self) -> virtio_balloon_config1249*bb4ee6a4SAndroid Build Coastguard Worker     fn get_config(&self) -> virtio_balloon_config {
1250*bb4ee6a4SAndroid Build Coastguard Worker         let state = block_on(self.state.lock());
1251*bb4ee6a4SAndroid Build Coastguard Worker         virtio_balloon_config {
1252*bb4ee6a4SAndroid Build Coastguard Worker             num_pages: state.num_pages.into(),
1253*bb4ee6a4SAndroid Build Coastguard Worker             actual: state.actual_pages.into(),
1254*bb4ee6a4SAndroid Build Coastguard Worker             // crosvm does not (currently) use free_page_hint_cmd_id or
1255*bb4ee6a4SAndroid Build Coastguard Worker             // poison_val, but they must be present in the right order and size
1256*bb4ee6a4SAndroid Build Coastguard Worker             // for the virtio-balloon driver in the guest to deserialize the
1257*bb4ee6a4SAndroid Build Coastguard Worker             // config correctly.
1258*bb4ee6a4SAndroid Build Coastguard Worker             free_page_hint_cmd_id: 0.into(),
1259*bb4ee6a4SAndroid Build Coastguard Worker             poison_val: 0.into(),
1260*bb4ee6a4SAndroid Build Coastguard Worker             ws_num_bins: self.ws_num_bins,
1261*bb4ee6a4SAndroid Build Coastguard Worker             _reserved: [0, 0, 0],
1262*bb4ee6a4SAndroid Build Coastguard Worker         }
1263*bb4ee6a4SAndroid Build Coastguard Worker     }
1264*bb4ee6a4SAndroid Build Coastguard Worker 
stop_worker(&mut self) -> StoppedWorker<PausedQueues>1265*bb4ee6a4SAndroid Build Coastguard Worker     fn stop_worker(&mut self) -> StoppedWorker<PausedQueues> {
1266*bb4ee6a4SAndroid Build Coastguard Worker         if let Some(worker_thread) = self.worker_thread.take() {
1267*bb4ee6a4SAndroid Build Coastguard Worker             let worker_ret = worker_thread.stop();
1268*bb4ee6a4SAndroid Build Coastguard Worker             self.release_memory_tube = worker_ret.release_memory_tube;
1269*bb4ee6a4SAndroid Build Coastguard Worker             self.command_tube = Some(worker_ret.command_tube);
1270*bb4ee6a4SAndroid Build Coastguard Worker             #[cfg(feature = "registered_events")]
1271*bb4ee6a4SAndroid Build Coastguard Worker             {
1272*bb4ee6a4SAndroid Build Coastguard Worker                 self.registered_evt_q = worker_ret.registered_evt_q;
1273*bb4ee6a4SAndroid Build Coastguard Worker             }
1274*bb4ee6a4SAndroid Build Coastguard Worker             #[cfg(windows)]
1275*bb4ee6a4SAndroid Build Coastguard Worker             {
1276*bb4ee6a4SAndroid Build Coastguard Worker                 self.vm_memory_client = Some(worker_ret.vm_memory_client);
1277*bb4ee6a4SAndroid Build Coastguard Worker             }
1278*bb4ee6a4SAndroid Build Coastguard Worker 
1279*bb4ee6a4SAndroid Build Coastguard Worker             if let Some(queues) = worker_ret.paused_queues {
1280*bb4ee6a4SAndroid Build Coastguard Worker                 StoppedWorker::WithQueues(Box::new(queues))
1281*bb4ee6a4SAndroid Build Coastguard Worker             } else {
1282*bb4ee6a4SAndroid Build Coastguard Worker                 StoppedWorker::MissingQueues
1283*bb4ee6a4SAndroid Build Coastguard Worker             }
1284*bb4ee6a4SAndroid Build Coastguard Worker         } else {
1285*bb4ee6a4SAndroid Build Coastguard Worker             StoppedWorker::AlreadyStopped
1286*bb4ee6a4SAndroid Build Coastguard Worker         }
1287*bb4ee6a4SAndroid Build Coastguard Worker     }
1288*bb4ee6a4SAndroid Build Coastguard Worker 
1289*bb4ee6a4SAndroid Build Coastguard Worker     /// Given a filtered queue vector from [VirtioDevice::activate], extract
1290*bb4ee6a4SAndroid Build Coastguard Worker     /// the queues (accounting for queues that are missing because the features
1291*bb4ee6a4SAndroid Build Coastguard Worker     /// are not negotiated) into a structure that is easier to work with.
get_queues_from_map( &self, mut queues: BTreeMap<usize, Queue>, ) -> anyhow::Result<BalloonQueues>1292*bb4ee6a4SAndroid Build Coastguard Worker     fn get_queues_from_map(
1293*bb4ee6a4SAndroid Build Coastguard Worker         &self,
1294*bb4ee6a4SAndroid Build Coastguard Worker         mut queues: BTreeMap<usize, Queue>,
1295*bb4ee6a4SAndroid Build Coastguard Worker     ) -> anyhow::Result<BalloonQueues> {
1296*bb4ee6a4SAndroid Build Coastguard Worker         fn pop_queue(
1297*bb4ee6a4SAndroid Build Coastguard Worker             queues: &mut BTreeMap<usize, Queue>,
1298*bb4ee6a4SAndroid Build Coastguard Worker             expected_index: usize,
1299*bb4ee6a4SAndroid Build Coastguard Worker             name: &str,
1300*bb4ee6a4SAndroid Build Coastguard Worker         ) -> anyhow::Result<Queue> {
1301*bb4ee6a4SAndroid Build Coastguard Worker             let (queue_index, queue) = queues
1302*bb4ee6a4SAndroid Build Coastguard Worker                 .pop_first()
1303*bb4ee6a4SAndroid Build Coastguard Worker                 .with_context(|| format!("missing {}", name))?;
1304*bb4ee6a4SAndroid Build Coastguard Worker 
1305*bb4ee6a4SAndroid Build Coastguard Worker             if queue_index == expected_index {
1306*bb4ee6a4SAndroid Build Coastguard Worker                 debug!("{name} index {queue_index}");
1307*bb4ee6a4SAndroid Build Coastguard Worker             } else {
1308*bb4ee6a4SAndroid Build Coastguard Worker                 warn!("expected {name} index {expected_index}, got {queue_index}");
1309*bb4ee6a4SAndroid Build Coastguard Worker             }
1310*bb4ee6a4SAndroid Build Coastguard Worker 
1311*bb4ee6a4SAndroid Build Coastguard Worker             Ok(queue)
1312*bb4ee6a4SAndroid Build Coastguard Worker         }
1313*bb4ee6a4SAndroid Build Coastguard Worker 
1314*bb4ee6a4SAndroid Build Coastguard Worker         // WARNING: We use `pop_first` instead of explicitly using the indices from the virtio spec
1315*bb4ee6a4SAndroid Build Coastguard Worker         // because the Linux virtio drivers only "allocates" queue indices that are used, so queues
1316*bb4ee6a4SAndroid Build Coastguard Worker         // need to be removed in order of ascending virtqueue index.
1317*bb4ee6a4SAndroid Build Coastguard Worker         let inflate_queue = pop_queue(&mut queues, INFLATEQ, "inflateq")?;
1318*bb4ee6a4SAndroid Build Coastguard Worker         let deflate_queue = pop_queue(&mut queues, DEFLATEQ, "deflateq")?;
1319*bb4ee6a4SAndroid Build Coastguard Worker         let mut queue_struct = BalloonQueues::new(inflate_queue, deflate_queue);
1320*bb4ee6a4SAndroid Build Coastguard Worker 
1321*bb4ee6a4SAndroid Build Coastguard Worker         if self.acked_features & (1 << VIRTIO_BALLOON_F_STATS_VQ) != 0 {
1322*bb4ee6a4SAndroid Build Coastguard Worker             queue_struct.stats = Some(pop_queue(&mut queues, STATSQ, "statsq")?);
1323*bb4ee6a4SAndroid Build Coastguard Worker         }
1324*bb4ee6a4SAndroid Build Coastguard Worker         if self.acked_features & (1 << VIRTIO_BALLOON_F_PAGE_REPORTING) != 0 {
1325*bb4ee6a4SAndroid Build Coastguard Worker             queue_struct.reporting = Some(pop_queue(&mut queues, REPORTING_VQ, "reporting_vq")?);
1326*bb4ee6a4SAndroid Build Coastguard Worker         }
1327*bb4ee6a4SAndroid Build Coastguard Worker         if self.acked_features & (1 << VIRTIO_BALLOON_F_WS_REPORTING) != 0 {
1328*bb4ee6a4SAndroid Build Coastguard Worker             queue_struct.ws_data = Some(pop_queue(&mut queues, WS_DATA_VQ, "ws_data_vq")?);
1329*bb4ee6a4SAndroid Build Coastguard Worker             queue_struct.ws_op = Some(pop_queue(&mut queues, WS_OP_VQ, "ws_op_vq")?);
1330*bb4ee6a4SAndroid Build Coastguard Worker         }
1331*bb4ee6a4SAndroid Build Coastguard Worker 
1332*bb4ee6a4SAndroid Build Coastguard Worker         if !queues.is_empty() {
1333*bb4ee6a4SAndroid Build Coastguard Worker             return Err(anyhow!("unexpected queues {:?}", queues.into_keys()));
1334*bb4ee6a4SAndroid Build Coastguard Worker         }
1335*bb4ee6a4SAndroid Build Coastguard Worker 
1336*bb4ee6a4SAndroid Build Coastguard Worker         Ok(queue_struct)
1337*bb4ee6a4SAndroid Build Coastguard Worker     }
1338*bb4ee6a4SAndroid Build Coastguard Worker 
start_worker( &mut self, mem: GuestMemory, interrupt: Interrupt, queues: BalloonQueues, ) -> anyhow::Result<()>1339*bb4ee6a4SAndroid Build Coastguard Worker     fn start_worker(
1340*bb4ee6a4SAndroid Build Coastguard Worker         &mut self,
1341*bb4ee6a4SAndroid Build Coastguard Worker         mem: GuestMemory,
1342*bb4ee6a4SAndroid Build Coastguard Worker         interrupt: Interrupt,
1343*bb4ee6a4SAndroid Build Coastguard Worker         queues: BalloonQueues,
1344*bb4ee6a4SAndroid Build Coastguard Worker     ) -> anyhow::Result<()> {
1345*bb4ee6a4SAndroid Build Coastguard Worker         let (self_target_reached_evt, target_reached_evt) = Event::new()
1346*bb4ee6a4SAndroid Build Coastguard Worker             .and_then(|e| Ok((e.try_clone()?, e)))
1347*bb4ee6a4SAndroid Build Coastguard Worker             .context("failed to create target_reached Event pair: {}")?;
1348*bb4ee6a4SAndroid Build Coastguard Worker         self.target_reached_evt = Some(self_target_reached_evt);
1349*bb4ee6a4SAndroid Build Coastguard Worker 
1350*bb4ee6a4SAndroid Build Coastguard Worker         let state = self.state.clone();
1351*bb4ee6a4SAndroid Build Coastguard Worker 
1352*bb4ee6a4SAndroid Build Coastguard Worker         let command_tube = self.command_tube.take().unwrap();
1353*bb4ee6a4SAndroid Build Coastguard Worker 
1354*bb4ee6a4SAndroid Build Coastguard Worker         #[cfg(windows)]
1355*bb4ee6a4SAndroid Build Coastguard Worker         let vm_memory_client = self.vm_memory_client.take().unwrap();
1356*bb4ee6a4SAndroid Build Coastguard Worker         let release_memory_tube = self.release_memory_tube.take();
1357*bb4ee6a4SAndroid Build Coastguard Worker         #[cfg(feature = "registered_events")]
1358*bb4ee6a4SAndroid Build Coastguard Worker         let registered_evt_q = self.registered_evt_q.take();
1359*bb4ee6a4SAndroid Build Coastguard Worker         let pending_adjusted_response_event = self
1360*bb4ee6a4SAndroid Build Coastguard Worker             .pending_adjusted_response_event
1361*bb4ee6a4SAndroid Build Coastguard Worker             .try_clone()
1362*bb4ee6a4SAndroid Build Coastguard Worker             .context("failed to clone Event")?;
1363*bb4ee6a4SAndroid Build Coastguard Worker 
1364*bb4ee6a4SAndroid Build Coastguard Worker         self.worker_thread = Some(WorkerThread::start("v_balloon", move |kill_evt| {
1365*bb4ee6a4SAndroid Build Coastguard Worker             run_worker(
1366*bb4ee6a4SAndroid Build Coastguard Worker                 queues.inflate,
1367*bb4ee6a4SAndroid Build Coastguard Worker                 queues.deflate,
1368*bb4ee6a4SAndroid Build Coastguard Worker                 queues.stats,
1369*bb4ee6a4SAndroid Build Coastguard Worker                 queues.reporting,
1370*bb4ee6a4SAndroid Build Coastguard Worker                 queues.ws_data,
1371*bb4ee6a4SAndroid Build Coastguard Worker                 queues.ws_op,
1372*bb4ee6a4SAndroid Build Coastguard Worker                 command_tube,
1373*bb4ee6a4SAndroid Build Coastguard Worker                 #[cfg(windows)]
1374*bb4ee6a4SAndroid Build Coastguard Worker                 vm_memory_client,
1375*bb4ee6a4SAndroid Build Coastguard Worker                 release_memory_tube,
1376*bb4ee6a4SAndroid Build Coastguard Worker                 interrupt,
1377*bb4ee6a4SAndroid Build Coastguard Worker                 kill_evt,
1378*bb4ee6a4SAndroid Build Coastguard Worker                 target_reached_evt,
1379*bb4ee6a4SAndroid Build Coastguard Worker                 pending_adjusted_response_event,
1380*bb4ee6a4SAndroid Build Coastguard Worker                 mem,
1381*bb4ee6a4SAndroid Build Coastguard Worker                 state,
1382*bb4ee6a4SAndroid Build Coastguard Worker                 #[cfg(feature = "registered_events")]
1383*bb4ee6a4SAndroid Build Coastguard Worker                 registered_evt_q,
1384*bb4ee6a4SAndroid Build Coastguard Worker             )
1385*bb4ee6a4SAndroid Build Coastguard Worker         }));
1386*bb4ee6a4SAndroid Build Coastguard Worker 
1387*bb4ee6a4SAndroid Build Coastguard Worker         Ok(())
1388*bb4ee6a4SAndroid Build Coastguard Worker     }
1389*bb4ee6a4SAndroid Build Coastguard Worker }
1390*bb4ee6a4SAndroid Build Coastguard Worker 
1391*bb4ee6a4SAndroid Build Coastguard Worker impl VirtioDevice for Balloon {
keep_rds(&self) -> Vec<RawDescriptor>1392*bb4ee6a4SAndroid Build Coastguard Worker     fn keep_rds(&self) -> Vec<RawDescriptor> {
1393*bb4ee6a4SAndroid Build Coastguard Worker         let mut rds = Vec::new();
1394*bb4ee6a4SAndroid Build Coastguard Worker         if let Some(command_tube) = &self.command_tube {
1395*bb4ee6a4SAndroid Build Coastguard Worker             rds.push(command_tube.as_raw_descriptor());
1396*bb4ee6a4SAndroid Build Coastguard Worker         }
1397*bb4ee6a4SAndroid Build Coastguard Worker         if let Some(release_memory_tube) = &self.release_memory_tube {
1398*bb4ee6a4SAndroid Build Coastguard Worker             rds.push(release_memory_tube.as_raw_descriptor());
1399*bb4ee6a4SAndroid Build Coastguard Worker         }
1400*bb4ee6a4SAndroid Build Coastguard Worker         #[cfg(feature = "registered_events")]
1401*bb4ee6a4SAndroid Build Coastguard Worker         if let Some(registered_evt_q) = &self.registered_evt_q {
1402*bb4ee6a4SAndroid Build Coastguard Worker             rds.push(registered_evt_q.as_raw_descriptor());
1403*bb4ee6a4SAndroid Build Coastguard Worker         }
1404*bb4ee6a4SAndroid Build Coastguard Worker         rds.push(self.pending_adjusted_response_event.as_raw_descriptor());
1405*bb4ee6a4SAndroid Build Coastguard Worker         rds
1406*bb4ee6a4SAndroid Build Coastguard Worker     }
1407*bb4ee6a4SAndroid Build Coastguard Worker 
device_type(&self) -> DeviceType1408*bb4ee6a4SAndroid Build Coastguard Worker     fn device_type(&self) -> DeviceType {
1409*bb4ee6a4SAndroid Build Coastguard Worker         DeviceType::Balloon
1410*bb4ee6a4SAndroid Build Coastguard Worker     }
1411*bb4ee6a4SAndroid Build Coastguard Worker 
queue_max_sizes(&self) -> &[u16]1412*bb4ee6a4SAndroid Build Coastguard Worker     fn queue_max_sizes(&self) -> &[u16] {
1413*bb4ee6a4SAndroid Build Coastguard Worker         QUEUE_SIZES
1414*bb4ee6a4SAndroid Build Coastguard Worker     }
1415*bb4ee6a4SAndroid Build Coastguard Worker 
read_config(&self, offset: u64, data: &mut [u8])1416*bb4ee6a4SAndroid Build Coastguard Worker     fn read_config(&self, offset: u64, data: &mut [u8]) {
1417*bb4ee6a4SAndroid Build Coastguard Worker         copy_config(data, 0, self.get_config().as_bytes(), offset);
1418*bb4ee6a4SAndroid Build Coastguard Worker     }
1419*bb4ee6a4SAndroid Build Coastguard Worker 
write_config(&mut self, offset: u64, data: &[u8])1420*bb4ee6a4SAndroid Build Coastguard Worker     fn write_config(&mut self, offset: u64, data: &[u8]) {
1421*bb4ee6a4SAndroid Build Coastguard Worker         let mut config = self.get_config();
1422*bb4ee6a4SAndroid Build Coastguard Worker         copy_config(config.as_bytes_mut(), offset, data, 0);
1423*bb4ee6a4SAndroid Build Coastguard Worker         let mut state = block_on(self.state.lock());
1424*bb4ee6a4SAndroid Build Coastguard Worker         state.actual_pages = config.actual.to_native();
1425*bb4ee6a4SAndroid Build Coastguard Worker 
1426*bb4ee6a4SAndroid Build Coastguard Worker         // If balloon has updated to the requested memory, let the hypervisor know.
1427*bb4ee6a4SAndroid Build Coastguard Worker         if config.num_pages == config.actual {
1428*bb4ee6a4SAndroid Build Coastguard Worker             debug!(
1429*bb4ee6a4SAndroid Build Coastguard Worker                 "sending target reached event at {}",
1430*bb4ee6a4SAndroid Build Coastguard Worker                 u32::from(config.num_pages)
1431*bb4ee6a4SAndroid Build Coastguard Worker             );
1432*bb4ee6a4SAndroid Build Coastguard Worker             self.target_reached_evt.as_ref().map(|e| e.signal());
1433*bb4ee6a4SAndroid Build Coastguard Worker         }
1434*bb4ee6a4SAndroid Build Coastguard Worker         if state.failable_update && state.actual_pages == state.num_pages {
1435*bb4ee6a4SAndroid Build Coastguard Worker             state.failable_update = false;
1436*bb4ee6a4SAndroid Build Coastguard Worker             let num_pages = state.num_pages;
1437*bb4ee6a4SAndroid Build Coastguard Worker             state.pending_adjusted_responses.push_back(num_pages);
1438*bb4ee6a4SAndroid Build Coastguard Worker             let _ = self.pending_adjusted_response_event.signal();
1439*bb4ee6a4SAndroid Build Coastguard Worker         }
1440*bb4ee6a4SAndroid Build Coastguard Worker     }
1441*bb4ee6a4SAndroid Build Coastguard Worker 
features(&self) -> u641442*bb4ee6a4SAndroid Build Coastguard Worker     fn features(&self) -> u64 {
1443*bb4ee6a4SAndroid Build Coastguard Worker         self.features
1444*bb4ee6a4SAndroid Build Coastguard Worker     }
1445*bb4ee6a4SAndroid Build Coastguard Worker 
ack_features(&mut self, mut value: u64)1446*bb4ee6a4SAndroid Build Coastguard Worker     fn ack_features(&mut self, mut value: u64) {
1447*bb4ee6a4SAndroid Build Coastguard Worker         if value & !self.features != 0 {
1448*bb4ee6a4SAndroid Build Coastguard Worker             warn!("virtio_balloon got unknown feature ack {:x}", value);
1449*bb4ee6a4SAndroid Build Coastguard Worker             value &= self.features;
1450*bb4ee6a4SAndroid Build Coastguard Worker         }
1451*bb4ee6a4SAndroid Build Coastguard Worker         self.acked_features |= value;
1452*bb4ee6a4SAndroid Build Coastguard Worker     }
1453*bb4ee6a4SAndroid Build Coastguard Worker 
activate( &mut self, mem: GuestMemory, interrupt: Interrupt, queues: BTreeMap<usize, Queue>, ) -> anyhow::Result<()>1454*bb4ee6a4SAndroid Build Coastguard Worker     fn activate(
1455*bb4ee6a4SAndroid Build Coastguard Worker         &mut self,
1456*bb4ee6a4SAndroid Build Coastguard Worker         mem: GuestMemory,
1457*bb4ee6a4SAndroid Build Coastguard Worker         interrupt: Interrupt,
1458*bb4ee6a4SAndroid Build Coastguard Worker         queues: BTreeMap<usize, Queue>,
1459*bb4ee6a4SAndroid Build Coastguard Worker     ) -> anyhow::Result<()> {
1460*bb4ee6a4SAndroid Build Coastguard Worker         let queues = self.get_queues_from_map(queues)?;
1461*bb4ee6a4SAndroid Build Coastguard Worker         self.start_worker(mem, interrupt, queues)
1462*bb4ee6a4SAndroid Build Coastguard Worker     }
1463*bb4ee6a4SAndroid Build Coastguard Worker 
reset(&mut self) -> anyhow::Result<()>1464*bb4ee6a4SAndroid Build Coastguard Worker     fn reset(&mut self) -> anyhow::Result<()> {
1465*bb4ee6a4SAndroid Build Coastguard Worker         let _worker = self.stop_worker();
1466*bb4ee6a4SAndroid Build Coastguard Worker         Ok(())
1467*bb4ee6a4SAndroid Build Coastguard Worker     }
1468*bb4ee6a4SAndroid Build Coastguard Worker 
virtio_sleep(&mut self) -> anyhow::Result<Option<BTreeMap<usize, Queue>>>1469*bb4ee6a4SAndroid Build Coastguard Worker     fn virtio_sleep(&mut self) -> anyhow::Result<Option<BTreeMap<usize, Queue>>> {
1470*bb4ee6a4SAndroid Build Coastguard Worker         match self.stop_worker() {
1471*bb4ee6a4SAndroid Build Coastguard Worker             StoppedWorker::WithQueues(paused_queues) => Ok(Some(paused_queues.into())),
1472*bb4ee6a4SAndroid Build Coastguard Worker             StoppedWorker::MissingQueues => {
1473*bb4ee6a4SAndroid Build Coastguard Worker                 anyhow::bail!("balloon queue workers did not stop cleanly.")
1474*bb4ee6a4SAndroid Build Coastguard Worker             }
1475*bb4ee6a4SAndroid Build Coastguard Worker             StoppedWorker::AlreadyStopped => {
1476*bb4ee6a4SAndroid Build Coastguard Worker                 // Device hasn't been activated.
1477*bb4ee6a4SAndroid Build Coastguard Worker                 Ok(None)
1478*bb4ee6a4SAndroid Build Coastguard Worker             }
1479*bb4ee6a4SAndroid Build Coastguard Worker         }
1480*bb4ee6a4SAndroid Build Coastguard Worker     }
1481*bb4ee6a4SAndroid Build Coastguard Worker 
virtio_wake( &mut self, queues_state: Option<(GuestMemory, Interrupt, BTreeMap<usize, Queue>)>, ) -> anyhow::Result<()>1482*bb4ee6a4SAndroid Build Coastguard Worker     fn virtio_wake(
1483*bb4ee6a4SAndroid Build Coastguard Worker         &mut self,
1484*bb4ee6a4SAndroid Build Coastguard Worker         queues_state: Option<(GuestMemory, Interrupt, BTreeMap<usize, Queue>)>,
1485*bb4ee6a4SAndroid Build Coastguard Worker     ) -> anyhow::Result<()> {
1486*bb4ee6a4SAndroid Build Coastguard Worker         if let Some((mem, interrupt, queues)) = queues_state {
1487*bb4ee6a4SAndroid Build Coastguard Worker             if queues.len() < 2 {
1488*bb4ee6a4SAndroid Build Coastguard Worker                 anyhow::bail!("{} queues were found, but an activated balloon must have at least 2 active queues.", queues.len());
1489*bb4ee6a4SAndroid Build Coastguard Worker             }
1490*bb4ee6a4SAndroid Build Coastguard Worker 
1491*bb4ee6a4SAndroid Build Coastguard Worker             let balloon_queues = self.get_queues_from_map(queues)?;
1492*bb4ee6a4SAndroid Build Coastguard Worker             self.start_worker(mem, interrupt, balloon_queues)?;
1493*bb4ee6a4SAndroid Build Coastguard Worker         }
1494*bb4ee6a4SAndroid Build Coastguard Worker         Ok(())
1495*bb4ee6a4SAndroid Build Coastguard Worker     }
1496*bb4ee6a4SAndroid Build Coastguard Worker 
virtio_snapshot(&mut self) -> anyhow::Result<serde_json::Value>1497*bb4ee6a4SAndroid Build Coastguard Worker     fn virtio_snapshot(&mut self) -> anyhow::Result<serde_json::Value> {
1498*bb4ee6a4SAndroid Build Coastguard Worker         let state = self
1499*bb4ee6a4SAndroid Build Coastguard Worker             .state
1500*bb4ee6a4SAndroid Build Coastguard Worker             .lock()
1501*bb4ee6a4SAndroid Build Coastguard Worker             .now_or_never()
1502*bb4ee6a4SAndroid Build Coastguard Worker             .context("failed to acquire balloon lock")?;
1503*bb4ee6a4SAndroid Build Coastguard Worker         serde_json::to_value(BalloonSnapshot {
1504*bb4ee6a4SAndroid Build Coastguard Worker             features: self.features,
1505*bb4ee6a4SAndroid Build Coastguard Worker             acked_features: self.acked_features,
1506*bb4ee6a4SAndroid Build Coastguard Worker             state: state.clone(),
1507*bb4ee6a4SAndroid Build Coastguard Worker             ws_num_bins: self.ws_num_bins,
1508*bb4ee6a4SAndroid Build Coastguard Worker         })
1509*bb4ee6a4SAndroid Build Coastguard Worker         .context("failed to serialize balloon state")
1510*bb4ee6a4SAndroid Build Coastguard Worker     }
1511*bb4ee6a4SAndroid Build Coastguard Worker 
virtio_restore(&mut self, data: serde_json::Value) -> anyhow::Result<()>1512*bb4ee6a4SAndroid Build Coastguard Worker     fn virtio_restore(&mut self, data: serde_json::Value) -> anyhow::Result<()> {
1513*bb4ee6a4SAndroid Build Coastguard Worker         let snap: BalloonSnapshot = serde_json::from_value(data).context("error deserializing")?;
1514*bb4ee6a4SAndroid Build Coastguard Worker         if snap.features != self.features {
1515*bb4ee6a4SAndroid Build Coastguard Worker             anyhow::bail!(
1516*bb4ee6a4SAndroid Build Coastguard Worker                 "balloon: expected features to match, but they did not. Live: {:?}, snapshot {:?}",
1517*bb4ee6a4SAndroid Build Coastguard Worker                 self.features,
1518*bb4ee6a4SAndroid Build Coastguard Worker                 snap.features,
1519*bb4ee6a4SAndroid Build Coastguard Worker             );
1520*bb4ee6a4SAndroid Build Coastguard Worker         }
1521*bb4ee6a4SAndroid Build Coastguard Worker 
1522*bb4ee6a4SAndroid Build Coastguard Worker         let mut state = self
1523*bb4ee6a4SAndroid Build Coastguard Worker             .state
1524*bb4ee6a4SAndroid Build Coastguard Worker             .lock()
1525*bb4ee6a4SAndroid Build Coastguard Worker             .now_or_never()
1526*bb4ee6a4SAndroid Build Coastguard Worker             .context("failed to acquire balloon lock")?;
1527*bb4ee6a4SAndroid Build Coastguard Worker         *state = snap.state;
1528*bb4ee6a4SAndroid Build Coastguard Worker         self.ws_num_bins = snap.ws_num_bins;
1529*bb4ee6a4SAndroid Build Coastguard Worker         self.acked_features = snap.acked_features;
1530*bb4ee6a4SAndroid Build Coastguard Worker         Ok(())
1531*bb4ee6a4SAndroid Build Coastguard Worker     }
1532*bb4ee6a4SAndroid Build Coastguard Worker }
1533*bb4ee6a4SAndroid Build Coastguard Worker 
1534*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(test)]
1535*bb4ee6a4SAndroid Build Coastguard Worker mod tests {
1536*bb4ee6a4SAndroid Build Coastguard Worker     use super::*;
1537*bb4ee6a4SAndroid Build Coastguard Worker     use crate::suspendable_virtio_tests;
1538*bb4ee6a4SAndroid Build Coastguard Worker     use crate::virtio::descriptor_utils::create_descriptor_chain;
1539*bb4ee6a4SAndroid Build Coastguard Worker     use crate::virtio::descriptor_utils::DescriptorType;
1540*bb4ee6a4SAndroid Build Coastguard Worker 
1541*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
desc_parsing_inflate()1542*bb4ee6a4SAndroid Build Coastguard Worker     fn desc_parsing_inflate() {
1543*bb4ee6a4SAndroid Build Coastguard Worker         // Check that the memory addresses are parsed correctly by 'handle_address_chain' and passed
1544*bb4ee6a4SAndroid Build Coastguard Worker         // to the closure.
1545*bb4ee6a4SAndroid Build Coastguard Worker         let memory_start_addr = GuestAddress(0x0);
1546*bb4ee6a4SAndroid Build Coastguard Worker         let memory = GuestMemory::new(&[(memory_start_addr, 0x10000)]).unwrap();
1547*bb4ee6a4SAndroid Build Coastguard Worker         memory
1548*bb4ee6a4SAndroid Build Coastguard Worker             .write_obj_at_addr(0x10u32, GuestAddress(0x100))
1549*bb4ee6a4SAndroid Build Coastguard Worker             .unwrap();
1550*bb4ee6a4SAndroid Build Coastguard Worker         memory
1551*bb4ee6a4SAndroid Build Coastguard Worker             .write_obj_at_addr(0xaa55aa55u32, GuestAddress(0x104))
1552*bb4ee6a4SAndroid Build Coastguard Worker             .unwrap();
1553*bb4ee6a4SAndroid Build Coastguard Worker 
1554*bb4ee6a4SAndroid Build Coastguard Worker         let mut chain = create_descriptor_chain(
1555*bb4ee6a4SAndroid Build Coastguard Worker             &memory,
1556*bb4ee6a4SAndroid Build Coastguard Worker             GuestAddress(0x0),
1557*bb4ee6a4SAndroid Build Coastguard Worker             GuestAddress(0x100),
1558*bb4ee6a4SAndroid Build Coastguard Worker             vec![(DescriptorType::Readable, 8)],
1559*bb4ee6a4SAndroid Build Coastguard Worker             0,
1560*bb4ee6a4SAndroid Build Coastguard Worker         )
1561*bb4ee6a4SAndroid Build Coastguard Worker         .expect("create_descriptor_chain failed");
1562*bb4ee6a4SAndroid Build Coastguard Worker 
1563*bb4ee6a4SAndroid Build Coastguard Worker         let mut addrs = Vec::new();
1564*bb4ee6a4SAndroid Build Coastguard Worker         let res = handle_address_chain(None, &mut chain, &mut |guest_address, len| {
1565*bb4ee6a4SAndroid Build Coastguard Worker             addrs.push((guest_address, len));
1566*bb4ee6a4SAndroid Build Coastguard Worker         });
1567*bb4ee6a4SAndroid Build Coastguard Worker         assert!(res.is_ok());
1568*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(addrs.len(), 2);
1569*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(
1570*bb4ee6a4SAndroid Build Coastguard Worker             addrs[0].0,
1571*bb4ee6a4SAndroid Build Coastguard Worker             GuestAddress(0x10u64 << VIRTIO_BALLOON_PFN_SHIFT)
1572*bb4ee6a4SAndroid Build Coastguard Worker         );
1573*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(
1574*bb4ee6a4SAndroid Build Coastguard Worker             addrs[1].0,
1575*bb4ee6a4SAndroid Build Coastguard Worker             GuestAddress(0xaa55aa55u64 << VIRTIO_BALLOON_PFN_SHIFT)
1576*bb4ee6a4SAndroid Build Coastguard Worker         );
1577*bb4ee6a4SAndroid Build Coastguard Worker     }
1578*bb4ee6a4SAndroid Build Coastguard Worker 
1579*bb4ee6a4SAndroid Build Coastguard Worker     struct BalloonContext {
1580*bb4ee6a4SAndroid Build Coastguard Worker         _ctrl_tube: Tube,
1581*bb4ee6a4SAndroid Build Coastguard Worker         #[cfg(windows)]
1582*bb4ee6a4SAndroid Build Coastguard Worker         _mem_client_tube: Tube,
1583*bb4ee6a4SAndroid Build Coastguard Worker     }
1584*bb4ee6a4SAndroid Build Coastguard Worker 
modify_device(_balloon_context: &mut BalloonContext, balloon: &mut Balloon)1585*bb4ee6a4SAndroid Build Coastguard Worker     fn modify_device(_balloon_context: &mut BalloonContext, balloon: &mut Balloon) {
1586*bb4ee6a4SAndroid Build Coastguard Worker         balloon.ws_num_bins = !balloon.ws_num_bins;
1587*bb4ee6a4SAndroid Build Coastguard Worker     }
1588*bb4ee6a4SAndroid Build Coastguard Worker 
create_device() -> (BalloonContext, Balloon)1589*bb4ee6a4SAndroid Build Coastguard Worker     fn create_device() -> (BalloonContext, Balloon) {
1590*bb4ee6a4SAndroid Build Coastguard Worker         let (_ctrl_tube, ctrl_tube_device) = Tube::pair().unwrap();
1591*bb4ee6a4SAndroid Build Coastguard Worker         #[cfg(windows)]
1592*bb4ee6a4SAndroid Build Coastguard Worker         let (_mem_client_tube, mem_client_tube_device) = Tube::pair().unwrap();
1593*bb4ee6a4SAndroid Build Coastguard Worker         (
1594*bb4ee6a4SAndroid Build Coastguard Worker             BalloonContext {
1595*bb4ee6a4SAndroid Build Coastguard Worker                 _ctrl_tube,
1596*bb4ee6a4SAndroid Build Coastguard Worker                 #[cfg(windows)]
1597*bb4ee6a4SAndroid Build Coastguard Worker                 _mem_client_tube,
1598*bb4ee6a4SAndroid Build Coastguard Worker             },
1599*bb4ee6a4SAndroid Build Coastguard Worker             Balloon::new(
1600*bb4ee6a4SAndroid Build Coastguard Worker                 0,
1601*bb4ee6a4SAndroid Build Coastguard Worker                 ctrl_tube_device,
1602*bb4ee6a4SAndroid Build Coastguard Worker                 #[cfg(windows)]
1603*bb4ee6a4SAndroid Build Coastguard Worker                 VmMemoryClient::new(mem_client_tube_device),
1604*bb4ee6a4SAndroid Build Coastguard Worker                 None,
1605*bb4ee6a4SAndroid Build Coastguard Worker                 1024,
1606*bb4ee6a4SAndroid Build Coastguard Worker                 0,
1607*bb4ee6a4SAndroid Build Coastguard Worker                 #[cfg(feature = "registered_events")]
1608*bb4ee6a4SAndroid Build Coastguard Worker                 None,
1609*bb4ee6a4SAndroid Build Coastguard Worker                 0,
1610*bb4ee6a4SAndroid Build Coastguard Worker             )
1611*bb4ee6a4SAndroid Build Coastguard Worker             .unwrap(),
1612*bb4ee6a4SAndroid Build Coastguard Worker         )
1613*bb4ee6a4SAndroid Build Coastguard Worker     }
1614*bb4ee6a4SAndroid Build Coastguard Worker 
1615*bb4ee6a4SAndroid Build Coastguard Worker     suspendable_virtio_tests!(balloon, create_device, 2, modify_device);
1616*bb4ee6a4SAndroid Build Coastguard Worker }
1617