@@ -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 ,
@@ -152,18 +147,21 @@ impl<const L: u16> IovDeque<L> {
152147
153148 /// Create a new [`IovDeque`] that can hold memory described by a single VirtIO queue.
154149 pub fn new ( ) -> Result < Self , IovDequeError > {
155- assert ! ( Self :: BYTES % host_page_size( ) == 0 ) ;
150+ let host_page_size = host_page_size ( ) ;
151+ let bytes = L as usize * std:: mem:: size_of :: < iovec > ( ) ;
152+ let num_host_pages = bytes. div_ceil ( host_page_size) ;
153+ let pages_bytes = num_host_pages * host_page_size;
156154
157- let memfd = Self :: create_memfd ( ) ?;
155+ let memfd = Self :: create_memfd ( pages_bytes ) ?;
158156 let raw_memfd = memfd. as_file ( ) . as_raw_fd ( ) ;
159- let buffer = Self :: allocate_ring_buffer_memory ( ) ?;
157+ let buffer = Self :: allocate_ring_buffer_memory ( pages_bytes ) ?;
160158
161159 // Map the first page of virtual memory to the physical page described by the memfd object
162160 // SAFETY: We are calling the system call with valid arguments
163161 let _ = unsafe {
164162 Self :: mmap (
165163 buffer,
166- Self :: BYTES ,
164+ pages_bytes ,
167165 libc:: PROT_READ | libc:: PROT_WRITE ,
168166 libc:: MAP_SHARED | libc:: MAP_FIXED ,
169167 raw_memfd,
@@ -174,17 +172,17 @@ impl<const L: u16> IovDeque<L> {
174172 // Map the second page of virtual memory to the physical page described by the memfd object
175173 //
176174 // SAFETY: This is safe because:
177- // * Both `buffer` and the result of `buffer.add(Self::BYTES )` are within bounds of the
175+ // * Both `buffer` and the result of `buffer.add(pages_bytes )` are within bounds of the
178176 // allocation we got from `Self::allocate_ring_buffer_memory`.
179177 // * The resulting pointer is the beginning of the second page of our allocation, so it
180178 // doesn't wrap around the address space.
181- let next_page = unsafe { buffer. add ( Self :: BYTES ) } ;
179+ let next_page = unsafe { buffer. add ( pages_bytes ) } ;
182180
183181 // SAFETY: We are calling the system call with valid arguments
184182 let _ = unsafe {
185183 Self :: mmap (
186184 next_page,
187- Self :: BYTES ,
185+ pages_bytes ,
188186 libc:: PROT_READ | libc:: PROT_WRITE ,
189187 libc:: MAP_SHARED | libc:: MAP_FIXED ,
190188 raw_memfd,
@@ -312,9 +310,13 @@ impl<const L: u16> IovDeque<L> {
312310
313311impl < const L : u16 > Drop for IovDeque < L > {
314312 fn drop ( & mut self ) {
313+ let host_page_size = host_page_size ( ) ;
314+ let bytes = L as usize * std:: mem:: size_of :: < iovec > ( ) ;
315+ let num_host_pages = bytes. div_ceil ( host_page_size) ;
316+ let pages_bytes = num_host_pages * host_page_size;
315317 // 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 ) } ;
318+ // pages_bytes` by calling mmap
319+ let _ = unsafe { libc:: munmap ( self . iov . cast ( ) , 2 * pages_bytes ) } ;
318320 }
319321}
320322
@@ -332,6 +334,18 @@ mod tests {
332334 assert_eq ! ( deque. len( ) , 0 ) ;
333335 }
334336
337+ #[ test]
338+ fn test_new_less_than_page ( ) {
339+ let deque = super :: IovDeque :: < 128 > :: new ( ) . unwrap ( ) ;
340+ assert_eq ! ( deque. len( ) , 0 ) ;
341+ }
342+
343+ #[ test]
344+ fn test_new_more_than_page ( ) {
345+ let deque = super :: IovDeque :: < 512 > :: new ( ) . unwrap ( ) ;
346+ assert_eq ! ( deque. len( ) , 0 ) ;
347+ }
348+
335349 fn make_iovec ( id : u16 , len : u16 ) -> iovec {
336350 iovec {
337351 iov_base : id as * mut libc:: c_void ,
0 commit comments