1 // Copyright 2019 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 use std::io; 6 use std::sync::Arc; 7 8 use anyhow::anyhow; 9 use base::error; 10 use base::warn; 11 use base::AsRawDescriptor; 12 use base::Error as SysError; 13 use base::Event; 14 use base::RawDescriptor; 15 use base::Tube; 16 use base::WorkerThread; 17 use data_model::Le32; 18 use remain::sorted; 19 use resources::Alloc; 20 use sync::Mutex; 21 use thiserror::Error; 22 use virtio_sys::virtio_fs::virtio_fs_config; 23 use virtio_sys::virtio_fs::VIRTIO_FS_SHMCAP_ID_CACHE; 24 use vm_control::FsMappingRequest; 25 use vm_control::VmResponse; 26 use vm_memory::GuestMemory; 27 use zerocopy::AsBytes; 28 29 use crate::pci::PciAddress; 30 use crate::pci::PciBarConfiguration; 31 use crate::pci::PciBarPrefetchable; 32 use crate::pci::PciBarRegionType; 33 use crate::pci::PciCapability; 34 use crate::virtio::copy_config; 35 use crate::virtio::device_constants::fs::FS_MAX_TAG_LEN; 36 use crate::virtio::device_constants::fs::QUEUE_SIZE; 37 use crate::virtio::DescriptorError; 38 use crate::virtio::DeviceType; 39 use crate::virtio::Interrupt; 40 use crate::virtio::PciCapabilityType; 41 use crate::virtio::Queue; 42 use crate::virtio::VirtioDevice; 43 use crate::virtio::VirtioPciShmCap; 44 use crate::Suspendable; 45 46 mod caps; 47 mod multikey; 48 pub mod passthrough; 49 mod read_dir; 50 mod worker; 51 52 use fuse::Server; 53 use passthrough::PassthroughFs; 54 pub use worker::process_fs_queue; 55 use worker::Worker; 56 57 const FS_BAR_NUM: u8 = 4; 58 const FS_BAR_OFFSET: u64 = 0; 59 const FS_BAR_SIZE: u64 = 1 << 33; 60 61 /// Errors that may occur during the creation or operation of an Fs device. 62 #[sorted] 63 #[derive(Error, Debug)] 64 pub enum Error { 65 /// Failed to create the file system. 66 #[error("failed to create file system: {0}")] 67 CreateFs(io::Error), 68 /// Creating WaitContext failed. 69 #[error("failed to create WaitContext: {0}")] 70 CreateWaitContext(SysError), 71 /// Error happened in FUSE. 72 #[error("fuse error: {0}")] 73 FuseError(fuse::Error), 74 /// Failed to get the securebits for the worker thread. 75 #[error("failed to get securebits for the worker thread: {0}")] 76 GetSecurebits(SysError), 77 /// The `len` field of the header is too small. 78 #[error("DescriptorChain is invalid: {0}")] 79 InvalidDescriptorChain(DescriptorError), 80 /// A request is missing readable descriptors. 81 #[error("request does not have any readable descriptors")] 82 NoReadableDescriptors, 83 /// A request is missing writable descriptors. 84 #[error("request does not have any writable descriptors")] 85 NoWritableDescriptors, 86 /// Error while reading from the virtio queue's Event. 87 #[error("failed to read from virtio queue Event: {0}")] 88 ReadQueueEvent(SysError), 89 /// Failed to set the securebits for the worker thread. 90 #[error("failed to set securebits for the worker thread: {0}")] 91 SetSecurebits(SysError), 92 /// Failed to signal the virio used queue. 93 #[error("failed to signal used queue: {0}")] 94 SignalUsedQueue(SysError), 95 /// The tag for the Fs device was too long to fit in the config space. 96 #[error("Fs device tag is too long: len = {0}, max = {}", FS_MAX_TAG_LEN)] 97 TagTooLong(usize), 98 /// Calling unshare to disassociate FS attributes from parent failed. 99 #[error("failed to unshare fs from parent: {0}")] 100 UnshareFromParent(SysError), 101 /// Error while polling for events. 102 #[error("failed to wait for events: {0}")] 103 WaitError(SysError), 104 } 105 106 impl From<fuse::Error> for Error { from(err: fuse::Error) -> Error107 fn from(err: fuse::Error) -> Error { 108 Error::FuseError(err) 109 } 110 } 111 112 pub type Result<T> = ::std::result::Result<T, Error>; 113 114 pub struct Fs { 115 cfg: virtio_fs_config, 116 tag: String, 117 fs: Option<PassthroughFs>, 118 queue_sizes: Box<[u16]>, 119 avail_features: u64, 120 acked_features: u64, 121 pci_bar: Option<Alloc>, 122 tube: Option<Tube>, 123 workers: Vec<WorkerThread<Result<()>>>, 124 } 125 126 impl Fs { new( base_features: u64, tag: &str, num_workers: usize, fs_cfg: passthrough::Config, tube: Tube, ) -> Result<Fs>127 pub fn new( 128 base_features: u64, 129 tag: &str, 130 num_workers: usize, 131 fs_cfg: passthrough::Config, 132 tube: Tube, 133 ) -> Result<Fs> { 134 if tag.len() > FS_MAX_TAG_LEN { 135 return Err(Error::TagTooLong(tag.len())); 136 } 137 138 let mut cfg_tag = [0u8; FS_MAX_TAG_LEN]; 139 cfg_tag[..tag.len()].copy_from_slice(tag.as_bytes()); 140 141 let cfg = virtio_fs_config { 142 tag: cfg_tag, 143 num_request_queues: Le32::from(num_workers as u32), 144 }; 145 146 let fs = PassthroughFs::new(tag, fs_cfg).map_err(Error::CreateFs)?; 147 148 // There is always a high priority queue in addition to the request queues. 149 let num_queues = num_workers + 1; 150 151 Ok(Fs { 152 cfg, 153 tag: tag.to_string(), 154 fs: Some(fs), 155 queue_sizes: vec![QUEUE_SIZE; num_queues].into_boxed_slice(), 156 avail_features: base_features, 157 acked_features: 0, 158 pci_bar: None, 159 tube: Some(tube), 160 workers: Vec::with_capacity(num_workers + 1), 161 }) 162 } 163 } 164 165 impl VirtioDevice for Fs { keep_rds(&self) -> Vec<RawDescriptor>166 fn keep_rds(&self) -> Vec<RawDescriptor> { 167 let mut fds = self 168 .fs 169 .as_ref() 170 .map(PassthroughFs::keep_rds) 171 .unwrap_or_else(Vec::new); 172 if let Some(rd) = self.tube.as_ref().map(|s| s.as_raw_descriptor()) { 173 fds.push(rd); 174 } 175 176 fds 177 } 178 device_type(&self) -> DeviceType179 fn device_type(&self) -> DeviceType { 180 DeviceType::Fs 181 } 182 queue_max_sizes(&self) -> &[u16]183 fn queue_max_sizes(&self) -> &[u16] { 184 &self.queue_sizes 185 } 186 features(&self) -> u64187 fn features(&self) -> u64 { 188 self.avail_features 189 } 190 ack_features(&mut self, mut v: u64)191 fn ack_features(&mut self, mut v: u64) { 192 // Check if the guest is ACK'ing a feature that we didn't claim to have. 193 let unrequested_features = v & !self.avail_features; 194 if unrequested_features != 0 { 195 warn!("virtio_fs got unknown feature ack: {:x}", v); 196 197 // Don't count these features as acked. 198 v &= !unrequested_features; 199 } 200 self.acked_features |= v; 201 } 202 read_config(&self, offset: u64, data: &mut [u8])203 fn read_config(&self, offset: u64, data: &mut [u8]) { 204 copy_config(data, 0, self.cfg.as_bytes(), offset) 205 } 206 activate( &mut self, guest_mem: GuestMemory, interrupt: Interrupt, queues: Vec<(Queue, Event)>, ) -> anyhow::Result<()>207 fn activate( 208 &mut self, 209 guest_mem: GuestMemory, 210 interrupt: Interrupt, 211 queues: Vec<(Queue, Event)>, 212 ) -> anyhow::Result<()> { 213 if queues.len() != self.queue_sizes.len() { 214 return Err(anyhow!( 215 "expected {} queues, got {}", 216 self.queue_sizes.len(), 217 queues.len() 218 )); 219 } 220 221 let fs = self.fs.take().expect("missing file system implementation"); 222 let use_dax = fs.cfg().use_dax; 223 224 let server = Arc::new(Server::new(fs)); 225 let socket = self.tube.take().expect("missing mapping socket"); 226 let mut slot = 0; 227 228 // Set up shared memory for DAX. 229 // TODO(b/176129399): Remove cfg! once DAX is supported on ARM. 230 if cfg!(any(target_arch = "x86", target_arch = "x86_64")) && use_dax { 231 // Create the shared memory region now before we start processing requests. 232 let request = FsMappingRequest::AllocateSharedMemoryRegion( 233 self.pci_bar.as_ref().cloned().expect("No pci_bar"), 234 ); 235 socket 236 .send(&request) 237 .expect("failed to send allocation message"); 238 slot = match socket.recv() { 239 Ok(VmResponse::RegisterMemory { pfn: _, slot }) => slot, 240 Ok(VmResponse::Err(e)) => panic!("failed to allocate shared memory region: {}", e), 241 r => panic!( 242 "unexpected response to allocate shared memory region: {:?}", 243 r 244 ), 245 }; 246 } 247 248 let socket = Arc::new(Mutex::new(socket)); 249 let mut watch_resample_event = true; 250 251 self.workers = queues 252 .into_iter() 253 .enumerate() 254 .map(|(idx, (queue, evt))| { 255 let mem = guest_mem.clone(); 256 let server = server.clone(); 257 let irq = interrupt.clone(); 258 let socket = Arc::clone(&socket); 259 260 let worker = 261 WorkerThread::start(format!("v_fs:{}:{}", self.tag, idx), move |kill_evt| { 262 let mut worker = Worker::new(mem, queue, server, irq, socket, slot); 263 worker.run(evt, kill_evt, watch_resample_event) 264 }); 265 266 if watch_resample_event { 267 watch_resample_event = false; 268 } 269 270 worker 271 }) 272 .collect(); 273 Ok(()) 274 } 275 get_device_bars(&mut self, address: PciAddress) -> Vec<PciBarConfiguration>276 fn get_device_bars(&mut self, address: PciAddress) -> Vec<PciBarConfiguration> { 277 if self.fs.as_ref().map_or(false, |fs| !fs.cfg().use_dax) { 278 return vec![]; 279 } 280 281 self.pci_bar = Some(Alloc::PciBar { 282 bus: address.bus, 283 dev: address.dev, 284 func: address.func, 285 bar: FS_BAR_NUM, 286 }); 287 288 vec![PciBarConfiguration::new( 289 FS_BAR_NUM as usize, 290 FS_BAR_SIZE, 291 PciBarRegionType::Memory64BitRegion, 292 PciBarPrefetchable::Prefetchable, 293 )] 294 } 295 get_device_caps(&self) -> Vec<Box<dyn PciCapability>>296 fn get_device_caps(&self) -> Vec<Box<dyn PciCapability>> { 297 if self.fs.as_ref().map_or(false, |fs| !fs.cfg().use_dax) { 298 return vec![]; 299 } 300 301 vec![Box::new(VirtioPciShmCap::new( 302 PciCapabilityType::SharedMemoryConfig, 303 FS_BAR_NUM, 304 FS_BAR_OFFSET, 305 FS_BAR_SIZE, 306 VIRTIO_FS_SHMCAP_ID_CACHE as u8, 307 ))] 308 } 309 } 310 311 impl Suspendable for Fs {} 312