@@ -24,13 +24,15 @@ pub enum IoVecError {
24
24
GuestMemory ( #[ from] GuestMemoryError ) ,
25
25
}
26
26
27
+ const SMALL_VEC_SIZE : usize = 4 ;
28
+
27
29
// Using SmallVec in the kani proofs causes kani to use unbounded amounts of memory
28
30
// during post-processing, and then crash.
29
31
// TODO: remove new-type once kani performance regression are resolved
30
32
#[ cfg( kani) ]
31
33
type IoVecVec = Vec < iovec > ;
32
34
#[ cfg( not( kani) ) ]
33
- type IoVecVec = SmallVec < [ iovec ; 4 ] > ;
35
+ type IoVecVec = SmallVec < [ iovec ; SMALL_VEC_SIZE ] > ;
34
36
35
37
/// This is essentially a wrapper of a `Vec<libc::iovec>` which can be passed to `libc::writev`.
36
38
///
@@ -45,6 +47,15 @@ pub struct IoVecBuffer {
45
47
len : u32 ,
46
48
}
47
49
50
+ impl IoVecBuffer {
51
+ pub fn with_capacity ( cap : usize ) -> IoVecBuffer {
52
+ IoVecBuffer {
53
+ vecs : IoVecVec :: with_capacity ( cap) ,
54
+ len : 0 ,
55
+ }
56
+ }
57
+ }
58
+
48
59
// SAFETY: `IoVecBuffer` doesn't allow for interior mutability and no shared ownership is possible
49
60
// as it doesn't implement clone
50
61
unsafe impl Send for IoVecBuffer { }
@@ -57,12 +68,11 @@ impl IoVecBuffer {
57
68
/// The descriptor chain cannot be referencing the same memory location as another chain
58
69
pub unsafe fn load_descriptor_chain (
59
70
& mut self ,
60
- head : DescriptorChain ,
71
+ mut desc : DescriptorChain ,
61
72
) -> Result < ( ) , IoVecError > {
62
73
self . clear ( ) ;
63
74
64
- let mut next_descriptor = Some ( head) ;
65
- while let Some ( desc) = next_descriptor {
75
+ loop {
66
76
if desc. is_write_only ( ) {
67
77
return Err ( IoVecError :: WriteOnlyDescriptor ) ;
68
78
}
@@ -85,7 +95,9 @@ impl IoVecBuffer {
85
95
. checked_add ( desc. len )
86
96
. ok_or ( IoVecError :: OverflowedDescriptor ) ?;
87
97
88
- next_descriptor = desc. next_descriptor ( ) ;
98
+ if desc. load_next_descriptor ( ) . is_none ( ) {
99
+ break ;
100
+ }
89
101
}
90
102
91
103
Ok ( ( ) )
@@ -217,21 +229,38 @@ impl IoVecBuffer {
217
229
/// It describes a write-only buffer passed to us by the guest that is scattered across multiple
218
230
/// memory regions. Additionally, this wrapper provides methods that allow reading arbitrary ranges
219
231
/// of data from that buffer.
220
- #[ derive( Debug ) ]
232
+ #[ derive( Debug , Default ) ]
221
233
pub struct IoVecBufferMut {
222
234
// container of the memory regions included in this IO vector
223
- vecs : IoVecVec ,
235
+ pub ( crate ) vecs : IoVecVec ,
224
236
// Total length of the IoVecBufferMut
225
- len : u32 ,
237
+ pub ( crate ) len : u32 ,
238
+ }
239
+
240
+ impl IoVecBufferMut {
241
+ pub fn with_capacity ( cap : usize ) -> IoVecBufferMut {
242
+ IoVecBufferMut {
243
+ vecs : IoVecVec :: with_capacity ( cap) ,
244
+ len : 0 ,
245
+ }
246
+ }
226
247
}
227
248
249
+ // SAFETY: iovec pointers are safe to send across threads.
250
+ unsafe impl Send for IoVecBufferMut { }
251
+
228
252
impl IoVecBufferMut {
229
253
/// Create an `IoVecBufferMut` from a `DescriptorChain`
230
- pub fn from_descriptor_chain ( head : DescriptorChain ) -> Result < Self , IoVecError > {
231
- let mut vecs = IoVecVec :: new ( ) ;
232
- let mut len = 0u32 ;
254
+ /// # Safety
255
+ /// The descriptor chain cannot be referencing the same memory location as another chain.
256
+ pub unsafe fn load_descriptor_chain (
257
+ & mut self ,
258
+ mut desc : DescriptorChain ,
259
+ max_size : Option < u32 > ,
260
+ ) -> Result < ( ) , IoVecError > {
261
+ self . clear ( ) ;
233
262
234
- for desc in head {
263
+ loop {
235
264
if !desc. is_write_only ( ) {
236
265
return Err ( IoVecError :: ReadOnlyDescriptor ) ;
237
266
}
@@ -247,16 +276,34 @@ impl IoVecBufferMut {
247
276
slice. bitmap ( ) . mark_dirty ( 0 , desc. len as usize ) ;
248
277
249
278
let iov_base = slice. ptr_guard_mut ( ) . as_ptr ( ) . cast :: < c_void > ( ) ;
250
- vecs. push ( iovec {
279
+ self . vecs . push ( iovec {
251
280
iov_base,
252
281
iov_len : desc. len as size_t ,
253
282
} ) ;
254
- len = len
283
+ self . len = self
284
+ . len
255
285
. checked_add ( desc. len )
256
286
. ok_or ( IoVecError :: OverflowedDescriptor ) ?;
287
+ if matches ! ( max_size, Some ( max) if self . len >= max) {
288
+ break ;
289
+ }
290
+ if desc. load_next_descriptor ( ) . is_none ( ) {
291
+ break ;
292
+ }
257
293
}
258
294
259
- Ok ( Self { vecs, len } )
295
+ Ok ( ( ) )
296
+ }
297
+
298
+ /// Create an `IoVecBufferMut` from a `DescriptorChain`
299
+ /// # Safety
300
+ /// The descriptor chain cannot be referencing the same memory location as another chain.
301
+ pub unsafe fn from_descriptor_chain ( head : DescriptorChain ) -> Result < Self , IoVecError > {
302
+ let mut new_buffer = Self :: default ( ) ;
303
+
304
+ Self :: load_descriptor_chain ( & mut new_buffer, head, None ) ?;
305
+
306
+ Ok ( new_buffer)
260
307
}
261
308
262
309
/// Get the total length of the memory regions covered by this `IoVecBuffer`
@@ -298,6 +345,22 @@ impl IoVecBufferMut {
298
345
}
299
346
}
300
347
348
+ /// Returns a pointer to the memory keeping the `iovec` structs
349
+ pub fn as_iovec_ptr ( & self ) -> * const iovec {
350
+ self . vecs . as_ptr ( )
351
+ }
352
+
353
+ /// Returns the length of the `iovec` array.
354
+ pub fn iovec_count ( & self ) -> usize {
355
+ self . vecs . len ( )
356
+ }
357
+
358
+ /// Clears the `iovec` array
359
+ pub fn clear ( & mut self ) {
360
+ self . vecs . clear ( ) ;
361
+ self . len = 0u32 ;
362
+ }
363
+
301
364
/// Writes up to `len` bytes into the `IoVecBuffer` starting at the given offset.
302
365
///
303
366
/// This will try to write to the given [`WriteVolatile`].
@@ -468,11 +531,13 @@ mod tests {
468
531
469
532
let ( mut q, _) = read_only_chain ( & mem) ;
470
533
let head = q. pop ( & mem) . unwrap ( ) ;
471
- IoVecBufferMut :: from_descriptor_chain ( head) . unwrap_err ( ) ;
534
+ // SAFETY: This descriptor chain is only loaded into one buffer.
535
+ unsafe { IoVecBufferMut :: from_descriptor_chain ( head) . unwrap_err ( ) } ;
472
536
473
537
let ( mut q, _) = write_only_chain ( & mem) ;
474
538
let head = q. pop ( & mem) . unwrap ( ) ;
475
- IoVecBufferMut :: from_descriptor_chain ( head) . unwrap ( ) ;
539
+ // SAFETY: This descriptor chain is only loaded into one buffer.
540
+ unsafe { IoVecBufferMut :: from_descriptor_chain ( head) . unwrap ( ) } ;
476
541
}
477
542
478
543
#[ test]
@@ -493,7 +558,7 @@ mod tests {
493
558
let head = q. pop ( & mem) . unwrap ( ) ;
494
559
495
560
// SAFETY: This descriptor chain is only loaded once in this test
496
- let iovec = IoVecBufferMut :: from_descriptor_chain ( head) . unwrap ( ) ;
561
+ let iovec = unsafe { IoVecBufferMut :: from_descriptor_chain ( head) . unwrap ( ) } ;
497
562
assert_eq ! ( iovec. len( ) , 4 * 64 ) ;
498
563
}
499
564
@@ -558,7 +623,8 @@ mod tests {
558
623
// This is a descriptor chain with 4 elements 64 bytes long each.
559
624
let head = q. pop ( & mem) . unwrap ( ) ;
560
625
561
- let mut iovec = IoVecBufferMut :: from_descriptor_chain ( head) . unwrap ( ) ;
626
+ // SAFETY: This descriptor chain is only loaded into one buffer.
627
+ let mut iovec = unsafe { IoVecBufferMut :: from_descriptor_chain ( head) . unwrap ( ) } ;
562
628
let buf = vec ! [ 0u8 , 1 , 2 , 3 , 4 ] ;
563
629
564
630
// One test vector for each part of the chain
0 commit comments