1 // Copyright 2019 The Chromium OS Authors. All rights reserved. 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::mem; 7 use std::sync::Arc; 8 use std::thread; 9 10 use base::{error, warn, AsRawDescriptor, Error as SysError, Event, RawDescriptor, Tube}; 11 use data_model::{DataInit, Le32}; 12 use remain::sorted; 13 use resources::Alloc; 14 use sync::Mutex; 15 use thiserror::Error; 16 use vm_control::{FsMappingRequest, VmResponse}; 17 use vm_memory::GuestMemory; 18 19 use crate::pci::{ 20 PciAddress, PciBarConfiguration, PciBarPrefetchable, PciBarRegionType, PciCapability, 21 }; 22 use crate::virtio::{ 23 copy_config, DescriptorError, Interrupt, PciCapabilityType, Queue, VirtioDevice, 24 VirtioPciShmCap, TYPE_FS, 25 }; 26 27 mod caps; 28 mod multikey; 29 pub mod passthrough; 30 mod read_dir; 31 mod worker; 32 33 use fuse::Server; 34 use passthrough::PassthroughFs; 35 use worker::Worker; 36 37 pub use worker::process_fs_queue; 38 39 // The fs device does not have a fixed number of queues. 40 pub const QUEUE_SIZE: u16 = 1024; 41 42 const FS_BAR_NUM: u8 = 4; 43 const FS_BAR_OFFSET: u64 = 0; 44 const FS_BAR_SIZE: u64 = 1 << 33; 45 46 /// Defined in kernel/include/uapi/linux/virtio_fs.h. 47 const VIRTIO_FS_SHMCAP_ID_CACHE: u8 = 0; 48 49 /// The maximum allowable length of the tag used to identify a specific virtio-fs device. 50 pub const FS_MAX_TAG_LEN: usize = 36; 51 52 /// kernel/include/uapi/linux/virtio_fs.h 53 #[repr(C, packed)] 54 #[derive(Clone, Copy)] 55 pub struct virtio_fs_config { 56 /// Filesystem name (UTF-8, not NUL-terminated, padded with NULs) 57 pub tag: [u8; FS_MAX_TAG_LEN], 58 /// Number of request queues 59 pub num_request_queues: Le32, 60 } 61 62 // Safe because all members are plain old data and any value is valid. 63 unsafe impl DataInit for virtio_fs_config {} 64 65 /// Errors that may occur during the creation or operation of an Fs device. 66 #[sorted] 67 #[derive(Error, Debug)] 68 pub enum Error { 69 /// Failed to create the file system. 70 #[error("failed to create file system: {0}")] 71 CreateFs(io::Error), 72 /// Creating WaitContext failed. 73 #[error("failed to create WaitContext: {0}")] 74 CreateWaitContext(SysError), 75 /// Error happened in FUSE. 76 #[error("fuse error: {0}")] 77 FuseError(fuse::Error), 78 /// Failed to get the securebits for the worker thread. 79 #[error("failed to get securebits for the worker thread: {0}")] 80 GetSecurebits(SysError), 81 /// The `len` field of the header is too small. 82 #[error("DescriptorChain is invalid: {0}")] 83 InvalidDescriptorChain(DescriptorError), 84 /// A request is missing readable descriptors. 85 #[error("request does not have any readable descriptors")] 86 NoReadableDescriptors, 87 /// A request is missing writable descriptors. 88 #[error("request does not have any writable descriptors")] 89 NoWritableDescriptors, 90 /// Error while reading from the virtio queue's Event. 91 #[error("failed to read from virtio queue Event: {0}")] 92 ReadQueueEvent(SysError), 93 /// Failed to set the securebits for the worker thread. 94 #[error("failed to set securebits for the worker thread: {0}")] 95 SetSecurebits(SysError), 96 /// Failed to signal the virio used queue. 97 #[error("failed to signal used queue: {0}")] 98 SignalUsedQueue(SysError), 99 /// The tag for the Fs device was too long to fit in the config space. 100 #[error("Fs device tag is too long: len = {0}, max = {}", FS_MAX_TAG_LEN)] 101 TagTooLong(usize), 102 /// Calling unshare to disassociate FS attributes from parent failed. 103 #[error("failed to unshare fs from parent: {0}")] 104 UnshareFromParent(SysError), 105 /// Error while polling for events. 106 #[error("failed to wait for events: {0}")] 107 WaitError(SysError), 108 } 109 110 impl From<fuse::Error> for Error { from(err: fuse::Error) -> Error111 fn from(err: fuse::Error) -> Error { 112 Error::FuseError(err) 113 } 114 } 115 116 pub type Result<T> = ::std::result::Result<T, Error>; 117 118 pub struct Fs { 119 cfg: virtio_fs_config, 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<(Event, thread::JoinHandle<Result<()>>)>, 127 } 128 129 impl Fs { new( base_features: u64, tag: &str, num_workers: usize, fs_cfg: passthrough::Config, tube: Tube, ) -> Result<Fs>130 pub fn new( 131 base_features: u64, 132 tag: &str, 133 num_workers: usize, 134 fs_cfg: passthrough::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(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 fs: Some(fs), 157 queue_sizes: vec![QUEUE_SIZE; num_queues].into_boxed_slice(), 158 avail_features: base_features, 159 acked_features: 0, 160 pci_bar: None, 161 tube: Some(tube), 162 workers: Vec::with_capacity(num_workers + 1), 163 }) 164 } 165 stop_workers(&mut self)166 fn stop_workers(&mut self) { 167 for (kill_evt, handle) in mem::take(&mut self.workers) { 168 if let Err(e) = kill_evt.write(1) { 169 error!("failed to kill virtio-fs worker thread: {}", e); 170 continue; 171 } 172 173 // Only wait on the child thread if we were able to send it a kill event. 174 match handle.join() { 175 Ok(r) => { 176 if let Err(e) = r { 177 error!("virtio-fs worker thread exited with error: {}", e) 178 } 179 } 180 Err(e) => error!("virtio-fs worker thread panicked: {:?}", e), 181 } 182 } 183 } 184 } 185 186 impl VirtioDevice for Fs { keep_rds(&self) -> Vec<RawDescriptor>187 fn keep_rds(&self) -> Vec<RawDescriptor> { 188 let mut fds = self 189 .fs 190 .as_ref() 191 .map(PassthroughFs::keep_rds) 192 .unwrap_or_else(Vec::new); 193 if let Some(rd) = self.tube.as_ref().map(|s| s.as_raw_descriptor()) { 194 fds.push(rd); 195 } 196 197 fds 198 } 199 device_type(&self) -> u32200 fn device_type(&self) -> u32 { 201 TYPE_FS 202 } 203 queue_max_sizes(&self) -> &[u16]204 fn queue_max_sizes(&self) -> &[u16] { 205 &self.queue_sizes 206 } 207 features(&self) -> u64208 fn features(&self) -> u64 { 209 self.avail_features 210 } 211 ack_features(&mut self, mut v: u64)212 fn ack_features(&mut self, mut v: u64) { 213 // Check if the guest is ACK'ing a feature that we didn't claim to have. 214 let unrequested_features = v & !self.avail_features; 215 if unrequested_features != 0 { 216 warn!("virtio_fs got unknown feature ack: {:x}", v); 217 218 // Don't count these features as acked. 219 v &= !unrequested_features; 220 } 221 self.acked_features |= v; 222 } 223 read_config(&self, offset: u64, data: &mut [u8])224 fn read_config(&self, offset: u64, data: &mut [u8]) { 225 copy_config(data, 0, self.cfg.as_slice(), offset) 226 } 227 activate( &mut self, guest_mem: GuestMemory, interrupt: Interrupt, queues: Vec<Queue>, queue_evts: Vec<Event>, )228 fn activate( 229 &mut self, 230 guest_mem: GuestMemory, 231 interrupt: Interrupt, 232 queues: Vec<Queue>, 233 queue_evts: Vec<Event>, 234 ) { 235 if queues.len() != self.queue_sizes.len() || queue_evts.len() != self.queue_sizes.len() { 236 return; 237 } 238 239 let fs = self.fs.take().expect("missing file system implementation"); 240 let use_dax = fs.cfg().use_dax; 241 242 let server = Arc::new(Server::new(fs)); 243 let irq = Arc::new(interrupt); 244 let socket = self.tube.take().expect("missing mapping socket"); 245 let mut slot = 0; 246 247 // Set up shared memory for DAX. 248 // TODO(b/176129399): Remove cfg! once DAX is supported on ARM. 249 if cfg!(any(target_arch = "x86", target_arch = "x86_64")) && use_dax { 250 // Create the shared memory region now before we start processing requests. 251 let request = FsMappingRequest::AllocateSharedMemoryRegion( 252 self.pci_bar.as_ref().cloned().expect("No pci_bar"), 253 ); 254 socket 255 .send(&request) 256 .expect("failed to send allocation message"); 257 slot = match socket.recv() { 258 Ok(VmResponse::RegisterMemory { pfn: _, slot }) => slot, 259 Ok(VmResponse::Err(e)) => panic!("failed to allocate shared memory region: {}", e), 260 r => panic!( 261 "unexpected response to allocate shared memory region: {:?}", 262 r 263 ), 264 }; 265 } 266 267 let socket = Arc::new(Mutex::new(socket)); 268 let mut watch_resample_event = true; 269 for (idx, (queue, evt)) in queues.into_iter().zip(queue_evts.into_iter()).enumerate() { 270 let (self_kill_evt, kill_evt) = match Event::new().and_then(|e| Ok((e.try_clone()?, e))) 271 { 272 Ok(v) => v, 273 Err(e) => { 274 error!("fs: failed creating kill Event pair: {}", e); 275 self.stop_workers(); 276 return; 277 } 278 }; 279 280 let mem = guest_mem.clone(); 281 let server = server.clone(); 282 let irq = irq.clone(); 283 let socket = Arc::clone(&socket); 284 285 let worker_result = thread::Builder::new() 286 .name(format!("virtio-fs worker {}", idx)) 287 .spawn(move || { 288 let mut worker = Worker::new(mem, queue, server, irq, socket, slot); 289 worker.run(evt, kill_evt, watch_resample_event) 290 }); 291 292 if watch_resample_event { 293 watch_resample_event = false; 294 } 295 296 match worker_result { 297 Ok(worker) => self.workers.push((self_kill_evt, worker)), 298 Err(e) => { 299 error!("fs: failed to spawn virtio_fs worker: {}", e); 300 self.stop_workers(); 301 return; 302 } 303 } 304 } 305 } 306 get_device_bars(&mut self, address: PciAddress) -> Vec<PciBarConfiguration>307 fn get_device_bars(&mut self, address: PciAddress) -> Vec<PciBarConfiguration> { 308 if self.fs.as_ref().map_or(false, |fs| !fs.cfg().use_dax) { 309 return vec![]; 310 } 311 312 self.pci_bar = Some(Alloc::PciBar { 313 bus: address.bus, 314 dev: address.dev, 315 func: address.func, 316 bar: FS_BAR_NUM, 317 }); 318 319 vec![PciBarConfiguration::new( 320 FS_BAR_NUM as usize, 321 FS_BAR_SIZE, 322 PciBarRegionType::Memory64BitRegion, 323 PciBarPrefetchable::NotPrefetchable, 324 )] 325 } 326 get_device_caps(&self) -> Vec<Box<dyn PciCapability>>327 fn get_device_caps(&self) -> Vec<Box<dyn PciCapability>> { 328 if self.fs.as_ref().map_or(false, |fs| !fs.cfg().use_dax) { 329 return vec![]; 330 } 331 332 vec![Box::new(VirtioPciShmCap::new( 333 PciCapabilityType::SharedMemoryConfig, 334 FS_BAR_NUM, 335 FS_BAR_OFFSET, 336 FS_BAR_SIZE, 337 VIRTIO_FS_SHMCAP_ID_CACHE, 338 ))] 339 } 340 } 341 342 impl Drop for Fs { drop(&mut self)343 fn drop(&mut self) { 344 self.stop_workers() 345 } 346 } 347