1 // Copyright 2018 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::io::Write; 8 use std::mem; 9 use std::result; 10 11 use anyhow::anyhow; 12 use anyhow::Context; 13 use base::error; 14 use base::warn; 15 use base::Error as SysError; 16 use base::Event; 17 use base::EventToken; 18 use base::RawDescriptor; 19 use base::WaitContext; 20 use base::WorkerThread; 21 use remain::sorted; 22 use thiserror::Error; 23 use vm_memory::GuestMemory; 24 25 use super::copy_config; 26 use super::queue::Queue; 27 use super::DeviceType; 28 use super::Interrupt; 29 use super::VirtioDevice; 30 31 const QUEUE_SIZE: u16 = 128; 32 const QUEUE_SIZES: &[u16] = &[QUEUE_SIZE]; 33 34 // The only virtio_9p feature. 35 const VIRTIO_9P_MOUNT_TAG: u8 = 0; 36 37 /// Errors that occur during operation of a virtio 9P device. 38 #[sorted] 39 #[derive(Error, Debug)] 40 pub enum P9Error { 41 /// Failed to create a 9p server. 42 #[error("failed to create 9p server: {0}")] 43 CreateServer(io::Error), 44 /// Creating WaitContext failed. 45 #[error("failed to create WaitContext: {0}")] 46 CreateWaitContext(SysError), 47 /// An internal I/O error occurred. 48 #[error("P9 internal server error: {0}")] 49 Internal(io::Error), 50 /// A request is missing readable descriptors. 51 #[error("request does not have any readable descriptors")] 52 NoReadableDescriptors, 53 /// A request is missing writable descriptors. 54 #[error("request does not have any writable descriptors")] 55 NoWritableDescriptors, 56 /// Error while reading from the virtio queue's Event. 57 #[error("failed to read from virtio queue Event: {0}")] 58 ReadQueueEvent(SysError), 59 /// Failed to signal the virio used queue. 60 #[error("failed to signal used queue: {0}")] 61 SignalUsedQueue(SysError), 62 /// The tag for the 9P device was too large to fit in the config space. 63 #[error("P9 device tag is too long: len = {0}, max = {}", u16::MAX)] 64 TagTooLong(usize), 65 /// Error while polling for events. 66 #[error("failed to wait for events: {0}")] 67 WaitError(SysError), 68 } 69 70 pub type P9Result<T> = result::Result<T, P9Error>; 71 72 struct Worker { 73 interrupt: Interrupt, 74 queue: Queue, 75 server: p9::Server, 76 } 77 78 impl Worker { process_queue(&mut self) -> P9Result<()>79 fn process_queue(&mut self) -> P9Result<()> { 80 while let Some(mut avail_desc) = self.queue.pop() { 81 self.server 82 .handle_message(&mut avail_desc.reader, &mut avail_desc.writer) 83 .map_err(P9Error::Internal)?; 84 85 let len = avail_desc.writer.bytes_written() as u32; 86 87 self.queue.add_used(avail_desc, len); 88 } 89 self.queue.trigger_interrupt(); 90 91 Ok(()) 92 } 93 run(&mut self, kill_evt: Event) -> P9Result<()>94 fn run(&mut self, kill_evt: Event) -> P9Result<()> { 95 #[derive(EventToken)] 96 enum Token { 97 // A request is ready on the queue. 98 QueueReady, 99 // Check if any interrupts need to be re-asserted. 100 InterruptResample, 101 // The parent thread requested an exit. 102 Kill, 103 } 104 105 let wait_ctx: WaitContext<Token> = WaitContext::build_with(&[ 106 (self.queue.event(), Token::QueueReady), 107 (&kill_evt, Token::Kill), 108 ]) 109 .map_err(P9Error::CreateWaitContext)?; 110 if let Some(resample_evt) = self.interrupt.get_resample_evt() { 111 wait_ctx 112 .add(resample_evt, Token::InterruptResample) 113 .map_err(P9Error::CreateWaitContext)?; 114 } 115 116 loop { 117 let events = wait_ctx.wait().map_err(P9Error::WaitError)?; 118 for event in events.iter().filter(|e| e.is_readable) { 119 match event.token { 120 Token::QueueReady => { 121 self.queue.event().wait().map_err(P9Error::ReadQueueEvent)?; 122 self.process_queue()?; 123 } 124 Token::InterruptResample => { 125 self.interrupt.interrupt_resample(); 126 } 127 Token::Kill => return Ok(()), 128 } 129 } 130 } 131 } 132 } 133 134 /// Virtio device for sharing specific directories on the host system with the guest VM. 135 pub struct P9 { 136 config: Vec<u8>, 137 server: Option<p9::Server>, 138 avail_features: u64, 139 acked_features: u64, 140 worker: Option<WorkerThread<P9Result<()>>>, 141 } 142 143 impl P9 { new(base_features: u64, tag: &str, p9_cfg: p9::Config) -> P9Result<P9>144 pub fn new(base_features: u64, tag: &str, p9_cfg: p9::Config) -> P9Result<P9> { 145 if tag.len() > u16::MAX as usize { 146 return Err(P9Error::TagTooLong(tag.len())); 147 } 148 149 let len = tag.len() as u16; 150 let mut cfg = Vec::with_capacity(tag.len() + mem::size_of::<u16>()); 151 cfg.push(len as u8); 152 cfg.push((len >> 8) as u8); 153 154 cfg.write_all(tag.as_bytes()).map_err(P9Error::Internal)?; 155 156 let server = p9::Server::with_config(p9_cfg).map_err(P9Error::CreateServer)?; 157 Ok(P9 { 158 config: cfg, 159 server: Some(server), 160 avail_features: base_features | 1 << VIRTIO_9P_MOUNT_TAG, 161 acked_features: 0, 162 worker: None, 163 }) 164 } 165 } 166 167 impl VirtioDevice for P9 { keep_rds(&self) -> Vec<RawDescriptor>168 fn keep_rds(&self) -> Vec<RawDescriptor> { 169 self.server 170 .as_ref() 171 .map(p9::Server::keep_fds) 172 .unwrap_or_default() 173 } 174 device_type(&self) -> DeviceType175 fn device_type(&self) -> DeviceType { 176 DeviceType::P9 177 } 178 queue_max_sizes(&self) -> &[u16]179 fn queue_max_sizes(&self) -> &[u16] { 180 QUEUE_SIZES 181 } 182 features(&self) -> u64183 fn features(&self) -> u64 { 184 self.avail_features 185 } 186 ack_features(&mut self, value: u64)187 fn ack_features(&mut self, value: u64) { 188 let mut v = value; 189 190 // Check if the guest is ACK'ing a feature that we didn't claim to have. 191 let unrequested_features = v & !self.avail_features; 192 if unrequested_features != 0 { 193 warn!("virtio_9p got unknown feature ack: {:x}", v); 194 195 // Don't count these features as acked. 196 v &= !unrequested_features; 197 } 198 self.acked_features |= v; 199 } 200 read_config(&self, offset: u64, data: &mut [u8])201 fn read_config(&self, offset: u64, data: &mut [u8]) { 202 copy_config(data, 0, self.config.as_slice(), offset); 203 } 204 activate( &mut self, _guest_mem: GuestMemory, interrupt: Interrupt, mut queues: BTreeMap<usize, Queue>, ) -> anyhow::Result<()>205 fn activate( 206 &mut self, 207 _guest_mem: GuestMemory, 208 interrupt: Interrupt, 209 mut queues: BTreeMap<usize, Queue>, 210 ) -> anyhow::Result<()> { 211 if queues.len() != 1 { 212 return Err(anyhow!("expected 1 queue, got {}", queues.len())); 213 } 214 215 let queue = queues.remove(&0).unwrap(); 216 217 let server = self.server.take().context("missing server")?; 218 219 self.worker = Some(WorkerThread::start("v_9p", move |kill_evt| { 220 let mut worker = Worker { 221 interrupt, 222 queue, 223 server, 224 }; 225 226 worker.run(kill_evt) 227 })); 228 229 Ok(()) 230 } 231 } 232