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