@@ -77,10 +77,7 @@ pub enum IovDequeError {
7777// pub iov_len: ::size_t,
7878// }
7979// ```
80- //
81- // This value must be a multiple of 256 because this is the maximum number of `iovec` can fit into
82- // 1 memory page: 256 * sizeof(iovec) == 4096 == HOST_PAGE_SIZE. IovDeque only operates with
83- // `HOST_PAGE_SIZE` granularity.
80+
8481#[ derive( Debug ) ]
8582pub struct IovDeque < const L : u16 > {
8683 pub iov : * mut libc:: iovec ,
@@ -92,17 +89,15 @@ pub struct IovDeque<const L: u16> {
9289unsafe impl < const L : u16 > Send for IovDeque < L > { }
9390
9491impl < const L : u16 > IovDeque < L > {
95- const BYTES : usize = L as usize * std:: mem:: size_of :: < iovec > ( ) ;
96-
9792 /// Create a [`memfd`] object that represents a single physical page
98- fn create_memfd ( ) -> Result < memfd:: Memfd , IovDequeError > {
93+ fn create_memfd ( pages_bytes : usize ) -> Result < memfd:: Memfd , IovDequeError > {
9994 // Create a sealable memfd.
10095 let opts = memfd:: MemfdOptions :: default ( ) . allow_sealing ( true ) ;
10196 let mfd = opts. create ( "iov_deque" ) ?;
10297
10398 // Resize to system page size.
10499 mfd. as_file ( )
105- . set_len ( Self :: BYTES . try_into ( ) . unwrap ( ) )
100+ . set_len ( pages_bytes . try_into ( ) . unwrap ( ) )
106101 . map_err ( IovDequeError :: MemfdResize ) ?;
107102
108103 // Add seals to prevent further resizing.
@@ -135,13 +130,13 @@ impl<const L: u16> IovDeque<L> {
135130
136131 /// Allocate memory for our ring buffer
137132 ///
138- /// This will allocate 2 * `Self::BYTES ` bytes of virtual memory.
139- fn allocate_ring_buffer_memory ( ) -> Result < * mut c_void , IovDequeError > {
133+ /// This will allocate 2 * `pages_bytes ` bytes of virtual memory.
134+ fn allocate_ring_buffer_memory ( pages_bytes : usize ) -> Result < * mut c_void , IovDequeError > {
140135 // SAFETY: We are calling the system call with valid arguments
141136 unsafe {
142137 Self :: mmap (
143138 std:: ptr:: null_mut ( ) ,
144- Self :: BYTES * 2 ,
139+ pages_bytes * 2 ,
145140 libc:: PROT_NONE ,
146141 libc:: MAP_PRIVATE | libc:: MAP_ANONYMOUS ,
147142 -1 ,
@@ -150,20 +145,29 @@ impl<const L: u16> IovDeque<L> {
150145 }
151146 }
152147
148+ /// Calculate a number of bytes in full pages required for
149+ /// the type to operate.
150+ fn pages_bytes ( ) -> usize {
151+ let host_page_size = host_page_size ( ) ;
152+ let bytes = L as usize * std:: mem:: size_of :: < iovec > ( ) ;
153+ let num_host_pages = bytes. div_ceil ( host_page_size) ;
154+ num_host_pages * host_page_size
155+ }
156+
153157 /// Create a new [`IovDeque`] that can hold memory described by a single VirtIO queue.
154158 pub fn new ( ) -> Result < Self , IovDequeError > {
155- assert ! ( Self :: BYTES % host_page_size ( ) == 0 ) ;
159+ let pages_bytes = Self :: pages_bytes ( ) ;
156160
157- let memfd = Self :: create_memfd ( ) ?;
161+ let memfd = Self :: create_memfd ( pages_bytes ) ?;
158162 let raw_memfd = memfd. as_file ( ) . as_raw_fd ( ) ;
159- let buffer = Self :: allocate_ring_buffer_memory ( ) ?;
163+ let buffer = Self :: allocate_ring_buffer_memory ( pages_bytes ) ?;
160164
161165 // Map the first page of virtual memory to the physical page described by the memfd object
162166 // SAFETY: We are calling the system call with valid arguments
163167 let _ = unsafe {
164168 Self :: mmap (
165169 buffer,
166- Self :: BYTES ,
170+ pages_bytes ,
167171 libc:: PROT_READ | libc:: PROT_WRITE ,
168172 libc:: MAP_SHARED | libc:: MAP_FIXED ,
169173 raw_memfd,
@@ -174,17 +178,17 @@ impl<const L: u16> IovDeque<L> {
174178 // Map the second page of virtual memory to the physical page described by the memfd object
175179 //
176180 // SAFETY: This is safe because:
177- // * Both `buffer` and the result of `buffer.add(Self::BYTES )` are within bounds of the
181+ // * Both `buffer` and the result of `buffer.add(pages_bytes )` are within bounds of the
178182 // allocation we got from `Self::allocate_ring_buffer_memory`.
179183 // * The resulting pointer is the beginning of the second page of our allocation, so it
180184 // doesn't wrap around the address space.
181- let next_page = unsafe { buffer. add ( Self :: BYTES ) } ;
185+ let next_page = unsafe { buffer. add ( pages_bytes ) } ;
182186
183187 // SAFETY: We are calling the system call with valid arguments
184188 let _ = unsafe {
185189 Self :: mmap (
186190 next_page,
187- Self :: BYTES ,
191+ pages_bytes ,
188192 libc:: PROT_READ | libc:: PROT_WRITE ,
189193 libc:: MAP_SHARED | libc:: MAP_FIXED ,
190194 raw_memfd,
@@ -312,9 +316,10 @@ impl<const L: u16> IovDeque<L> {
312316
313317impl < const L : u16 > Drop for IovDeque < L > {
314318 fn drop ( & mut self ) {
319+ let pages_bytes = Self :: pages_bytes ( ) ;
315320 // SAFETY: We are passing an address that we got from a previous allocation of `2 *
316- // Self::BYTES` bytes by calling mmap
317- let _ = unsafe { libc:: munmap ( self . iov . cast ( ) , Self :: BYTES * 2 ) } ;
321+ // pages_bytes` by calling mmap
322+ let _ = unsafe { libc:: munmap ( self . iov . cast ( ) , 2 * pages_bytes ) } ;
318323 }
319324}
320325
@@ -332,6 +337,18 @@ mod tests {
332337 assert_eq ! ( deque. len( ) , 0 ) ;
333338 }
334339
340+ #[ test]
341+ fn test_new_less_than_page ( ) {
342+ let deque = super :: IovDeque :: < 128 > :: new ( ) . unwrap ( ) ;
343+ assert_eq ! ( deque. len( ) , 0 ) ;
344+ }
345+
346+ #[ test]
347+ fn test_new_more_than_page ( ) {
348+ let deque = super :: IovDeque :: < 512 > :: new ( ) . unwrap ( ) ;
349+ assert_eq ! ( deque. len( ) , 0 ) ;
350+ }
351+
335352 fn make_iovec ( id : u16 , len : u16 ) -> iovec {
336353 iovec {
337354 iov_base : id as * mut libc:: c_void ,
0 commit comments