1use super::mappable::Mappable;
9use super::object_cache::ObjectCache;
10use super::object_cache::ObjectId;
11use super::va_mapper::MapperRole;
12use super::va_mapper::VaMapper;
13use super::va_mapper::VaMapperError;
14use crate::RemoteProcess;
15use crate::region_manager::MappingType;
16use futures::StreamExt;
17use futures::future::join_all;
18use guestmem::ProvideShareableRegions;
19use guestmem::ShareableRegion;
20use inspect::Inspect;
21use inspect::InspectMut;
22use memory_range::MemoryRange;
23use mesh::MeshPayload;
24use mesh::error::RemoteError;
25use mesh::rpc::FailableRpc;
26use mesh::rpc::Rpc;
27use mesh::rpc::RpcSend;
28use pal_async::task::Spawn;
29use slab::Slab;
30use std::sync::Arc;
31use thiserror::Error;
32
33#[derive(Debug, Inspect)]
35pub struct MappingManager {
36 #[inspect(
37 flatten,
38 with = "|x| inspect::send(&x.req_send, MappingRequest::Inspect)"
39 )]
40 client: MappingManagerClient,
41}
42
43impl MappingManager {
44 pub async fn new(
60 spawn: impl Spawn,
61 max_addr: u64,
62 minimum_va_alignment: Option<usize>,
63 supports_memory_fault_resolution: bool,
64 ) -> Result<(Self, Arc<VaMapper>), VaMapperError> {
65 let this = Self::new_bare(spawn, max_addr, minimum_va_alignment);
66 let primary = this
70 .client()
71 .get_or_create_mapper(
72 true,
73 MapperRole::Primary {
74 supports_memory_fault_resolution,
75 },
76 )
77 .await?;
78 Ok((this, primary))
79 }
80
81 fn new_bare(spawn: impl Spawn, max_addr: u64, minimum_va_alignment: Option<usize>) -> Self {
84 let (req_send, mut req_recv) = mesh::mpsc_channel();
85 spawn
86 .spawn("mapping_manager", {
87 let mut task = MappingManagerTask::new();
88 async move {
89 task.run(&mut req_recv).await;
90 }
91 })
92 .detach();
93 Self {
94 client: MappingManagerClient {
95 id: ObjectId::new(),
96 req_send,
97 max_addr,
98 minimum_va_alignment,
99 },
100 }
101 }
102
103 #[cfg(test)]
107 pub(crate) fn new_without_primary(
108 spawn: impl Spawn,
109 max_addr: u64,
110 minimum_va_alignment: Option<usize>,
111 ) -> Self {
112 Self::new_bare(spawn, max_addr, minimum_va_alignment)
113 }
114
115 pub fn client(&self) -> &MappingManagerClient {
118 &self.client
119 }
120}
121
122#[derive(Debug, MeshPayload, Clone)]
124pub struct MappingManagerClient {
125 req_send: mesh::Sender<MappingRequest>,
126 id: ObjectId,
127 max_addr: u64,
128 minimum_va_alignment: Option<usize>,
129}
130
131static MAPPER_CACHE: ObjectCache<VaMapper> = ObjectCache::new();
132
133impl MappingManagerClient {
134 pub async fn new_mapper(&self, eager: bool) -> Result<Arc<VaMapper>, VaMapperError> {
165 self.get_or_create_mapper(eager, MapperRole::Secondary)
166 .await
167 }
168
169 async fn get_or_create_mapper(
170 &self,
171 eager: bool,
172 role: MapperRole,
173 ) -> Result<Arc<VaMapper>, VaMapperError> {
174 let mapper = MAPPER_CACHE
175 .get_or_insert_with(&self.id, async {
176 VaMapper::new(
177 self.req_send.clone(),
178 self.max_addr,
179 None,
180 self.minimum_va_alignment,
181 eager,
182 role,
183 )
184 .await
185 })
186 .await?;
187
188 if eager && !mapper.is_eager() {
191 self.req_send
192 .call(MappingRequest::UpgradeToEager, mapper.mapper_id())
193 .await
194 .map_err(VaMapperError::MemoryManagerGone)?
195 .map_err(VaMapperError::Registration)?;
196 }
197
198 Ok(mapper)
199 }
200
201 pub async fn new_remote_mapper(
210 &self,
211 process: RemoteProcess,
212 ) -> Result<Arc<VaMapper>, VaMapperError> {
213 Ok(Arc::new(
214 VaMapper::new(
215 self.req_send.clone(),
216 self.max_addr,
217 Some(process),
218 self.minimum_va_alignment,
219 true, MapperRole::Secondary,
226 )
227 .await?,
228 ))
229 }
230
231 pub async fn add_mapping(&self, params: MappingParams) -> anyhow::Result<()> {
240 self.req_send
241 .call_failable(MappingRequest::AddMapping, params)
242 .await?;
243 Ok(())
244 }
245
246 pub async fn remove_mappings(&self, range: MemoryRange) {
250 self.req_send
251 .call(MappingRequest::RemoveMappings, range)
252 .await
253 .unwrap();
254 }
255}
256
257#[derive(MeshPayload)]
259pub struct AddMapperParams {
260 pub send: mesh::Sender<MapperRequest>,
262 pub eager: bool,
265}
266
267#[derive(MeshPayload)]
269pub enum MappingRequest {
270 AddMapper(FailableRpc<AddMapperParams, MapperId>),
272 RemoveMapper(MapperId),
273 SendMappings(MapperId, MemoryRange),
277 UpgradeToEager(FailableRpc<MapperId, ()>),
280 AddMapping(FailableRpc<MappingParams, ()>),
281 RemoveMappings(Rpc<MemoryRange, ()>),
282 GetDmaTargetMappings(Rpc<(), Vec<MappingParams>>),
284 Inspect(inspect::Deferred),
285}
286
287#[derive(InspectMut)]
288struct MappingManagerTask {
289 #[inspect(with = "inspect_mappings")]
290 mappings: Vec<Mapping>,
291 #[inspect(skip)]
292 mappers: Mappers,
293}
294
295fn inspect_mappings(mappings: &Vec<Mapping>) -> impl '_ + Inspect {
296 inspect::adhoc(move |req| {
297 let mut resp = req.respond();
298 for mapping in mappings {
299 resp.field(
300 &mapping.params.range.to_string(),
301 inspect::adhoc(|req| {
302 req.respond()
303 .field("writable", mapping.params.writable)
304 .field("mapping_type", mapping.params.mapping_type)
305 .field("backed_by_fd", mapping.params.backing.mappable().is_some())
306 .hex("file_offset", mapping.params.backing.file_offset());
307 }),
308 );
309 }
310 })
311}
312
313struct Mapping {
314 params: MappingParams,
315 active_mappers: Vec<MapperId>,
316}
317
318#[derive(Debug, MeshPayload, Clone)]
320pub enum MappingBacking {
321 File {
326 mappable: Mappable,
328 file_offset: u64,
330 },
331 Private,
350}
351
352impl MappingBacking {
353 pub fn mappable(&self) -> Option<&Mappable> {
355 match self {
356 MappingBacking::File { mappable, .. } => Some(mappable),
357 MappingBacking::Private => None,
358 }
359 }
360
361 pub fn file_offset(&self) -> u64 {
363 match self {
364 MappingBacking::File { file_offset, .. } => *file_offset,
365 MappingBacking::Private => 0,
366 }
367 }
368}
369
370#[derive(Debug, Copy, Clone, MeshPayload)]
379pub struct MemoryPolicy {
380 pub numa_node: Option<u32>,
383 pub transparent_hugepages: bool,
386 pub prefetch: bool,
392}
393
394impl MemoryPolicy {
395 pub fn none() -> Self {
402 Self {
403 numa_node: None,
404 transparent_hugepages: false,
405 prefetch: false,
406 }
407 }
408}
409
410#[derive(Debug, MeshPayload, Clone)]
412pub struct MappingParams {
413 pub range: MemoryRange,
415 pub backing: MappingBacking,
417 pub writable: bool,
419 pub mapping_type: MappingType,
425 pub policy: MemoryPolicy,
427}
428
429#[derive(Debug, Error)]
431#[error("failed to map {range}")]
432pub struct MappingError {
433 pub range: MemoryRange,
435 #[source]
437 pub error: std::io::Error,
438}
439
440impl MappingError {
441 pub(crate) fn new(range: MemoryRange, error: std::io::Error) -> Self {
442 Self { range, error }
443 }
444}
445
446struct Mappers {
447 mappers: Slab<MapperComm>,
448}
449
450struct MapperComm {
451 req_send: mesh::Sender<MapperRequest>,
452 eager: bool,
453}
454
455#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, MeshPayload)]
456pub struct MapperId(pub(crate) usize);
457
458#[derive(Debug, MeshPayload)]
460pub enum MapperRequest {
461 MapEager(Rpc<MappingParams, Result<(), RemoteError>>),
464 MapLazy(MappingParams),
468 NoMapping(MemoryRange),
471 Unmap(Rpc<MemoryRange, ()>),
473 SetEager(Rpc<(), ()>),
477}
478
479impl MappingManagerTask {
480 fn new() -> Self {
481 Self {
482 mappers: Mappers {
483 mappers: Slab::new(),
484 },
485 mappings: Vec::new(),
486 }
487 }
488
489 async fn run(&mut self, req_recv: &mut mesh::Receiver<MappingRequest>) {
490 while let Some(req) = req_recv.next().await {
491 match req {
492 MappingRequest::AddMapper(rpc) => {
493 rpc.handle_failable(async |params: AddMapperParams| {
494 if !self.mappers.mappers.is_empty() && self.has_private_mapping() {
502 return Err(MappingError::new(
503 MemoryRange::EMPTY,
504 std::io::Error::other(
505 "cannot add a second mapper while private memory is present",
506 ),
507 ));
508 }
509 self.add_mapper(params.send, params.eager).await
510 })
511 .await
512 }
513 MappingRequest::RemoveMapper(id) => {
514 self.remove_mapper(id);
515 }
516 MappingRequest::SendMappings(id, range) => {
517 self.send_mappings(id, range);
518 }
519 MappingRequest::UpgradeToEager(rpc) => {
520 rpc.handle_failable(async |id| self.upgrade_to_eager(id).await)
521 .await
522 }
523 MappingRequest::AddMapping(rpc) => {
524 rpc.handle_failable(async |params| self.add_mapping(params).await)
525 .await
526 }
527 MappingRequest::RemoveMappings(rpc) => {
528 rpc.handle(async |range| self.remove_mappings(range).await)
529 .await
530 }
531 MappingRequest::GetDmaTargetMappings(rpc) => {
532 rpc.handle_sync(|()| self.get_dma_target_mappings())
533 }
534 MappingRequest::Inspect(deferred) => deferred.inspect(&mut *self),
535 }
536 }
537 }
538
539 async fn add_mapper(
540 &mut self,
541 req_send: mesh::Sender<MapperRequest>,
542 eager: bool,
543 ) -> Result<MapperId, MappingError> {
544 let id = self.mappers.mappers.insert(MapperComm { req_send, eager });
545 let mapper_id = MapperId(id);
546 tracing::debug!(?id, eager, "adding mapper");
547
548 if eager {
549 let mut failed = None;
551 for mapping in &mut self.mappings {
552 match self.mappers.mappers[id]
553 .req_send
554 .call(MapperRequest::MapEager, mapping.params.clone())
555 .await
556 {
557 Ok(Ok(())) => {
558 mapping.active_mappers.push(mapper_id);
559 }
560 Ok(Err(e)) => {
561 failed = Some(MappingError::new(
562 mapping.params.range,
563 std::io::Error::other(e),
564 ));
565 break;
566 }
567 Err(_) => {
568 failed = Some(MappingError::new(
569 MemoryRange::EMPTY,
570 std::io::Error::other("mapper gone during replay"),
571 ));
572 break;
573 }
574 }
575 }
576 if let Some(err) = failed {
577 self.remove_mapper(mapper_id);
578 return Err(err);
579 }
580 }
581
582 Ok(mapper_id)
583 }
584
585 fn remove_mapper(&mut self, id: MapperId) {
586 tracing::debug!(?id, "removing mapper");
587 self.mappers.mappers.remove(id.0);
588 for mapping in &mut self.mappings {
589 mapping.active_mappers.retain(|m| m != &id);
590 }
591 }
592
593 async fn upgrade_to_eager(&mut self, id: MapperId) -> Result<(), MappingError> {
596 let mapper = &mut self.mappers.mappers[id.0];
597 if mapper.eager {
598 return Ok(()); }
600 mapper.eager = true;
609 tracing::debug!(?id, "upgrading mapper to eager");
610
611 let mut failed = None;
612 for mapping in &mut self.mappings {
613 if mapping.active_mappers.contains(&id) {
615 continue;
616 }
617 match self.mappers.mappers[id.0]
618 .req_send
619 .call(MapperRequest::MapEager, mapping.params.clone())
620 .await
621 {
622 Ok(Ok(())) => {
623 mapping.active_mappers.push(id);
624 }
625 Ok(Err(e)) => {
626 failed = Some(MappingError::new(
627 mapping.params.range,
628 std::io::Error::other(e),
629 ));
630 break;
631 }
632 Err(_) => {
633 failed = Some(MappingError::new(
634 MemoryRange::EMPTY,
635 std::io::Error::other("mapper gone during eager upgrade"),
636 ));
637 break;
638 }
639 }
640 }
641
642 if let Some(err) = failed {
643 self.mappers.mappers[id.0].eager = false;
648 return Err(err);
649 }
650
651 self.mappers.mappers[id.0]
655 .req_send
656 .call(MapperRequest::SetEager, ())
657 .await
658 .ok();
659
660 Ok(())
661 }
662
663 fn send_mappings(&mut self, id: MapperId, mut range: MemoryRange) {
669 while !range.is_empty() {
670 let (this_end, params) = if let Some(mapping) = self
672 .mappings
673 .iter_mut()
674 .filter(|mapping| mapping.params.range.overlaps(&range))
675 .min_by_key(|mapping| mapping.params.range.start())
676 {
677 if mapping.params.range.start() <= range.start() {
678 if !mapping.active_mappers.contains(&id) {
679 mapping.active_mappers.push(id);
680 }
681 (
683 mapping.params.range.end().min(range.end()),
684 Some(mapping.params.clone()),
685 )
686 } else {
687 (mapping.params.range.start(), None)
689 }
690 } else {
691 (range.end(), None)
693 };
694 let this_range = MemoryRange::new(range.start()..this_end);
695 let req = if let Some(params) = params {
696 tracing::debug!(range = %this_range, full_range = %params.range, "sending lazy mapping");
697 MapperRequest::MapLazy(params)
698 } else {
699 tracing::debug!(range = %this_range, "no mapping for range");
700 MapperRequest::NoMapping(this_range)
701 };
702 self.mappers.mappers[id.0].req_send.send(req);
703 range = MemoryRange::new(this_end..range.end());
704 }
705 }
706
707 async fn add_mapping(&mut self, params: MappingParams) -> anyhow::Result<()> {
708 tracing::debug!(range = %params.range, "adding mapping");
709
710 if matches!(params.backing, MappingBacking::Private) && self.mappers.mappers.len() > 1 {
714 anyhow::bail!("cannot add private memory while multiple mappers are present");
715 }
716
717 assert!(!self.mappings.iter().any(|m| m.params.range == params.range));
718
719 let mut active_mappers = Vec::new();
721 for (i, mapper) in self.mappers.mappers.iter() {
722 if !mapper.eager {
723 continue;
724 }
725 let id = MapperId(i);
726 match mapper
727 .req_send
728 .call(MapperRequest::MapEager, params.clone())
729 .await
730 {
731 Ok(Ok(())) => {
732 active_mappers.push(id);
733 }
734 Ok(Err(e)) => {
735 for &rollback_id in &active_mappers {
738 if let Err(err) = self.mappers.mappers[rollback_id.0]
739 .req_send
740 .call(MapperRequest::Unmap, params.range)
741 .await
742 {
743 tracing::warn!(
744 error = &err as &dyn std::error::Error,
745 "mapper dropped unmap during rollback"
746 );
747 }
748 }
749 return Err(e.into());
750 }
751 Err(_) => {
752 tracing::debug!(?id, "mapper gone during add_mapping");
755 }
756 }
757 }
758
759 self.mappings.push(Mapping {
760 params,
761 active_mappers,
762 });
763 Ok(())
764 }
765
766 fn has_private_mapping(&self) -> bool {
768 self.mappings
769 .iter()
770 .any(|m| matches!(m.params.backing, MappingBacking::Private))
771 }
772
773 fn get_dma_target_mappings(&self) -> Vec<MappingParams> {
774 self.mappings
775 .iter()
776 .filter(|m| {
779 m.params.mapping_type == MappingType::Ram && m.params.backing.mappable().is_some()
780 })
781 .map(|m| m.params.clone())
782 .collect()
783 }
784
785 async fn remove_mappings(&mut self, range: MemoryRange) {
786 let mut mappers = Vec::new();
787 self.mappings.retain_mut(|mapping| {
788 if !range.contains(&mapping.params.range) {
789 assert!(
790 !range.overlaps(&mapping.params.range),
791 "no partial unmappings allowed"
792 );
793 return true;
794 }
795 tracing::debug!(range = %mapping.params.range, "removing mapping");
796 mappers.append(&mut mapping.active_mappers);
797 false
798 });
799 mappers.sort();
800 mappers.dedup();
801 self.mappers.invalidate(&mappers, range).await;
802 }
803}
804
805impl Mappers {
806 async fn invalidate(&self, ids: &[MapperId], range: MemoryRange) {
807 tracing::debug!(mapper_count = ids.len(), %range, "sending invalidations");
808 join_all(ids.iter().map(async |&MapperId(i)| {
809 if let Err(err) = self.mappers[i]
810 .req_send
811 .call(MapperRequest::Unmap, range)
812 .await
813 {
814 tracing::warn!(
815 error = &err as &dyn std::error::Error,
816 "mapper dropped invalidate request"
817 );
818 }
819 }))
820 .await;
821 }
822}
823
824pub(crate) struct DmaRegionProvider {
828 pub req_send: mesh::Sender<MappingRequest>,
829}
830
831impl ProvideShareableRegions for DmaRegionProvider {
832 async fn get_regions(&self) -> Result<Vec<ShareableRegion>, guestmem::ShareableRegionError> {
833 let mappings = self
834 .req_send
835 .call(MappingRequest::GetDmaTargetMappings, ())
836 .await?;
837
838 Ok(mappings
839 .into_iter()
840 .filter_map(|m| {
841 let mappable = m.backing.mappable()?;
842 Some(ShareableRegion {
843 guest_address: m.range.start(),
844 size: m.range.len(),
845 file: mappable.inner_arc(),
846 file_offset: m.backing.file_offset(),
847 })
848 })
849 .collect())
850 }
851}
852
853#[cfg(test)]
854mod tests {
855 use super::*;
856 use crate::region_manager::MappingType;
857 use guestmem::GuestMemoryAccess;
858 use guestmem::ProvideShareableRegions;
859 use memory_range::MemoryRange;
860
861 #[pal_async::async_test]
862 async fn test_dma_target_regions_returned(spawn: impl Spawn) {
863 let mm = MappingManager::new_without_primary(&spawn, 0x200000, None);
864 let client = mm.client().clone();
865
866 let ram: Mappable = sparse_mmap::alloc_shared_memory(0x100000, "test-ram")
867 .unwrap()
868 .into();
869 let device: Mappable = sparse_mmap::alloc_shared_memory(0x1000, "test-dev")
870 .unwrap()
871 .into();
872
873 client
874 .add_mapping(MappingParams {
875 range: MemoryRange::new(0..0x100000),
876 backing: MappingBacking::File {
877 mappable: ram,
878 file_offset: 0,
879 },
880 writable: true,
881 mapping_type: MappingType::Ram,
882 policy: MemoryPolicy::none(),
883 })
884 .await
885 .unwrap();
886
887 client
888 .add_mapping(MappingParams {
889 range: MemoryRange::new(0x100000..0x101000),
890 backing: MappingBacking::File {
891 mappable: device,
892 file_offset: 0,
893 },
894 writable: true,
895 mapping_type: MappingType::Device,
896 policy: MemoryPolicy::none(),
897 })
898 .await
899 .unwrap();
900
901 let provider = DmaRegionProvider {
902 req_send: client.req_send.clone(),
903 };
904 let regions = provider.get_regions().await.unwrap();
905
906 assert_eq!(regions.len(), 1);
908 assert_eq!(regions[0].guest_address, 0);
909 assert_eq!(regions[0].size, 0x100000);
910 assert_eq!(regions[0].file_offset, 0);
911 }
912
913 #[pal_async::async_test]
914 async fn test_no_dma_targets_returns_empty(spawn: impl Spawn) {
915 let mm = MappingManager::new_without_primary(&spawn, 0x100000, None);
916 let client = mm.client().clone();
917
918 let mappable: Mappable = sparse_mmap::alloc_shared_memory(0x1000, "test")
919 .unwrap()
920 .into();
921
922 client
923 .add_mapping(MappingParams {
924 range: MemoryRange::new(0..0x1000),
925 backing: MappingBacking::File {
926 mappable,
927 file_offset: 0,
928 },
929 writable: true,
930 mapping_type: MappingType::Device,
931 policy: MemoryPolicy::none(),
932 })
933 .await
934 .unwrap();
935
936 let provider = DmaRegionProvider {
937 req_send: client.req_send.clone(),
938 };
939 let regions = provider.get_regions().await.unwrap();
940 assert!(regions.is_empty());
941 }
942
943 async fn task_with_mapping() -> (MappingManagerTask, MappingParams) {
945 let mut task = MappingManagerTask::new();
946 let mappable: Mappable = sparse_mmap::alloc_shared_memory(0x10000, "test")
947 .unwrap()
948 .into();
949 let params = MappingParams {
950 range: MemoryRange::new(0..0x10000),
951 backing: MappingBacking::File {
952 mappable,
953 file_offset: 0,
954 },
955 writable: true,
956 mapping_type: MappingType::Ram,
957 policy: MemoryPolicy::none(),
958 };
959 task.add_mapping(params.clone()).await.unwrap();
960 (task, params)
961 }
962
963 async fn add_mapper_and_drain(
966 task: &mut MappingManagerTask,
967 eager: bool,
968 ) -> (MapperId, Vec<MapperRequest>) {
969 let (send, mut recv) = mesh::channel();
970 let id = task.add_mapper(send, eager).await.unwrap();
971 let mut msgs = Vec::new();
973 while let Ok(msg) = recv.try_recv() {
974 msgs.push(msg);
975 }
976 (id, msgs)
977 }
978
979 #[pal_async::async_test]
980 async fn test_eager_mapper_gets_replay(_spawn: impl Spawn) {
981 let (mut task, _params) = task_with_mapping().await;
982
983 let (send, mut recv) = mesh::channel();
984 let (id, _) = futures::join!(task.add_mapper(send, true), async {
987 let msg = recv.recv().await.unwrap();
988 match msg {
989 MapperRequest::MapEager(rpc) => {
990 let (params, rpc) = rpc.split();
991 assert_eq!(params.range, MemoryRange::new(0..0x10000));
992 rpc.complete(Ok(()));
993 }
994 other => panic!("expected MapEager, got {other:?}"),
995 }
996 });
997 let _ = id;
998 }
999
1000 #[pal_async::async_test]
1001 async fn test_lazy_mapper_no_replay(_spawn: impl Spawn) {
1002 let (mut task, _params) = task_with_mapping().await;
1003
1004 let (_id, msgs) = add_mapper_and_drain(&mut task, false).await;
1005
1006 assert!(msgs.is_empty(), "lazy mapper should not get replay");
1008 }
1009
1010 #[pal_async::async_test]
1011 async fn test_add_mapping_pushes_only_to_eager(_spawn: impl Spawn) {
1012 let mut task = MappingManagerTask::new();
1013
1014 let (eager_send, mut eager_recv) = mesh::channel();
1016 let _eager_id = task.add_mapper(eager_send, true).await.unwrap();
1017
1018 let (lazy_send, mut lazy_recv) = mesh::channel();
1019 let _lazy_id = task.add_mapper(lazy_send, false).await.unwrap();
1020
1021 let mappable: Mappable = sparse_mmap::alloc_shared_memory(0x1000, "test")
1023 .unwrap()
1024 .into();
1025 let params = MappingParams {
1026 range: MemoryRange::new(0..0x1000),
1027 backing: MappingBacking::File {
1028 mappable,
1029 file_offset: 0,
1030 },
1031 writable: true,
1032 mapping_type: MappingType::Device,
1033 policy: MemoryPolicy::none(),
1034 };
1035
1036 let add_future = task.add_mapping(params);
1038 let (add_result, _) = futures::join!(add_future, async {
1040 let msg = eager_recv.recv().await.unwrap();
1041 match msg {
1042 MapperRequest::MapEager(rpc) => rpc.complete(Ok(())),
1043 other => panic!("expected MapEager, got {other:?}"),
1044 }
1045 });
1046 add_result.unwrap();
1047
1048 assert!(
1050 lazy_recv.try_recv().is_err(),
1051 "lazy mapper should not be notified on add_mapping"
1052 );
1053 }
1054
1055 #[pal_async::async_test]
1056 async fn test_upgrade_to_eager_replays(_spawn: impl Spawn) {
1057 let (mut task, _params) = task_with_mapping().await;
1058
1059 let (send, mut recv) = mesh::channel();
1061 let id = task.add_mapper(send, false).await.unwrap();
1062 assert!(
1063 recv.try_recv().is_err(),
1064 "lazy mapper should not get replay"
1065 );
1066
1067 let upgrade_future = task.upgrade_to_eager(id);
1069 let (result, _) = futures::join!(upgrade_future, async {
1070 let msg = recv.recv().await.unwrap();
1071 match msg {
1072 MapperRequest::MapEager(rpc) => {
1073 let (params, rpc) = rpc.split();
1074 assert_eq!(params.range, MemoryRange::new(0..0x10000));
1075 rpc.complete(Ok(()));
1076 }
1077 other => panic!("expected MapEager during upgrade, got {other:?}"),
1078 }
1079 let msg = recv.recv().await.unwrap();
1081 match msg {
1082 MapperRequest::SetEager(rpc) => rpc.complete(()),
1083 other => panic!("expected SetEager, got {other:?}"),
1084 }
1085 });
1086 result.unwrap();
1087
1088 assert!(task.mappers.mappers[id.0].eager);
1090 }
1091
1092 #[pal_async::async_test]
1093 async fn test_upgrade_already_eager_is_noop(_spawn: impl Spawn) {
1094 let (mut task, _params) = task_with_mapping().await;
1095
1096 let (send, mut recv) = mesh::channel();
1098 let upgrade_future = task.add_mapper(send, true);
1099 let (id, _) = futures::join!(upgrade_future, async {
1100 let msg = recv.recv().await.unwrap();
1101 match msg {
1102 MapperRequest::MapEager(rpc) => rpc.complete(Ok(())),
1103 other => panic!("expected MapEager, got {other:?}"),
1104 }
1105 });
1106 let id = id.unwrap();
1107
1108 task.upgrade_to_eager(id).await.unwrap();
1110 assert!(
1111 recv.try_recv().is_err(),
1112 "upgrade of already-eager mapper should send nothing"
1113 );
1114 }
1115
1116 #[pal_async::async_test]
1117 async fn test_after_upgrade_new_mappings_are_pushed(_spawn: impl Spawn) {
1118 let mut task = MappingManagerTask::new();
1119
1120 let (send, mut recv) = mesh::channel();
1122 let id = task.add_mapper(send, false).await.unwrap();
1123
1124 let upgrade_future = task.upgrade_to_eager(id);
1127 let (result, _) = futures::join!(upgrade_future, async {
1128 let msg = recv.recv().await.unwrap();
1129 match msg {
1130 MapperRequest::SetEager(rpc) => rpc.complete(()),
1131 other => panic!("expected SetEager, got {other:?}"),
1132 }
1133 });
1134 result.unwrap();
1135
1136 let mappable: Mappable = sparse_mmap::alloc_shared_memory(0x1000, "test")
1138 .unwrap()
1139 .into();
1140 let params = MappingParams {
1141 range: MemoryRange::new(0..0x1000),
1142 backing: MappingBacking::File {
1143 mappable,
1144 file_offset: 0,
1145 },
1146 writable: true,
1147 mapping_type: MappingType::Device,
1148 policy: MemoryPolicy::none(),
1149 };
1150
1151 let add_future = task.add_mapping(params);
1152 let (result, _) = futures::join!(add_future, async {
1153 let msg = recv.recv().await.unwrap();
1154 match msg {
1155 MapperRequest::MapEager(rpc) => rpc.complete(Ok(())),
1156 other => panic!("expected MapEager after upgrade, got {other:?}"),
1157 }
1158 });
1159 result.unwrap();
1160 }
1161
1162 #[pal_async::async_test]
1163 async fn test_send_mappings_for_lazy(_spawn: impl Spawn) {
1164 let (mut task, _params) = task_with_mapping().await;
1165
1166 let (send, mut recv) = mesh::channel();
1168 let id = task.add_mapper(send, false).await.unwrap();
1169
1170 task.send_mappings(id, MemoryRange::new(0..0x10000));
1172
1173 let msg = recv.recv().await.unwrap();
1175 match msg {
1176 MapperRequest::MapLazy(params) => {
1177 assert_eq!(params.range, MemoryRange::new(0..0x10000));
1178 }
1179 other => panic!("expected MapLazy, got {other:?}"),
1180 }
1181 }
1182
1183 #[pal_async::async_test]
1184 async fn test_send_mappings_gap_sends_no_mapping(_spawn: impl Spawn) {
1185 let (mut task, _params) = task_with_mapping().await;
1186
1187 let (send, mut recv) = mesh::channel();
1188 let id = task.add_mapper(send, false).await.unwrap();
1189
1190 task.send_mappings(id, MemoryRange::new(0x10000..0x20000));
1192
1193 let msg = recv.recv().await.unwrap();
1194 match msg {
1195 MapperRequest::NoMapping(range) => {
1196 assert_eq!(range, MemoryRange::new(0x10000..0x20000));
1197 }
1198 other => panic!("expected NoMapping, got {other:?}"),
1199 }
1200 }
1201
1202 #[pal_async::async_test]
1203 async fn test_remove_mapping_invalidates_both_eager_and_lazy(_spawn: impl Spawn) {
1204 let (mut task, _params) = task_with_mapping().await;
1205
1206 let (eager_send, mut eager_recv) = mesh::channel();
1208 let add_future = task.add_mapper(eager_send, true);
1209 let (_eager_id, _) = futures::join!(add_future, async {
1210 let msg = eager_recv.recv().await.unwrap();
1211 match msg {
1212 MapperRequest::MapEager(rpc) => rpc.complete(Ok(())),
1213 other => panic!("expected MapEager, got {other:?}"),
1214 }
1215 });
1216
1217 let (lazy_send, mut lazy_recv) = mesh::channel();
1219 let lazy_id = task.add_mapper(lazy_send, false).await.unwrap();
1220 task.send_mappings(lazy_id, MemoryRange::new(0..0x10000));
1221 let _ = lazy_recv.recv().await.unwrap();
1223
1224 let remove_future = task.remove_mappings(MemoryRange::new(0..0x10000));
1226 let ((), _, _) = futures::join!(
1227 remove_future,
1228 async {
1229 let msg = eager_recv.recv().await.unwrap();
1230 match msg {
1231 MapperRequest::Unmap(rpc) => {
1232 let (range, rpc) = rpc.split();
1233 assert_eq!(range, MemoryRange::new(0..0x10000));
1234 rpc.complete(());
1235 }
1236 other => panic!("expected Unmap for eager, got {other:?}"),
1237 }
1238 },
1239 async {
1240 let msg = lazy_recv.recv().await.unwrap();
1241 match msg {
1242 MapperRequest::Unmap(rpc) => {
1243 let (range, rpc) = rpc.split();
1244 assert_eq!(range, MemoryRange::new(0..0x10000));
1245 rpc.complete(());
1246 }
1247 other => panic!("expected Unmap for lazy, got {other:?}"),
1248 }
1249 }
1250 );
1251 }
1252
1253 async fn task_with_two_mappings() -> MappingManagerTask {
1255 let mut task = MappingManagerTask::new();
1256 for (start, end) in [(0u64, 0x10000u64), (0x10000, 0x20000)] {
1257 let mappable: Mappable = sparse_mmap::alloc_shared_memory(0x10000, "test")
1258 .unwrap()
1259 .into();
1260 task.add_mapping(MappingParams {
1261 range: MemoryRange::new(start..end),
1262 backing: MappingBacking::File {
1263 mappable,
1264 file_offset: 0,
1265 },
1266 writable: true,
1267 mapping_type: MappingType::Ram,
1268 policy: MemoryPolicy::none(),
1269 })
1270 .await
1271 .unwrap();
1272 }
1273 task
1274 }
1275
1276 #[pal_async::async_test]
1277 async fn test_add_eager_mapper_rollback_on_replay_failure(_spawn: impl Spawn) {
1278 let mut task = task_with_two_mappings().await;
1279
1280 let (send, mut recv) = mesh::channel();
1283 let add_future = task.add_mapper(send, true);
1284 let (result, _) = futures::join!(add_future, async {
1285 let msg = recv.recv().await.unwrap();
1287 match msg {
1288 MapperRequest::MapEager(rpc) => rpc.complete(Ok(())),
1289 other => panic!("expected MapEager #1, got {other:?}"),
1290 }
1291 let msg = recv.recv().await.unwrap();
1293 match msg {
1294 MapperRequest::MapEager(rpc) => {
1295 rpc.complete(Err(RemoteError::new(std::io::Error::other(
1296 "simulated failure",
1297 ))));
1298 }
1299 other => panic!("expected MapEager #2, got {other:?}"),
1300 }
1301 });
1302
1303 assert!(result.is_err());
1305
1306 assert_eq!(task.mappers.mappers.len(), 0);
1308
1309 for mapping in &task.mappings {
1311 assert!(
1312 mapping.active_mappers.is_empty(),
1313 "active_mappers should be empty after rollback, got {:?} for {}",
1314 mapping.active_mappers,
1315 mapping.params.range
1316 );
1317 }
1318
1319 let (send2, mut recv2) = mesh::channel();
1322 let add_future2 = task.add_mapper(send2, true);
1323 let (result2, _) = futures::join!(add_future2, async {
1324 for _ in 0..2 {
1325 let msg = recv2.recv().await.unwrap();
1326 match msg {
1327 MapperRequest::MapEager(rpc) => rpc.complete(Ok(())),
1328 other => panic!("expected MapEager during second add, got {other:?}"),
1329 }
1330 }
1331 });
1332 assert!(result2.is_ok());
1333 }
1334
1335 #[pal_async::async_test]
1336 async fn test_add_mapping_rollback_on_eager_failure(_spawn: impl Spawn) {
1337 let mut task = MappingManagerTask::new();
1338
1339 let (send1, mut recv1) = mesh::channel();
1341 let _id1 = task.add_mapper(send1, true).await.unwrap();
1342
1343 let (send2, mut recv2) = mesh::channel();
1344 let _id2 = task.add_mapper(send2, true).await.unwrap();
1345
1346 let mappable: Mappable = sparse_mmap::alloc_shared_memory(0x1000, "test")
1348 .unwrap()
1349 .into();
1350 let params = MappingParams {
1351 range: MemoryRange::new(0..0x1000),
1352 backing: MappingBacking::File {
1353 mappable,
1354 file_offset: 0,
1355 },
1356 writable: true,
1357 mapping_type: MappingType::Device,
1358 policy: MemoryPolicy::none(),
1359 };
1360
1361 let add_future = task.add_mapping(params);
1362 let (result, _, _) = futures::join!(
1363 add_future,
1364 async {
1365 let msg = recv1.recv().await.unwrap();
1367 match msg {
1368 MapperRequest::MapEager(rpc) => rpc.complete(Ok(())),
1369 other => panic!("expected MapEager, got {other:?}"),
1370 }
1371 let msg = recv1.recv().await.unwrap();
1373 match msg {
1374 MapperRequest::Unmap(rpc) => {
1375 let (range, rpc) = rpc.split();
1376 assert_eq!(range, MemoryRange::new(0..0x1000));
1377 rpc.complete(());
1378 }
1379 other => panic!("expected Unmap rollback, got {other:?}"),
1380 }
1381 },
1382 async {
1383 let msg = recv2.recv().await.unwrap();
1385 match msg {
1386 MapperRequest::MapEager(rpc) => {
1387 rpc.complete(Err(RemoteError::new(std::io::Error::other(
1388 "simulated failure",
1389 ))));
1390 }
1391 other => panic!("expected MapEager, got {other:?}"),
1392 }
1393 }
1394 );
1395
1396 assert!(result.is_err());
1398
1399 assert!(task.mappings.is_empty());
1401 }
1402
1403 #[pal_async::async_test]
1404 async fn test_upgrade_to_eager_rollback_on_failure(_spawn: impl Spawn) {
1405 let mut task = task_with_two_mappings().await;
1406
1407 let (send, mut recv) = mesh::channel();
1409 let id = task.add_mapper(send, false).await.unwrap();
1410 assert!(!task.mappers.mappers[id.0].eager);
1411
1412 let upgrade_future = task.upgrade_to_eager(id);
1414 let (result, _) = futures::join!(upgrade_future, async {
1415 let msg = recv.recv().await.unwrap();
1417 match msg {
1418 MapperRequest::MapEager(rpc) => rpc.complete(Ok(())),
1419 other => panic!("expected MapEager #1, got {other:?}"),
1420 }
1421 let msg = recv.recv().await.unwrap();
1423 match msg {
1424 MapperRequest::MapEager(rpc) => {
1425 rpc.complete(Err(RemoteError::new(std::io::Error::other(
1426 "simulated failure",
1427 ))));
1428 }
1429 other => panic!("expected MapEager #2, got {other:?}"),
1430 }
1431 });
1432
1433 assert!(result.is_err());
1435
1436 assert!(!task.mappers.mappers[id.0].eager);
1438
1439 assert!(
1443 task.mappings[0].active_mappers.contains(&id),
1444 "first mapping should retain mapper in active_mappers"
1445 );
1446 assert!(
1447 !task.mappings[1].active_mappers.contains(&id),
1448 "second mapping should not have mapper (replay failed)"
1449 );
1450
1451 assert!(task.mappers.mappers.contains(id.0));
1453
1454 let mappable: Mappable = sparse_mmap::alloc_shared_memory(0x1000, "test")
1457 .unwrap()
1458 .into();
1459 task.add_mapping(MappingParams {
1460 range: MemoryRange::new(0x20000..0x21000),
1461 backing: MappingBacking::File {
1462 mappable,
1463 file_offset: 0,
1464 },
1465 writable: true,
1466 mapping_type: MappingType::Device,
1467 policy: MemoryPolicy::none(),
1468 })
1469 .await
1470 .unwrap();
1471
1472 assert!(
1474 recv.try_recv().is_err(),
1475 "lazy mapper should not receive add_mapping push after failed upgrade"
1476 );
1477 }
1478
1479 #[pal_async::async_test]
1480 async fn test_eager_page_fault_fails_immediately(_spawn: impl Spawn) {
1481 use super::super::va_mapper::VaMapper;
1482
1483 let (req_send, mut req_recv) = mesh::channel::<MappingRequest>();
1485 let mapper_future = VaMapper::new(
1486 req_send,
1487 0x10000,
1488 None,
1489 None,
1490 true, MapperRole::Primary {
1492 supports_memory_fault_resolution: false,
1493 },
1494 );
1495 let (mapper, _) = futures::join!(mapper_future, async {
1496 let msg = req_recv.recv().await.unwrap();
1497 match msg {
1498 MappingRequest::AddMapper(rpc) => {
1499 rpc.handle_failable_sync(|params| {
1500 assert!(params.eager);
1501 Ok::<_, MappingError>(MapperId(0))
1502 });
1503 }
1504 _ => panic!("expected AddMapper"),
1505 }
1506 });
1507 let mapper = mapper.unwrap();
1508 assert!(mapper.is_eager());
1509
1510 let action = mapper.page_fault(0x1000, 0x1000, false, false);
1514 assert!(
1515 matches!(action, guestmem::PageFaultAction::Fail(_)),
1516 "eager mapper should fail page faults on unmapped file-backed ranges"
1517 );
1518 }
1519
1520 #[pal_async::async_test]
1521 async fn test_va_mapper_drop_removes_mapper(_spawn: impl Spawn) {
1522 use super::super::va_mapper::VaMapper;
1523
1524 let (req_send, mut req_recv) = mesh::channel::<MappingRequest>();
1525 let mapper_future = VaMapper::new(
1526 req_send,
1527 0x10000,
1528 None,
1529 None,
1530 true, MapperRole::Primary {
1532 supports_memory_fault_resolution: false,
1533 },
1534 );
1535 let (mapper, mapper_req_send) = futures::join!(mapper_future, async {
1536 let msg = req_recv.recv().await.unwrap();
1537 match msg {
1538 MappingRequest::AddMapper(rpc) => {
1539 let (params, rpc) = rpc.split();
1540 assert!(params.eager);
1541 rpc.complete(Ok(MapperId(7)));
1542 params.send
1543 }
1544 _ => panic!("expected AddMapper"),
1545 }
1546 });
1547 drop(mapper.unwrap());
1548
1549 match req_recv.recv().await.unwrap() {
1550 MappingRequest::RemoveMapper(id) => assert_eq!(id, MapperId(7)),
1551 _ => panic!("expected RemoveMapper"),
1552 }
1553
1554 drop(mapper_req_send);
1557 }
1558
1559 #[pal_async::async_test]
1560 async fn test_lazy_page_fault_requests_mapping(spawn: impl Spawn) {
1561 let _ = spawn;
1562 let (manager_thread, manager_driver) =
1563 pal_async::DefaultPool::spawn_on_thread("mapping-manager-test");
1564 let mm = MappingManager::new_without_primary(&manager_driver, 0x10000, None);
1565 let client = mm.client().clone();
1566
1567 let mappable: Mappable = sparse_mmap::alloc_shared_memory(0x10000, "test")
1569 .unwrap()
1570 .into();
1571 client
1572 .add_mapping(MappingParams {
1573 range: MemoryRange::new(0..0x10000),
1574 backing: MappingBacking::File {
1575 mappable,
1576 file_offset: 0,
1577 },
1578 writable: true,
1579 mapping_type: MappingType::Device,
1580 policy: MemoryPolicy::none(),
1581 })
1582 .await
1583 .unwrap();
1584
1585 let mapper = client.new_mapper(false).await.unwrap();
1587 assert!(!mapper.is_eager());
1588
1589 let action = mapper.page_fault(0x1000, 0x1000, false, false);
1594 assert!(
1595 matches!(action, guestmem::PageFaultAction::Retry),
1596 "lazy mapper should request mapping on page fault and succeed"
1597 );
1598
1599 drop(mapper);
1600 drop(client);
1601 drop(mm);
1602 drop(manager_driver);
1603 manager_thread.join().unwrap();
1604 }
1605
1606 #[pal_async::async_test]
1610 async fn test_eager_mapper_with_existing_mappings(spawn: impl Spawn) {
1611 let _ = spawn;
1612 let (manager_thread, manager_driver) =
1613 pal_async::DefaultPool::spawn_on_thread("mapping-manager-test");
1614 let mm = MappingManager::new_without_primary(&manager_driver, 0x10000, None);
1615 let client = mm.client().clone();
1616
1617 let mappable: Mappable = sparse_mmap::alloc_shared_memory(0x10000, "test")
1619 .unwrap()
1620 .into();
1621 client
1622 .add_mapping(MappingParams {
1623 range: MemoryRange::new(0..0x10000),
1624 backing: MappingBacking::File {
1625 mappable,
1626 file_offset: 0,
1627 },
1628 writable: true,
1629 mapping_type: MappingType::Ram,
1630 policy: MemoryPolicy::none(),
1631 })
1632 .await
1633 .unwrap();
1634
1635 let mapper = client.new_mapper(true).await.unwrap();
1638 assert!(mapper.is_eager());
1639
1640 drop(mapper);
1641 drop(client);
1642 drop(mm);
1643 drop(manager_driver);
1644 manager_thread.join().unwrap();
1645 }
1646
1647 #[pal_async::async_test]
1648 async fn test_new_mapper_upgrades_cached_lazy_to_eager(spawn: impl Spawn) {
1649 let _ = spawn;
1650 let (manager_thread, manager_driver) =
1651 pal_async::DefaultPool::spawn_on_thread("mapping-manager-test");
1652 let mm = MappingManager::new_without_primary(&manager_driver, 0x20000, None);
1653 let client = mm.client().clone();
1654
1655 let mappable: Mappable = sparse_mmap::alloc_shared_memory(0x10000, "test")
1657 .unwrap()
1658 .into();
1659 client
1660 .add_mapping(MappingParams {
1661 range: MemoryRange::new(0..0x10000),
1662 backing: MappingBacking::File {
1663 mappable,
1664 file_offset: 0,
1665 },
1666 writable: true,
1667 mapping_type: MappingType::Device,
1668 policy: MemoryPolicy::none(),
1669 })
1670 .await
1671 .unwrap();
1672
1673 let lazy = client.new_mapper(false).await.unwrap();
1675 assert!(!lazy.is_eager());
1676
1677 let eager = client.new_mapper(true).await.unwrap();
1679
1680 assert!(Arc::ptr_eq(&lazy, &eager));
1682
1683 let mappable: Mappable = sparse_mmap::alloc_shared_memory(0x1000, "test")
1688 .unwrap()
1689 .into();
1690 client
1691 .add_mapping(MappingParams {
1692 range: MemoryRange::new(0x10000..0x11000),
1693 backing: MappingBacking::File {
1694 mappable,
1695 file_offset: 0,
1696 },
1697 writable: true,
1698 mapping_type: MappingType::Device,
1699 policy: MemoryPolicy::none(),
1700 })
1701 .await
1702 .unwrap();
1703
1704 assert!(eager.is_eager());
1706
1707 drop(eager);
1708 drop(lazy);
1709 drop(client);
1710 drop(mm);
1711 drop(manager_driver);
1712 manager_thread.join().unwrap();
1713 }
1714}