@@ -77,13 +77,11 @@ 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 ,
84+ pub bytes : u32 ,
8785 pub start : u16 ,
8886 pub len : u16 ,
8987}
@@ -92,17 +90,15 @@ pub struct IovDeque<const L: u16> {
9290unsafe impl < const L : u16 > Send for IovDeque < L > { }
9391
9492impl < const L : u16 > IovDeque < L > {
95- const BYTES : usize = L as usize * std:: mem:: size_of :: < iovec > ( ) ;
96-
9793 /// Create a [`memfd`] object that represents a single physical page
98- fn create_memfd ( ) -> Result < memfd:: Memfd , IovDequeError > {
94+ fn create_memfd ( pages_bytes : usize ) -> Result < memfd:: Memfd , IovDequeError > {
9995 // Create a sealable memfd.
10096 let opts = memfd:: MemfdOptions :: default ( ) . allow_sealing ( true ) ;
10197 let mfd = opts. create ( "iov_deque" ) ?;
10298
10399 // Resize to system page size.
104100 mfd. as_file ( )
105- . set_len ( Self :: BYTES . try_into ( ) . unwrap ( ) )
101+ . set_len ( pages_bytes . try_into ( ) . unwrap ( ) )
106102 . map_err ( IovDequeError :: MemfdResize ) ?;
107103
108104 // Add seals to prevent further resizing.
@@ -135,13 +131,13 @@ impl<const L: u16> IovDeque<L> {
135131
136132 /// Allocate memory for our ring buffer
137133 ///
138- /// This will allocate 2 * `Self::BYTES ` bytes of virtual memory.
139- fn allocate_ring_buffer_memory ( ) -> Result < * mut c_void , IovDequeError > {
134+ /// This will allocate 2 * `pages_bytes ` bytes of virtual memory.
135+ fn allocate_ring_buffer_memory ( pages_bytes : usize ) -> Result < * mut c_void , IovDequeError > {
140136 // SAFETY: We are calling the system call with valid arguments
141137 unsafe {
142138 Self :: mmap (
143139 std:: ptr:: null_mut ( ) ,
144- Self :: BYTES * 2 ,
140+ pages_bytes * 2 ,
145141 libc:: PROT_NONE ,
146142 libc:: MAP_PRIVATE | libc:: MAP_ANONYMOUS ,
147143 -1 ,
@@ -152,18 +148,21 @@ impl<const L: u16> IovDeque<L> {
152148
153149 /// Create a new [`IovDeque`] that can hold memory described by a single VirtIO queue.
154150 pub fn new ( ) -> Result < Self , IovDequeError > {
155- assert ! ( Self :: BYTES % host_page_size( ) == 0 ) ;
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+ let pages_bytes = num_host_pages * host_page_size;
156155
157- let memfd = Self :: create_memfd ( ) ?;
156+ let memfd = Self :: create_memfd ( pages_bytes ) ?;
158157 let raw_memfd = memfd. as_file ( ) . as_raw_fd ( ) ;
159- let buffer = Self :: allocate_ring_buffer_memory ( ) ?;
158+ let buffer = Self :: allocate_ring_buffer_memory ( pages_bytes ) ?;
160159
161160 // Map the first page of virtual memory to the physical page described by the memfd object
162161 // SAFETY: We are calling the system call with valid arguments
163162 let _ = unsafe {
164163 Self :: mmap (
165164 buffer,
166- Self :: BYTES ,
165+ pages_bytes ,
167166 libc:: PROT_READ | libc:: PROT_WRITE ,
168167 libc:: MAP_SHARED | libc:: MAP_FIXED ,
169168 raw_memfd,
@@ -174,17 +173,17 @@ impl<const L: u16> IovDeque<L> {
174173 // Map the second page of virtual memory to the physical page described by the memfd object
175174 //
176175 // SAFETY: This is safe because:
177- // * Both `buffer` and the result of `buffer.add(Self::BYTES )` are within bounds of the
176+ // * Both `buffer` and the result of `buffer.add(pages_bytes )` are within bounds of the
178177 // allocation we got from `Self::allocate_ring_buffer_memory`.
179178 // * The resulting pointer is the beginning of the second page of our allocation, so it
180179 // doesn't wrap around the address space.
181- let next_page = unsafe { buffer. add ( Self :: BYTES ) } ;
180+ let next_page = unsafe { buffer. add ( pages_bytes ) } ;
182181
183182 // SAFETY: We are calling the system call with valid arguments
184183 let _ = unsafe {
185184 Self :: mmap (
186185 next_page,
187- Self :: BYTES ,
186+ pages_bytes ,
188187 libc:: PROT_READ | libc:: PROT_WRITE ,
189188 libc:: MAP_SHARED | libc:: MAP_FIXED ,
190189 raw_memfd,
@@ -194,6 +193,7 @@ impl<const L: u16> IovDeque<L> {
194193
195194 Ok ( Self {
196195 iov : buffer. cast ( ) ,
196+ bytes : u32:: try_from ( pages_bytes) . unwrap ( ) ,
197197 start : 0 ,
198198 len : 0 ,
199199 } )
@@ -313,8 +313,8 @@ impl<const L: u16> IovDeque<L> {
313313impl < const L : u16 > Drop for IovDeque < L > {
314314 fn drop ( & mut self ) {
315315 // 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 ) } ;
316+ // self. bytes` by calling mmap
317+ let _ = unsafe { libc:: munmap ( self . iov . cast ( ) , usize :: try_from ( self . bytes ) . unwrap ( ) * 2 ) } ;
318318 }
319319}
320320
@@ -332,6 +332,18 @@ mod tests {
332332 assert_eq ! ( deque. len( ) , 0 ) ;
333333 }
334334
335+ #[ test]
336+ fn test_new_less_than_page ( ) {
337+ let deque = super :: IovDeque :: < 128 > :: new ( ) . unwrap ( ) ;
338+ assert_eq ! ( deque. len( ) , 0 ) ;
339+ }
340+
341+ #[ test]
342+ fn test_new_more_than_page ( ) {
343+ let deque = super :: IovDeque :: < 512 > :: new ( ) . unwrap ( ) ;
344+ assert_eq ! ( deque. len( ) , 0 ) ;
345+ }
346+
335347 fn make_iovec ( id : u16 , len : u16 ) -> iovec {
336348 iovec {
337349 iov_base : id as * mut libc:: c_void ,
0 commit comments