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