Skip to content

Commit 91c18a6

Browse files
committed
refactor: VirtIO MMIO persistence logic
VirtIO MMIO restore logic activates the device the moment we restore the device state, if the device was activated when snapshotted. Move the activation responsibility to the logic the restores the MMIO transport. The reason for this change is that that's how it will be done for the PCI transport. Unifying this will allow us reusing the same types for restoring the non-transport state of devices. Note that we needed to change the way Net devices are saved/restored. RxBuffer type of Net devices holds RX descriptors that we have parsed from the Queue ahead of time. The way we restored this info was manipulating the queue to re-parse the RX descriptors during the restore phase. However, we need the device to be activated to do so, which now isn't. So, instead of storing this info inside the snapshot make sure we have flushed everything before taking the snapshot. Also, simplify a bit the types that we use for serializing/deserializing the state of a device. Signed-off-by: Babis Chalios <[email protected]>
1 parent 9400d39 commit 91c18a6

File tree

8 files changed

+106
-239
lines changed

8 files changed

+106
-239
lines changed

src/vmm/src/device_manager/persist.rs

Lines changed: 62 additions & 129 deletions
Large diffs are not rendered by default.

src/vmm/src/devices/virtio/balloon/persist.rs

Lines changed: 13 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -87,16 +87,14 @@ pub struct BalloonState {
8787
stats_desc_index: Option<u16>,
8888
latest_stats: BalloonStatsState,
8989
config_space: BalloonConfigSpaceState,
90-
virtio_state: VirtioDeviceState,
90+
pub virtio_state: VirtioDeviceState,
9191
}
9292

9393
/// Auxiliary structure for creating a device when resuming from a snapshot.
9494
#[derive(Debug)]
9595
pub struct BalloonConstructorArgs {
9696
/// Pointer to guest memory.
9797
pub mem: GuestMemoryMmap,
98-
/// Interrupt used from the device.
99-
pub interrupt: Arc<dyn VirtioInterrupt>,
10098
pub restored_from_file: bool,
10199
}
102100

@@ -154,25 +152,18 @@ impl Persist<'_> for Balloon {
154152
actual_pages: state.config_space.actual_pages,
155153
};
156154

157-
if state.virtio_state.activated {
158-
balloon.device_state = DeviceState::Activated(ActiveState {
159-
mem: constructor_args.mem,
160-
interrupt: constructor_args.interrupt,
161-
});
162-
163-
if balloon.stats_enabled() {
164-
// Restore the stats descriptor.
165-
balloon.set_stats_desc_index(state.stats_desc_index);
166-
167-
// Restart timer if needed.
168-
let timer_state = TimerState::Periodic {
169-
current: Duration::from_secs(u64::from(state.stats_polling_interval_s)),
170-
interval: Duration::from_secs(u64::from(state.stats_polling_interval_s)),
171-
};
172-
balloon
173-
.stats_timer
174-
.set_state(timer_state, SetTimeFlags::Default);
175-
}
155+
if state.virtio_state.activated && balloon.stats_enabled() {
156+
// Restore the stats descriptor.
157+
balloon.set_stats_desc_index(state.stats_desc_index);
158+
159+
// Restart timer if needed.
160+
let timer_state = TimerState::Periodic {
161+
current: Duration::from_secs(u64::from(state.stats_polling_interval_s)),
162+
interval: Duration::from_secs(u64::from(state.stats_polling_interval_s)),
163+
};
164+
balloon
165+
.stats_timer
166+
.set_state(timer_state, SetTimeFlags::Default);
176167
}
177168

178169
Ok(balloon)
@@ -202,7 +193,6 @@ mod tests {
202193
let restored_balloon = Balloon::restore(
203194
BalloonConstructorArgs {
204195
mem: guest_mem,
205-
interrupt: default_interrupt(),
206196
restored_from_file: true,
207197
},
208198
&Snapshot::deserialize(&mut mem.as_slice()).unwrap(),

src/vmm/src/devices/virtio/block/persist.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,17 @@ pub enum BlockState {
1717
VhostUser(VhostUserBlockState),
1818
}
1919

20+
impl BlockState {
21+
pub fn is_activated(&self) -> bool {
22+
match self {
23+
BlockState::Virtio(virtio_block_state) => virtio_block_state.virtio_state.activated,
24+
BlockState::VhostUser(vhost_user_block_state) => false,
25+
}
26+
}
27+
}
28+
2029
/// Auxiliary structure for creating a device when resuming from a snapshot.
2130
#[derive(Debug)]
2231
pub struct BlockConstructorArgs {
2332
pub mem: GuestMemoryMmap,
24-
pub interrupt: Arc<dyn VirtioInterrupt>,
2533
}

src/vmm/src/devices/virtio/block/virtio/persist.rs

Lines changed: 3 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ pub struct VirtioBlockState {
5858
cache_type: CacheType,
5959
root_device: bool,
6060
disk_path: String,
61-
virtio_state: VirtioDeviceState,
61+
pub virtio_state: VirtioDeviceState,
6262
rate_limiter_state: RateLimiterState,
6363
file_engine_type: FileEngineTypeState,
6464
}
@@ -111,15 +111,6 @@ impl Persist<'_> for VirtioBlock {
111111
let avail_features = state.virtio_state.avail_features;
112112
let acked_features = state.virtio_state.acked_features;
113113

114-
let device_state = if state.virtio_state.activated {
115-
DeviceState::Activated(ActiveState {
116-
mem: constructor_args.mem,
117-
interrupt: constructor_args.interrupt,
118-
})
119-
} else {
120-
DeviceState::Inactive
121-
};
122-
123114
let config_space = ConfigSpace {
124115
capacity: disk_properties.nsectors.to_le(),
125116
};
@@ -132,7 +123,7 @@ impl Persist<'_> for VirtioBlock {
132123

133124
queues,
134125
queue_evts,
135-
device_state,
126+
device_state: DeviceState::Inactive,
136127

137128
id: state.id.clone(),
138129
partuuid: state.partuuid.clone(),
@@ -227,10 +218,7 @@ mod tests {
227218

228219
// Restore the block device.
229220
let restored_block = VirtioBlock::restore(
230-
BlockConstructorArgs {
231-
mem: guest_mem,
232-
interrupt: default_interrupt(),
233-
},
221+
BlockConstructorArgs { mem: guest_mem },
234222
&Snapshot::deserialize(&mut mem.as_slice()).unwrap(),
235223
)
236224
.unwrap();

src/vmm/src/devices/virtio/net/device.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -930,6 +930,19 @@ impl Net {
930930
let _ = self.resume_rx();
931931
let _ = self.process_tx();
932932
}
933+
934+
/// Prepare saving state
935+
pub fn prepare_save(&mut self) {
936+
if !self.is_activated() {
937+
return;
938+
}
939+
940+
// Give potential deferred RX frame to guest
941+
self.rx_buffer.finish_frame(&mut self.queues[RX_INDEX]);
942+
// Reset the parsed available descriptors, so we will re-parse them
943+
self.queues[RX_INDEX].next_avail -=
944+
u16::try_from(self.rx_buffer.parsed_descriptors.len()).unwrap();
945+
}
933946
}
934947

935948
impl VirtioDevice for Net {

src/vmm/src/devices/virtio/net/persist.rs

Lines changed: 1 addition & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -30,27 +30,6 @@ pub struct NetConfigSpaceState {
3030
guest_mac: Option<MacAddr>,
3131
}
3232

33-
/// Information about the parsed RX buffers
34-
#[derive(Debug, Default, Clone, Serialize, Deserialize)]
35-
pub struct RxBufferState {
36-
// Number of iovecs we have parsed from the guest
37-
parsed_descriptor_chains_nr: u16,
38-
// Number of used descriptors
39-
used_descriptors: u16,
40-
// Number of used bytes
41-
used_bytes: u32,
42-
}
43-
44-
impl RxBufferState {
45-
fn from_rx_buffers(rx_buffer: &RxBuffers) -> Self {
46-
RxBufferState {
47-
parsed_descriptor_chains_nr: rx_buffer.parsed_descriptors.len().try_into().unwrap(),
48-
used_descriptors: rx_buffer.used_descriptors,
49-
used_bytes: rx_buffer.used_bytes,
50-
}
51-
}
52-
}
53-
5433
/// Information about the network device that are saved
5534
/// at snapshot.
5635
#[derive(Debug, Clone, Serialize, Deserialize)]
@@ -62,17 +41,14 @@ pub struct NetState {
6241
/// The associated MMDS network stack.
6342
pub mmds_ns: Option<MmdsNetworkStackState>,
6443
config_space: NetConfigSpaceState,
65-
virtio_state: VirtioDeviceState,
66-
rx_buffers_state: RxBufferState,
44+
pub virtio_state: VirtioDeviceState,
6745
}
6846

6947
/// Auxiliary structure for creating a device when resuming from a snapshot.
7048
#[derive(Debug)]
7149
pub struct NetConstructorArgs {
7250
/// Pointer to guest memory.
7351
pub mem: GuestMemoryMmap,
74-
/// Interrupt for the device.
75-
pub interrupt: Arc<dyn VirtioInterrupt>,
7652
/// Pointer to the MMDS data store.
7753
pub mmds: Option<Arc<Mutex<Mmds>>>,
7854
}
@@ -108,7 +84,6 @@ impl Persist<'_> for Net {
10884
guest_mac: self.guest_mac,
10985
},
11086
virtio_state: VirtioDeviceState::from_device(self),
111-
rx_buffers_state: RxBufferState::from_rx_buffers(&self.rx_buffer),
11287
}
11388
}
11489

@@ -153,25 +128,6 @@ impl Persist<'_> for Net {
153128
net.avail_features = state.virtio_state.avail_features;
154129
net.acked_features = state.virtio_state.acked_features;
155130

156-
if state.virtio_state.activated {
157-
let supported_flags: u32 = Net::build_tap_offload_features(net.acked_features);
158-
net.tap
159-
.set_offload(supported_flags)
160-
.map_err(NetPersistError::TapSetOffload)?;
161-
162-
net.device_state = DeviceState::Activated(ActiveState {
163-
mem: constructor_args.mem,
164-
interrupt: constructor_args.interrupt,
165-
});
166-
167-
// Recreate `Net::rx_buffer`. We do it by re-parsing the RX queue. We're temporarily
168-
// rolling back `next_avail` in the RX queue and call `parse_rx_descriptors`.
169-
net.queues[RX_INDEX].next_avail -= state.rx_buffers_state.parsed_descriptor_chains_nr;
170-
net.parse_rx_descriptors();
171-
net.rx_buffer.used_descriptors = state.rx_buffers_state.used_descriptors;
172-
net.rx_buffer.used_bytes = state.rx_buffers_state.used_bytes;
173-
}
174-
175131
Ok(net)
176132
}
177133
}
@@ -215,7 +171,6 @@ mod tests {
215171
match Net::restore(
216172
NetConstructorArgs {
217173
mem: guest_mem,
218-
interrupt: default_interrupt(),
219174
mmds: mmds_ds,
220175
},
221176
&Snapshot::deserialize(&mut mem.as_slice()).unwrap(),

src/vmm/src/devices/virtio/rng/persist.rs

Lines changed: 3 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -19,20 +19,13 @@ use crate::vstate::memory::GuestMemoryMmap;
1919

2020
#[derive(Debug, Clone, Serialize, Deserialize)]
2121
pub struct EntropyState {
22-
virtio_state: VirtioDeviceState,
22+
pub virtio_state: VirtioDeviceState,
2323
rate_limiter_state: RateLimiterState,
2424
}
2525

2626
#[derive(Debug)]
2727
pub struct EntropyConstructorArgs {
28-
mem: GuestMemoryMmap,
29-
interrupt: Arc<dyn VirtioInterrupt>,
30-
}
31-
32-
impl EntropyConstructorArgs {
33-
pub fn new(mem: GuestMemoryMmap, interrupt: Arc<dyn VirtioInterrupt>) -> Self {
34-
Self { mem, interrupt }
35-
}
28+
pub mem: GuestMemoryMmap,
3629
}
3730

3831
#[derive(Debug, thiserror::Error, displaydoc::Display)]
@@ -72,9 +65,6 @@ impl Persist<'_> for Entropy {
7265
let mut entropy = Entropy::new_with_queues(queues, rate_limiter)?;
7366
entropy.set_avail_features(state.virtio_state.avail_features);
7467
entropy.set_acked_features(state.virtio_state.acked_features);
75-
if state.virtio_state.activated {
76-
entropy.set_activated(constructor_args.mem, constructor_args.interrupt);
77-
}
7868

7969
Ok(entropy)
8070
}
@@ -99,7 +89,7 @@ mod tests {
9989

10090
let guest_mem = create_virtio_mem();
10191
let restored = Entropy::restore(
102-
EntropyConstructorArgs::new(guest_mem, default_interrupt()),
92+
EntropyConstructorArgs { mem: guest_mem },
10393
&Snapshot::deserialize(&mut mem.as_slice()).unwrap(),
10494
)
10595
.unwrap();

src/vmm/src/devices/virtio/vsock/persist.rs

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ pub struct VsockState {
3131
pub struct VsockFrontendState {
3232
/// Context Identifier.
3333
pub cid: u64,
34-
virtio_state: VirtioDeviceState,
34+
pub virtio_state: VirtioDeviceState,
3535
}
3636

3737
/// An enum for the serializable backend state types.
@@ -53,8 +53,6 @@ pub struct VsockUdsState {
5353
pub struct VsockConstructorArgs<B> {
5454
/// Pointer to guest memory.
5555
pub mem: GuestMemoryMmap,
56-
/// Interrupt to use for the device.
57-
pub interrupt: Arc<dyn VirtioInterrupt>,
5856
/// The vsock Unix Backend.
5957
pub backend: B,
6058
}
@@ -123,14 +121,7 @@ where
123121

124122
vsock.acked_features = state.virtio_state.acked_features;
125123
vsock.avail_features = state.virtio_state.avail_features;
126-
vsock.device_state = if state.virtio_state.activated {
127-
DeviceState::Activated(ActiveState {
128-
mem: constructor_args.mem,
129-
interrupt: constructor_args.interrupt,
130-
})
131-
} else {
132-
DeviceState::Inactive
133-
};
124+
vsock.device_state = DeviceState::Inactive;
134125
Ok(vsock)
135126
}
136127
}
@@ -193,7 +184,6 @@ pub(crate) mod tests {
193184
let mut restored_device = Vsock::restore(
194185
VsockConstructorArgs {
195186
mem: ctx.mem.clone(),
196-
interrupt: default_interrupt(),
197187
backend: match restored_state.backend {
198188
VsockBackendState::Uds(uds_state) => {
199189
assert_eq!(uds_state.path, "test".to_owned());

0 commit comments

Comments
 (0)