xref: /aosp_15_r20/external/virtio-media/device/src/mmap.rs (revision 1b4853f54772485c5dd4001ae33a7a958bcc97a1)
1 // Copyright 2024 The ChromiumOS Authors
2 
3 use std::os::fd::BorrowedFd;
4 
5 use thiserror::Error;
6 
7 use crate::VirtioMediaHostMemoryMapper;
8 
9 #[derive(Debug, PartialEq, Eq)]
10 pub struct MmapBufferMapping {
11     /// Number of times `mmap` has been performed for this buffer.
12     num_mappings: usize,
13     /// Guest address at which the buffer is currently mapped.
14     guest_addr: u64,
15     /// Whether the mapping of this buffer is read-only or read-write.
16     rw: bool,
17 }
18 
19 /// Information about a MMAP buffer.
20 #[derive(Debug, PartialEq, Eq)]
21 pub struct MmapBuffer {
22     /// Start offset in the MMAP range of this buffer.
23     offset: u32,
24     /// Size of the buffer.
25     size: u32,
26     /// Whether this buffer is still registered, i.e. hasn't been deleted by the driver.
27     /// Unregistered buffers can still have active mappings, and are kept alive until their mapping
28     /// count reaches zero. However such buffers cannot be mapped anymore and take no space in the
29     /// MMAP range.
30     registered: bool,
31     /// Mapping information about this buffer, if the buffer is currently mapped into the guest.
32     mapping: Option<MmapBufferMapping>,
33 }
34 
35 impl MmapBuffer {
36     /// Returns a new instance of `MmapBuffer` with the given parameters, zero mappings and
37     /// a registered status.
new(offset: u32, size: u32) -> Self38     fn new(offset: u32, size: u32) -> Self {
39         Self {
40             offset,
41             size,
42             registered: true,
43             mapping: None,
44         }
45     }
46 }
47 
48 /// Range manager for MMAP buffers, using a host memory mapper.
49 ///
50 /// Devices that allocate MMAP buffers can register a buffer using [`Self::register_buffer`] and
51 /// unregister them with [`Self::unregister_buffer`]. Registered buffers can then be mapped into the
52 /// guest address space by calling [`Self::create_mapping`] on their offset. This will return the address
53 /// of their guest mapping, which can then be accessed or used to unmap them with [`Self::remove_mapping`].
54 pub struct MmapMappingManager<M: VirtioMediaHostMemoryMapper> {
55     /// Sorted MMAP space of the device. Each registered MMAP buffer takes the `[offset, size - 1]`
56     /// range in this space, which is sorted in order to be binary-searchable.
57     ///
58     /// Buffers that are unregistered but still mapped are still kept here, but do not take space
59     /// in the MMAP range (i.e. they are skipped during the binary search).
60     buffers: Vec<MmapBuffer>,
61     /// Memory mapper used to create buffer mappings.
62     mapper: M,
63 }
64 
65 impl<M: VirtioMediaHostMemoryMapper> From<M> for MmapMappingManager<M> {
from(mapper: M) -> Self66     fn from(mapper: M) -> Self {
67         Self {
68             buffers: Vec::new(),
69             mapper,
70         }
71     }
72 }
73 
74 #[derive(Debug, Error, PartialEq, Eq)]
75 pub enum RegisterBufferError {
76     #[error("insufficient free space in the MMAP range")]
77     NoFreeSpace,
78     #[error("requested offset is already occupied")]
79     OffsetOccupied,
80     #[error("buffers of size 0 cannot be registered")]
81     EmptyBuffer,
82     #[error("buffer offset must be a multiple of the memory page size")]
83     UnalignedOffset,
84 }
85 
86 #[derive(Debug, Error, PartialEq, Eq)]
87 pub enum CreateMappingError {
88     #[error("no buffer registered at the requested offset")]
89     InvalidOffset,
90     #[error("cannot create new mappings for unregistered buffers")]
91     UnregisteredBuffer,
92     #[error("requested mapping range goes outside the buffer")]
93     SizeOutOfBounds,
94     #[error("error while cloning the FD for the buffer")]
95     FdCloneFailure(std::io::ErrorKind),
96     #[error("error while mapping the buffer: {0}")]
97     MappingFailure(i32),
98     #[error("mapping requested with different permission from the old one")]
99     NonMatchingPermissions,
100 }
101 
102 #[derive(Debug, Error, PartialEq, Eq)]
103 pub enum RemoveMappingError {
104     #[error("no buffer registered at the requested offset")]
105     InvalidOffset,
106 }
107 
108 const PAGE_SIZE: u32 = 0x1000;
109 const PAGE_MASK: u32 = !(PAGE_SIZE - 1);
110 
111 impl<M: VirtioMediaHostMemoryMapper> MmapMappingManager<M> {
112     /// Registers a new buffer at `offset`. If `offset` if `None`, then an offset is allocated and
113     /// returned.
114     ///
115     /// This method fails if the range is full, or if `offset` is `Some` and the requested offset
116     /// if already used by some other buffer. If `offset` is `Some` and the function succeed, then
117     /// the returned value is guaranteed to be the passed offset.
118     ///
119     /// Note that the ranges automatically allocated are of fixed size: only the offset of a
120     /// buffer is relevant when mapping it, not its size. Real V4L2 drivers also use this trick of
121     /// allocating ranges such that buffers appear to overlap. This is useful as the address space
122     /// is technically 32-bit, and we might need to use buffers which added size would not fit.
123     ///
124     /// TODO: we should recycle offsets, and further type `MmapMappingManager` so that only one
125     /// allocation type can be used per instance (fixed or dynamic).
register_buffer( &mut self, offset: Option<u32>, size: u32, ) -> Result<u32, RegisterBufferError>126     pub fn register_buffer(
127         &mut self,
128         offset: Option<u32>,
129         size: u32,
130     ) -> Result<u32, RegisterBufferError> {
131         let offset = offset.unwrap_or_else(|| {
132             self.buffers
133                 .last()
134                 // Align the start offset to the next page, or `register_buffer_by_offset` will
135                 // fail.
136                 .map(|b| ((b.offset + 1).next_multiple_of(PAGE_SIZE)))
137                 .unwrap_or(0)
138         });
139 
140         self.register_buffer_by_offset(offset, size)
141             .map(|()| offset)
142     }
143 
144     /// Unregisters the buffer previously registered at `offset`. Returns `true` if a buffer was
145     /// indeed registered as starting at `offset`, `false` otherwise.
unregister_buffer(&mut self, offset: u32) -> bool146     pub fn unregister_buffer(&mut self, offset: u32) -> bool {
147         match self.buffers.binary_search_by_key(&offset, |b| b.offset) {
148             Err(_) => false,
149             Ok(index) => {
150                 let buffer = &mut self.buffers[index];
151 
152                 buffer.registered = false;
153                 // If there is no mapping then the buffer can be removed from the MMAP range.
154                 if buffer.mapping.is_none() {
155                     self.buffers.remove(index);
156                 }
157 
158                 true
159             }
160         }
161     }
162 
163     // Register a new buffer of `size` at `offset`. Returns an error if `offset` is` already
164     // occupied by another buffer.
165     //
166     // `size` must be greater than `0` and `offset` must be a multiple of `PAGE_SIZE`.
register_buffer_by_offset( &mut self, offset: u32, size: u32, ) -> Result<(), RegisterBufferError>167     fn register_buffer_by_offset(
168         &mut self,
169         offset: u32,
170         size: u32,
171     ) -> Result<(), RegisterBufferError> {
172         if size == 0 {
173             return Err(RegisterBufferError::EmptyBuffer);
174         }
175         if offset & PAGE_MASK != offset {
176             return Err(RegisterBufferError::UnalignedOffset);
177         }
178 
179         // Check that `offset` is actually available.
180         match self.buffers.binary_search_by_key(&offset, |b| b.offset) {
181             // Already have a registered buffer at that very offset.
182             Ok(_) => Err(RegisterBufferError::OffsetOccupied),
183             Err(index) => {
184                 self.buffers.insert(index, MmapBuffer::new(offset, size));
185                 Ok(())
186             }
187         }
188     }
189 
190     /// Create a new mapping for the buffer registered at `offset`. `rw` indicates whether the
191     /// mapping is read-only or read-write. Returns the guest address at which the buffer is
192     /// mapped, and the size of the mapping, which should be equal to the size of the buffer.
193     ///
194     /// This method can be called several times and will reuse the prior mapping if it exists. The
195     /// mapping will also persist until an identical number of calls to [`Self::remove_mapping`]
196     /// are performed.
197     ///
198     /// Note however that requiring the same active mapping with different `rw` permissions will
199     /// result in a `EPERM` error.
create_mapping( &mut self, offset: u32, fd: BorrowedFd, rw: bool, ) -> Result<(u64, u64), CreateMappingError>200     pub fn create_mapping(
201         &mut self,
202         offset: u32,
203         fd: BorrowedFd,
204         rw: bool,
205     ) -> Result<(u64, u64), CreateMappingError> {
206         let buffer = self
207             .buffers
208             .binary_search_by_key(&offset, |b| b.offset)
209             .map(|i| &mut self.buffers[i])
210             .map_err(|_| CreateMappingError::InvalidOffset)?;
211         let last_buffer_address = buffer
212             .offset
213             .checked_add(buffer.size - 1)
214             .ok_or(CreateMappingError::InvalidOffset)?;
215 
216         // Cannot create additional mappings for buffers that have been destroyed on the guest side.
217         if !buffer.registered {
218             return Err(CreateMappingError::UnregisteredBuffer);
219         }
220 
221         // Check that we are not requiring more mapping than the buffer can cover.
222         if last_buffer_address > buffer.offset + (buffer.size - 1) {
223             return Err(CreateMappingError::SizeOutOfBounds);
224         }
225 
226         let guest_addr = match &mut buffer.mapping {
227             None => {
228                 let guest_addr = self
229                     .mapper
230                     .add_mapping(
231                         fd,
232                         // Always map the full buffer so we can reuse the mapping even with different
233                         // sizes.
234                         buffer.size as u64,
235                         buffer.offset as u64,
236                         rw,
237                     )
238                     .map_err(CreateMappingError::MappingFailure)?;
239 
240                 buffer.mapping = Some(MmapBufferMapping {
241                     num_mappings: 1,
242                     rw,
243                     guest_addr,
244                 });
245 
246                 // TODO: need to be able to lookup the buffer back by guest address - add a
247                 // guest_addr -> offset table?
248                 guest_addr
249             }
250             Some(mapping) => {
251                 if mapping.rw != rw {
252                     return Err(CreateMappingError::NonMatchingPermissions);
253                 }
254                 mapping.num_mappings += 1;
255                 mapping.guest_addr
256             }
257         };
258 
259         Ok((guest_addr, buffer.size as u64))
260     }
261 
262     /// Returns `true` if the buffer still has other mappings, `false` if this was the last mapping.
remove_mapping(&mut self, guest_addr: u64) -> Result<bool, RemoveMappingError>263     pub fn remove_mapping(&mut self, guest_addr: u64) -> Result<bool, RemoveMappingError> {
264         // TODO: use a guest_addr -> offset table to avoid O(n) here?
265         for (i, buffer) in self.buffers.iter_mut().enumerate() {
266             match &mut buffer.mapping {
267                 Some(mapping) if mapping.guest_addr == guest_addr => {
268                     mapping.num_mappings -= 1;
269                     if mapping.num_mappings == 0 {
270                         if let Err(e) = self.mapper.remove_mapping(guest_addr) {
271                             log::error!("error while unmapping MMAP buffer: {:#}", e);
272                         }
273                         buffer.mapping = None;
274                         // If this was the last dangling mapping then the buffer can be removed
275                         // from the MMAP range.
276                         if !buffer.registered {
277                             self.buffers.remove(i);
278                         }
279                         return Ok(false);
280                     } else {
281                         return Ok(true);
282                     }
283                 }
284                 _ => (),
285             }
286         }
287 
288         Err(RemoveMappingError::InvalidOffset)
289     }
290     /// Returns `true` if the buffer registered at `offset` is already mapped.
is_mapped(&self, offset: u64) -> bool291     pub fn is_mapped(&self, offset: u64) -> bool {
292         let Ok(offset) = u32::try_from(offset) else {
293             return false;
294         };
295 
296         match self.buffers.binary_search_by_key(&offset, |b| b.offset) {
297             Err(_) => false,
298             Ok(index) => self.buffers[index].mapping.is_some(),
299         }
300     }
301 
302     /// Consume the mapping manager and return the mapper it has been constructed from.
into_mapper(self) -> M303     pub fn into_mapper(self) -> M {
304         self.mapper
305     }
306 }
307 
308 #[cfg(test)]
309 mod tests {
310     use std::fs::File;
311     use std::os::fd::AsFd;
312     use std::os::fd::BorrowedFd;
313     use std::os::fd::FromRawFd;
314 
315     use crate::VirtioMediaHostMemoryMapper;
316 
317     use super::CreateMappingError;
318     use super::MmapBuffer;
319     use super::MmapBufferMapping;
320     use super::MmapMappingManager;
321     use super::RegisterBufferError;
322     use super::RemoveMappingError;
323 
324     struct DummyHostMemoryMapper;
325 
326     impl VirtioMediaHostMemoryMapper for DummyHostMemoryMapper {
add_mapping( &mut self, _buffer: BorrowedFd, _length: u64, offset: u64, _rw: bool, ) -> Result<u64, i32>327         fn add_mapping(
328             &mut self,
329             _buffer: BorrowedFd,
330             _length: u64,
331             offset: u64,
332             _rw: bool,
333         ) -> Result<u64, i32> {
334             Ok(offset | 0x8000_0000)
335         }
336 
remove_mapping(&mut self, _guest_addr: u64) -> Result<(), i32>337         fn remove_mapping(&mut self, _guest_addr: u64) -> Result<(), i32> {
338             Ok(())
339         }
340     }
341 
342     #[test]
mmap_manager_register_by_offset()343     fn mmap_manager_register_by_offset() {
344         let mut mm = MmapMappingManager::from(DummyHostMemoryMapper);
345         assert_eq!(mm.buffers, vec![]);
346 
347         assert_eq!(mm.register_buffer_by_offset(0x0, 0x1000), Ok(()));
348         assert_eq!(mm.buffers, vec![MmapBuffer::new(0x0, 0x1000)]);
349 
350         assert_eq!(mm.register_buffer_by_offset(0x1000, 0x5000), Ok(()));
351         assert_eq!(
352             mm.buffers,
353             vec![
354                 MmapBuffer::new(0x0, 0x1000),
355                 MmapBuffer::new(0x1000, 0x5000),
356             ]
357         );
358 
359         assert_eq!(mm.register_buffer_by_offset(0xa000, 0x1000), Ok(()));
360         assert_eq!(
361             mm.buffers,
362             vec![
363                 MmapBuffer::new(0x0, 0x1000),
364                 MmapBuffer::new(0x1000, 0x5000),
365                 MmapBuffer::new(0xa000, 0x1000),
366             ]
367         );
368 
369         assert_eq!(mm.register_buffer_by_offset(0x6000, 0x2000), Ok(()));
370         assert_eq!(
371             mm.buffers,
372             vec![
373                 MmapBuffer::new(0x0, 0x1000),
374                 MmapBuffer::new(0x1000, 0x5000),
375                 MmapBuffer::new(0x6000, 0x2000),
376                 MmapBuffer::new(0xa000, 0x1000),
377             ]
378         );
379 
380         assert_eq!(
381             mm.register_buffer_by_offset(0x8000, 0x0),
382             Err(RegisterBufferError::EmptyBuffer)
383         );
384 
385         assert_eq!(
386             mm.register_buffer_by_offset(0x8100, 0x1000),
387             Err(RegisterBufferError::UnalignedOffset)
388         );
389 
390         assert_eq!(
391             mm.register_buffer_by_offset(0x0, 0x1000),
392             Err(RegisterBufferError::OffsetOccupied)
393         );
394 
395         assert_eq!(
396             mm.register_buffer_by_offset(0x1000, 0x1000),
397             Err(RegisterBufferError::OffsetOccupied)
398         );
399 
400         assert_eq!(mm.register_buffer_by_offset(0x2000, 0x1000), Ok(()));
401         assert_eq!(
402             mm.buffers,
403             vec![
404                 MmapBuffer::new(0x0, 0x1000),
405                 MmapBuffer::new(0x1000, 0x5000),
406                 MmapBuffer::new(0x2000, 0x1000),
407                 MmapBuffer::new(0x6000, 0x2000),
408                 MmapBuffer::new(0xa000, 0x1000),
409             ]
410         );
411 
412         assert_eq!(mm.register_buffer_by_offset(0x7000, 0x2000), Ok(()));
413         assert_eq!(
414             mm.buffers,
415             vec![
416                 MmapBuffer::new(0x0, 0x1000),
417                 MmapBuffer::new(0x1000, 0x5000),
418                 MmapBuffer::new(0x2000, 0x1000),
419                 MmapBuffer::new(0x6000, 0x2000),
420                 MmapBuffer::new(0x7000, 0x2000),
421                 MmapBuffer::new(0xa000, 0x1000),
422             ]
423         );
424 
425         assert_eq!(mm.register_buffer_by_offset(0x8000, 0x2000), Ok(()));
426         assert_eq!(
427             mm.buffers,
428             vec![
429                 MmapBuffer::new(0x0, 0x1000),
430                 MmapBuffer::new(0x1000, 0x5000),
431                 MmapBuffer::new(0x2000, 0x1000),
432                 MmapBuffer::new(0x6000, 0x2000),
433                 MmapBuffer::new(0x7000, 0x2000),
434                 MmapBuffer::new(0x8000, 0x2000),
435                 MmapBuffer::new(0xa000, 0x1000),
436             ]
437         );
438 
439         assert_eq!(mm.register_buffer_by_offset(0xffff_f000, 0x1000), Ok(()));
440         assert_eq!(
441             mm.buffers,
442             vec![
443                 MmapBuffer::new(0x0, 0x1000),
444                 MmapBuffer::new(0x1000, 0x5000),
445                 MmapBuffer::new(0x2000, 0x1000),
446                 MmapBuffer::new(0x6000, 0x2000),
447                 MmapBuffer::new(0x7000, 0x2000),
448                 MmapBuffer::new(0x8000, 0x2000),
449                 MmapBuffer::new(0xa000, 0x1000),
450                 MmapBuffer::new(0xffff_f000, 0x1000),
451             ]
452         );
453 
454         assert!(mm.unregister_buffer(0xffff_f000));
455         assert_eq!(
456             mm.buffers,
457             vec![
458                 MmapBuffer::new(0x0, 0x1000),
459                 MmapBuffer::new(0x1000, 0x5000),
460                 MmapBuffer::new(0x2000, 0x1000),
461                 MmapBuffer::new(0x6000, 0x2000),
462                 MmapBuffer::new(0x7000, 0x2000),
463                 MmapBuffer::new(0x8000, 0x2000),
464                 MmapBuffer::new(0xa000, 0x1000),
465             ]
466         );
467 
468         assert!(mm.unregister_buffer(0x6000));
469         assert_eq!(
470             mm.buffers,
471             vec![
472                 MmapBuffer::new(0x0, 0x1000),
473                 MmapBuffer::new(0x1000, 0x5000),
474                 MmapBuffer::new(0x2000, 0x1000),
475                 MmapBuffer::new(0x7000, 0x2000),
476                 MmapBuffer::new(0x8000, 0x2000),
477                 MmapBuffer::new(0xa000, 0x1000),
478             ]
479         );
480 
481         assert!(!mm.unregister_buffer(0x6000));
482         assert_eq!(
483             mm.buffers,
484             vec![
485                 MmapBuffer::new(0x0, 0x1000),
486                 MmapBuffer::new(0x1000, 0x5000),
487                 MmapBuffer::new(0x2000, 0x1000),
488                 MmapBuffer::new(0x7000, 0x2000),
489                 MmapBuffer::new(0x8000, 0x2000),
490                 MmapBuffer::new(0xa000, 0x1000),
491             ]
492         );
493 
494         assert!(!mm.unregister_buffer(0x8100));
495         assert_eq!(
496             mm.buffers,
497             vec![
498                 MmapBuffer::new(0x0, 0x1000),
499                 MmapBuffer::new(0x1000, 0x5000),
500                 MmapBuffer::new(0x2000, 0x1000),
501                 MmapBuffer::new(0x7000, 0x2000),
502                 MmapBuffer::new(0x8000, 0x2000),
503                 MmapBuffer::new(0xa000, 0x1000),
504             ]
505         );
506 
507         assert!(mm.unregister_buffer(0x0));
508         assert_eq!(
509             mm.buffers,
510             vec![
511                 MmapBuffer::new(0x1000, 0x5000),
512                 MmapBuffer::new(0x2000, 0x1000),
513                 MmapBuffer::new(0x7000, 0x2000),
514                 MmapBuffer::new(0x8000, 0x2000),
515                 MmapBuffer::new(0xa000, 0x1000),
516             ]
517         );
518 
519         assert!(mm.unregister_buffer(0xa000));
520         assert_eq!(
521             mm.buffers,
522             vec![
523                 MmapBuffer::new(0x1000, 0x5000),
524                 MmapBuffer::new(0x2000, 0x1000),
525                 MmapBuffer::new(0x7000, 0x2000),
526                 MmapBuffer::new(0x8000, 0x2000),
527             ]
528         );
529 
530         assert!(mm.unregister_buffer(0x1000));
531         assert_eq!(
532             mm.buffers,
533             vec![
534                 MmapBuffer::new(0x2000, 0x1000),
535                 MmapBuffer::new(0x7000, 0x2000),
536                 MmapBuffer::new(0x8000, 0x2000),
537             ]
538         );
539 
540         assert!(mm.unregister_buffer(0x8000));
541         assert_eq!(
542             mm.buffers,
543             vec![
544                 MmapBuffer::new(0x2000, 0x1000),
545                 MmapBuffer::new(0x7000, 0x2000),
546             ]
547         );
548 
549         assert_eq!(
550             mm.buffers,
551             vec![
552                 MmapBuffer::new(0x2000, 0x1000),
553                 MmapBuffer::new(0x7000, 0x2000),
554             ]
555         );
556     }
557 
558     #[test]
mmap_manager_register()559     fn mmap_manager_register() {
560         let mut mm = MmapMappingManager::from(DummyHostMemoryMapper);
561 
562         assert_eq!(mm.register_buffer(None, 0x1000), Ok(0x0));
563         assert_eq!(mm.buffers, vec![MmapBuffer::new(0x0, 0x1000)]);
564 
565         assert_eq!(mm.register_buffer(None, 0x5000), Ok(0x1000));
566         assert_eq!(
567             mm.buffers,
568             vec![
569                 MmapBuffer::new(0x0, 0x1000),
570                 MmapBuffer::new(0x1000, 0x5000),
571             ]
572         );
573 
574         assert_eq!(mm.register_buffer(None, 0xffff_a000), Ok(0x2000));
575         assert_eq!(
576             mm.buffers,
577             vec![
578                 MmapBuffer::new(0x0, 0x1000),
579                 MmapBuffer::new(0x1000, 0x5000),
580                 MmapBuffer::new(0x2000, 0xffff_a000),
581             ]
582         );
583 
584         assert!(mm.unregister_buffer(0x2000));
585         assert_eq!(
586             mm.buffers,
587             vec![
588                 MmapBuffer::new(0x0, 0x1000),
589                 MmapBuffer::new(0x1000, 0x5000),
590             ]
591         );
592 
593         assert_eq!(mm.register_buffer(None, 0xffff_b000), Ok(0x2000));
594         assert_eq!(
595             mm.buffers,
596             vec![
597                 MmapBuffer::new(0x0, 0x1000),
598                 MmapBuffer::new(0x1000, 0x5000),
599                 MmapBuffer::new(0x2000, 0xffff_b000),
600             ]
601         );
602     }
603 
604     #[test]
mmap_manager_mapping()605     fn mmap_manager_mapping() {
606         let mut mm = MmapMappingManager::from(DummyHostMemoryMapper);
607 
608         assert_eq!(mm.register_buffer(None, 0x1000), Ok(0x0));
609         assert_eq!(mm.register_buffer(None, 0x5000), Ok(0x1000));
610         assert_eq!(
611             mm.buffers,
612             vec![
613                 MmapBuffer::new(0x0, 0x1000),
614                 MmapBuffer::new(0x1000, 0x5000),
615             ]
616         );
617 
618         let file = unsafe { File::from_raw_fd(0) };
619 
620         // Single mapping
621         assert_eq!(
622             mm.create_mapping(0x1000, file.as_fd(), false),
623             Ok((0x8000_1000, 0x5000))
624         );
625         assert_eq!(mm.remove_mapping(0x8000_1000), Ok(false));
626         assert_eq!(
627             mm.remove_mapping(0x8000_1000),
628             Err(RemoveMappingError::InvalidOffset)
629         );
630 
631         // Multiple mappings
632         assert_eq!(
633             mm.create_mapping(0x1000, file.as_fd(), false),
634             Ok((0x8000_1000, 0x5000))
635         );
636         assert_eq!(
637             mm.create_mapping(0x1000, file.as_fd(), false),
638             Ok((0x8000_1000, 0x5000))
639         );
640         assert_eq!(mm.remove_mapping(0x8000_1000), Ok(true));
641         assert_eq!(mm.remove_mapping(0x8000_1000), Ok(false));
642         assert_eq!(
643             mm.remove_mapping(0x8000_1000),
644             Err(RemoveMappingError::InvalidOffset)
645         );
646 
647         // Mapping at non-existing offset
648         assert_eq!(
649             mm.create_mapping(0x2000, file.as_fd(), false),
650             Err(CreateMappingError::InvalidOffset)
651         );
652 
653         // Requesting same mapping with different access
654         assert_eq!(
655             mm.create_mapping(0x1000, file.as_fd(), false),
656             Ok((0x8000_1000, 0x5000))
657         );
658         assert_eq!(
659             mm.create_mapping(0x1000, file.as_fd(), true),
660             Err(CreateMappingError::NonMatchingPermissions)
661         );
662         assert_eq!(mm.remove_mapping(0x8000_1000), Ok(false));
663 
664         // Mappings must survive a buffer's deregistration
665         assert_eq!(
666             mm.create_mapping(0x1000, file.as_fd(), false),
667             Ok((0x8000_1000, 0x5000))
668         );
669         assert!(mm.unregister_buffer(0x1000));
670         assert_eq!(
671             mm.buffers,
672             vec![
673                 MmapBuffer::new(0x0, 0x1000),
674                 MmapBuffer {
675                     offset: 0x1000,
676                     size: 0x5000,
677                     registered: false,
678                     mapping: Some(MmapBufferMapping {
679                         num_mappings: 1,
680                         guest_addr: 0x8000_1000,
681                         rw: false
682                     })
683                 }
684             ]
685         );
686         // ... but un-registered buffers are removed alongside their last mapping.
687         assert_eq!(mm.remove_mapping(0x8000_1000), Ok(false));
688         assert_eq!(mm.buffers, vec![MmapBuffer::new(0x0, 0x1000),])
689     }
690 }
691