1*bb4ee6a4SAndroid Build Coastguard Worker // Copyright 2019 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 use std::collections::BTreeMap;
6*bb4ee6a4SAndroid Build Coastguard Worker use std::fs::File;
7*bb4ee6a4SAndroid Build Coastguard Worker use std::io;
8*bb4ee6a4SAndroid Build Coastguard Worker use std::mem::size_of;
9*bb4ee6a4SAndroid Build Coastguard Worker use std::time::Duration;
10*bb4ee6a4SAndroid Build Coastguard Worker
11*bb4ee6a4SAndroid Build Coastguard Worker use anyhow::anyhow;
12*bb4ee6a4SAndroid Build Coastguard Worker use anyhow::Context;
13*bb4ee6a4SAndroid Build Coastguard Worker use base::error;
14*bb4ee6a4SAndroid Build Coastguard Worker use base::AsRawDescriptor;
15*bb4ee6a4SAndroid Build Coastguard Worker use base::Error as SysError;
16*bb4ee6a4SAndroid Build Coastguard Worker use base::Event;
17*bb4ee6a4SAndroid Build Coastguard Worker use base::RawDescriptor;
18*bb4ee6a4SAndroid Build Coastguard Worker use base::Result as SysResult;
19*bb4ee6a4SAndroid Build Coastguard Worker use base::Timer;
20*bb4ee6a4SAndroid Build Coastguard Worker use base::Tube;
21*bb4ee6a4SAndroid Build Coastguard Worker use base::TubeError;
22*bb4ee6a4SAndroid Build Coastguard Worker use base::WorkerThread;
23*bb4ee6a4SAndroid Build Coastguard Worker use cros_async::select3;
24*bb4ee6a4SAndroid Build Coastguard Worker use cros_async::select4;
25*bb4ee6a4SAndroid Build Coastguard Worker use cros_async::AsyncError;
26*bb4ee6a4SAndroid Build Coastguard Worker use cros_async::EventAsync;
27*bb4ee6a4SAndroid Build Coastguard Worker use cros_async::Executor;
28*bb4ee6a4SAndroid Build Coastguard Worker use cros_async::TimerAsync;
29*bb4ee6a4SAndroid Build Coastguard Worker use data_model::Le32;
30*bb4ee6a4SAndroid Build Coastguard Worker use data_model::Le64;
31*bb4ee6a4SAndroid Build Coastguard Worker use futures::pin_mut;
32*bb4ee6a4SAndroid Build Coastguard Worker use remain::sorted;
33*bb4ee6a4SAndroid Build Coastguard Worker use thiserror::Error;
34*bb4ee6a4SAndroid Build Coastguard Worker use vm_control::MemSlot;
35*bb4ee6a4SAndroid Build Coastguard Worker use vm_control::VmMemoryMappingRequest;
36*bb4ee6a4SAndroid Build Coastguard Worker use vm_control::VmMemoryMappingResponse;
37*bb4ee6a4SAndroid Build Coastguard Worker use vm_memory::GuestAddress;
38*bb4ee6a4SAndroid Build Coastguard Worker use vm_memory::GuestMemory;
39*bb4ee6a4SAndroid Build Coastguard Worker use zerocopy::AsBytes;
40*bb4ee6a4SAndroid Build Coastguard Worker use zerocopy::FromBytes;
41*bb4ee6a4SAndroid Build Coastguard Worker use zerocopy::FromZeroes;
42*bb4ee6a4SAndroid Build Coastguard Worker
43*bb4ee6a4SAndroid Build Coastguard Worker use super::async_utils;
44*bb4ee6a4SAndroid Build Coastguard Worker use super::copy_config;
45*bb4ee6a4SAndroid Build Coastguard Worker use super::DescriptorChain;
46*bb4ee6a4SAndroid Build Coastguard Worker use super::DeviceType;
47*bb4ee6a4SAndroid Build Coastguard Worker use super::Interrupt;
48*bb4ee6a4SAndroid Build Coastguard Worker use super::Queue;
49*bb4ee6a4SAndroid Build Coastguard Worker use super::VirtioDevice;
50*bb4ee6a4SAndroid Build Coastguard Worker
51*bb4ee6a4SAndroid Build Coastguard Worker const QUEUE_SIZE: u16 = 256;
52*bb4ee6a4SAndroid Build Coastguard Worker const QUEUE_SIZES: &[u16] = &[QUEUE_SIZE];
53*bb4ee6a4SAndroid Build Coastguard Worker
54*bb4ee6a4SAndroid Build Coastguard Worker /* Feature bits */
55*bb4ee6a4SAndroid Build Coastguard Worker const VIRTIO_PMEM_F_DISCARD: u32 = 63;
56*bb4ee6a4SAndroid Build Coastguard Worker
57*bb4ee6a4SAndroid Build Coastguard Worker const VIRTIO_PMEM_REQ_TYPE_FLUSH: u32 = 0;
58*bb4ee6a4SAndroid Build Coastguard Worker const VIRTIO_PMEM_REQ_TYPE_DISCARD: u32 = u32::MAX;
59*bb4ee6a4SAndroid Build Coastguard Worker const VIRTIO_PMEM_RESP_TYPE_OK: u32 = 0;
60*bb4ee6a4SAndroid Build Coastguard Worker const VIRTIO_PMEM_RESP_TYPE_EIO: u32 = 1;
61*bb4ee6a4SAndroid Build Coastguard Worker
62*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Copy, Clone, Debug, Default, AsBytes, FromZeroes, FromBytes)]
63*bb4ee6a4SAndroid Build Coastguard Worker #[repr(C)]
64*bb4ee6a4SAndroid Build Coastguard Worker struct virtio_pmem_config {
65*bb4ee6a4SAndroid Build Coastguard Worker start_address: Le64,
66*bb4ee6a4SAndroid Build Coastguard Worker size: Le64,
67*bb4ee6a4SAndroid Build Coastguard Worker }
68*bb4ee6a4SAndroid Build Coastguard Worker
69*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Copy, Clone, Debug, Default, AsBytes, FromZeroes, FromBytes)]
70*bb4ee6a4SAndroid Build Coastguard Worker #[repr(C)]
71*bb4ee6a4SAndroid Build Coastguard Worker struct virtio_pmem_resp {
72*bb4ee6a4SAndroid Build Coastguard Worker status_code: Le32,
73*bb4ee6a4SAndroid Build Coastguard Worker }
74*bb4ee6a4SAndroid Build Coastguard Worker
75*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Copy, Clone, Debug, Default, AsBytes, FromZeroes, FromBytes)]
76*bb4ee6a4SAndroid Build Coastguard Worker #[repr(C)]
77*bb4ee6a4SAndroid Build Coastguard Worker struct virtio_pmem_req {
78*bb4ee6a4SAndroid Build Coastguard Worker type_: Le32,
79*bb4ee6a4SAndroid Build Coastguard Worker }
80*bb4ee6a4SAndroid Build Coastguard Worker
81*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Copy, Clone, Debug, Default, AsBytes, FromZeroes, FromBytes)]
82*bb4ee6a4SAndroid Build Coastguard Worker #[repr(C)]
83*bb4ee6a4SAndroid Build Coastguard Worker struct virtio_pmem_range_req {
84*bb4ee6a4SAndroid Build Coastguard Worker type_: Le32,
85*bb4ee6a4SAndroid Build Coastguard Worker padding_: Le32,
86*bb4ee6a4SAndroid Build Coastguard Worker start_address: Le64,
87*bb4ee6a4SAndroid Build Coastguard Worker size: Le64,
88*bb4ee6a4SAndroid Build Coastguard Worker }
89*bb4ee6a4SAndroid Build Coastguard Worker
90*bb4ee6a4SAndroid Build Coastguard Worker #[sorted]
91*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Error, Debug)]
92*bb4ee6a4SAndroid Build Coastguard Worker enum Error {
93*bb4ee6a4SAndroid Build Coastguard Worker /// Failed to get value from pageout timer.
94*bb4ee6a4SAndroid Build Coastguard Worker #[error("failed to get value from pageout timer: {0}")]
95*bb4ee6a4SAndroid Build Coastguard Worker PageoutTimer(AsyncError),
96*bb4ee6a4SAndroid Build Coastguard Worker /// Failed to read from virtqueue.
97*bb4ee6a4SAndroid Build Coastguard Worker #[error("failed to read from virtqueue: {0}")]
98*bb4ee6a4SAndroid Build Coastguard Worker ReadQueue(io::Error),
99*bb4ee6a4SAndroid Build Coastguard Worker /// Failed to receive tube response.
100*bb4ee6a4SAndroid Build Coastguard Worker #[error("failed to receive tube response: {0}")]
101*bb4ee6a4SAndroid Build Coastguard Worker ReceiveResponse(TubeError),
102*bb4ee6a4SAndroid Build Coastguard Worker /// Failed to send tube request.
103*bb4ee6a4SAndroid Build Coastguard Worker #[error("failed to send tube request: {0}")]
104*bb4ee6a4SAndroid Build Coastguard Worker SendingRequest(TubeError),
105*bb4ee6a4SAndroid Build Coastguard Worker /// Failed to write to virtqueue.
106*bb4ee6a4SAndroid Build Coastguard Worker #[error("failed to write to virtqueue: {0}")]
107*bb4ee6a4SAndroid Build Coastguard Worker WriteQueue(io::Error),
108*bb4ee6a4SAndroid Build Coastguard Worker }
109*bb4ee6a4SAndroid Build Coastguard Worker
110*bb4ee6a4SAndroid Build Coastguard Worker type Result<T> = ::std::result::Result<T, Error>;
111*bb4ee6a4SAndroid Build Coastguard Worker
pageout( ex: &Executor, swap_interval: Duration, pmem_device_tube: &Tube, mapping_arena_slot: u32, mapping_size: usize, ) -> Result<()>112*bb4ee6a4SAndroid Build Coastguard Worker async fn pageout(
113*bb4ee6a4SAndroid Build Coastguard Worker ex: &Executor,
114*bb4ee6a4SAndroid Build Coastguard Worker swap_interval: Duration,
115*bb4ee6a4SAndroid Build Coastguard Worker pmem_device_tube: &Tube,
116*bb4ee6a4SAndroid Build Coastguard Worker mapping_arena_slot: u32,
117*bb4ee6a4SAndroid Build Coastguard Worker mapping_size: usize,
118*bb4ee6a4SAndroid Build Coastguard Worker ) -> Result<()> {
119*bb4ee6a4SAndroid Build Coastguard Worker let timer = Timer::new().expect("Failed to create a timer");
120*bb4ee6a4SAndroid Build Coastguard Worker let mut pageout_timer =
121*bb4ee6a4SAndroid Build Coastguard Worker TimerAsync::new(timer, ex).expect("Failed to create an async pageout timer");
122*bb4ee6a4SAndroid Build Coastguard Worker pageout_timer
123*bb4ee6a4SAndroid Build Coastguard Worker .reset_repeating(swap_interval)
124*bb4ee6a4SAndroid Build Coastguard Worker .expect("Failed to reset pageout timer");
125*bb4ee6a4SAndroid Build Coastguard Worker
126*bb4ee6a4SAndroid Build Coastguard Worker loop {
127*bb4ee6a4SAndroid Build Coastguard Worker pageout_timer.wait().await.map_err(Error::PageoutTimer)?;
128*bb4ee6a4SAndroid Build Coastguard Worker let request = VmMemoryMappingRequest::MadvisePageout {
129*bb4ee6a4SAndroid Build Coastguard Worker slot: mapping_arena_slot,
130*bb4ee6a4SAndroid Build Coastguard Worker offset: 0,
131*bb4ee6a4SAndroid Build Coastguard Worker size: mapping_size,
132*bb4ee6a4SAndroid Build Coastguard Worker };
133*bb4ee6a4SAndroid Build Coastguard Worker
134*bb4ee6a4SAndroid Build Coastguard Worker pmem_device_tube
135*bb4ee6a4SAndroid Build Coastguard Worker .send(&request)
136*bb4ee6a4SAndroid Build Coastguard Worker .map_err(Error::SendingRequest)?;
137*bb4ee6a4SAndroid Build Coastguard Worker match pmem_device_tube
138*bb4ee6a4SAndroid Build Coastguard Worker .recv::<VmMemoryMappingResponse>()
139*bb4ee6a4SAndroid Build Coastguard Worker .map_err(Error::ReceiveResponse)?
140*bb4ee6a4SAndroid Build Coastguard Worker {
141*bb4ee6a4SAndroid Build Coastguard Worker VmMemoryMappingResponse::Ok => {}
142*bb4ee6a4SAndroid Build Coastguard Worker VmMemoryMappingResponse::Err(e) => {
143*bb4ee6a4SAndroid Build Coastguard Worker error!("failed to page out the memory mapping: {}", e);
144*bb4ee6a4SAndroid Build Coastguard Worker }
145*bb4ee6a4SAndroid Build Coastguard Worker };
146*bb4ee6a4SAndroid Build Coastguard Worker }
147*bb4ee6a4SAndroid Build Coastguard Worker }
148*bb4ee6a4SAndroid Build Coastguard Worker
execute_request( request_type: u32, start_address: u64, size: u64, pmem_device_tube: &Tube, mapping_arena_slot: u32, mapping_size: usize, ) -> u32149*bb4ee6a4SAndroid Build Coastguard Worker fn execute_request(
150*bb4ee6a4SAndroid Build Coastguard Worker request_type: u32,
151*bb4ee6a4SAndroid Build Coastguard Worker start_address: u64,
152*bb4ee6a4SAndroid Build Coastguard Worker size: u64,
153*bb4ee6a4SAndroid Build Coastguard Worker pmem_device_tube: &Tube,
154*bb4ee6a4SAndroid Build Coastguard Worker mapping_arena_slot: u32,
155*bb4ee6a4SAndroid Build Coastguard Worker mapping_size: usize,
156*bb4ee6a4SAndroid Build Coastguard Worker ) -> u32 {
157*bb4ee6a4SAndroid Build Coastguard Worker match request_type {
158*bb4ee6a4SAndroid Build Coastguard Worker VIRTIO_PMEM_REQ_TYPE_FLUSH => {
159*bb4ee6a4SAndroid Build Coastguard Worker let request = VmMemoryMappingRequest::MsyncArena {
160*bb4ee6a4SAndroid Build Coastguard Worker slot: mapping_arena_slot,
161*bb4ee6a4SAndroid Build Coastguard Worker offset: 0, // The pmem backing file is always at offset 0 in the arena.
162*bb4ee6a4SAndroid Build Coastguard Worker size: mapping_size,
163*bb4ee6a4SAndroid Build Coastguard Worker };
164*bb4ee6a4SAndroid Build Coastguard Worker
165*bb4ee6a4SAndroid Build Coastguard Worker if let Err(e) = pmem_device_tube.send(&request) {
166*bb4ee6a4SAndroid Build Coastguard Worker error!("failed to send request: {}", e);
167*bb4ee6a4SAndroid Build Coastguard Worker return VIRTIO_PMEM_RESP_TYPE_EIO;
168*bb4ee6a4SAndroid Build Coastguard Worker }
169*bb4ee6a4SAndroid Build Coastguard Worker
170*bb4ee6a4SAndroid Build Coastguard Worker match pmem_device_tube.recv() {
171*bb4ee6a4SAndroid Build Coastguard Worker Ok(response) => match response {
172*bb4ee6a4SAndroid Build Coastguard Worker VmMemoryMappingResponse::Ok => VIRTIO_PMEM_RESP_TYPE_OK,
173*bb4ee6a4SAndroid Build Coastguard Worker VmMemoryMappingResponse::Err(e) => {
174*bb4ee6a4SAndroid Build Coastguard Worker error!("failed flushing disk image: {}", e);
175*bb4ee6a4SAndroid Build Coastguard Worker VIRTIO_PMEM_RESP_TYPE_EIO
176*bb4ee6a4SAndroid Build Coastguard Worker }
177*bb4ee6a4SAndroid Build Coastguard Worker },
178*bb4ee6a4SAndroid Build Coastguard Worker Err(e) => {
179*bb4ee6a4SAndroid Build Coastguard Worker error!("failed to receive data: {}", e);
180*bb4ee6a4SAndroid Build Coastguard Worker VIRTIO_PMEM_RESP_TYPE_EIO
181*bb4ee6a4SAndroid Build Coastguard Worker }
182*bb4ee6a4SAndroid Build Coastguard Worker }
183*bb4ee6a4SAndroid Build Coastguard Worker }
184*bb4ee6a4SAndroid Build Coastguard Worker
185*bb4ee6a4SAndroid Build Coastguard Worker VIRTIO_PMEM_REQ_TYPE_DISCARD => {
186*bb4ee6a4SAndroid Build Coastguard Worker let request = VmMemoryMappingRequest::MadviseRemove {
187*bb4ee6a4SAndroid Build Coastguard Worker slot: mapping_arena_slot,
188*bb4ee6a4SAndroid Build Coastguard Worker offset: usize::try_from(start_address).unwrap(),
189*bb4ee6a4SAndroid Build Coastguard Worker size: usize::try_from(size).unwrap(),
190*bb4ee6a4SAndroid Build Coastguard Worker };
191*bb4ee6a4SAndroid Build Coastguard Worker
192*bb4ee6a4SAndroid Build Coastguard Worker if let Err(e) = pmem_device_tube.send(&request) {
193*bb4ee6a4SAndroid Build Coastguard Worker error!("failed to send request: {}", e);
194*bb4ee6a4SAndroid Build Coastguard Worker return VIRTIO_PMEM_RESP_TYPE_EIO;
195*bb4ee6a4SAndroid Build Coastguard Worker }
196*bb4ee6a4SAndroid Build Coastguard Worker
197*bb4ee6a4SAndroid Build Coastguard Worker match pmem_device_tube.recv() {
198*bb4ee6a4SAndroid Build Coastguard Worker Ok(response) => match response {
199*bb4ee6a4SAndroid Build Coastguard Worker VmMemoryMappingResponse::Ok => VIRTIO_PMEM_RESP_TYPE_OK,
200*bb4ee6a4SAndroid Build Coastguard Worker VmMemoryMappingResponse::Err(e) => {
201*bb4ee6a4SAndroid Build Coastguard Worker error!("failed to discard memory range: {}", e);
202*bb4ee6a4SAndroid Build Coastguard Worker VIRTIO_PMEM_RESP_TYPE_EIO
203*bb4ee6a4SAndroid Build Coastguard Worker }
204*bb4ee6a4SAndroid Build Coastguard Worker },
205*bb4ee6a4SAndroid Build Coastguard Worker Err(e) => {
206*bb4ee6a4SAndroid Build Coastguard Worker error!("failed to receive data: {}", e);
207*bb4ee6a4SAndroid Build Coastguard Worker VIRTIO_PMEM_RESP_TYPE_EIO
208*bb4ee6a4SAndroid Build Coastguard Worker }
209*bb4ee6a4SAndroid Build Coastguard Worker }
210*bb4ee6a4SAndroid Build Coastguard Worker }
211*bb4ee6a4SAndroid Build Coastguard Worker
212*bb4ee6a4SAndroid Build Coastguard Worker _ => {
213*bb4ee6a4SAndroid Build Coastguard Worker error!("unknown request type: {}", request_type);
214*bb4ee6a4SAndroid Build Coastguard Worker VIRTIO_PMEM_RESP_TYPE_EIO
215*bb4ee6a4SAndroid Build Coastguard Worker }
216*bb4ee6a4SAndroid Build Coastguard Worker }
217*bb4ee6a4SAndroid Build Coastguard Worker }
218*bb4ee6a4SAndroid Build Coastguard Worker
handle_request( avail_desc: &mut DescriptorChain, pmem_device_tube: &Tube, mapping_arena_slot: u32, mapping_size: usize, ) -> Result<usize>219*bb4ee6a4SAndroid Build Coastguard Worker fn handle_request(
220*bb4ee6a4SAndroid Build Coastguard Worker avail_desc: &mut DescriptorChain,
221*bb4ee6a4SAndroid Build Coastguard Worker pmem_device_tube: &Tube,
222*bb4ee6a4SAndroid Build Coastguard Worker mapping_arena_slot: u32,
223*bb4ee6a4SAndroid Build Coastguard Worker mapping_size: usize,
224*bb4ee6a4SAndroid Build Coastguard Worker ) -> Result<usize> {
225*bb4ee6a4SAndroid Build Coastguard Worker let (request_type, start_address, size) =
226*bb4ee6a4SAndroid Build Coastguard Worker if avail_desc.reader.available_bytes() == size_of::<virtio_pmem_req>() {
227*bb4ee6a4SAndroid Build Coastguard Worker let request = avail_desc
228*bb4ee6a4SAndroid Build Coastguard Worker .reader
229*bb4ee6a4SAndroid Build Coastguard Worker .read_obj::<virtio_pmem_req>()
230*bb4ee6a4SAndroid Build Coastguard Worker .map_err(Error::ReadQueue)?;
231*bb4ee6a4SAndroid Build Coastguard Worker (request.type_.to_native(), 0, 0)
232*bb4ee6a4SAndroid Build Coastguard Worker } else {
233*bb4ee6a4SAndroid Build Coastguard Worker let request = avail_desc
234*bb4ee6a4SAndroid Build Coastguard Worker .reader
235*bb4ee6a4SAndroid Build Coastguard Worker .read_obj::<virtio_pmem_range_req>()
236*bb4ee6a4SAndroid Build Coastguard Worker .map_err(Error::ReadQueue)?;
237*bb4ee6a4SAndroid Build Coastguard Worker (
238*bb4ee6a4SAndroid Build Coastguard Worker request.type_.to_native(),
239*bb4ee6a4SAndroid Build Coastguard Worker request.start_address.to_native(),
240*bb4ee6a4SAndroid Build Coastguard Worker request.size.to_native(),
241*bb4ee6a4SAndroid Build Coastguard Worker )
242*bb4ee6a4SAndroid Build Coastguard Worker };
243*bb4ee6a4SAndroid Build Coastguard Worker let status_code = execute_request(
244*bb4ee6a4SAndroid Build Coastguard Worker request_type,
245*bb4ee6a4SAndroid Build Coastguard Worker start_address,
246*bb4ee6a4SAndroid Build Coastguard Worker size,
247*bb4ee6a4SAndroid Build Coastguard Worker pmem_device_tube,
248*bb4ee6a4SAndroid Build Coastguard Worker mapping_arena_slot,
249*bb4ee6a4SAndroid Build Coastguard Worker mapping_size,
250*bb4ee6a4SAndroid Build Coastguard Worker );
251*bb4ee6a4SAndroid Build Coastguard Worker
252*bb4ee6a4SAndroid Build Coastguard Worker let response = virtio_pmem_resp {
253*bb4ee6a4SAndroid Build Coastguard Worker status_code: status_code.into(),
254*bb4ee6a4SAndroid Build Coastguard Worker };
255*bb4ee6a4SAndroid Build Coastguard Worker
256*bb4ee6a4SAndroid Build Coastguard Worker avail_desc
257*bb4ee6a4SAndroid Build Coastguard Worker .writer
258*bb4ee6a4SAndroid Build Coastguard Worker .write_obj(response)
259*bb4ee6a4SAndroid Build Coastguard Worker .map_err(Error::WriteQueue)?;
260*bb4ee6a4SAndroid Build Coastguard Worker
261*bb4ee6a4SAndroid Build Coastguard Worker Ok(avail_desc.writer.bytes_written())
262*bb4ee6a4SAndroid Build Coastguard Worker }
263*bb4ee6a4SAndroid Build Coastguard Worker
handle_queue( queue: &mut Queue, mut queue_event: EventAsync, pmem_device_tube: &Tube, mapping_arena_slot: u32, mapping_size: usize, )264*bb4ee6a4SAndroid Build Coastguard Worker async fn handle_queue(
265*bb4ee6a4SAndroid Build Coastguard Worker queue: &mut Queue,
266*bb4ee6a4SAndroid Build Coastguard Worker mut queue_event: EventAsync,
267*bb4ee6a4SAndroid Build Coastguard Worker pmem_device_tube: &Tube,
268*bb4ee6a4SAndroid Build Coastguard Worker mapping_arena_slot: u32,
269*bb4ee6a4SAndroid Build Coastguard Worker mapping_size: usize,
270*bb4ee6a4SAndroid Build Coastguard Worker ) {
271*bb4ee6a4SAndroid Build Coastguard Worker loop {
272*bb4ee6a4SAndroid Build Coastguard Worker let mut avail_desc = match queue.next_async(&mut queue_event).await {
273*bb4ee6a4SAndroid Build Coastguard Worker Err(e) => {
274*bb4ee6a4SAndroid Build Coastguard Worker error!("Failed to read descriptor {}", e);
275*bb4ee6a4SAndroid Build Coastguard Worker return;
276*bb4ee6a4SAndroid Build Coastguard Worker }
277*bb4ee6a4SAndroid Build Coastguard Worker Ok(d) => d,
278*bb4ee6a4SAndroid Build Coastguard Worker };
279*bb4ee6a4SAndroid Build Coastguard Worker
280*bb4ee6a4SAndroid Build Coastguard Worker let written = match handle_request(
281*bb4ee6a4SAndroid Build Coastguard Worker &mut avail_desc,
282*bb4ee6a4SAndroid Build Coastguard Worker pmem_device_tube,
283*bb4ee6a4SAndroid Build Coastguard Worker mapping_arena_slot,
284*bb4ee6a4SAndroid Build Coastguard Worker mapping_size,
285*bb4ee6a4SAndroid Build Coastguard Worker ) {
286*bb4ee6a4SAndroid Build Coastguard Worker Ok(n) => n,
287*bb4ee6a4SAndroid Build Coastguard Worker Err(e) => {
288*bb4ee6a4SAndroid Build Coastguard Worker error!("pmem: failed to handle request: {}", e);
289*bb4ee6a4SAndroid Build Coastguard Worker 0
290*bb4ee6a4SAndroid Build Coastguard Worker }
291*bb4ee6a4SAndroid Build Coastguard Worker };
292*bb4ee6a4SAndroid Build Coastguard Worker queue.add_used(avail_desc, written as u32);
293*bb4ee6a4SAndroid Build Coastguard Worker queue.trigger_interrupt();
294*bb4ee6a4SAndroid Build Coastguard Worker }
295*bb4ee6a4SAndroid Build Coastguard Worker }
296*bb4ee6a4SAndroid Build Coastguard Worker
run_worker( queue: &mut Queue, pmem_device_tube: &Tube, interrupt: Interrupt, kill_evt: Event, mapping_arena_slot: u32, mapping_size: usize, swap_interval: Option<Duration>, )297*bb4ee6a4SAndroid Build Coastguard Worker fn run_worker(
298*bb4ee6a4SAndroid Build Coastguard Worker queue: &mut Queue,
299*bb4ee6a4SAndroid Build Coastguard Worker pmem_device_tube: &Tube,
300*bb4ee6a4SAndroid Build Coastguard Worker interrupt: Interrupt,
301*bb4ee6a4SAndroid Build Coastguard Worker kill_evt: Event,
302*bb4ee6a4SAndroid Build Coastguard Worker mapping_arena_slot: u32,
303*bb4ee6a4SAndroid Build Coastguard Worker mapping_size: usize,
304*bb4ee6a4SAndroid Build Coastguard Worker swap_interval: Option<Duration>,
305*bb4ee6a4SAndroid Build Coastguard Worker ) {
306*bb4ee6a4SAndroid Build Coastguard Worker let ex = Executor::new().unwrap();
307*bb4ee6a4SAndroid Build Coastguard Worker
308*bb4ee6a4SAndroid Build Coastguard Worker let queue_evt = queue
309*bb4ee6a4SAndroid Build Coastguard Worker .event()
310*bb4ee6a4SAndroid Build Coastguard Worker .try_clone()
311*bb4ee6a4SAndroid Build Coastguard Worker .expect("failed to clone queue event");
312*bb4ee6a4SAndroid Build Coastguard Worker let queue_evt = EventAsync::new(queue_evt, &ex).expect("failed to set up the queue event");
313*bb4ee6a4SAndroid Build Coastguard Worker
314*bb4ee6a4SAndroid Build Coastguard Worker // Process requests from the virtio queue.
315*bb4ee6a4SAndroid Build Coastguard Worker let queue_fut = handle_queue(
316*bb4ee6a4SAndroid Build Coastguard Worker queue,
317*bb4ee6a4SAndroid Build Coastguard Worker queue_evt,
318*bb4ee6a4SAndroid Build Coastguard Worker pmem_device_tube,
319*bb4ee6a4SAndroid Build Coastguard Worker mapping_arena_slot,
320*bb4ee6a4SAndroid Build Coastguard Worker mapping_size,
321*bb4ee6a4SAndroid Build Coastguard Worker );
322*bb4ee6a4SAndroid Build Coastguard Worker pin_mut!(queue_fut);
323*bb4ee6a4SAndroid Build Coastguard Worker
324*bb4ee6a4SAndroid Build Coastguard Worker // Process any requests to resample the irq value.
325*bb4ee6a4SAndroid Build Coastguard Worker let resample = async_utils::handle_irq_resample(&ex, interrupt);
326*bb4ee6a4SAndroid Build Coastguard Worker pin_mut!(resample);
327*bb4ee6a4SAndroid Build Coastguard Worker
328*bb4ee6a4SAndroid Build Coastguard Worker // Exit if the kill event is triggered.
329*bb4ee6a4SAndroid Build Coastguard Worker let kill = async_utils::await_and_exit(&ex, kill_evt);
330*bb4ee6a4SAndroid Build Coastguard Worker pin_mut!(kill);
331*bb4ee6a4SAndroid Build Coastguard Worker
332*bb4ee6a4SAndroid Build Coastguard Worker let interval = swap_interval.unwrap_or(Duration::ZERO);
333*bb4ee6a4SAndroid Build Coastguard Worker if interval.is_zero() {
334*bb4ee6a4SAndroid Build Coastguard Worker if let Err(e) = ex.run_until(select3(queue_fut, resample, kill)) {
335*bb4ee6a4SAndroid Build Coastguard Worker error!("error happened in executor: {}", e);
336*bb4ee6a4SAndroid Build Coastguard Worker }
337*bb4ee6a4SAndroid Build Coastguard Worker } else {
338*bb4ee6a4SAndroid Build Coastguard Worker let pageout_fut = pageout(
339*bb4ee6a4SAndroid Build Coastguard Worker &ex,
340*bb4ee6a4SAndroid Build Coastguard Worker interval,
341*bb4ee6a4SAndroid Build Coastguard Worker pmem_device_tube,
342*bb4ee6a4SAndroid Build Coastguard Worker mapping_arena_slot,
343*bb4ee6a4SAndroid Build Coastguard Worker mapping_size,
344*bb4ee6a4SAndroid Build Coastguard Worker );
345*bb4ee6a4SAndroid Build Coastguard Worker pin_mut!(pageout_fut);
346*bb4ee6a4SAndroid Build Coastguard Worker if let Err(e) = ex.run_until(select4(queue_fut, resample, kill, pageout_fut)) {
347*bb4ee6a4SAndroid Build Coastguard Worker error!("error happened in executor: {}", e);
348*bb4ee6a4SAndroid Build Coastguard Worker }
349*bb4ee6a4SAndroid Build Coastguard Worker }
350*bb4ee6a4SAndroid Build Coastguard Worker }
351*bb4ee6a4SAndroid Build Coastguard Worker
352*bb4ee6a4SAndroid Build Coastguard Worker /// Specifies how memory slot is initialized.
353*bb4ee6a4SAndroid Build Coastguard Worker pub enum MemSlotConfig {
354*bb4ee6a4SAndroid Build Coastguard Worker /// The memory region has already been mapped to the guest.
355*bb4ee6a4SAndroid Build Coastguard Worker MemSlot {
356*bb4ee6a4SAndroid Build Coastguard Worker /// index of the guest-mapped memory regions.
357*bb4ee6a4SAndroid Build Coastguard Worker idx: MemSlot,
358*bb4ee6a4SAndroid Build Coastguard Worker },
359*bb4ee6a4SAndroid Build Coastguard Worker /// The memory region that is not initialized yet and whose slot index will be provided via
360*bb4ee6a4SAndroid Build Coastguard Worker /// `Tube` later. e.g. pmem-ext2 device, where fs construction will be done in the main
361*bb4ee6a4SAndroid Build Coastguard Worker /// process.
362*bb4ee6a4SAndroid Build Coastguard Worker LazyInit { tube: Tube },
363*bb4ee6a4SAndroid Build Coastguard Worker }
364*bb4ee6a4SAndroid Build Coastguard Worker
365*bb4ee6a4SAndroid Build Coastguard Worker pub struct Pmem {
366*bb4ee6a4SAndroid Build Coastguard Worker worker_thread: Option<WorkerThread<(Queue, Tube)>>,
367*bb4ee6a4SAndroid Build Coastguard Worker features: u64,
368*bb4ee6a4SAndroid Build Coastguard Worker disk_image: Option<File>,
369*bb4ee6a4SAndroid Build Coastguard Worker mapping_address: GuestAddress,
370*bb4ee6a4SAndroid Build Coastguard Worker mem_slot: MemSlotConfig,
371*bb4ee6a4SAndroid Build Coastguard Worker mapping_size: u64,
372*bb4ee6a4SAndroid Build Coastguard Worker pmem_device_tube: Option<Tube>,
373*bb4ee6a4SAndroid Build Coastguard Worker swap_interval: Option<Duration>,
374*bb4ee6a4SAndroid Build Coastguard Worker }
375*bb4ee6a4SAndroid Build Coastguard Worker
376*bb4ee6a4SAndroid Build Coastguard Worker #[derive(serde::Serialize, serde::Deserialize)]
377*bb4ee6a4SAndroid Build Coastguard Worker struct PmemSnapshot {
378*bb4ee6a4SAndroid Build Coastguard Worker mapping_address: GuestAddress,
379*bb4ee6a4SAndroid Build Coastguard Worker mapping_size: u64,
380*bb4ee6a4SAndroid Build Coastguard Worker }
381*bb4ee6a4SAndroid Build Coastguard Worker
382*bb4ee6a4SAndroid Build Coastguard Worker /// Configuration of a virtio-pmem device.
383*bb4ee6a4SAndroid Build Coastguard Worker pub struct PmemConfig {
384*bb4ee6a4SAndroid Build Coastguard Worker /// Disk image exposed to the guest.
385*bb4ee6a4SAndroid Build Coastguard Worker /// If the memory region is not backed by a file, this should be `None`.
386*bb4ee6a4SAndroid Build Coastguard Worker pub disk_image: Option<File>,
387*bb4ee6a4SAndroid Build Coastguard Worker /// Guest physical address where the memory will be mapped.
388*bb4ee6a4SAndroid Build Coastguard Worker pub mapping_address: GuestAddress,
389*bb4ee6a4SAndroid Build Coastguard Worker pub mem_slot: MemSlotConfig,
390*bb4ee6a4SAndroid Build Coastguard Worker /// The size of the mapped region.
391*bb4ee6a4SAndroid Build Coastguard Worker pub mapping_size: u64,
392*bb4ee6a4SAndroid Build Coastguard Worker /// A communication channel to the main process to send memory requests.
393*bb4ee6a4SAndroid Build Coastguard Worker pub pmem_device_tube: Tube,
394*bb4ee6a4SAndroid Build Coastguard Worker /// Interval for periodic swap out of memory mapping
395*bb4ee6a4SAndroid Build Coastguard Worker pub swap_interval: Option<Duration>,
396*bb4ee6a4SAndroid Build Coastguard Worker /// Whether the region is writeble or not.
397*bb4ee6a4SAndroid Build Coastguard Worker pub mapping_writable: bool,
398*bb4ee6a4SAndroid Build Coastguard Worker }
399*bb4ee6a4SAndroid Build Coastguard Worker
400*bb4ee6a4SAndroid Build Coastguard Worker impl Pmem {
new(base_features: u64, cfg: PmemConfig) -> SysResult<Pmem>401*bb4ee6a4SAndroid Build Coastguard Worker pub fn new(base_features: u64, cfg: PmemConfig) -> SysResult<Pmem> {
402*bb4ee6a4SAndroid Build Coastguard Worker if cfg.mapping_size > usize::MAX as u64 {
403*bb4ee6a4SAndroid Build Coastguard Worker return Err(SysError::new(libc::EOVERFLOW));
404*bb4ee6a4SAndroid Build Coastguard Worker }
405*bb4ee6a4SAndroid Build Coastguard Worker
406*bb4ee6a4SAndroid Build Coastguard Worker let mut avail_features = base_features;
407*bb4ee6a4SAndroid Build Coastguard Worker if cfg.mapping_writable {
408*bb4ee6a4SAndroid Build Coastguard Worker if let MemSlotConfig::LazyInit { .. } = cfg.mem_slot {
409*bb4ee6a4SAndroid Build Coastguard Worker error!("pmem-ext2 must be a read-only device");
410*bb4ee6a4SAndroid Build Coastguard Worker return Err(SysError::new(libc::EINVAL));
411*bb4ee6a4SAndroid Build Coastguard Worker }
412*bb4ee6a4SAndroid Build Coastguard Worker
413*bb4ee6a4SAndroid Build Coastguard Worker avail_features |= 1 << VIRTIO_PMEM_F_DISCARD;
414*bb4ee6a4SAndroid Build Coastguard Worker }
415*bb4ee6a4SAndroid Build Coastguard Worker
416*bb4ee6a4SAndroid Build Coastguard Worker Ok(Pmem {
417*bb4ee6a4SAndroid Build Coastguard Worker worker_thread: None,
418*bb4ee6a4SAndroid Build Coastguard Worker features: avail_features,
419*bb4ee6a4SAndroid Build Coastguard Worker disk_image: cfg.disk_image,
420*bb4ee6a4SAndroid Build Coastguard Worker mapping_address: cfg.mapping_address,
421*bb4ee6a4SAndroid Build Coastguard Worker mem_slot: cfg.mem_slot,
422*bb4ee6a4SAndroid Build Coastguard Worker mapping_size: cfg.mapping_size,
423*bb4ee6a4SAndroid Build Coastguard Worker pmem_device_tube: Some(cfg.pmem_device_tube),
424*bb4ee6a4SAndroid Build Coastguard Worker swap_interval: cfg.swap_interval,
425*bb4ee6a4SAndroid Build Coastguard Worker })
426*bb4ee6a4SAndroid Build Coastguard Worker }
427*bb4ee6a4SAndroid Build Coastguard Worker }
428*bb4ee6a4SAndroid Build Coastguard Worker
429*bb4ee6a4SAndroid Build Coastguard Worker impl VirtioDevice for Pmem {
keep_rds(&self) -> Vec<RawDescriptor>430*bb4ee6a4SAndroid Build Coastguard Worker fn keep_rds(&self) -> Vec<RawDescriptor> {
431*bb4ee6a4SAndroid Build Coastguard Worker let mut keep_rds = Vec::new();
432*bb4ee6a4SAndroid Build Coastguard Worker if let Some(disk_image) = &self.disk_image {
433*bb4ee6a4SAndroid Build Coastguard Worker keep_rds.push(disk_image.as_raw_descriptor());
434*bb4ee6a4SAndroid Build Coastguard Worker }
435*bb4ee6a4SAndroid Build Coastguard Worker
436*bb4ee6a4SAndroid Build Coastguard Worker if let Some(ref pmem_device_tube) = self.pmem_device_tube {
437*bb4ee6a4SAndroid Build Coastguard Worker keep_rds.push(pmem_device_tube.as_raw_descriptor());
438*bb4ee6a4SAndroid Build Coastguard Worker }
439*bb4ee6a4SAndroid Build Coastguard Worker
440*bb4ee6a4SAndroid Build Coastguard Worker if let MemSlotConfig::LazyInit { tube } = &self.mem_slot {
441*bb4ee6a4SAndroid Build Coastguard Worker keep_rds.push(tube.as_raw_descriptor());
442*bb4ee6a4SAndroid Build Coastguard Worker }
443*bb4ee6a4SAndroid Build Coastguard Worker
444*bb4ee6a4SAndroid Build Coastguard Worker keep_rds
445*bb4ee6a4SAndroid Build Coastguard Worker }
446*bb4ee6a4SAndroid Build Coastguard Worker
device_type(&self) -> DeviceType447*bb4ee6a4SAndroid Build Coastguard Worker fn device_type(&self) -> DeviceType {
448*bb4ee6a4SAndroid Build Coastguard Worker DeviceType::Pmem
449*bb4ee6a4SAndroid Build Coastguard Worker }
450*bb4ee6a4SAndroid Build Coastguard Worker
queue_max_sizes(&self) -> &[u16]451*bb4ee6a4SAndroid Build Coastguard Worker fn queue_max_sizes(&self) -> &[u16] {
452*bb4ee6a4SAndroid Build Coastguard Worker QUEUE_SIZES
453*bb4ee6a4SAndroid Build Coastguard Worker }
454*bb4ee6a4SAndroid Build Coastguard Worker
features(&self) -> u64455*bb4ee6a4SAndroid Build Coastguard Worker fn features(&self) -> u64 {
456*bb4ee6a4SAndroid Build Coastguard Worker self.features
457*bb4ee6a4SAndroid Build Coastguard Worker }
458*bb4ee6a4SAndroid Build Coastguard Worker
read_config(&self, offset: u64, data: &mut [u8])459*bb4ee6a4SAndroid Build Coastguard Worker fn read_config(&self, offset: u64, data: &mut [u8]) {
460*bb4ee6a4SAndroid Build Coastguard Worker let config = virtio_pmem_config {
461*bb4ee6a4SAndroid Build Coastguard Worker start_address: Le64::from(self.mapping_address.offset()),
462*bb4ee6a4SAndroid Build Coastguard Worker size: Le64::from(self.mapping_size),
463*bb4ee6a4SAndroid Build Coastguard Worker };
464*bb4ee6a4SAndroid Build Coastguard Worker copy_config(data, 0, config.as_bytes(), offset);
465*bb4ee6a4SAndroid Build Coastguard Worker }
466*bb4ee6a4SAndroid Build Coastguard Worker
activate( &mut self, _memory: GuestMemory, interrupt: Interrupt, mut queues: BTreeMap<usize, Queue>, ) -> anyhow::Result<()>467*bb4ee6a4SAndroid Build Coastguard Worker fn activate(
468*bb4ee6a4SAndroid Build Coastguard Worker &mut self,
469*bb4ee6a4SAndroid Build Coastguard Worker _memory: GuestMemory,
470*bb4ee6a4SAndroid Build Coastguard Worker interrupt: Interrupt,
471*bb4ee6a4SAndroid Build Coastguard Worker mut queues: BTreeMap<usize, Queue>,
472*bb4ee6a4SAndroid Build Coastguard Worker ) -> anyhow::Result<()> {
473*bb4ee6a4SAndroid Build Coastguard Worker if queues.len() != 1 {
474*bb4ee6a4SAndroid Build Coastguard Worker return Err(anyhow!("expected 1 queue, got {}", queues.len()));
475*bb4ee6a4SAndroid Build Coastguard Worker }
476*bb4ee6a4SAndroid Build Coastguard Worker
477*bb4ee6a4SAndroid Build Coastguard Worker let mut queue = queues.remove(&0).unwrap();
478*bb4ee6a4SAndroid Build Coastguard Worker
479*bb4ee6a4SAndroid Build Coastguard Worker // We checked that this fits in a usize in `Pmem::new`.
480*bb4ee6a4SAndroid Build Coastguard Worker let mapping_size = self.mapping_size as usize;
481*bb4ee6a4SAndroid Build Coastguard Worker
482*bb4ee6a4SAndroid Build Coastguard Worker let pmem_device_tube = self
483*bb4ee6a4SAndroid Build Coastguard Worker .pmem_device_tube
484*bb4ee6a4SAndroid Build Coastguard Worker .take()
485*bb4ee6a4SAndroid Build Coastguard Worker .context("missing pmem device tube")?;
486*bb4ee6a4SAndroid Build Coastguard Worker
487*bb4ee6a4SAndroid Build Coastguard Worker let swap_interval = self.swap_interval;
488*bb4ee6a4SAndroid Build Coastguard Worker
489*bb4ee6a4SAndroid Build Coastguard Worker let mapping_arena_slot = match &self.mem_slot {
490*bb4ee6a4SAndroid Build Coastguard Worker MemSlotConfig::MemSlot { idx } => *idx,
491*bb4ee6a4SAndroid Build Coastguard Worker MemSlotConfig::LazyInit { tube } => tube
492*bb4ee6a4SAndroid Build Coastguard Worker .recv::<u32>()
493*bb4ee6a4SAndroid Build Coastguard Worker .context("failed to receive memory slot for ext2 pmem device")?,
494*bb4ee6a4SAndroid Build Coastguard Worker };
495*bb4ee6a4SAndroid Build Coastguard Worker
496*bb4ee6a4SAndroid Build Coastguard Worker self.worker_thread = Some(WorkerThread::start("v_pmem", move |kill_event| {
497*bb4ee6a4SAndroid Build Coastguard Worker run_worker(
498*bb4ee6a4SAndroid Build Coastguard Worker &mut queue,
499*bb4ee6a4SAndroid Build Coastguard Worker &pmem_device_tube,
500*bb4ee6a4SAndroid Build Coastguard Worker interrupt,
501*bb4ee6a4SAndroid Build Coastguard Worker kill_event,
502*bb4ee6a4SAndroid Build Coastguard Worker mapping_arena_slot,
503*bb4ee6a4SAndroid Build Coastguard Worker mapping_size,
504*bb4ee6a4SAndroid Build Coastguard Worker swap_interval,
505*bb4ee6a4SAndroid Build Coastguard Worker );
506*bb4ee6a4SAndroid Build Coastguard Worker (queue, pmem_device_tube)
507*bb4ee6a4SAndroid Build Coastguard Worker }));
508*bb4ee6a4SAndroid Build Coastguard Worker
509*bb4ee6a4SAndroid Build Coastguard Worker Ok(())
510*bb4ee6a4SAndroid Build Coastguard Worker }
511*bb4ee6a4SAndroid Build Coastguard Worker
reset(&mut self) -> anyhow::Result<()>512*bb4ee6a4SAndroid Build Coastguard Worker fn reset(&mut self) -> anyhow::Result<()> {
513*bb4ee6a4SAndroid Build Coastguard Worker if let Some(worker_thread) = self.worker_thread.take() {
514*bb4ee6a4SAndroid Build Coastguard Worker let (_queue, pmem_device_tube) = worker_thread.stop();
515*bb4ee6a4SAndroid Build Coastguard Worker self.pmem_device_tube = Some(pmem_device_tube);
516*bb4ee6a4SAndroid Build Coastguard Worker }
517*bb4ee6a4SAndroid Build Coastguard Worker Ok(())
518*bb4ee6a4SAndroid Build Coastguard Worker }
519*bb4ee6a4SAndroid Build Coastguard Worker
virtio_sleep(&mut self) -> anyhow::Result<Option<BTreeMap<usize, Queue>>>520*bb4ee6a4SAndroid Build Coastguard Worker fn virtio_sleep(&mut self) -> anyhow::Result<Option<BTreeMap<usize, Queue>>> {
521*bb4ee6a4SAndroid Build Coastguard Worker if let Some(worker_thread) = self.worker_thread.take() {
522*bb4ee6a4SAndroid Build Coastguard Worker let (queue, pmem_device_tube) = worker_thread.stop();
523*bb4ee6a4SAndroid Build Coastguard Worker self.pmem_device_tube = Some(pmem_device_tube);
524*bb4ee6a4SAndroid Build Coastguard Worker return Ok(Some(BTreeMap::from([(0, queue)])));
525*bb4ee6a4SAndroid Build Coastguard Worker }
526*bb4ee6a4SAndroid Build Coastguard Worker Ok(None)
527*bb4ee6a4SAndroid Build Coastguard Worker }
528*bb4ee6a4SAndroid Build Coastguard Worker
virtio_wake( &mut self, queues_state: Option<(GuestMemory, Interrupt, BTreeMap<usize, Queue>)>, ) -> anyhow::Result<()>529*bb4ee6a4SAndroid Build Coastguard Worker fn virtio_wake(
530*bb4ee6a4SAndroid Build Coastguard Worker &mut self,
531*bb4ee6a4SAndroid Build Coastguard Worker queues_state: Option<(GuestMemory, Interrupt, BTreeMap<usize, Queue>)>,
532*bb4ee6a4SAndroid Build Coastguard Worker ) -> anyhow::Result<()> {
533*bb4ee6a4SAndroid Build Coastguard Worker if let Some((mem, interrupt, queues)) = queues_state {
534*bb4ee6a4SAndroid Build Coastguard Worker self.activate(mem, interrupt, queues)?;
535*bb4ee6a4SAndroid Build Coastguard Worker }
536*bb4ee6a4SAndroid Build Coastguard Worker Ok(())
537*bb4ee6a4SAndroid Build Coastguard Worker }
538*bb4ee6a4SAndroid Build Coastguard Worker
virtio_snapshot(&mut self) -> anyhow::Result<serde_json::Value>539*bb4ee6a4SAndroid Build Coastguard Worker fn virtio_snapshot(&mut self) -> anyhow::Result<serde_json::Value> {
540*bb4ee6a4SAndroid Build Coastguard Worker serde_json::to_value(PmemSnapshot {
541*bb4ee6a4SAndroid Build Coastguard Worker mapping_address: self.mapping_address,
542*bb4ee6a4SAndroid Build Coastguard Worker mapping_size: self.mapping_size,
543*bb4ee6a4SAndroid Build Coastguard Worker })
544*bb4ee6a4SAndroid Build Coastguard Worker .context("failed to serialize pmem snapshot")
545*bb4ee6a4SAndroid Build Coastguard Worker }
546*bb4ee6a4SAndroid Build Coastguard Worker
virtio_restore(&mut self, data: serde_json::Value) -> anyhow::Result<()>547*bb4ee6a4SAndroid Build Coastguard Worker fn virtio_restore(&mut self, data: serde_json::Value) -> anyhow::Result<()> {
548*bb4ee6a4SAndroid Build Coastguard Worker let snapshot: PmemSnapshot =
549*bb4ee6a4SAndroid Build Coastguard Worker serde_json::from_value(data).context("failed to deserialize pmem snapshot")?;
550*bb4ee6a4SAndroid Build Coastguard Worker anyhow::ensure!(
551*bb4ee6a4SAndroid Build Coastguard Worker snapshot.mapping_address == self.mapping_address
552*bb4ee6a4SAndroid Build Coastguard Worker && snapshot.mapping_size == self.mapping_size,
553*bb4ee6a4SAndroid Build Coastguard Worker "pmem snapshot doesn't match config: expected {:?}, got {:?}",
554*bb4ee6a4SAndroid Build Coastguard Worker (self.mapping_address, self.mapping_size),
555*bb4ee6a4SAndroid Build Coastguard Worker (snapshot.mapping_address, snapshot.mapping_size),
556*bb4ee6a4SAndroid Build Coastguard Worker );
557*bb4ee6a4SAndroid Build Coastguard Worker Ok(())
558*bb4ee6a4SAndroid Build Coastguard Worker }
559*bb4ee6a4SAndroid Build Coastguard Worker }
560