@@ -10,6 +10,7 @@ use vm_memory::{
10
10
GuestMemory , GuestMemoryError , ReadVolatile , VolatileMemoryError , VolatileSlice , WriteVolatile ,
11
11
} ;
12
12
13
+ use super :: iov_deque:: { IovDeque , IovDequeError } ;
13
14
use crate :: devices:: virtio:: queue:: DescriptorChain ;
14
15
use crate :: vstate:: memory:: GuestMemoryMmap ;
15
16
@@ -23,6 +24,8 @@ pub enum IoVecError {
23
24
OverflowedDescriptor ,
24
25
/// Guest memory error: {0}
25
26
GuestMemory ( #[ from] GuestMemoryError ) ,
27
+ /// Error with underlying `IovDeque`: {0}
28
+ IovDeque ( #[ from] IovDequeError ) ,
26
29
}
27
30
28
31
// Using SmallVec in the kani proofs causes kani to use unbounded amounts of memory
@@ -219,28 +222,24 @@ impl IoVecBuffer {
219
222
/// It describes a write-only buffer passed to us by the guest that is scattered across multiple
220
223
/// memory regions. Additionally, this wrapper provides methods that allow reading arbitrary ranges
221
224
/// of data from that buffer.
222
- #[ derive( Debug , Default , Clone ) ]
223
- pub struct IoVecBufferMut {
225
+ #[ derive( Debug ) ]
226
+ pub struct IoVecBufferMut < ' a > {
224
227
// container of the memory regions included in this IO vector
225
- vecs : IoVecVec ,
228
+ vecs : IovDeque < ' a > ,
226
229
// Total length of the IoVecBufferMut
227
- len : u32 ,
230
+ len : usize ,
228
231
}
229
232
230
- impl IoVecBufferMut {
231
- /// Create an `IoVecBuffer` from a `DescriptorChain`
232
- ///
233
- /// # Safety
234
- ///
235
- /// The descriptor chain cannot be referencing the same memory location as another chain
236
- pub unsafe fn load_descriptor_chain (
233
+ impl < ' a > IoVecBufferMut < ' a > {
234
+ /// Parse a `DescriptorChain` object and append the memory regions it describes in the
235
+ /// underlying ring buffer.
236
+ fn parse_descriptor (
237
237
& mut self ,
238
238
mem : & GuestMemoryMmap ,
239
239
head : DescriptorChain ,
240
- ) -> Result < ( ) , IoVecError > {
241
- self . clear ( ) ;
242
-
240
+ ) -> Result < u32 , IoVecError > {
243
241
let mut next_descriptor = Some ( head) ;
242
+ let mut length = 0u32 ;
244
243
while let Some ( desc) = next_descriptor {
245
244
if !desc. is_write_only ( ) {
246
245
return Err ( IoVecError :: ReadOnlyDescriptor ) ;
@@ -257,18 +256,80 @@ impl IoVecBufferMut {
257
256
slice. bitmap ( ) . mark_dirty ( 0 , desc. len as usize ) ;
258
257
259
258
let iov_base = slice. ptr_guard_mut ( ) . as_ptr ( ) . cast :: < c_void > ( ) ;
260
- self . vecs . push ( iovec {
261
- iov_base,
262
- iov_len : desc. len as size_t ,
263
- } ) ;
264
- self . len = self
265
- . len
259
+ self . vecs
260
+ . push_back ( iovec {
261
+ iov_base,
262
+ iov_len : desc. len as size_t ,
263
+ } )
264
+ . unwrap ( ) ;
265
+ length = length
266
266
. checked_add ( desc. len )
267
267
. ok_or ( IoVecError :: OverflowedDescriptor ) ?;
268
268
269
269
next_descriptor = desc. next_descriptor ( ) ;
270
270
}
271
271
272
+ self . len = self
273
+ . len
274
+ . checked_add ( length as usize )
275
+ . ok_or ( IoVecError :: OverflowedDescriptor ) ?;
276
+
277
+ Ok ( length)
278
+ }
279
+
280
+ /// Create an empty `IoVecBufferMut`.
281
+ pub ( crate ) fn new ( ) -> Result < Self , IovDequeError > {
282
+ let vecs = IovDeque :: new ( ) ?;
283
+ Ok ( Self { vecs, len : 0 } )
284
+ }
285
+
286
+ /// Create an `IoVecBufferMut` from a `DescriptorChain`
287
+ ///
288
+ /// This will clear any previous `iovec` objects in the buffer and load the new
289
+ /// [`DescriptorChain`].
290
+ ///
291
+ /// # Safety
292
+ ///
293
+ /// The descriptor chain cannot be referencing the same memory location as another chain
294
+ pub unsafe fn load_descriptor_chain (
295
+ & mut self ,
296
+ mem : & GuestMemoryMmap ,
297
+ head : DescriptorChain ,
298
+ ) -> Result < ( ) , IoVecError > {
299
+ self . clear ( ) ;
300
+ let _ = self . parse_descriptor ( mem, head) ?;
301
+ Ok ( ( ) )
302
+ }
303
+
304
+ /// Append a `DescriptorChain` in this `IoVecBufferMut`
305
+ ///
306
+ /// # Safety
307
+ ///
308
+ /// The descriptor chain cannot be referencing the same memory location as another chain
309
+ pub unsafe fn append_descriptor_chain (
310
+ & mut self ,
311
+ mem : & GuestMemoryMmap ,
312
+ head : DescriptorChain ,
313
+ ) -> Result < u32 , IoVecError > {
314
+ self . parse_descriptor ( mem, head)
315
+ }
316
+
317
+ /// Drop memory from the `IoVecBufferMut`
318
+ ///
319
+ /// This will drop memory described by the `IoVecBufferMut` starting from the beginning.
320
+ pub fn drop_iovecs ( & mut self , size : u32 ) -> Result < ( ) , IoVecError > {
321
+ let dropped = self . vecs . drop_iovs ( size as usize ) ;
322
+
323
+ // Users should ask us to drop a `size` of memory that is not exactly covered by `iovec`
324
+ // objects. In other words, the sum of the lengths of all dropped `iovec` objects should be
325
+ // equal to the `size` we were asked to drop. If it isn't, something is seriously wrong
326
+ // with the VirtIO queue or the emulation logic, so fail at this point.
327
+ assert_eq ! ( u32 :: try_from( dropped) . unwrap( ) , size) ;
328
+ self . len = self
329
+ . len
330
+ . checked_sub ( size as usize )
331
+ . ok_or ( IoVecError :: OverflowedDescriptor ) ?;
332
+
272
333
Ok ( ( ) )
273
334
}
274
335
@@ -281,20 +342,34 @@ impl IoVecBufferMut {
281
342
mem : & GuestMemoryMmap ,
282
343
head : DescriptorChain ,
283
344
) -> Result < Self , IoVecError > {
284
- let mut new_buffer = Self :: default ( ) ;
345
+ let mut new_buffer = Self :: new ( ) ? ;
285
346
new_buffer. load_descriptor_chain ( mem, head) ?;
286
347
Ok ( new_buffer)
287
348
}
288
349
289
350
/// Get the total length of the memory regions covered by this `IoVecBuffer`
290
- pub ( crate ) fn len ( & self ) -> u32 {
351
+ ///
352
+ /// In contrast to the equivalent [`IoVecBuffer::len()`] which returns `u32`, this one returns
353
+ /// `usize` since the buffer can contain multiple `DescriptorChain` objects, so we don't have
354
+ /// the limit that the length of a buffer is limited by `u32`.
355
+ pub ( crate ) fn len ( & self ) -> usize {
291
356
self . len
292
357
}
293
358
359
+ /// Returns a pointer to the memory keeping the `iovec` structs
360
+ pub fn as_iovec_ptr ( & mut self ) -> * mut iovec {
361
+ self . vecs . as_mut_slice ( ) . as_mut_ptr ( )
362
+ }
363
+
364
+ /// Returns the length of the `iovec` array.
365
+ pub fn iovec_count ( & self ) -> usize {
366
+ self . vecs . len ( )
367
+ }
368
+
294
369
/// Clears the `iovec` array
295
370
pub fn clear ( & mut self ) {
296
371
self . vecs . clear ( ) ;
297
- self . len = 0u32 ;
372
+ self . len = 0 ;
298
373
}
299
374
300
375
/// Writes a number of bytes into the `IoVecBufferMut` starting at a given offset.
@@ -313,7 +388,7 @@ impl IoVecBufferMut {
313
388
mut buf : & [ u8 ] ,
314
389
offset : usize ,
315
390
) -> Result < ( ) , VolatileMemoryError > {
316
- if offset < self . len ( ) as usize {
391
+ if offset < self . len ( ) {
317
392
let expected = buf. len ( ) ;
318
393
let bytes_written = self . write_volatile_at ( & mut buf, offset, expected) ?;
319
394
@@ -342,7 +417,7 @@ impl IoVecBufferMut {
342
417
) -> Result < usize , VolatileMemoryError > {
343
418
let mut total_bytes_read = 0 ;
344
419
345
- for iov in & self . vecs {
420
+ for iov in self . vecs . as_mut_slice ( ) {
346
421
if len == 0 {
347
422
break ;
348
423
}
@@ -391,6 +466,7 @@ mod tests {
391
466
use vm_memory:: VolatileMemoryError ;
392
467
393
468
use super :: { IoVecBuffer , IoVecBufferMut } ;
469
+ use crate :: devices:: virtio:: iov_deque:: IovDeque ;
394
470
use crate :: devices:: virtio:: queue:: { Queue , VIRTQ_DESC_F_NEXT , VIRTQ_DESC_F_WRITE } ;
395
471
use crate :: devices:: virtio:: test_utils:: VirtQueue ;
396
472
use crate :: utilities:: test_utils:: multi_region_mem;
@@ -427,15 +503,18 @@ mod tests {
427
503
}
428
504
}
429
505
430
- impl From < & mut [ u8 ] > for IoVecBufferMut {
506
+ impl < ' a > From < & mut [ u8 ] > for IoVecBufferMut < ' a > {
431
507
fn from ( buf : & mut [ u8 ] ) -> Self {
508
+ let mut vecs = IovDeque :: new ( ) . unwrap ( ) ;
509
+ vecs. push_back ( iovec {
510
+ iov_base : buf. as_mut_ptr ( ) . cast :: < c_void > ( ) ,
511
+ iov_len : buf. len ( ) ,
512
+ } )
513
+ . unwrap ( ) ;
514
+
432
515
Self {
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 ( ) ,
516
+ vecs,
517
+ len : buf. len ( ) ,
439
518
}
440
519
}
441
520
}
@@ -528,8 +607,19 @@ mod tests {
528
607
let head = q. pop ( ) . unwrap ( ) ;
529
608
530
609
// SAFETY: This descriptor chain is only loaded once in this test
531
- let iovec = unsafe { IoVecBufferMut :: from_descriptor_chain ( & mem, head) . unwrap ( ) } ;
610
+ let mut iovec = unsafe { IoVecBufferMut :: from_descriptor_chain ( & mem, head) . unwrap ( ) } ;
532
611
assert_eq ! ( iovec. len( ) , 4 * 64 ) ;
612
+
613
+ // We are creating a new queue where we can get descriptors from. Probably, this is not
614
+ // something that we will ever want to do, as `IoVecBufferMut`s are typically
615
+ // (concpetually) associated with a single `Queue`. We just do this here to be able to test
616
+ // the appending logic.
617
+ let ( mut q, _) = write_only_chain ( & mem) ;
618
+ let head = q. pop ( ) . unwrap ( ) ;
619
+ // SAFETY: it is actually unsafe, but we just want to check the length of the
620
+ // `IoVecBufferMut` after appending.
621
+ let _ = unsafe { iovec. append_descriptor_chain ( & mem, head) . unwrap ( ) } ;
622
+ assert_eq ! ( iovec. len( ) , 8 * 64 ) ;
533
623
}
534
624
535
625
#[ test]
@@ -728,7 +818,7 @@ mod verification {
728
818
}
729
819
}
730
820
731
- impl IoVecBufferMut {
821
+ impl IoVecBufferMut < ' _ > {
732
822
fn any_of_length ( nr_descs : usize ) -> Self {
733
823
// We only write into `IoVecBufferMut` objects, so we can simply create a guest memory
734
824
// object initialized to zeroes, trying to be nice to Kani.
@@ -740,7 +830,10 @@ mod verification {
740
830
} ;
741
831
742
832
let ( vecs, len) = create_iovecs ( mem, GUEST_MEMORY_SIZE , nr_descs) ;
743
- Self { vecs, len }
833
+ Self {
834
+ vecs,
835
+ len : len. try_into ( ) . unwrap ( ) ,
836
+ }
744
837
}
745
838
}
746
839
0 commit comments