vmm/devices/virtio/block/
device.rs1use std::sync::Arc;
5
6use event_manager::{EventOps, Events, MutEventSubscriber};
7use log::info;
8use vmm_sys_util::eventfd::EventFd;
9
10use super::BlockError;
11use super::persist::{BlockConstructorArgs, BlockState};
12use super::vhost_user::device::{VhostUserBlock, VhostUserBlockConfig};
13use super::virtio::device::{VirtioBlock, VirtioBlockConfig};
14use crate::devices::virtio::ActivateError;
15use crate::devices::virtio::device::VirtioDevice;
16use crate::devices::virtio::generated::virtio_ids::VIRTIO_ID_BLOCK;
17use crate::devices::virtio::queue::{InvalidAvailIdx, Queue};
18use crate::devices::virtio::transport::VirtioInterrupt;
19use crate::impl_device_type;
20use crate::rate_limiter::BucketUpdate;
21use crate::snapshot::Persist;
22use crate::vmm_config::drive::BlockDeviceConfig;
23use crate::vstate::memory::GuestMemoryMmap;
24
25#[allow(clippy::large_enum_variant)]
27#[derive(Debug)]
28pub enum Block {
29 Virtio(VirtioBlock),
30 VhostUser(VhostUserBlock),
31}
32
33impl Block {
34 pub fn new(config: BlockDeviceConfig) -> Result<Block, BlockError> {
35 if let Ok(config) = VirtioBlockConfig::try_from(&config) {
36 Ok(Self::Virtio(
37 VirtioBlock::new(config).map_err(BlockError::VirtioBackend)?,
38 ))
39 } else if let Ok(config) = VhostUserBlockConfig::try_from(&config) {
40 Ok(Self::VhostUser(
41 VhostUserBlock::new(config).map_err(BlockError::VhostUserBackend)?,
42 ))
43 } else {
44 Err(BlockError::InvalidBlockConfig)
45 }
46 }
47
48 pub fn config(&self) -> BlockDeviceConfig {
49 match self {
50 Self::Virtio(b) => b.config().into(),
51 Self::VhostUser(b) => b.config().into(),
52 }
53 }
54
55 pub fn update_disk_image(&mut self, disk_image_path: String) -> Result<(), BlockError> {
56 match self {
57 Self::Virtio(b) => b
58 .update_disk_image(disk_image_path)
59 .map_err(BlockError::VirtioBackend),
60 Self::VhostUser(_) => Err(BlockError::InvalidBlockBackend),
61 }
62 }
63
64 pub fn update_rate_limiter(
65 &mut self,
66 bytes: BucketUpdate,
67 ops: BucketUpdate,
68 ) -> Result<(), BlockError> {
69 match self {
70 Self::Virtio(b) => {
71 b.update_rate_limiter(bytes, ops);
72 Ok(())
73 }
74 Self::VhostUser(_) => Err(BlockError::InvalidBlockBackend),
75 }
76 }
77
78 pub fn update_config(&mut self) -> Result<(), BlockError> {
79 match self {
80 Self::Virtio(_) => Err(BlockError::InvalidBlockBackend),
81 Self::VhostUser(b) => b.config_update().map_err(BlockError::VhostUserBackend),
82 }
83 }
84
85 pub fn prepare_save(&mut self) {
86 match self {
87 Self::Virtio(b) => b.prepare_save(),
88 Self::VhostUser(b) => b.prepare_save(),
89 }
90 }
91
92 pub fn process_virtio_queues(&mut self) -> Result<(), InvalidAvailIdx> {
93 match self {
94 Self::Virtio(b) => b.process_virtio_queues(),
95 Self::VhostUser(_) => Ok(()),
96 }
97 }
98
99 pub fn id(&self) -> &str {
100 match self {
101 Self::Virtio(b) => &b.id,
102 Self::VhostUser(b) => &b.id,
103 }
104 }
105
106 pub fn root_device(&self) -> bool {
107 match self {
108 Self::Virtio(b) => b.root_device,
109 Self::VhostUser(b) => b.root_device,
110 }
111 }
112
113 pub fn read_only(&self) -> bool {
114 match self {
115 Self::Virtio(b) => b.read_only,
116 Self::VhostUser(b) => b.read_only,
117 }
118 }
119
120 pub fn partuuid(&self) -> &Option<String> {
121 match self {
122 Self::Virtio(b) => &b.partuuid,
123 Self::VhostUser(b) => &b.partuuid,
124 }
125 }
126
127 pub fn is_vhost_user(&self) -> bool {
128 match self {
129 Self::Virtio(_) => false,
130 Self::VhostUser(_) => true,
131 }
132 }
133}
134
135impl VirtioDevice for Block {
136 impl_device_type!(VIRTIO_ID_BLOCK);
137
138 fn avail_features(&self) -> u64 {
139 match self {
140 Self::Virtio(b) => b.avail_features,
141 Self::VhostUser(b) => b.avail_features,
142 }
143 }
144
145 fn acked_features(&self) -> u64 {
146 match self {
147 Self::Virtio(b) => b.acked_features,
148 Self::VhostUser(b) => b.acked_features,
149 }
150 }
151
152 fn set_acked_features(&mut self, acked_features: u64) {
153 match self {
154 Self::Virtio(b) => b.acked_features = acked_features,
155 Self::VhostUser(b) => b.acked_features = acked_features,
156 }
157 }
158
159 fn queues(&self) -> &[Queue] {
160 match self {
161 Self::Virtio(b) => &b.queues,
162 Self::VhostUser(b) => &b.queues,
163 }
164 }
165
166 fn queues_mut(&mut self) -> &mut [Queue] {
167 match self {
168 Self::Virtio(b) => &mut b.queues,
169 Self::VhostUser(b) => &mut b.queues,
170 }
171 }
172
173 fn queue_events(&self) -> &[EventFd] {
174 match self {
175 Self::Virtio(b) => &b.queue_evts,
176 Self::VhostUser(b) => &b.queue_evts,
177 }
178 }
179
180 fn interrupt_trigger(&self) -> &dyn VirtioInterrupt {
181 match self {
182 Self::Virtio(b) => b.interrupt_trigger(),
183 Self::VhostUser(b) => b.interrupt_trigger(),
184 }
185 }
186
187 fn read_config(&self, offset: u64, data: &mut [u8]) {
188 match self {
189 Self::Virtio(b) => b.read_config(offset, data),
190 Self::VhostUser(b) => b.read_config(offset, data),
191 }
192 }
193
194 fn write_config(&mut self, offset: u64, data: &[u8]) {
195 match self {
196 Self::Virtio(b) => b.write_config(offset, data),
197 Self::VhostUser(b) => b.write_config(offset, data),
198 }
199 }
200
201 fn activate(
202 &mut self,
203 mem: GuestMemoryMmap,
204 interrupt: Arc<dyn VirtioInterrupt>,
205 ) -> Result<(), ActivateError> {
206 match self {
207 Self::Virtio(b) => b.activate(mem, interrupt),
208 Self::VhostUser(b) => b.activate(mem, interrupt),
209 }
210 }
211
212 fn is_activated(&self) -> bool {
213 match self {
214 Self::Virtio(b) => b.device_state.is_activated(),
215 Self::VhostUser(b) => b.device_state.is_activated(),
216 }
217 }
218
219 fn kick(&mut self) {
220 if self.is_activated() {
226 info!("kick block {}.", self.id());
227 self.process_virtio_queues();
228 }
229 }
230}
231
232impl MutEventSubscriber for Block {
233 fn process(&mut self, event: Events, ops: &mut EventOps) {
234 match self {
235 Self::Virtio(b) => b.process(event, ops),
236 Self::VhostUser(b) => b.process(event, ops),
237 }
238 }
239
240 fn init(&mut self, ops: &mut EventOps) {
241 match self {
242 Self::Virtio(b) => b.init(ops),
243 Self::VhostUser(b) => b.init(ops),
244 }
245 }
246}
247
248impl Persist<'_> for Block {
249 type State = BlockState;
250 type ConstructorArgs = BlockConstructorArgs;
251 type Error = BlockError;
252
253 fn save(&self) -> Self::State {
254 match self {
255 Self::Virtio(b) => BlockState::Virtio(b.save()),
256 Self::VhostUser(b) => BlockState::VhostUser(b.save()),
257 }
258 }
259
260 fn restore(
261 constructor_args: Self::ConstructorArgs,
262 state: &Self::State,
263 ) -> Result<Self, Self::Error> {
264 match state {
265 BlockState::Virtio(s) => Ok(Self::Virtio(
266 VirtioBlock::restore(constructor_args, s).map_err(BlockError::VirtioBackend)?,
267 )),
268 BlockState::VhostUser(s) => Ok(Self::VhostUser(
269 VhostUserBlock::restore(constructor_args, s)
270 .map_err(BlockError::VhostUserBackend)?,
271 )),
272 }
273 }
274}