• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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