• 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::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