Skip to content

Commit 1c96d02

Browse files
committed
Revert "virtio: allow IoVecBufferMut to hold multiple DescriptorChain objects"
This reverts commit 14e6e33. Signed-off-by: Babis Chalios <[email protected]>
1 parent adfd44b commit 1c96d02

File tree

4 files changed

+43
-186
lines changed

4 files changed

+43
-186
lines changed

src/vmm/src/devices/virtio/iovec.rs

Lines changed: 35 additions & 170 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,12 @@
44
use std::io::ErrorKind;
55

66
use libc::{c_void, iovec, size_t};
7-
#[cfg(not(kani))]
87
use smallvec::SmallVec;
98
use vm_memory::bitmap::Bitmap;
109
use vm_memory::{
1110
GuestMemory, GuestMemoryError, ReadVolatile, VolatileMemoryError, VolatileSlice, WriteVolatile,
1211
};
1312

14-
use super::iov_deque::{IovDeque, IovDequeError};
1513
use crate::devices::virtio::queue::DescriptorChain;
1614
use crate::vstate::memory::GuestMemoryMmap;
1715

@@ -25,8 +23,6 @@ pub enum IoVecError {
2523
OverflowedDescriptor,
2624
/// Guest memory error: {0}
2725
GuestMemory(#[from] GuestMemoryError),
28-
/// Error with underlying `IovDeque`: {0}
29-
IovDeque(#[from] IovDequeError),
3026
}
3127

3228
// Using SmallVec in the kani proofs causes kani to use unbounded amounts of memory
@@ -218,135 +214,64 @@ impl IoVecBuffer {
218214
}
219215
}
220216

221-
#[derive(Debug)]
222-
pub struct ParsedDescriptorChain {
223-
pub head_index: u16,
224-
pub length: u32,
225-
pub nr_iovecs: u16,
226-
}
227-
228217
/// This is essentially a wrapper of a `Vec<libc::iovec>` which can be passed to `libc::readv`.
229218
///
230219
/// It describes a write-only buffer passed to us by the guest that is scattered across multiple
231220
/// memory regions. Additionally, this wrapper provides methods that allow reading arbitrary ranges
232221
/// of data from that buffer.
233-
#[derive(Debug)]
222+
#[derive(Debug, Default, Clone)]
234223
pub struct IoVecBufferMut {
235224
// container of the memory regions included in this IO vector
236-
vecs: IovDeque,
225+
vecs: IoVecVec,
237226
// Total length of the IoVecBufferMut
238-
len: usize,
227+
len: u32,
239228
}
240229

241230
impl IoVecBufferMut {
242-
/// Parse a `DescriptorChain` object and append the memory regions it describes in the
243-
/// underlying ring buffer.
231+
/// Create an `IoVecBuffer` from a `DescriptorChain`
244232
///
245233
/// # Safety
246234
///
247235
/// The descriptor chain cannot be referencing the same memory location as another chain
248-
unsafe fn parse_descriptor(
236+
pub unsafe fn load_descriptor_chain(
249237
&mut self,
250238
mem: &GuestMemoryMmap,
251239
head: DescriptorChain,
252-
) -> Result<ParsedDescriptorChain, IoVecError> {
253-
let head_index = head.index;
240+
) -> Result<(), IoVecError> {
241+
self.clear();
242+
254243
let mut next_descriptor = Some(head);
255-
let mut length = 0u32;
256-
let mut nr_iovecs = 0u16;
257244
while let Some(desc) = next_descriptor {
258245
if !desc.is_write_only() {
259-
self.vecs.pop_front(nr_iovecs);
260246
return Err(IoVecError::ReadOnlyDescriptor);
261247
}
262248

263249
// We use get_slice instead of `get_host_address` here in order to have the whole
264250
// range of the descriptor chain checked, i.e. [addr, addr + len) is a valid memory
265251
// region in the GuestMemoryMmap.
266-
let slice = mem.get_slice(desc.addr, desc.len as usize).map_err(|err| {
267-
self.vecs.pop_front(nr_iovecs);
268-
err
269-
})?;
252+
let slice = mem.get_slice(desc.addr, desc.len as usize)?;
270253

271254
// We need to mark the area of guest memory that will be mutated through this
272255
// IoVecBufferMut as dirty ahead of time, as we loose access to all
273256
// vm-memory related information after converting down to iovecs.
274257
slice.bitmap().mark_dirty(0, desc.len as usize);
275258

276259
let iov_base = slice.ptr_guard_mut().as_ptr().cast::<c_void>();
277-
self.vecs.push_back(iovec {
260+
self.vecs.push(iovec {
278261
iov_base,
279262
iov_len: desc.len as size_t,
280263
});
281-
nr_iovecs += 1;
282-
length = length
264+
self.len = self
265+
.len
283266
.checked_add(desc.len)
284-
.ok_or(IoVecError::OverflowedDescriptor)
285-
.map_err(|err| {
286-
self.vecs.pop_front(nr_iovecs);
287-
err
288-
})?;
267+
.ok_or(IoVecError::OverflowedDescriptor)?;
289268

290269
next_descriptor = desc.next_descriptor();
291270
}
292271

293-
self.len = self.len.checked_add(length as usize).ok_or_else(|| {
294-
self.vecs.pop_front(nr_iovecs);
295-
IoVecError::OverflowedDescriptor
296-
})?;
297-
298-
Ok(ParsedDescriptorChain {
299-
head_index,
300-
length,
301-
nr_iovecs,
302-
})
303-
}
304-
305-
/// Create an empty `IoVecBufferMut`.
306-
pub fn new() -> Result<Self, IovDequeError> {
307-
let vecs = IovDeque::new()?;
308-
Ok(Self { vecs, len: 0 })
309-
}
310-
311-
/// Create an `IoVecBufferMut` from a `DescriptorChain`
312-
///
313-
/// This will clear any previous `iovec` objects in the buffer and load the new
314-
/// [`DescriptorChain`].
315-
///
316-
/// # Safety
317-
///
318-
/// The descriptor chain cannot be referencing the same memory location as another chain
319-
pub unsafe fn load_descriptor_chain(
320-
&mut self,
321-
mem: &GuestMemoryMmap,
322-
head: DescriptorChain,
323-
) -> Result<(), IoVecError> {
324-
self.clear();
325-
let _ = self.parse_descriptor(mem, head)?;
326272
Ok(())
327273
}
328274

329-
/// Append a `DescriptorChain` in this `IoVecBufferMut`
330-
///
331-
/// # Safety
332-
///
333-
/// The descriptor chain cannot be referencing the same memory location as another chain
334-
pub unsafe fn append_descriptor_chain(
335-
&mut self,
336-
mem: &GuestMemoryMmap,
337-
head: DescriptorChain,
338-
) -> Result<ParsedDescriptorChain, IoVecError> {
339-
self.parse_descriptor(mem, head)
340-
}
341-
342-
/// Drop memory from the `IoVecBufferMut`
343-
///
344-
/// This will drop memory described by the `IoVecBufferMut` from the beginning.
345-
pub fn drop_descriptor_chain(&mut self, parse_descriptor: &ParsedDescriptorChain) {
346-
self.vecs.pop_front(parse_descriptor.nr_iovecs);
347-
self.len -= parse_descriptor.length as usize;
348-
}
349-
350275
/// Create an `IoVecBuffer` from a `DescriptorChain`
351276
///
352277
/// # Safety
@@ -356,29 +281,20 @@ impl IoVecBufferMut {
356281
mem: &GuestMemoryMmap,
357282
head: DescriptorChain,
358283
) -> Result<Self, IoVecError> {
359-
let mut new_buffer = Self::new()?;
284+
let mut new_buffer = Self::default();
360285
new_buffer.load_descriptor_chain(mem, head)?;
361286
Ok(new_buffer)
362287
}
363288

364289
/// Get the total length of the memory regions covered by this `IoVecBuffer`
365-
///
366-
/// In contrast to the equivalent [`IoVecBuffer::len()`] which returns `u32`, this one returns
367-
/// `usize` since the buffer can contain multiple `DescriptorChain` objects, so we don't have
368-
/// the limit that the length of a buffer is limited by `u32`.
369-
pub(crate) fn len(&self) -> usize {
290+
pub(crate) fn len(&self) -> u32 {
370291
self.len
371292
}
372293

373-
/// Returns a pointer to the memory keeping the `iovec` structs
374-
pub fn as_iovec_mut_slice(&mut self) -> &mut [iovec] {
375-
self.vecs.as_mut_slice()
376-
}
377-
378294
/// Clears the `iovec` array
379295
pub fn clear(&mut self) {
380296
self.vecs.clear();
381-
self.len = 0;
297+
self.len = 0u32;
382298
}
383299

384300
/// Writes a number of bytes into the `IoVecBufferMut` starting at a given offset.
@@ -397,7 +313,7 @@ impl IoVecBufferMut {
397313
mut buf: &[u8],
398314
offset: usize,
399315
) -> Result<(), VolatileMemoryError> {
400-
if offset < self.len() {
316+
if offset < self.len() as usize {
401317
let expected = buf.len();
402318
let bytes_written = self.write_volatile_at(&mut buf, offset, expected)?;
403319

@@ -426,7 +342,7 @@ impl IoVecBufferMut {
426342
) -> Result<usize, VolatileMemoryError> {
427343
let mut total_bytes_read = 0;
428344

429-
for iov in self.vecs.as_slice() {
345+
for iov in &self.vecs {
430346
if len == 0 {
431347
break;
432348
}
@@ -475,7 +391,6 @@ mod tests {
475391
use vm_memory::VolatileMemoryError;
476392

477393
use super::{IoVecBuffer, IoVecBufferMut};
478-
use crate::devices::virtio::iov_deque::IovDeque;
479394
use crate::devices::virtio::queue::{Queue, VIRTQ_DESC_F_NEXT, VIRTQ_DESC_F_WRITE};
480395
use crate::devices::virtio::test_utils::VirtQueue;
481396
use crate::test_utils::multi_region_mem;
@@ -514,33 +429,14 @@ mod tests {
514429

515430
impl From<&mut [u8]> for IoVecBufferMut {
516431
fn from(buf: &mut [u8]) -> Self {
517-
let mut vecs = IovDeque::new().unwrap();
518-
vecs.push_back(iovec {
519-
iov_base: buf.as_mut_ptr().cast::<c_void>(),
520-
iov_len: buf.len(),
521-
});
522-
523432
Self {
524-
vecs,
525-
len: buf.len(),
526-
}
527-
}
528-
}
529-
530-
impl From<Vec<&mut [u8]>> for IoVecBufferMut {
531-
fn from(buffer: Vec<&mut [u8]>) -> Self {
532-
let mut len = 0usize;
533-
let mut vecs = IovDeque::new().unwrap();
534-
for slice in buffer {
535-
len += slice.len();
536-
537-
vecs.push_back(iovec {
538-
iov_base: slice.as_ptr() as *mut c_void,
539-
iov_len: slice.len(),
540-
});
433+
vecs: vec![iovec {
434+
iov_base: buf.as_mut_ptr().cast::<c_void>(),
435+
iov_len: buf.len(),
436+
}]
437+
.into(),
438+
len: buf.len().try_into().unwrap(),
541439
}
542-
543-
Self { vecs, len }
544440
}
545441
}
546442

@@ -632,19 +528,8 @@ mod tests {
632528
let head = q.pop().unwrap();
633529

634530
// SAFETY: This descriptor chain is only loaded once in this test
635-
let mut iovec = unsafe { IoVecBufferMut::from_descriptor_chain(&mem, head).unwrap() };
531+
let iovec = unsafe { IoVecBufferMut::from_descriptor_chain(&mem, head).unwrap() };
636532
assert_eq!(iovec.len(), 4 * 64);
637-
638-
// We are creating a new queue where we can get descriptors from. Probably, this is not
639-
// something that we will ever want to do, as `IoVecBufferMut`s are typically
640-
// (concpetually) associated with a single `Queue`. We just do this here to be able to test
641-
// the appending logic.
642-
let (mut q, _) = write_only_chain(&mem);
643-
let head = q.pop().unwrap();
644-
// SAFETY: it is actually unsafe, but we just want to check the length of the
645-
// `IoVecBufferMut` after appending.
646-
let _ = unsafe { iovec.append_descriptor_chain(&mem, head).unwrap() };
647-
assert_eq!(iovec.len(), 8 * 64);
648533
}
649534

650535
#[test]
@@ -802,7 +687,6 @@ mod verification {
802687
use vm_memory::VolatileSlice;
803688

804689
use super::{IoVecBuffer, IoVecBufferMut, IoVecVec};
805-
use crate::devices::virtio::iov_deque::IovDeque;
806690

807691
// Maximum memory size to use for our buffers. For the time being 1KB.
808692
const GUEST_MEMORY_SIZE: usize = 1 << 10;
@@ -818,10 +702,10 @@ mod verification {
818702
let mut vecs: Vec<iovec> = Vec::with_capacity(nr_descs);
819703
let mut len = 0u32;
820704
for _ in 0..nr_descs {
821-
// The `IoVecBuffer` constructors ensure that the memory region described by every
705+
// The `IoVecBuffer(Mut)` constructors ensure that the memory region described by every
822706
// `Descriptor` in the chain is a valid, i.e. it is memory with then guest's memory
823707
// mmap. The assumption, here, that the last address is within the memory object's
824-
// bound substitutes these checks that `IoVecBuffer::new() performs.`
708+
// bound substitutes these checks that `IoVecBuffer(Mut)::new() performs.`
825709
let addr: usize = kani::any();
826710
let iov_len: usize =
827711
kani::any_where(|&len| matches!(addr.checked_add(len), Some(x) if x <= size));
@@ -844,26 +728,6 @@ mod verification {
844728
}
845729
}
846730

847-
fn create_iovecs_mut(mem: *mut u8, size: usize, nr_descs: usize) -> (IovDeque, u32) {
848-
let mut vecs = IovDeque::new().unwrap();
849-
let mut len = 0u32;
850-
for _ in 0..nr_descs {
851-
// The `IoVecBufferMut` constructors ensure that the memory region described by every
852-
// `Descriptor` in the chain is a valid, i.e. it is memory with then guest's memory
853-
// mmap. The assumption, here, that the last address is within the memory object's
854-
// bound substitutes these checks that `IoVecBufferMut::new() performs.`
855-
let addr: usize = kani::any();
856-
let iov_len: usize =
857-
kani::any_where(|&len| matches!(addr.checked_add(len), Some(x) if x <= size));
858-
let iov_base = unsafe { mem.offset(addr.try_into().unwrap()) } as *mut c_void;
859-
860-
vecs.push_back(iovec { iov_base, iov_len });
861-
len += u32::try_from(iov_len).unwrap();
862-
}
863-
864-
(vecs, len)
865-
}
866-
867731
impl IoVecBufferMut {
868732
fn any_of_length(nr_descs: usize) -> Self {
869733
// We only write into `IoVecBufferMut` objects, so we can simply create a guest memory
@@ -875,11 +739,8 @@ mod verification {
875739
))
876740
};
877741

878-
let (vecs, len) = create_iovecs_mut(mem, GUEST_MEMORY_SIZE, nr_descs);
879-
Self {
880-
vecs,
881-
len: len.try_into().unwrap(),
882-
}
742+
let (vecs, len) = create_iovecs(mem, GUEST_MEMORY_SIZE, nr_descs);
743+
Self { vecs, len }
883744
}
884745
}
885746

@@ -959,7 +820,7 @@ mod verification {
959820
let mut iov_mut = IoVecBufferMut::any_of_length(nr_descs);
960821

961822
let mut buf = kani::vec::any_vec::<u8, GUEST_MEMORY_SIZE>();
962-
let offset: usize = kani::any();
823+
let offset: u32 = kani::any();
963824

964825
// We can't really check the contents that the operation here writes into
965826
// `IoVecBufferMut`, because our `IoVecBufferMut` being completely arbitrary
@@ -974,7 +835,11 @@ mod verification {
974835
// Ok(...)
975836
assert_eq!(
976837
iov_mut
977-
.write_volatile_at(&mut KaniBuffer(&mut buf), offset, GUEST_MEMORY_SIZE)
838+
.write_volatile_at(
839+
&mut KaniBuffer(&mut buf),
840+
offset as usize,
841+
GUEST_MEMORY_SIZE
842+
)
978843
.unwrap(),
979844
buf.len().min(iov_mut.len().saturating_sub(offset) as usize)
980845
);

0 commit comments

Comments
 (0)