diff --git a/Cargo.lock b/Cargo.lock index 22850cbe0..29872a66d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1017,6 +1017,7 @@ dependencies = [ "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "vm-memory 0.1.0 (git+https://github.com/rust-vmm/vm-memory)", + "vm-virtio 0.1.0", ] [[package]] diff --git a/vhost_user_fs/Cargo.toml b/vhost_user_fs/Cargo.toml index 826b26d74..8ffc1922a 100644 --- a/vhost_user_fs/Cargo.toml +++ b/vhost_user_fs/Cargo.toml @@ -9,3 +9,4 @@ bitflags = "1.1.0" libc = "0.2.65" log = "0.4.8" vm-memory = { git = "https://github.com/rust-vmm/vm-memory" } +vm-virtio = { path = "../vm-virtio" } diff --git a/vhost_user_fs/src/descriptor_utils.rs b/vhost_user_fs/src/descriptor_utils.rs new file mode 100644 index 000000000..4db6a5ae1 --- /dev/null +++ b/vhost_user_fs/src/descriptor_utils.rs @@ -0,0 +1,985 @@ +// Copyright 2019 The Chromium OS Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +use std::cmp; +use std::collections::VecDeque; +use std::fmt::{self, Display}; +use std::io::{self, Read, Write}; +use std::mem::{size_of, MaybeUninit}; +use std::ops::Deref; +use std::ptr::copy_nonoverlapping; +use std::result; + +use vm_memory::{ + Address, ByteValued, Bytes, GuestAddress, GuestMemory, GuestMemoryError, GuestMemoryMmap, + GuestMemoryRegion, Le16, Le32, Le64, VolatileMemory, VolatileMemoryError, VolatileSlice, +}; +use vm_virtio::DescriptorChain; + +use crate::file_traits::{FileReadWriteAtVolatile, FileReadWriteVolatile}; + +#[derive(Debug)] +pub enum Error { + DescriptorChainOverflow, + FindMemoryRegion, + GuestMemoryError(GuestMemoryError), + InvalidChain, + IoError(io::Error), + SplitOutOfBounds(usize), + VolatileMemoryError(VolatileMemoryError), +} + +impl Display for Error { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + use self::Error::*; + + match self { + DescriptorChainOverflow => write!( + f, + "the combined length of all the buffers in a `DescriptorChain` would overflow" + ), + FindMemoryRegion => write!(f, "no memory region for this address range"), + GuestMemoryError(e) => write!(f, "descriptor guest memory error: {}", e), + InvalidChain => write!(f, "invalid descriptor chain"), + IoError(e) => write!(f, "descriptor I/O error: {}", e), + SplitOutOfBounds(off) => write!(f, "`DescriptorChain` split is out of bounds: {}", off), + VolatileMemoryError(e) => write!(f, "volatile memory error: {}", e), + } + } +} + +pub type Result = result::Result; + +impl std::error::Error for Error {} + +#[derive(Clone)] +struct DescriptorChainConsumer<'a> { + buffers: VecDeque>, + bytes_consumed: usize, +} + +impl<'a> DescriptorChainConsumer<'a> { + fn available_bytes(&self) -> usize { + // This is guaranteed not to overflow because the total length of the chain + // is checked during all creations of `DescriptorChainConsumer` (see + // `Reader::new()` and `Writer::new()`). + self.buffers + .iter() + .fold(0usize, |count, vs| count + vs.len() as usize) + } + + fn bytes_consumed(&self) -> usize { + self.bytes_consumed + } + + /// Consumes at most `count` bytes from the `DescriptorChain`. Callers must provide a function + /// that takes a `&[VolatileSlice]` and returns the total number of bytes consumed. This + /// function guarantees that the combined length of all the slices in the `&[VolatileSlice]` is + /// less than or equal to `count`. + /// + /// # Errors + /// + /// If the provided function returns any error then no bytes are consumed from the buffer and + /// the error is returned to the caller. + fn consume(&mut self, count: usize, f: F) -> io::Result + where + F: FnOnce(&[VolatileSlice]) -> io::Result, + { + let mut buflen = 0; + let mut bufs = Vec::with_capacity(self.buffers.len()); + for &vs in &self.buffers { + if buflen >= count { + break; + } + + bufs.push(vs); + + let rem = count - buflen; + if rem < vs.len() { + buflen += rem; + } else { + buflen += vs.len() as usize; + } + } + + if bufs.is_empty() { + return Ok(0); + } + + let bytes_consumed = f(&*bufs)?; + + // This can happen if a driver tricks a device into reading/writing more data than + // fits in a `usize`. + let total_bytes_consumed = + self.bytes_consumed + .checked_add(bytes_consumed) + .ok_or_else(|| { + io::Error::new(io::ErrorKind::InvalidData, Error::DescriptorChainOverflow) + })?; + + let mut rem = bytes_consumed; + while let Some(vs) = self.buffers.pop_front() { + if rem < vs.len() { + // Split the slice and push the remainder back into the buffer list. Safe because we + // know that `rem` is not out of bounds due to the check and we checked the bounds + // on `vs` when we added it to the buffer list. + self.buffers.push_front(vs.offset(rem).unwrap()); + break; + } + + // No need for checked math because we know that `vs.size() <= rem`. + rem -= vs.len(); + } + + self.bytes_consumed = total_bytes_consumed; + + Ok(bytes_consumed) + } + + fn split_at(&mut self, offset: usize) -> Result> { + let mut rem = offset; + let pos = self.buffers.iter().position(|vs| { + if rem < vs.len() { + true + } else { + rem -= vs.len(); + false + } + }); + + if let Some(at) = pos { + let mut other = self.buffers.split_off(at); + + if rem > 0 { + // There must be at least one element in `other` because we checked + // its `size` value in the call to `position` above. + let front = other.pop_front().expect("empty VecDeque after split"); + self.buffers + .push_back(front.offset(rem).map_err(Error::VolatileMemoryError)?); + other.push_front(front.offset(rem).map_err(Error::VolatileMemoryError)?); + } + + Ok(DescriptorChainConsumer { + buffers: other, + bytes_consumed: 0, + }) + } else if rem == 0 { + Ok(DescriptorChainConsumer { + buffers: VecDeque::new(), + bytes_consumed: 0, + }) + } else { + Err(Error::SplitOutOfBounds(offset)) + } + } +} + +/// Provides high-level interface over the sequence of memory regions +/// defined by readable descriptors in the descriptor chain. +/// +/// Note that virtio spec requires driver to place any device-writable +/// descriptors after any device-readable descriptors (2.6.4.2 in Virtio Spec v1.1). +/// Reader will skip iterating over descriptor chain when first writable +/// descriptor is encountered. +#[derive(Clone)] +pub struct Reader<'a> { + buffer: DescriptorChainConsumer<'a>, +} + +impl<'a> Reader<'a> { + /// Construct a new Reader wrapper over `desc_chain`. + pub fn new(mem: &'a GuestMemoryMmap, desc_chain: DescriptorChain<'a>) -> Result> { + let mut total_len: usize = 0; + let buffers = desc_chain + .into_iter() + .readable() + .map(|desc| { + // Verify that summing the descriptor sizes does not overflow. + // This can happen if a driver tricks a device into reading more data than + // fits in a `usize`. + total_len = total_len + .checked_add(desc.len as usize) + .ok_or(Error::DescriptorChainOverflow)?; + + let region = mem.find_region(desc.addr).ok_or(Error::FindMemoryRegion)?; + let offset = desc + .addr + .checked_sub(region.start_addr().raw_value()) + .unwrap(); + region + .deref() + .get_slice(offset.raw_value() as usize, desc.len as usize) + .map_err(Error::VolatileMemoryError) + }) + .collect::>>>()?; + Ok(Reader { + buffer: DescriptorChainConsumer { + buffers, + bytes_consumed: 0, + }, + }) + } + + /// Reads an object from the descriptor chain buffer. + pub fn read_obj(&mut self) -> io::Result { + let mut obj = MaybeUninit::::uninit(); + + // Safe because `MaybeUninit` guarantees that the pointer is valid for + // `size_of::()` bytes. + let buf = unsafe { + ::std::slice::from_raw_parts_mut(obj.as_mut_ptr() as *mut u8, size_of::()) + }; + + self.read_exact(buf)?; + + // Safe because any type that implements `ByteValued` can be considered initialized + // even if it is filled with random data. + Ok(unsafe { obj.assume_init() }) + } + + /// Reads data from the descriptor chain buffer into a file descriptor. + /// Returns the number of bytes read from the descriptor chain buffer. + /// The number of bytes read can be less than `count` if there isn't + /// enough data in the descriptor chain buffer. + pub fn read_to( + &mut self, + mut dst: F, + count: usize, + ) -> io::Result { + self.buffer + .consume(count, |bufs| dst.write_vectored_volatile(bufs)) + } + + /// Reads data from the descriptor chain buffer into a File at offset `off`. + /// Returns the number of bytes read from the descriptor chain buffer. + /// The number of bytes read can be less than `count` if there isn't + /// enough data in the descriptor chain buffer. + pub fn read_to_at( + &mut self, + mut dst: F, + count: usize, + off: u64, + ) -> io::Result { + self.buffer + .consume(count, |bufs| dst.write_vectored_at_volatile(bufs, off)) + } + + pub fn read_exact_to( + &mut self, + mut dst: F, + mut count: usize, + ) -> io::Result<()> { + while count > 0 { + match self.read_to(&mut dst, count) { + Ok(0) => { + return Err(io::Error::new( + io::ErrorKind::UnexpectedEof, + "failed to fill whole buffer", + )) + } + Ok(n) => count -= n, + Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {} + Err(e) => return Err(e), + } + } + + Ok(()) + } + + /// Returns number of bytes available for reading. May return an error if the combined + /// lengths of all the buffers in the DescriptorChain would cause an integer overflow. + pub fn available_bytes(&self) -> usize { + self.buffer.available_bytes() + } + + /// Returns number of bytes already read from the descriptor chain buffer. + pub fn bytes_read(&self) -> usize { + self.buffer.bytes_consumed() + } + + /// Splits this `Reader` into two at the given offset in the `DescriptorChain` buffer. + /// After the split, `self` will be able to read up to `offset` bytes while the returned + /// `Reader` can read up to `available_bytes() - offset` bytes. Returns an error if + /// `offset > self.available_bytes()`. + pub fn split_at(&mut self, offset: usize) -> Result> { + self.buffer.split_at(offset).map(|buffer| Reader { buffer }) + } +} + +impl<'a> io::Read for Reader<'a> { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + self.buffer.consume(buf.len(), |bufs| { + let mut rem = buf; + let mut total = 0; + for vs in bufs { + let copy_len = cmp::min(rem.len(), vs.len()); + + // Safe because we have already verified that `vs` points to valid memory. + unsafe { + copy_nonoverlapping(vs.as_ptr() as *const u8, rem.as_mut_ptr(), copy_len); + } + rem = &mut rem[copy_len..]; + total += copy_len; + } + Ok(total) + }) + } +} + +/// Provides high-level interface over the sequence of memory regions +/// defined by writable descriptors in the descriptor chain. +/// +/// Note that virtio spec requires driver to place any device-writable +/// descriptors after any device-readable descriptors (2.6.4.2 in Virtio Spec v1.1). +/// Writer will start iterating the descriptors from the first writable one and will +/// assume that all following descriptors are writable. +#[derive(Clone)] +pub struct Writer<'a> { + buffer: DescriptorChainConsumer<'a>, +} + +impl<'a> Writer<'a> { + /// Construct a new Writer wrapper over `desc_chain`. + pub fn new(mem: &'a GuestMemoryMmap, desc_chain: DescriptorChain<'a>) -> Result> { + let mut total_len: usize = 0; + let buffers = desc_chain + .into_iter() + .writable() + .map(|desc| { + // Verify that summing the descriptor sizes does not overflow. + // This can happen if a driver tricks a device into writing more data than + // fits in a `usize`. + total_len = total_len + .checked_add(desc.len as usize) + .ok_or(Error::DescriptorChainOverflow)?; + + let region = mem.find_region(desc.addr).ok_or(Error::FindMemoryRegion)?; + let offset = desc + .addr + .checked_sub(region.start_addr().raw_value()) + .unwrap(); + region + .deref() + .get_slice(offset.raw_value() as usize, desc.len as usize) + .map_err(Error::VolatileMemoryError) + }) + .collect::>>>()?; + + Ok(Writer { + buffer: DescriptorChainConsumer { + buffers, + bytes_consumed: 0, + }, + }) + } + + /// Writes an object to the descriptor chain buffer. + pub fn write_obj(&mut self, val: T) -> io::Result<()> { + self.write_all(val.as_slice()) + } + + /// Returns number of bytes available for writing. May return an error if the combined + /// lengths of all the buffers in the DescriptorChain would cause an overflow. + pub fn available_bytes(&self) -> usize { + self.buffer.available_bytes() + } + + /// Writes data to the descriptor chain buffer from a file descriptor. + /// Returns the number of bytes written to the descriptor chain buffer. + /// The number of bytes written can be less than `count` if + /// there isn't enough data in the descriptor chain buffer. + pub fn write_from( + &mut self, + mut src: F, + count: usize, + ) -> io::Result { + self.buffer + .consume(count, |bufs| src.read_vectored_volatile(bufs)) + } + + /// Writes data to the descriptor chain buffer from a File at offset `off`. + /// Returns the number of bytes written to the descriptor chain buffer. + /// The number of bytes written can be less than `count` if + /// there isn't enough data in the descriptor chain buffer. + pub fn write_from_at( + &mut self, + mut src: F, + count: usize, + off: u64, + ) -> io::Result { + self.buffer + .consume(count, |bufs| src.read_vectored_at_volatile(bufs, off)) + } + + pub fn write_all_from( + &mut self, + mut src: F, + mut count: usize, + ) -> io::Result<()> { + while count > 0 { + match self.write_from(&mut src, count) { + Ok(0) => { + return Err(io::Error::new( + io::ErrorKind::WriteZero, + "failed to write whole buffer", + )) + } + Ok(n) => count -= n, + Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {} + Err(e) => return Err(e), + } + } + + Ok(()) + } + + /// Returns number of bytes already written to the descriptor chain buffer. + pub fn bytes_written(&self) -> usize { + self.buffer.bytes_consumed() + } + + /// Splits this `Writer` into two at the given offset in the `DescriptorChain` buffer. + /// After the split, `self` will be able to write up to `offset` bytes while the returned + /// `Writer` can write up to `available_bytes() - offset` bytes. Returns an error if + /// `offset > self.available_bytes()`. + pub fn split_at(&mut self, offset: usize) -> Result> { + self.buffer.split_at(offset).map(|buffer| Writer { buffer }) + } +} + +impl<'a> io::Write for Writer<'a> { + fn write(&mut self, buf: &[u8]) -> io::Result { + self.buffer.consume(buf.len(), |bufs| { + let mut rem = buf; + let mut total = 0; + for vs in bufs { + let copy_len = cmp::min(rem.len(), vs.len()); + + // Safe because we have already verified that `vs` points to valid memory. + unsafe { + copy_nonoverlapping(rem.as_ptr(), vs.as_ptr(), copy_len); + } + rem = &rem[copy_len..]; + total += copy_len; + } + Ok(total) + }) + } + + fn flush(&mut self) -> io::Result<()> { + // Nothing to flush since the writes go straight into the buffer. + Ok(()) + } +} + +const VIRTQ_DESC_F_NEXT: u16 = 0x1; +const VIRTQ_DESC_F_WRITE: u16 = 0x2; + +#[derive(Copy, Clone, PartialEq, Eq)] +pub enum DescriptorType { + Readable, + Writable, +} + +#[derive(Copy, Clone, Debug, Default)] +#[repr(C)] +struct virtq_desc { + addr: Le64, + len: Le32, + flags: Le16, + next: Le16, +} + +// Safe because it only has data and has no implicit padding. +unsafe impl ByteValued for virtq_desc {} + +/// Test utility function to create a descriptor chain in guest memory. +pub fn create_descriptor_chain( + memory: &GuestMemoryMmap, + descriptor_array_addr: GuestAddress, + mut buffers_start_addr: GuestAddress, + descriptors: Vec<(DescriptorType, u32)>, + spaces_between_regions: u32, +) -> Result { + let descriptors_len = descriptors.len(); + for (index, (type_, size)) in descriptors.into_iter().enumerate() { + let mut flags = 0; + if let DescriptorType::Writable = type_ { + flags |= VIRTQ_DESC_F_WRITE; + } + if index + 1 < descriptors_len { + flags |= VIRTQ_DESC_F_NEXT; + } + + let index = index as u16; + let desc = virtq_desc { + addr: buffers_start_addr.raw_value().into(), + len: size.into(), + flags: flags.into(), + next: (index + 1).into(), + }; + + let offset = size + spaces_between_regions; + buffers_start_addr = buffers_start_addr + .checked_add(u64::from(offset)) + .ok_or(Error::InvalidChain)?; + + let _ = memory.write_obj( + desc, + descriptor_array_addr + .checked_add(u64::from(index) * std::mem::size_of::() as u64) + .ok_or(Error::InvalidChain)?, + ); + } + + DescriptorChain::checked_new(memory, descriptor_array_addr, 0x100, 0, None) + .ok_or(Error::InvalidChain) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn reader_test_simple_chain() { + use DescriptorType::*; + + let memory_start_addr = GuestAddress(0x0); + let memory = GuestMemoryMmap::new(&vec![(memory_start_addr, 0x10000)]).unwrap(); + + let chain = create_descriptor_chain( + &memory, + GuestAddress(0x0), + GuestAddress(0x100), + vec![ + (Readable, 8), + (Readable, 16), + (Readable, 18), + (Readable, 64), + ], + 0, + ) + .expect("create_descriptor_chain failed"); + let mut reader = Reader::new(&memory, chain).expect("failed to create Reader"); + assert_eq!(reader.available_bytes(), 106); + assert_eq!(reader.bytes_read(), 0); + + let mut buffer = [0 as u8; 64]; + if let Err(_) = reader.read_exact(&mut buffer) { + panic!("read_exact should not fail here"); + } + + assert_eq!(reader.available_bytes(), 42); + assert_eq!(reader.bytes_read(), 64); + + match reader.read(&mut buffer) { + Err(_) => panic!("read should not fail here"), + Ok(length) => assert_eq!(length, 42), + } + + assert_eq!(reader.available_bytes(), 0); + assert_eq!(reader.bytes_read(), 106); + } + + #[test] + fn writer_test_simple_chain() { + use DescriptorType::*; + + let memory_start_addr = GuestAddress(0x0); + let memory = GuestMemoryMmap::new(&vec![(memory_start_addr, 0x10000)]).unwrap(); + + let chain = create_descriptor_chain( + &memory, + GuestAddress(0x0), + GuestAddress(0x100), + vec![ + (Writable, 8), + (Writable, 16), + (Writable, 18), + (Writable, 64), + ], + 0, + ) + .expect("create_descriptor_chain failed"); + let mut writer = Writer::new(&memory, chain).expect("failed to create Writer"); + assert_eq!(writer.available_bytes(), 106); + assert_eq!(writer.bytes_written(), 0); + + let mut buffer = [0 as u8; 64]; + if let Err(_) = writer.write_all(&mut buffer) { + panic!("write_all should not fail here"); + } + + assert_eq!(writer.available_bytes(), 42); + assert_eq!(writer.bytes_written(), 64); + + match writer.write(&mut buffer) { + Err(_) => panic!("write should not fail here"), + Ok(length) => assert_eq!(length, 42), + } + + assert_eq!(writer.available_bytes(), 0); + assert_eq!(writer.bytes_written(), 106); + } + + #[test] + fn reader_test_incompatible_chain() { + use DescriptorType::*; + + let memory_start_addr = GuestAddress(0x0); + let memory = GuestMemoryMmap::new(&vec![(memory_start_addr, 0x10000)]).unwrap(); + + let chain = create_descriptor_chain( + &memory, + GuestAddress(0x0), + GuestAddress(0x100), + vec![(Writable, 8)], + 0, + ) + .expect("create_descriptor_chain failed"); + let mut reader = Reader::new(&memory, chain).expect("failed to create Reader"); + assert_eq!(reader.available_bytes(), 0); + assert_eq!(reader.bytes_read(), 0); + + assert!(reader.read_obj::().is_err()); + + assert_eq!(reader.available_bytes(), 0); + assert_eq!(reader.bytes_read(), 0); + } + + #[test] + fn writer_test_incompatible_chain() { + use DescriptorType::*; + + let memory_start_addr = GuestAddress(0x0); + let memory = GuestMemoryMmap::new(&vec![(memory_start_addr, 0x10000)]).unwrap(); + + let chain = create_descriptor_chain( + &memory, + GuestAddress(0x0), + GuestAddress(0x100), + vec![(Readable, 8)], + 0, + ) + .expect("create_descriptor_chain failed"); + let mut writer = Writer::new(&memory, chain).expect("failed to create Writer"); + assert_eq!(writer.available_bytes(), 0); + assert_eq!(writer.bytes_written(), 0); + + assert!(writer.write_obj(0u8).is_err()); + + assert_eq!(writer.available_bytes(), 0); + assert_eq!(writer.bytes_written(), 0); + } + + #[test] + fn reader_writer_shared_chain() { + use DescriptorType::*; + + let memory_start_addr = GuestAddress(0x0); + let memory = GuestMemoryMmap::new(&vec![(memory_start_addr, 0x10000)]).unwrap(); + + let chain = create_descriptor_chain( + &memory, + GuestAddress(0x0), + GuestAddress(0x100), + vec![ + (Readable, 16), + (Readable, 16), + (Readable, 96), + (Writable, 64), + (Writable, 1), + (Writable, 3), + ], + 0, + ) + .expect("create_descriptor_chain failed"); + let mut reader = Reader::new(&memory, chain.clone()).expect("failed to create Reader"); + let mut writer = Writer::new(&memory, chain).expect("failed to create Writer"); + + assert_eq!(reader.bytes_read(), 0); + assert_eq!(writer.bytes_written(), 0); + + let mut buffer = Vec::with_capacity(200); + + assert_eq!( + reader + .read_to_end(&mut buffer) + .expect("read should not fail here"), + 128 + ); + + // The writable descriptors are only 68 bytes long. + writer + .write_all(&buffer[..68]) + .expect("write should not fail here"); + + assert_eq!(reader.available_bytes(), 0); + assert_eq!(reader.bytes_read(), 128); + assert_eq!(writer.available_bytes(), 0); + assert_eq!(writer.bytes_written(), 68); + } + + #[test] + fn reader_writer_shattered_object() { + use DescriptorType::*; + + let memory_start_addr = GuestAddress(0x0); + let memory = GuestMemoryMmap::new(&vec![(memory_start_addr, 0x10000)]).unwrap(); + + let secret: Le32 = 0x12345678.into(); + + // Create a descriptor chain with memory regions that are properly separated. + let chain_writer = create_descriptor_chain( + &memory, + GuestAddress(0x0), + GuestAddress(0x100), + vec![(Writable, 1), (Writable, 1), (Writable, 1), (Writable, 1)], + 123, + ) + .expect("create_descriptor_chain failed"); + let mut writer = Writer::new(&memory, chain_writer).expect("failed to create Writer"); + if let Err(_) = writer.write_obj(secret) { + panic!("write_obj should not fail here"); + } + + // Now create new descriptor chain pointing to the same memory and try to read it. + let chain_reader = create_descriptor_chain( + &memory, + GuestAddress(0x0), + GuestAddress(0x100), + vec![(Readable, 1), (Readable, 1), (Readable, 1), (Readable, 1)], + 123, + ) + .expect("create_descriptor_chain failed"); + let mut reader = Reader::new(&memory, chain_reader).expect("failed to create Reader"); + match reader.read_obj::() { + Err(_) => panic!("read_obj should not fail here"), + Ok(read_secret) => assert_eq!(read_secret, secret), + } + } + + #[test] + fn reader_unexpected_eof() { + use DescriptorType::*; + + let memory_start_addr = GuestAddress(0x0); + let memory = GuestMemoryMmap::new(&vec![(memory_start_addr, 0x10000)]).unwrap(); + + let chain = create_descriptor_chain( + &memory, + GuestAddress(0x0), + GuestAddress(0x100), + vec![(Readable, 256), (Readable, 256)], + 0, + ) + .expect("create_descriptor_chain failed"); + + let mut reader = Reader::new(&memory, chain).expect("failed to create Reader"); + + let mut buf = Vec::with_capacity(1024); + buf.resize(1024, 0); + + assert_eq!( + reader + .read_exact(&mut buf[..]) + .expect_err("read more bytes than available") + .kind(), + io::ErrorKind::UnexpectedEof + ); + } + + #[test] + fn split_border() { + use DescriptorType::*; + + let memory_start_addr = GuestAddress(0x0); + let memory = GuestMemoryMmap::new(&vec![(memory_start_addr, 0x10000)]).unwrap(); + + let chain = create_descriptor_chain( + &memory, + GuestAddress(0x0), + GuestAddress(0x100), + vec![ + (Readable, 16), + (Readable, 16), + (Readable, 96), + (Writable, 64), + (Writable, 1), + (Writable, 3), + ], + 0, + ) + .expect("create_descriptor_chain failed"); + let mut reader = Reader::new(&memory, chain).expect("failed to create Reader"); + + let other = reader.split_at(32).expect("failed to split Reader"); + assert_eq!(reader.available_bytes(), 32); + assert_eq!(other.available_bytes(), 96); + } + + #[test] + fn split_middle() { + use DescriptorType::*; + + let memory_start_addr = GuestAddress(0x0); + let memory = GuestMemoryMmap::new(&vec![(memory_start_addr, 0x10000)]).unwrap(); + + let chain = create_descriptor_chain( + &memory, + GuestAddress(0x0), + GuestAddress(0x100), + vec![ + (Readable, 16), + (Readable, 16), + (Readable, 96), + (Writable, 64), + (Writable, 1), + (Writable, 3), + ], + 0, + ) + .expect("create_descriptor_chain failed"); + let mut reader = Reader::new(&memory, chain).expect("failed to create Reader"); + + let other = reader.split_at(24).expect("failed to split Reader"); + assert_eq!(reader.available_bytes(), 24); + assert_eq!(other.available_bytes(), 104); + } + + #[test] + fn split_end() { + use DescriptorType::*; + + let memory_start_addr = GuestAddress(0x0); + let memory = GuestMemoryMmap::new(&vec![(memory_start_addr, 0x10000)]).unwrap(); + + let chain = create_descriptor_chain( + &memory, + GuestAddress(0x0), + GuestAddress(0x100), + vec![ + (Readable, 16), + (Readable, 16), + (Readable, 96), + (Writable, 64), + (Writable, 1), + (Writable, 3), + ], + 0, + ) + .expect("create_descriptor_chain failed"); + let mut reader = Reader::new(&memory, chain).expect("failed to create Reader"); + + let other = reader.split_at(128).expect("failed to split Reader"); + assert_eq!(reader.available_bytes(), 128); + assert_eq!(other.available_bytes(), 0); + } + + #[test] + fn split_beginning() { + use DescriptorType::*; + + let memory_start_addr = GuestAddress(0x0); + let memory = GuestMemoryMmap::new(&vec![(memory_start_addr, 0x10000)]).unwrap(); + + let chain = create_descriptor_chain( + &memory, + GuestAddress(0x0), + GuestAddress(0x100), + vec![ + (Readable, 16), + (Readable, 16), + (Readable, 96), + (Writable, 64), + (Writable, 1), + (Writable, 3), + ], + 0, + ) + .expect("create_descriptor_chain failed"); + let mut reader = Reader::new(&memory, chain).expect("failed to create Reader"); + + let other = reader.split_at(0).expect("failed to split Reader"); + assert_eq!(reader.available_bytes(), 0); + assert_eq!(other.available_bytes(), 128); + } + + #[test] + fn split_outofbounds() { + use DescriptorType::*; + + let memory_start_addr = GuestAddress(0x0); + let memory = GuestMemoryMmap::new(&vec![(memory_start_addr, 0x10000)]).unwrap(); + + let chain = create_descriptor_chain( + &memory, + GuestAddress(0x0), + GuestAddress(0x100), + vec![ + (Readable, 16), + (Readable, 16), + (Readable, 96), + (Writable, 64), + (Writable, 1), + (Writable, 3), + ], + 0, + ) + .expect("create_descriptor_chain failed"); + let mut reader = Reader::new(&memory, chain).expect("failed to create Reader"); + + if let Ok(_) = reader.split_at(256) { + panic!("successfully split Reader with out of bounds offset"); + } + } + + #[test] + fn read_full() { + use DescriptorType::*; + + let memory_start_addr = GuestAddress(0x0); + let memory = GuestMemoryMmap::new(&vec![(memory_start_addr, 0x10000)]).unwrap(); + + let chain = create_descriptor_chain( + &memory, + GuestAddress(0x0), + GuestAddress(0x100), + vec![(Readable, 16), (Readable, 16), (Readable, 16)], + 0, + ) + .expect("create_descriptor_chain failed"); + let mut reader = Reader::new(&memory, chain).expect("failed to create Reader"); + + let mut buf = vec![0u8; 64]; + assert_eq!( + reader.read(&mut buf[..]).expect("failed to read to buffer"), + 48 + ); + } + + #[test] + fn write_full() { + use DescriptorType::*; + + let memory_start_addr = GuestAddress(0x0); + let memory = GuestMemoryMmap::new(&vec![(memory_start_addr, 0x10000)]).unwrap(); + + let chain = create_descriptor_chain( + &memory, + GuestAddress(0x0), + GuestAddress(0x100), + vec![(Writable, 16), (Writable, 16), (Writable, 16)], + 0, + ) + .expect("create_descriptor_chain failed"); + let mut writer = Writer::new(&memory, chain).expect("failed to create Writer"); + + let buf = vec![0xdeu8; 64]; + assert_eq!( + writer.write(&buf[..]).expect("failed to write from buffer"), + 48 + ); + } +} diff --git a/vhost_user_fs/src/lib.rs b/vhost_user_fs/src/lib.rs index ce0549bb8..1f11ff546 100644 --- a/vhost_user_fs/src/lib.rs +++ b/vhost_user_fs/src/lib.rs @@ -5,6 +5,7 @@ #[macro_use] extern crate log; +pub mod descriptor_utils; pub mod file_traits; pub mod filesystem; pub mod fuse;