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