1 // Copyright 2021 The ChromiumOS Authors 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 mod sys; 6 7 use anyhow::anyhow; 8 use anyhow::bail; 9 use anyhow::Context; 10 use cros_async::Executor; 11 use serde::Deserialize; 12 use serde::Serialize; 13 pub use sys::start_device as run_block_device; 14 pub use sys::Options; 15 use vm_memory::GuestMemory; 16 use vmm_vhost::message::*; 17 18 use crate::virtio; 19 use crate::virtio::block::asynchronous::BlockAsync; 20 use crate::virtio::vhost::user::device::handler::DeviceRequestHandler; 21 use crate::virtio::vhost::user::device::handler::VhostUserDevice; 22 use crate::virtio::vhost::user::device::VhostUserDeviceBuilder; 23 use crate::virtio::Interrupt; 24 use crate::virtio::VirtioDevice; 25 26 const NUM_QUEUES: u16 = 16; 27 28 struct BlockBackend { 29 inner: Box<BlockAsync>, 30 31 avail_features: u64, 32 acked_features: u64, 33 acked_protocol_features: VhostUserProtocolFeatures, 34 } 35 36 #[derive(Serialize, Deserialize)] 37 struct BlockBackendSnapshot { 38 acked_features: u64, 39 // `avail_features` and `acked_protocol_features` don't need to be snapshotted, but they are 40 // to be used to make sure that the proper features are used on `restore`. 41 avail_features: u64, 42 acked_protocol_features: u64, 43 } 44 45 impl VhostUserDeviceBuilder for BlockAsync { build(self: Box<Self>, _ex: &Executor) -> anyhow::Result<Box<dyn vmm_vhost::Backend>>46 fn build(self: Box<Self>, _ex: &Executor) -> anyhow::Result<Box<dyn vmm_vhost::Backend>> { 47 let avail_features = self.features() | 1 << VHOST_USER_F_PROTOCOL_FEATURES; 48 let backend = BlockBackend { 49 inner: self, 50 avail_features, 51 acked_features: 0, 52 acked_protocol_features: VhostUserProtocolFeatures::empty(), 53 }; 54 let handler = DeviceRequestHandler::new(backend); 55 Ok(Box::new(handler)) 56 } 57 } 58 59 impl VhostUserDevice for BlockBackend { max_queue_num(&self) -> usize60 fn max_queue_num(&self) -> usize { 61 NUM_QUEUES as usize 62 } 63 features(&self) -> u6464 fn features(&self) -> u64 { 65 self.avail_features 66 } 67 ack_features(&mut self, value: u64) -> anyhow::Result<()>68 fn ack_features(&mut self, value: u64) -> anyhow::Result<()> { 69 let unrequested_features = value & !self.avail_features; 70 if unrequested_features != 0 { 71 bail!("invalid features are given: {:#x}", unrequested_features); 72 } 73 74 self.acked_features |= value; 75 76 Ok(()) 77 } 78 acked_features(&self) -> u6479 fn acked_features(&self) -> u64 { 80 self.acked_features 81 } 82 protocol_features(&self) -> VhostUserProtocolFeatures83 fn protocol_features(&self) -> VhostUserProtocolFeatures { 84 VhostUserProtocolFeatures::CONFIG 85 | VhostUserProtocolFeatures::MQ 86 | VhostUserProtocolFeatures::BACKEND_REQ 87 } 88 ack_protocol_features(&mut self, features: u64) -> anyhow::Result<()>89 fn ack_protocol_features(&mut self, features: u64) -> anyhow::Result<()> { 90 let features = VhostUserProtocolFeatures::from_bits(features) 91 .ok_or_else(|| anyhow!("invalid protocol features are given: {:#x}", features))?; 92 let supported = self.protocol_features(); 93 self.acked_protocol_features = features & supported; 94 Ok(()) 95 } 96 acked_protocol_features(&self) -> u6497 fn acked_protocol_features(&self) -> u64 { 98 self.acked_protocol_features.bits() 99 } 100 read_config(&self, offset: u64, data: &mut [u8])101 fn read_config(&self, offset: u64, data: &mut [u8]) { 102 self.inner.read_config(offset, data) 103 } 104 reset(&mut self)105 fn reset(&mut self) { 106 if let Err(e) = self.inner.reset() { 107 base::error!("reset failed: {:#}", e); 108 } 109 } 110 start_queue( &mut self, idx: usize, queue: virtio::Queue, mem: GuestMemory, doorbell: Interrupt, ) -> anyhow::Result<()>111 fn start_queue( 112 &mut self, 113 idx: usize, 114 queue: virtio::Queue, 115 mem: GuestMemory, 116 doorbell: Interrupt, 117 ) -> anyhow::Result<()> { 118 self.inner.start_queue(idx, queue, mem, doorbell) 119 } 120 stop_queue(&mut self, idx: usize) -> anyhow::Result<virtio::Queue>121 fn stop_queue(&mut self, idx: usize) -> anyhow::Result<virtio::Queue> { 122 self.inner.stop_queue(idx) 123 } 124 stop_non_queue_workers(&mut self) -> anyhow::Result<()>125 fn stop_non_queue_workers(&mut self) -> anyhow::Result<()> { 126 // TODO: This assumes that `reset` only stops workers which might not be true in the 127 // future. Consider moving the `reset` code into a `stop_all_workers` method or, maybe, 128 // make `stop_queue` implicitly stop a worker thread when there is no active queue. 129 self.inner.reset() 130 } 131 snapshot(&self) -> anyhow::Result<Vec<u8>>132 fn snapshot(&self) -> anyhow::Result<Vec<u8>> { 133 // The queue states are being snapshotted in the device handler. 134 let serialized_bytes = serde_json::to_vec(&BlockBackendSnapshot { 135 acked_features: self.acked_features, 136 avail_features: self.avail_features, 137 acked_protocol_features: self.acked_protocol_features.bits(), 138 }) 139 .context("Failed to serialize BlockBackendSnapshot")?; 140 141 Ok(serialized_bytes) 142 } 143 restore(&mut self, data: Vec<u8>) -> anyhow::Result<()>144 fn restore(&mut self, data: Vec<u8>) -> anyhow::Result<()> { 145 let block_backend_snapshot: BlockBackendSnapshot = 146 serde_json::from_slice(&data).context("Failed to deserialize BlockBackendSnapshot")?; 147 anyhow::ensure!( 148 self.avail_features == block_backend_snapshot.avail_features, 149 "Vhost user block restored avail_features do not match. Live: {:?}, snapshot: {:?}", 150 self.avail_features, 151 block_backend_snapshot.avail_features, 152 ); 153 anyhow::ensure!( 154 self.acked_protocol_features.bits() == block_backend_snapshot.acked_protocol_features, 155 "Vhost user block restored acked_protocol_features do not match. Live: {:?}, \ 156 snapshot: {:?}", 157 self.acked_protocol_features, 158 block_backend_snapshot.acked_protocol_features 159 ); 160 self.acked_features = block_backend_snapshot.acked_features; 161 Ok(()) 162 } 163 } 164