1 // Copyright 2019 Intel Corporation. All Rights Reserved. 2 // SPDX-License-Identifier: Apache-2.0 3 4 use super::super::{ActivateResult, Queue, VirtioCommon, VirtioDevice, VirtioDeviceType}; 5 use super::vu_common_ctrl::{VhostUserConfig, VhostUserHandle}; 6 use super::{Error, Result, DEFAULT_VIRTIO_FEATURES}; 7 use crate::seccomp_filters::Thread; 8 use crate::thread_helper::spawn_virtio_thread; 9 use crate::vhost_user::VhostUserCommon; 10 use crate::VirtioInterrupt; 11 use crate::{GuestMemoryMmap, GuestRegionMmap}; 12 use block_util::VirtioBlockConfig; 13 use seccompiler::SeccompAction; 14 use std::mem; 15 use std::result; 16 use std::sync::{Arc, Barrier, Mutex}; 17 use std::thread; 18 use std::vec::Vec; 19 use versionize::{VersionMap, Versionize, VersionizeResult}; 20 use versionize_derive::Versionize; 21 use vhost::vhost_user::message::{ 22 VhostUserConfigFlags, VhostUserProtocolFeatures, VhostUserVirtioFeatures, 23 VHOST_USER_CONFIG_OFFSET, 24 }; 25 use vhost::vhost_user::{MasterReqHandler, VhostUserMaster, VhostUserMasterReqHandler}; 26 use virtio_bindings::bindings::virtio_blk::{ 27 VIRTIO_BLK_F_BLK_SIZE, VIRTIO_BLK_F_CONFIG_WCE, VIRTIO_BLK_F_DISCARD, VIRTIO_BLK_F_FLUSH, 28 VIRTIO_BLK_F_GEOMETRY, VIRTIO_BLK_F_MQ, VIRTIO_BLK_F_RO, VIRTIO_BLK_F_SEG_MAX, 29 VIRTIO_BLK_F_SIZE_MAX, VIRTIO_BLK_F_TOPOLOGY, VIRTIO_BLK_F_WRITE_ZEROES, 30 }; 31 use vm_memory::{ByteValued, GuestMemoryAtomic}; 32 use vm_migration::{ 33 protocol::MemoryRangeTable, Migratable, MigratableError, Pausable, Snapshot, Snapshottable, 34 Transportable, VersionMapped, 35 }; 36 use vmm_sys_util::eventfd::EventFd; 37 38 const DEFAULT_QUEUE_NUMBER: usize = 1; 39 40 #[derive(Versionize)] 41 pub struct State { 42 pub avail_features: u64, 43 pub acked_features: u64, 44 pub config: VirtioBlockConfig, 45 pub acked_protocol_features: u64, 46 pub vu_num_queues: usize, 47 } 48 49 impl VersionMapped for State {} 50 51 struct SlaveReqHandler {} 52 impl VhostUserMasterReqHandler for SlaveReqHandler {} 53 54 pub struct Blk { 55 common: VirtioCommon, 56 vu_common: VhostUserCommon, 57 id: String, 58 config: VirtioBlockConfig, 59 guest_memory: Option<GuestMemoryAtomic<GuestMemoryMmap>>, 60 epoll_thread: Option<thread::JoinHandle<()>>, 61 seccomp_action: SeccompAction, 62 exit_evt: EventFd, 63 } 64 65 impl Blk { 66 /// Create a new vhost-user-blk device 67 pub fn new( 68 id: String, 69 vu_cfg: VhostUserConfig, 70 restoring: bool, 71 seccomp_action: SeccompAction, 72 exit_evt: EventFd, 73 ) -> Result<Blk> { 74 let num_queues = vu_cfg.num_queues; 75 76 if restoring { 77 // We need 'queue_sizes' to report a number of queues that will be 78 // enough to handle all the potential queues. VirtioPciDevice::new() 79 // will create the actual queues based on this information. 80 return Ok(Blk { 81 common: VirtioCommon { 82 device_type: VirtioDeviceType::Block as u32, 83 queue_sizes: vec![vu_cfg.queue_size; num_queues], 84 paused_sync: Some(Arc::new(Barrier::new(2))), 85 min_queues: DEFAULT_QUEUE_NUMBER as u16, 86 ..Default::default() 87 }, 88 vu_common: VhostUserCommon { 89 socket_path: vu_cfg.socket, 90 vu_num_queues: num_queues, 91 ..Default::default() 92 }, 93 id, 94 config: VirtioBlockConfig::default(), 95 guest_memory: None, 96 epoll_thread: None, 97 seccomp_action, 98 exit_evt, 99 }); 100 } 101 102 let mut vu = 103 VhostUserHandle::connect_vhost_user(false, &vu_cfg.socket, num_queues as u64, false)?; 104 105 // Filling device and vring features VMM supports. 106 let mut avail_features = 1 << VIRTIO_BLK_F_SIZE_MAX 107 | 1 << VIRTIO_BLK_F_SEG_MAX 108 | 1 << VIRTIO_BLK_F_GEOMETRY 109 | 1 << VIRTIO_BLK_F_RO 110 | 1 << VIRTIO_BLK_F_BLK_SIZE 111 | 1 << VIRTIO_BLK_F_FLUSH 112 | 1 << VIRTIO_BLK_F_TOPOLOGY 113 | 1 << VIRTIO_BLK_F_CONFIG_WCE 114 | 1 << VIRTIO_BLK_F_DISCARD 115 | 1 << VIRTIO_BLK_F_WRITE_ZEROES 116 | DEFAULT_VIRTIO_FEATURES; 117 118 if num_queues > 1 { 119 avail_features |= 1 << VIRTIO_BLK_F_MQ; 120 } 121 122 let avail_protocol_features = VhostUserProtocolFeatures::CONFIG 123 | VhostUserProtocolFeatures::MQ 124 | VhostUserProtocolFeatures::CONFIGURE_MEM_SLOTS 125 | VhostUserProtocolFeatures::REPLY_ACK 126 | VhostUserProtocolFeatures::INFLIGHT_SHMFD 127 | VhostUserProtocolFeatures::LOG_SHMFD; 128 129 let (acked_features, acked_protocol_features) = 130 vu.negotiate_features_vhost_user(avail_features, avail_protocol_features)?; 131 132 let backend_num_queues = 133 if acked_protocol_features & VhostUserProtocolFeatures::MQ.bits() != 0 { 134 vu.socket_handle() 135 .get_queue_num() 136 .map_err(Error::VhostUserGetQueueMaxNum)? as usize 137 } else { 138 DEFAULT_QUEUE_NUMBER 139 }; 140 141 if num_queues > backend_num_queues { 142 error!("vhost-user-blk requested too many queues ({}) since the backend only supports {}\n", 143 num_queues, backend_num_queues); 144 return Err(Error::BadQueueNum); 145 } 146 147 let config_len = mem::size_of::<VirtioBlockConfig>(); 148 let config_space: Vec<u8> = vec![0u8; config_len as usize]; 149 let (_, config_space) = vu 150 .socket_handle() 151 .get_config( 152 VHOST_USER_CONFIG_OFFSET, 153 config_len as u32, 154 VhostUserConfigFlags::WRITABLE, 155 config_space.as_slice(), 156 ) 157 .map_err(Error::VhostUserGetConfig)?; 158 let mut config = VirtioBlockConfig::default(); 159 if let Some(backend_config) = VirtioBlockConfig::from_slice(config_space.as_slice()) { 160 config = *backend_config; 161 config.num_queues = num_queues as u16; 162 } 163 164 Ok(Blk { 165 common: VirtioCommon { 166 device_type: VirtioDeviceType::Block as u32, 167 queue_sizes: vec![vu_cfg.queue_size; num_queues], 168 avail_features: acked_features, 169 acked_features: 0, 170 paused_sync: Some(Arc::new(Barrier::new(2))), 171 min_queues: DEFAULT_QUEUE_NUMBER as u16, 172 ..Default::default() 173 }, 174 vu_common: VhostUserCommon { 175 vu: Some(Arc::new(Mutex::new(vu))), 176 acked_protocol_features, 177 socket_path: vu_cfg.socket, 178 vu_num_queues: num_queues, 179 ..Default::default() 180 }, 181 id, 182 config, 183 guest_memory: None, 184 epoll_thread: None, 185 seccomp_action, 186 exit_evt, 187 }) 188 } 189 190 fn state(&self) -> State { 191 State { 192 avail_features: self.common.avail_features, 193 acked_features: self.common.acked_features, 194 config: self.config, 195 acked_protocol_features: self.vu_common.acked_protocol_features, 196 vu_num_queues: self.vu_common.vu_num_queues, 197 } 198 } 199 200 fn set_state(&mut self, state: &State) { 201 self.common.avail_features = state.avail_features; 202 self.common.acked_features = state.acked_features; 203 self.config = state.config; 204 self.vu_common.acked_protocol_features = state.acked_protocol_features; 205 self.vu_common.vu_num_queues = state.vu_num_queues; 206 207 if let Err(e) = self 208 .vu_common 209 .restore_backend_connection(self.common.acked_features) 210 { 211 error!( 212 "Failed restoring connection with vhost-user backend: {:?}", 213 e 214 ); 215 } 216 } 217 } 218 219 impl Drop for Blk { 220 fn drop(&mut self) { 221 if let Some(kill_evt) = self.common.kill_evt.take() { 222 if let Err(e) = kill_evt.write(1) { 223 error!("failed to kill vhost-user-blk: {:?}", e); 224 } 225 } 226 } 227 } 228 229 impl VirtioDevice for Blk { 230 fn device_type(&self) -> u32 { 231 self.common.device_type 232 } 233 234 fn queue_max_sizes(&self) -> &[u16] { 235 &self.common.queue_sizes 236 } 237 238 fn features(&self) -> u64 { 239 self.common.avail_features 240 } 241 242 fn ack_features(&mut self, value: u64) { 243 self.common.ack_features(value) 244 } 245 246 fn read_config(&self, offset: u64, data: &mut [u8]) { 247 self.read_config_from_slice(self.config.as_slice(), offset, data); 248 } 249 250 fn write_config(&mut self, offset: u64, data: &[u8]) { 251 // The "writeback" field is the only mutable field 252 let writeback_offset = 253 (&self.config.writeback as *const _ as u64) - (&self.config as *const _ as u64); 254 if offset != writeback_offset || data.len() != std::mem::size_of_val(&self.config.writeback) 255 { 256 error!( 257 "Attempt to write to read-only field: offset {:x} length {}", 258 offset, 259 data.len() 260 ); 261 return; 262 } 263 264 self.config.writeback = data[0]; 265 if let Some(vu) = &self.vu_common.vu { 266 if let Err(e) = vu 267 .lock() 268 .unwrap() 269 .socket_handle() 270 .set_config(offset as u32, VhostUserConfigFlags::WRITABLE, data) 271 .map_err(Error::VhostUserSetConfig) 272 { 273 error!("Failed setting vhost-user-blk configuration: {:?}", e); 274 } 275 } 276 } 277 278 fn activate( 279 &mut self, 280 mem: GuestMemoryAtomic<GuestMemoryMmap>, 281 interrupt_cb: Arc<dyn VirtioInterrupt>, 282 queues: Vec<Queue>, 283 queue_evts: Vec<EventFd>, 284 ) -> ActivateResult { 285 self.common.activate(&queues, &queue_evts, &interrupt_cb)?; 286 self.guest_memory = Some(mem.clone()); 287 288 let slave_req_handler: Option<MasterReqHandler<SlaveReqHandler>> = None; 289 290 // The backend acknowledged features must contain the protocol feature 291 // bit in case it was initially set but lost through the features 292 // negotiation with the guest. 293 let backend_acked_features = self.common.acked_features 294 | (self.common.avail_features & VhostUserVirtioFeatures::PROTOCOL_FEATURES.bits()); 295 296 // Run a dedicated thread for handling potential reconnections with 297 // the backend. 298 let (kill_evt, pause_evt) = self.common.dup_eventfds(); 299 300 let mut handler = self.vu_common.activate( 301 mem, 302 queues, 303 queue_evts, 304 interrupt_cb, 305 backend_acked_features, 306 slave_req_handler, 307 kill_evt, 308 pause_evt, 309 )?; 310 311 let paused = self.common.paused.clone(); 312 let paused_sync = self.common.paused_sync.clone(); 313 314 let mut epoll_threads = Vec::new(); 315 316 spawn_virtio_thread( 317 &self.id, 318 &self.seccomp_action, 319 Thread::VirtioVhostBlock, 320 &mut epoll_threads, 321 &self.exit_evt, 322 move || { 323 if let Err(e) = handler.run(paused, paused_sync.unwrap()) { 324 error!("Error running worker: {:?}", e); 325 } 326 }, 327 )?; 328 self.epoll_thread = Some(epoll_threads.remove(0)); 329 330 Ok(()) 331 } 332 333 fn reset(&mut self) -> Option<Arc<dyn VirtioInterrupt>> { 334 // We first must resume the virtio thread if it was paused. 335 if self.common.pause_evt.take().is_some() { 336 self.common.resume().ok()?; 337 } 338 339 if let Some(vu) = &self.vu_common.vu { 340 if let Err(e) = vu 341 .lock() 342 .unwrap() 343 .reset_vhost_user(self.common.queue_sizes.len()) 344 { 345 error!("Failed to reset vhost-user daemon: {:?}", e); 346 return None; 347 } 348 } 349 350 if let Some(kill_evt) = self.common.kill_evt.take() { 351 // Ignore the result because there is nothing we can do about it. 352 let _ = kill_evt.write(1); 353 } 354 355 event!("virtio-device", "reset", "id", &self.id); 356 357 // Return the interrupt 358 Some(self.common.interrupt_cb.take().unwrap()) 359 } 360 361 fn shutdown(&mut self) { 362 self.vu_common.shutdown() 363 } 364 365 fn add_memory_region( 366 &mut self, 367 region: &Arc<GuestRegionMmap>, 368 ) -> std::result::Result<(), crate::Error> { 369 self.vu_common.add_memory_region(&self.guest_memory, region) 370 } 371 } 372 373 impl Pausable for Blk { 374 fn pause(&mut self) -> result::Result<(), MigratableError> { 375 self.vu_common.pause()?; 376 self.common.pause() 377 } 378 379 fn resume(&mut self) -> result::Result<(), MigratableError> { 380 self.common.resume()?; 381 382 if let Some(epoll_thread) = &self.epoll_thread { 383 epoll_thread.thread().unpark(); 384 } 385 386 self.vu_common.resume() 387 } 388 } 389 390 impl Snapshottable for Blk { 391 fn id(&self) -> String { 392 self.id.clone() 393 } 394 395 fn snapshot(&mut self) -> std::result::Result<Snapshot, MigratableError> { 396 self.vu_common.snapshot(&self.id(), &self.state()) 397 } 398 399 fn restore(&mut self, snapshot: Snapshot) -> std::result::Result<(), MigratableError> { 400 self.set_state(&snapshot.to_versioned_state(&self.id)?); 401 Ok(()) 402 } 403 } 404 impl Transportable for Blk {} 405 406 impl Migratable for Blk { 407 fn start_dirty_log(&mut self) -> std::result::Result<(), MigratableError> { 408 self.vu_common.start_dirty_log(&self.guest_memory) 409 } 410 411 fn stop_dirty_log(&mut self) -> std::result::Result<(), MigratableError> { 412 self.vu_common.stop_dirty_log() 413 } 414 415 fn dirty_log(&mut self) -> std::result::Result<MemoryRangeTable, MigratableError> { 416 self.vu_common.dirty_log(&self.guest_memory) 417 } 418 419 fn complete_migration(&mut self) -> std::result::Result<(), MigratableError> { 420 self.vu_common 421 .complete_migration(self.common.kill_evt.take()) 422 } 423 } 424