@@ -6,7 +6,7 @@ use std::os::fd::AsRawFd;
66use  libc:: { c_int,  c_void,  iovec,  off_t,  size_t} ; 
77use  memfd; 
88
9- use  crate :: arch:: PAGE_SIZE ; 
9+ use  crate :: arch:: host_page_size ; 
1010
1111#[ derive( Debug ,  thiserror:: Error ,  displaydoc:: Display ) ]  
1212pub  enum  IovDequeError  { 
@@ -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 == PAGE_SIZE. IovDeque only operates with `PAGE_SIZE` 
83- // granularity. 
80+ 
8481#[ derive( Debug ) ]  
8582pub  struct  IovDeque < const  L :  u16 >  { 
8683    pub  iov :  * mut  libc:: iovec , 
@@ -92,18 +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-     const  _ASSERT:  ( )  = assert ! ( Self :: BYTES  % PAGE_SIZE  == 0 ) ; 
97- 
9892    /// Create a [`memfd`] object that represents a single physical page 
99-      fn  create_memfd ( )  -> Result < memfd:: Memfd ,  IovDequeError >  { 
93+      fn  create_memfd ( pages_bytes :   usize )  -> Result < memfd:: Memfd ,  IovDequeError >  { 
10094        // Create a sealable memfd. 
10195        let  opts = memfd:: MemfdOptions :: default ( ) . allow_sealing ( true ) ; 
10296        let  mfd = opts. create ( "iov_deque" ) ?; 
10397
10498        // Resize to system page size. 
10599        mfd. as_file ( ) 
106-             . set_len ( Self :: BYTES . try_into ( ) . unwrap ( ) ) 
100+             . set_len ( pages_bytes . try_into ( ) . unwrap ( ) ) 
107101            . map_err ( IovDequeError :: MemfdResize ) ?; 
108102
109103        // Add seals to prevent further resizing. 
@@ -136,13 +130,13 @@ impl<const L: u16> IovDeque<L> {
136130
137131    /// Allocate memory for our ring buffer 
138132     /// 
139-      /// This will allocate 2 * `Self::BYTES ` bytes of virtual memory. 
140-      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 >  { 
141135        // SAFETY: We are calling the system call with valid arguments 
142136        unsafe  { 
143137            Self :: mmap ( 
144138                std:: ptr:: null_mut ( ) , 
145-                 Self :: BYTES  *  2 , 
139+                 pages_bytes  *  2 , 
146140                libc:: PROT_NONE , 
147141                libc:: MAP_PRIVATE  | libc:: MAP_ANONYMOUS , 
148142                -1 , 
@@ -151,18 +145,29 @@ impl<const L: u16> IovDeque<L> {
151145        } 
152146    } 
153147
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+ 
154157    /// Create a new [`IovDeque`] that can hold memory described by a single VirtIO queue. 
155158     pub  fn  new ( )  -> Result < Self ,  IovDequeError >  { 
156-         let  memfd = Self :: create_memfd ( ) ?; 
159+         let  pages_bytes = Self :: pages_bytes ( ) ; 
160+ 
161+         let  memfd = Self :: create_memfd ( pages_bytes) ?; 
157162        let  raw_memfd = memfd. as_file ( ) . as_raw_fd ( ) ; 
158-         let  buffer = Self :: allocate_ring_buffer_memory ( ) ?; 
163+         let  buffer = Self :: allocate_ring_buffer_memory ( pages_bytes ) ?; 
159164
160165        // Map the first page of virtual memory to the physical page described by the memfd object 
161166        // SAFETY: We are calling the system call with valid arguments 
162167        let  _ = unsafe  { 
163168            Self :: mmap ( 
164169                buffer, 
165-                 Self :: BYTES , 
170+                 pages_bytes , 
166171                libc:: PROT_READ  | libc:: PROT_WRITE , 
167172                libc:: MAP_SHARED  | libc:: MAP_FIXED , 
168173                raw_memfd, 
@@ -173,17 +178,17 @@ impl<const L: u16> IovDeque<L> {
173178        // Map the second page of virtual memory to the physical page described by the memfd object 
174179        // 
175180        // SAFETY: This is safe because: 
176-         // * 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 
177182        //   allocation we got from `Self::allocate_ring_buffer_memory`. 
178183        // * The resulting pointer is the beginning of the second page of our allocation, so it 
179184        //   doesn't wrap around the address space. 
180-         let  next_page = unsafe  {  buffer. add ( Self :: BYTES )  } ; 
185+         let  next_page = unsafe  {  buffer. add ( pages_bytes )  } ; 
181186
182187        // SAFETY: We are calling the system call with valid arguments 
183188        let  _ = unsafe  { 
184189            Self :: mmap ( 
185190                next_page, 
186-                 Self :: BYTES , 
191+                 pages_bytes , 
187192                libc:: PROT_READ  | libc:: PROT_WRITE , 
188193                libc:: MAP_SHARED  | libc:: MAP_FIXED , 
189194                raw_memfd, 
@@ -311,9 +316,10 @@ impl<const L: u16> IovDeque<L> {
311316
312317impl < const  L :  u16 >  Drop  for  IovDeque < L >  { 
313318    fn  drop ( & mut  self )  { 
319+         let  pages_bytes = Self :: pages_bytes ( ) ; 
314320        // SAFETY: We are passing an address that we got from a previous allocation of `2 * 
315-         // Self::BYTES` bytes  by calling mmap 
316-         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 )  } ; 
317323    } 
318324} 
319325
@@ -331,6 +337,18 @@ mod tests {
331337        assert_eq ! ( deque. len( ) ,  0 ) ; 
332338    } 
333339
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+ 
334352    fn  make_iovec ( id :  u16 ,  len :  u16 )  -> iovec  { 
335353        iovec  { 
336354            iov_base :  id as  * mut  libc:: c_void , 
0 commit comments