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::IntoBytes; 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 #[cfg(feature = "arc_quota")] 44 mod arc_ioctl; 45 mod caps; 46 mod config; 47 mod expiring_map; 48 mod multikey; 49 pub mod passthrough; 50 mod read_dir; 51 mod worker; 52 53 pub use config::CachePolicy; 54 pub use config::Config; 55 use fuse::Server; 56 use passthrough::PassthroughFs; 57 pub use worker::Worker; 58 59 const QUEUE_SIZE: u16 = 1024; 60 61 const FS_BAR_NUM: u8 = 4; 62 const FS_BAR_OFFSET: u64 = 0; 63 const FS_BAR_SIZE: u64 = 1 << 33; 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 uids for the worker thread. 79 #[error("failed to get uids for the worker thread: {0}")] 80 GetResuid(SysError), 81 /// Failed to get the securebits for the worker thread. 82 #[error("failed to get securebits for the worker thread: {0}")] 83 GetSecurebits(SysError), 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 tag: String, 121 fs: Option<PassthroughFs>, 122 queue_sizes: Box<[u16]>, 123 avail_features: u64, 124 acked_features: u64, 125 use_dax: bool, 126 pci_bar: Option<Alloc>, 127 tube: Option<Tube>, 128 workers: Vec<WorkerThread<Result<()>>>, 129 } 130 131 impl Fs { new( base_features: u64, tag: &str, num_workers: usize, fs_cfg: Config, tube: Tube, ) -> Result<Fs>132 pub fn new( 133 base_features: u64, 134 tag: &str, 135 num_workers: usize, 136 fs_cfg: Config, 137 tube: Tube, 138 ) -> Result<Fs> { 139 if tag.len() > FS_MAX_TAG_LEN { 140 return Err(Error::TagTooLong(tag.len())); 141 } 142 143 let mut cfg_tag = [0u8; FS_MAX_TAG_LEN]; 144 cfg_tag[..tag.len()].copy_from_slice(tag.as_bytes()); 145 146 let cfg = virtio_fs_config { 147 tag: cfg_tag, 148 num_request_queues: Le32::from(num_workers as u32), 149 }; 150 151 let fs = PassthroughFs::new(tag, fs_cfg).map_err(Error::CreateFs)?; 152 153 // There is always a high priority queue in addition to the request queues. 154 let num_queues = num_workers + 1; 155 156 // TODO(b/176129399): Remove cfg! once DAX is supported on ARM. 157 let use_dax = cfg!(target_arch = "x86_64") && fs.cfg().use_dax; 158 159 Ok(Fs { 160 cfg, 161 tag: tag.to_string(), 162 fs: Some(fs), 163 queue_sizes: vec![QUEUE_SIZE; num_queues].into_boxed_slice(), 164 avail_features: base_features, 165 acked_features: 0, 166 use_dax, 167 pci_bar: None, 168 tube: Some(tube), 169 workers: Vec::with_capacity(num_workers + 1), 170 }) 171 } 172 } 173 174 impl VirtioDevice for Fs { keep_rds(&self) -> Vec<RawDescriptor>175 fn keep_rds(&self) -> Vec<RawDescriptor> { 176 let mut fds = self 177 .fs 178 .as_ref() 179 .map(PassthroughFs::keep_rds) 180 .unwrap_or_default(); 181 if let Some(rd) = self.tube.as_ref().map(|s| s.as_raw_descriptor()) { 182 fds.push(rd); 183 } 184 185 fds 186 } 187 device_type(&self) -> DeviceType188 fn device_type(&self) -> DeviceType { 189 DeviceType::Fs 190 } 191 queue_max_sizes(&self) -> &[u16]192 fn queue_max_sizes(&self) -> &[u16] { 193 &self.queue_sizes 194 } 195 features(&self) -> u64196 fn features(&self) -> u64 { 197 self.avail_features 198 } 199 ack_features(&mut self, mut v: u64)200 fn ack_features(&mut self, mut v: u64) { 201 // Check if the guest is ACK'ing a feature that we didn't claim to have. 202 let unrequested_features = v & !self.avail_features; 203 if unrequested_features != 0 { 204 warn!("virtio_fs got unknown feature ack: {:x}", v); 205 206 // Don't count these features as acked. 207 v &= !unrequested_features; 208 } 209 self.acked_features |= v; 210 } 211 read_config(&self, offset: u64, data: &mut [u8])212 fn read_config(&self, offset: u64, data: &mut [u8]) { 213 copy_config(data, 0, self.cfg.as_bytes(), offset) 214 } 215 activate( &mut self, _guest_mem: GuestMemory, _interrupt: Interrupt, queues: BTreeMap<usize, Queue>, ) -> anyhow::Result<()>216 fn activate( 217 &mut self, 218 _guest_mem: GuestMemory, 219 _interrupt: Interrupt, 220 queues: BTreeMap<usize, Queue>, 221 ) -> anyhow::Result<()> { 222 if queues.len() != self.queue_sizes.len() { 223 return Err(anyhow!( 224 "expected {} queues, got {}", 225 self.queue_sizes.len(), 226 queues.len() 227 )); 228 } 229 230 let fs = self.fs.take().expect("missing file system implementation"); 231 232 let server = Arc::new(Server::new(fs)); 233 let socket = self.tube.take().expect("missing mapping socket"); 234 let mut slot = 0; 235 236 // Set up shared memory for DAX. 237 if let Some(pci_bar) = self.pci_bar { 238 // Create the shared memory region now before we start processing requests. 239 let request = FsMappingRequest::AllocateSharedMemoryRegion(pci_bar); 240 socket 241 .send(&request) 242 .expect("failed to send allocation message"); 243 slot = match socket.recv() { 244 Ok(VmResponse::RegisterMemory { slot }) => slot, 245 Ok(VmResponse::Err(e)) => panic!("failed to allocate shared memory region: {}", e), 246 r => panic!( 247 "unexpected response to allocate shared memory region: {:?}", 248 r 249 ), 250 }; 251 } 252 253 let socket = Arc::new(Mutex::new(socket)); 254 255 self.workers = queues 256 .into_iter() 257 .map(|(idx, queue)| { 258 let server = server.clone(); 259 let socket = Arc::clone(&socket); 260 261 WorkerThread::start(format!("v_fs:{}:{}", self.tag, idx), move |kill_evt| { 262 let mut worker = Worker::new(queue, server, socket, slot); 263 worker.run(kill_evt) 264 }) 265 }) 266 .collect(); 267 Ok(()) 268 } 269 get_device_bars(&mut self, address: PciAddress) -> Vec<PciBarConfiguration>270 fn get_device_bars(&mut self, address: PciAddress) -> Vec<PciBarConfiguration> { 271 if !self.use_dax { 272 return vec![]; 273 } 274 275 self.pci_bar = Some(Alloc::PciBar { 276 bus: address.bus, 277 dev: address.dev, 278 func: address.func, 279 bar: FS_BAR_NUM, 280 }); 281 282 vec![PciBarConfiguration::new( 283 FS_BAR_NUM as usize, 284 FS_BAR_SIZE, 285 PciBarRegionType::Memory64BitRegion, 286 PciBarPrefetchable::Prefetchable, 287 )] 288 } 289 get_device_caps(&self) -> Vec<Box<dyn PciCapability>>290 fn get_device_caps(&self) -> Vec<Box<dyn PciCapability>> { 291 if !self.use_dax { 292 return vec![]; 293 } 294 295 vec![Box::new(VirtioPciShmCap::new( 296 PciCapabilityType::SharedMemoryConfig, 297 FS_BAR_NUM, 298 FS_BAR_OFFSET, 299 FS_BAR_SIZE, 300 VIRTIO_FS_SHMCAP_ID_CACHE as u8, 301 ))] 302 } 303 } 304