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 = {max}", 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 queue: Queue, 74 server: p9::Server, 75 } 76 77 impl Worker { process_queue(&mut self) -> P9Result<()>78 fn process_queue(&mut self) -> P9Result<()> { 79 while let Some(mut avail_desc) = self.queue.pop() { 80 self.server 81 .handle_message(&mut avail_desc.reader, &mut avail_desc.writer) 82 .map_err(P9Error::Internal)?; 83 84 let len = avail_desc.writer.bytes_written() as u32; 85 86 self.queue.add_used(avail_desc, len); 87 } 88 self.queue.trigger_interrupt(); 89 90 Ok(()) 91 } 92 run(&mut self, kill_evt: Event) -> P9Result<()>93 fn run(&mut self, kill_evt: Event) -> P9Result<()> { 94 #[derive(EventToken)] 95 enum Token { 96 // A request is ready on the queue. 97 QueueReady, 98 // The parent thread requested an exit. 99 Kill, 100 } 101 102 let wait_ctx: WaitContext<Token> = WaitContext::build_with(&[ 103 (self.queue.event(), Token::QueueReady), 104 (&kill_evt, Token::Kill), 105 ]) 106 .map_err(P9Error::CreateWaitContext)?; 107 108 loop { 109 let events = wait_ctx.wait().map_err(P9Error::WaitError)?; 110 for event in events.iter().filter(|e| e.is_readable) { 111 match event.token { 112 Token::QueueReady => { 113 self.queue.event().wait().map_err(P9Error::ReadQueueEvent)?; 114 self.process_queue()?; 115 } 116 Token::Kill => return Ok(()), 117 } 118 } 119 } 120 } 121 } 122 123 /// Virtio device for sharing specific directories on the host system with the guest VM. 124 pub struct P9 { 125 config: Vec<u8>, 126 server: Option<p9::Server>, 127 avail_features: u64, 128 acked_features: u64, 129 worker: Option<WorkerThread<P9Result<()>>>, 130 } 131 132 impl P9 { new(base_features: u64, tag: &str, p9_cfg: p9::Config) -> P9Result<P9>133 pub fn new(base_features: u64, tag: &str, p9_cfg: p9::Config) -> P9Result<P9> { 134 if tag.len() > u16::MAX as usize { 135 return Err(P9Error::TagTooLong(tag.len())); 136 } 137 138 let len = tag.len() as u16; 139 let mut cfg = Vec::with_capacity(tag.len() + mem::size_of::<u16>()); 140 cfg.push(len as u8); 141 cfg.push((len >> 8) as u8); 142 143 cfg.write_all(tag.as_bytes()).map_err(P9Error::Internal)?; 144 145 let server = p9::Server::with_config(p9_cfg).map_err(P9Error::CreateServer)?; 146 Ok(P9 { 147 config: cfg, 148 server: Some(server), 149 avail_features: base_features | 1 << VIRTIO_9P_MOUNT_TAG, 150 acked_features: 0, 151 worker: None, 152 }) 153 } 154 } 155 156 impl VirtioDevice for P9 { keep_rds(&self) -> Vec<RawDescriptor>157 fn keep_rds(&self) -> Vec<RawDescriptor> { 158 self.server 159 .as_ref() 160 .map(p9::Server::keep_fds) 161 .unwrap_or_default() 162 } 163 device_type(&self) -> DeviceType164 fn device_type(&self) -> DeviceType { 165 DeviceType::P9 166 } 167 queue_max_sizes(&self) -> &[u16]168 fn queue_max_sizes(&self) -> &[u16] { 169 QUEUE_SIZES 170 } 171 features(&self) -> u64172 fn features(&self) -> u64 { 173 self.avail_features 174 } 175 ack_features(&mut self, value: u64)176 fn ack_features(&mut self, value: u64) { 177 let mut v = value; 178 179 // Check if the guest is ACK'ing a feature that we didn't claim to have. 180 let unrequested_features = v & !self.avail_features; 181 if unrequested_features != 0 { 182 warn!("virtio_9p got unknown feature ack: {:x}", v); 183 184 // Don't count these features as acked. 185 v &= !unrequested_features; 186 } 187 self.acked_features |= v; 188 } 189 read_config(&self, offset: u64, data: &mut [u8])190 fn read_config(&self, offset: u64, data: &mut [u8]) { 191 copy_config(data, 0, self.config.as_slice(), offset); 192 } 193 activate( &mut self, _guest_mem: GuestMemory, _interrupt: Interrupt, mut queues: BTreeMap<usize, Queue>, ) -> anyhow::Result<()>194 fn activate( 195 &mut self, 196 _guest_mem: GuestMemory, 197 _interrupt: Interrupt, 198 mut queues: BTreeMap<usize, Queue>, 199 ) -> anyhow::Result<()> { 200 if queues.len() != 1 { 201 return Err(anyhow!("expected 1 queue, got {}", queues.len())); 202 } 203 204 let queue = queues.remove(&0).unwrap(); 205 206 let server = self.server.take().context("missing server")?; 207 208 self.worker = Some(WorkerThread::start("v_9p", move |kill_evt| { 209 let mut worker = Worker { queue, server }; 210 211 worker.run(kill_evt) 212 })); 213 214 Ok(()) 215 } 216 } 217