1mod delivery;
40mod profile;
41
42pub use delivery::{
43 DeliveryQueueProcessor, DeliveryQueueProvider, TestVmoProvider, UnverifiedPages,
44};
45pub use profile::ProfileRecording;
46pub use storage_profile::BOOT_PROFILE_NAME;
47
48use anyhow::{Context, Error, anyhow, bail};
49use event_listener as _;
50use fidl_fuchsia_storage_block as fblock;
51use fidl_fuchsia_storage_mapping as fmapping;
52use fuchsia_async as fasync;
53use fuchsia_hash::{HASH_SIZE, Hash};
54use fuchsia_merkle::{MerkleVerifier, ReadSizedMerkleVerifier};
55use fuchsia_sync::Mutex;
56use futures::TryStreamExt as _;
57use linked_hash_map::LinkedHashMap;
58use std::collections::{HashMap, HashSet, VecDeque, hash_map};
59use std::ops::Range;
60use std::sync::{Arc, OnceLock, Weak};
61use storage_ptr_slice::PtrByteSlice;
62use zx;
63
64const DEFAULT_CACHE_CAPACITY: usize = 2000;
67
68struct ZeroChildrenReceiver {
71 blob: OnceLock<Weak<CachedBlob>>,
72}
73
74impl fasync::PacketReceiver for ZeroChildrenReceiver {
75 fn receive_packet(&self, packet: zx::Packet) {
76 if let zx::PacketContents::SignalOne(signals) = packet.contents() {
77 if signals.observed().contains(zx::Signals::VMO_ZERO_CHILDREN) {
78 if let Some(cached_blob) = self.blob.get().and_then(|w| w.upgrade()) {
79 if let Some(cache) = cached_blob.cache.upgrade() {
80 cache.on_zero_children(&cached_blob);
81 }
82 }
83 }
84 }
85 }
86}
87
88#[derive(Default)]
89struct InlineTailQueue {
90 busy: bool,
91 pending: VecDeque<delivery::ChildInlineTail>,
92}
93
94struct CachedBlob {
102 vmo: zx::Vmo,
105 root_hash: [u8; 32],
107 cache: Weak<Cache>,
110 vmo_key: u64,
113 len: u64,
115 registration: fasync::ReceiverRegistration<ZeroChildrenReceiver>,
117 merkle_verifier: OnceLock<ReadSizedMerkleVerifier>,
119}
120
121impl CachedBlob {
122 fn create_child(&self) -> Result<zx::Vmo, zx::Status> {
123 self.vmo.create_child(zx::VmoChildOptions::REFERENCE | zx::VmoChildOptions::NO_WRITE, 0, 0)
124 }
125
126 fn wait_for_zero_children(&self) {
127 let _ = self.vmo.wait_async(
128 fasync::EHandle::local().port(),
129 self.registration.key(),
130 zx::Signals::VMO_ZERO_CHILDREN,
131 zx::WaitAsyncOpts::empty(),
132 );
133 }
134}
135
136impl Drop for CachedBlob {
137 fn drop(&mut self) {
138 if let Some(cache) = self.cache.upgrade() {
139 let session = cache.mapping_session.clone();
140 let vmo_key = self.vmo_key;
141 cache.scope.spawn(async move {
142 let _ = session.close(vmo_key).await;
143 });
144 }
145 }
146}
147
148enum BlobState {
149 Opening {
153 root_hash: [u8; 32],
154 event: Arc<event_listener::Event>,
155 verifier: Option<ReadSizedMerkleVerifier>,
156 },
157 Ready(Arc<CachedBlob>),
160}
161
162pub(crate) struct ActiveRecording {
163 pub(crate) opened_hashes: HashSet<Hash>,
165 pub(crate) hash_by_key: HashMap<u64, Hash>,
173}
174
175struct ChildVmo {
178 parent_key: u64,
179 vmo: zx::Vmo,
180 len: u64,
181}
182
183struct CacheState {
184 next_key: u64,
185 keys_by_hash: HashMap<[u8; 32], u64>,
187 blob_states_by_key: HashMap<u64, BlobState>,
188 recording: Option<ActiveRecording>,
189 child_vmos: HashMap<u64, Arc<ChildVmo>>,
192 unreferenced_lru: LinkedHashMap<u64, ()>,
194}
195
196impl Default for CacheState {
197 fn default() -> Self {
198 Self {
199 next_key: 1,
200 keys_by_hash: HashMap::default(),
201 blob_states_by_key: HashMap::default(),
202 recording: None,
203 child_vmos: HashMap::default(),
204 unreferenced_lru: LinkedHashMap::default(),
205 }
206 }
207}
208
209impl CacheState {
210 fn generate_key(&mut self) -> u64 {
211 let key = self.next_key;
212 self.next_key += 1;
213 key
214 }
215
216 fn evict_excess_unreferenced(&mut self, capacity: usize) -> Vec<Arc<CachedBlob>> {
217 let mut evicted = Vec::new();
218 while self.unreferenced_lru.len() > capacity {
219 let Some((evict_key, ())) = self.unreferenced_lru.pop_front() else {
220 break;
221 };
222 if let Some(BlobState::Ready(cached)) = self.blob_states_by_key.remove(&evict_key) {
223 if let hash_map::Entry::Occupied(entry) = self.keys_by_hash.entry(cached.root_hash)
224 {
225 if *entry.get() == evict_key {
226 entry.remove();
227 }
228 }
229 evicted.push(cached);
230 }
231 }
232 evicted
233 }
234}
235
236struct PendingEntry {
242 cache: Arc<Cache>,
243 key: u64,
244}
245
246impl PendingEntry {
247 fn key(&self) -> u64 {
248 self.key
249 }
250
251 fn commit(self, vmo: zx::Vmo, size: u64) -> Arc<CachedBlob> {
254 let zero_children_receiver = ZeroChildrenReceiver { blob: OnceLock::new() };
255 let zero_children_registration =
256 fasync::EHandle::local().register_receiver(zero_children_receiver);
257
258 let (cached, event) = {
259 let mut state = self.cache.state.lock();
260 let (root_hash, event, verifier) = match state.blob_states_by_key.remove(&self.key) {
261 Some(BlobState::Opening { root_hash, event, verifier }) => {
262 (root_hash, event, verifier)
263 }
264 _ => {
265 unreachable!("Blob for key {} was unexpectedly not in Opening state", self.key)
266 }
267 };
268
269 let merkle_verifier = OnceLock::new();
270 if let Some(verifier) = verifier {
271 let _ = merkle_verifier.set(verifier);
272 }
273
274 let cached = Arc::new(CachedBlob {
275 vmo,
276 root_hash,
277 cache: Arc::downgrade(&self.cache),
278 vmo_key: self.key,
279 len: size,
280 registration: zero_children_registration,
281 merkle_verifier,
282 });
283
284 cached
285 .registration
286 .receiver()
287 .blob
288 .set(Arc::downgrade(&cached))
289 .expect("Failed to bind CachedBlob to ZeroChildrenReceiver: already initialized");
290
291 state.blob_states_by_key.insert(self.key, BlobState::Ready(cached.clone()));
292 if let Some(recording) = state.recording.as_mut() {
293 recording.hash_by_key.insert(self.key, Hash::from(root_hash));
294 }
295
296 (cached, event)
297 };
298
299 cached.wait_for_zero_children();
300 event.notify(usize::MAX);
301 cached
302 }
303}
304
305impl Drop for PendingEntry {
306 fn drop(&mut self) {
307 let event = {
308 let mut state = self.cache.state.lock();
309 match state.blob_states_by_key.get(&self.key) {
310 Some(BlobState::Ready(_)) => return,
312 Some(BlobState::Opening { .. }) => {
313 if let Some(BlobState::Opening { root_hash, event, .. }) =
314 state.blob_states_by_key.remove(&self.key)
315 {
316 state.keys_by_hash.remove(&root_hash);
317 event
318 } else {
319 return;
320 }
321 }
322 None => {
323 log::error!(
324 key = self.key;
325 "PendingEntry::drop: key unexpectedly absent from cache"
326 );
327 return;
328 }
329 }
330 };
331
332 let session = self.cache.mapping_session.clone();
338 let key = self.key;
339 self.cache.scope.spawn(async move {
340 let _ = session.close(key).await;
341 });
342
343 event.notify(usize::MAX);
345 }
346}
347
348enum CacheLookup {
350 Ready(zx::Vmo),
352 Pending(event_listener::EventListener),
355 Missing(PendingEntry),
358}
359
360pub(crate) struct Cache {
362 state: Mutex<CacheState>,
363 pub(crate) mapping_session: fmapping::MappingSessionProxy,
364 pager: Arc<zx::Pager>,
365 port: zx::Port,
366 delivery_vmo: zx::Vmo,
367 pub(crate) scope: fasync::ScopeHandle,
368 cache_capacity: usize,
369 transfer_vmos: Mutex<Vec<zx::Vmo>>,
371 inline_tail_queue: Mutex<InlineTailQueue>,
374}
375
376const MAX_POOLED_TRANSFER_VMOS: usize = 8;
377
378fn status_from_error(err: &Error) -> zx::Status {
380 err.downcast_ref::<zx::Status>().copied().unwrap_or(zx::Status::BAD_STATE)
381}
382
383impl Cache {
384 fn new(
385 mapping_session: fmapping::MappingSessionProxy,
386 pager: Arc<zx::Pager>,
387 port: zx::Port,
388 delivery_vmo: zx::Vmo,
389 scope: fasync::ScopeHandle,
390 cache_capacity: usize,
391 ) -> Self {
392 Self {
393 state: Mutex::new(CacheState::default()),
394 mapping_session,
395 pager,
396 port,
397 delivery_vmo,
398 scope,
399 cache_capacity,
400 transfer_vmos: Mutex::new(Vec::new()),
401 inline_tail_queue: Mutex::new(InlineTailQueue::default()),
402 }
403 }
404
405 fn delivery_vmo(&self) -> &zx::Vmo {
406 &self.delivery_vmo
407 }
408
409 fn get_by_key(&self, key: u64) -> Option<Arc<CachedBlob>> {
410 let state = self.state.lock();
411 match state.blob_states_by_key.get(&key) {
412 Some(BlobState::Ready(cached)) => Some(cached.clone()),
413 _ => None,
414 }
415 }
416
417 fn register_child_vmo(&self, parent_key: u64, child_key: u64, vmo: zx::Vmo, len: u64) {
420 self.state.lock().child_vmos.insert(child_key, Arc::new(ChildVmo { parent_key, vmo, len }));
421 }
422
423 fn unregister_child_vmo(&self, child_key: u64) {
425 self.state.lock().child_vmos.remove(&child_key);
426 }
427
428 fn get_child_vmo(&self, child_key: u64) -> Option<Arc<ChildVmo>> {
430 self.state.lock().child_vmos.get(&child_key).cloned()
431 }
432
433 fn acquire_transfer_vmo(&self) -> Result<zx::Vmo, zx::Status> {
436 if let Some(vmo) = self.transfer_vmos.lock().pop() {
437 return Ok(vmo);
438 }
439 zx::Vmo::create_with_opts(zx::VmoOptions::UNBOUNDED, 0)
440 }
441
442 fn release_transfer_vmo(&self, vmo: zx::Vmo) {
444 let mut pool = self.transfer_vmos.lock();
445 if pool.len() < MAX_POOLED_TRANSFER_VMOS {
446 pool.push(vmo);
447 }
448 }
449
450 fn supply_slice_via_transfer_vmo(
454 &self,
455 child_vmo: &zx::Vmo,
456 child_range: Range<u64>,
457 valid_bytes: &[u8],
458 ) -> Result<(), zx::Status> {
459 let bounded_len = (child_range.end - child_range.start) as usize;
460 let copy_len = std::cmp::min(valid_bytes.len(), bounded_len);
461 let transfer_vmo = self.acquire_transfer_vmo()?;
462 if copy_len > 0 {
463 transfer_vmo.write(&valid_bytes[..copy_len], 0)?;
464 }
465 self.pager.supply_pages(child_vmo, child_range, &transfer_vmo, 0)?;
466 self.release_transfer_vmo(transfer_vmo);
467 Ok(())
468 }
469
470 fn verify_parent_chunk(
473 &self,
474 parent_key: u64,
475 parent_offset: u64,
476 offset: u32,
477 length: u32,
478 payload: Option<PtrByteSlice<'_>>,
479 ) -> Result<(), Error> {
480 let page_size = zx::system_get_page_size() as u64;
481 let page_size_u32 = page_size as u32;
482 let Some(parent_slice) = payload else {
483 return Err(
484 Error::from(zx::Status::INVALID_ARGS).context("ChildData payload out of bounds")
485 );
486 };
487 if offset % page_size_u32 != 0 {
488 return Err(Error::from(zx::Status::INVALID_ARGS)
489 .context(format!("ChildData payload offset must be page aligned: {offset}")));
490 }
491 if length % page_size_u32 != 0 {
492 return Err(Error::from(zx::Status::INVALID_ARGS)
493 .context(format!("ChildData payload length must be page aligned: {length}")));
494 }
495 if parent_offset % page_size != 0 {
496 return Err(Error::from(zx::Status::INVALID_ARGS).context(format!(
497 "ChildData parent_offset must be page aligned: {parent_offset}"
498 )));
499 }
500
501 let cached_blob = self.get_by_key(parent_key).ok_or_else(|| {
502 Error::from(zx::Status::BAD_STATE).context(format!(
503 "Unknown or expired parent key {parent_key} in deliver_child_pages"
504 ))
505 })?;
506 let verifier = cached_blob.merkle_verifier.get().ok_or_else(|| {
507 Error::from(zx::Status::BAD_STATE)
508 .context(format!("ChildData received for uninitialized parent blob {parent_key}"))
509 })?;
510 let remaining_in_parent = cached_blob.len.saturating_sub(parent_offset);
511 let unaligned_parent_len = std::cmp::min(length as u64, remaining_in_parent) as usize;
512 if let Err(e) =
513 verifier.verify_aligned(parent_offset as usize, parent_slice, unaligned_parent_len)
514 {
515 return Err(Error::from(zx::Status::IO_DATA_INTEGRITY)
516 .context(format!("Failed to verify parent payload for blob {parent_key}: {e:?}")));
517 }
518 Ok(())
519 }
520
521 fn process_one_inline_tail(&self, data: delivery::ChildInlineTail) -> Result<(), Error> {
532 let Some(child_vmo) = self.get_child_vmo(data.child_key) else {
533 bail!("Unknown child VMO {}", data.child_key);
534 };
535 let parent_key = child_vmo.parent_key;
536 let page_size = zx::system_get_page_size() as u64;
537 if data.child_target_offset % page_size != 0 {
538 bail!(
539 "ChildInlineTail child_target_offset must be page aligned: {}",
540 data.child_target_offset
541 );
542 }
543 if data.tail_length == 0 || (data.tail_length as u64) > page_size {
544 bail!("ChildInlineTail invalid tail_length: {}", data.tail_length);
545 }
546 let child_page_aligned_size = child_vmo.len.next_multiple_of(page_size);
547 if data.child_target_offset >= child_page_aligned_size {
548 return Ok(());
549 }
550 let child_range = data.child_target_offset..data.child_target_offset + page_size;
551
552 let res: Result<(), Error> = (|| {
553 let cached_blob = self.get_by_key(parent_key).ok_or_else(|| {
554 Error::from(zx::Status::BAD_STATE).context(format!(
555 "Unknown or expired parent key {parent_key} in deliver_child_inline_tail",
556 ))
557 })?;
558 let valid_in_child = child_vmo.len.saturating_sub(data.child_target_offset);
559 let copy_len = std::cmp::min(data.tail_length as u64, valid_in_child) as usize;
560 let mut page = [0u8; 4096];
561 if copy_len > 0 {
562 if data.parent_byte_offset.checked_add(copy_len as u64).unwrap_or(u64::MAX)
563 > cached_blob.len
564 {
565 return Err(Error::from(zx::Status::IO_DATA_INTEGRITY)
566 .context("ChildInlineTail parent_byte_offset out of parent blob bounds"));
567 }
568 cached_blob
574 .vmo
575 .read(&mut page[..copy_len], data.parent_byte_offset)
576 .context("Failed to read inline tail from parent VMO")?;
577 }
578 self.supply_slice_via_transfer_vmo(
579 &child_vmo.vmo,
580 child_range.clone(),
581 &page[..copy_len],
582 )
583 .context("Failed to supply inline tail page")?;
584 Ok(())
585 })();
586
587 if let Err(err) = res {
588 self.report_pager_failure(&child_vmo.vmo, child_range, status_from_error(&err));
589 return Err(err);
590 }
591 Ok(())
592 }
593
594 #[cfg(test)]
595 fn is_merkle_initialized(&self, key: u64) -> bool {
596 let state = self.state.lock();
597 match state.blob_states_by_key.get(&key) {
598 Some(BlobState::Opening { verifier, .. }) => verifier.is_some(),
599 Some(BlobState::Ready(blob)) => blob.merkle_verifier.get().is_some(),
600 None => false,
601 }
602 }
603
604 pub(crate) fn start_recording(&self) -> Result<(), zx::Status> {
605 let mut state = self.state.lock();
606 if state.recording.is_some() {
607 return Err(zx::Status::BAD_STATE);
608 }
609 let hash_by_key =
610 state.keys_by_hash.iter().map(|(&hash, &key)| (key, Hash::from(hash))).collect();
611 state.recording = Some(ActiveRecording { opened_hashes: HashSet::new(), hash_by_key });
612 Ok(())
613 }
614
615 fn record_open(&self, identifier: &[u8; 32]) {
616 let mut state = self.state.lock();
617 if let Some(recording) = state.recording.as_mut() {
618 recording.opened_hashes.insert(Hash::from(*identifier));
619 }
620 }
621
622 pub(crate) fn take_recording(&self) -> Option<ActiveRecording> {
623 self.state.lock().recording.take()
624 }
625
626 pub(crate) fn abort_recording(&self) {
627 self.state.lock().recording = None;
628 }
629
630 fn lookup(self: &Arc<Self>, identifier: &[u8; 32]) -> Result<CacheLookup, Error> {
638 let mut state = self.state.lock();
639 if let Some(&key) = state.keys_by_hash.get(identifier) {
640 let was_unreferenced = state.unreferenced_lru.remove(&key).is_some();
641 match state.blob_states_by_key.get(&key) {
642 Some(BlobState::Ready(cached)) => {
643 let child = cached
644 .create_child()
645 .map_err(|s| anyhow!("Failed to create child VMO: {s}"))?;
646 if was_unreferenced {
647 cached.wait_for_zero_children();
648 }
649 return Ok(CacheLookup::Ready(child));
650 }
651 Some(BlobState::Opening { event, .. }) => {
652 return Ok(CacheLookup::Pending(event.listen()));
653 }
654 None => unreachable!("keys_by_hash pointed to non-existent key {key}"),
655 }
656 }
657
658 let event = Arc::new(event_listener::Event::new());
659 let key = state.generate_key();
660 state.keys_by_hash.insert(*identifier, key);
661 state
662 .blob_states_by_key
663 .insert(key, BlobState::Opening { root_hash: *identifier, event, verifier: None });
664 Ok(CacheLookup::Missing(PendingEntry { cache: self.clone(), key }))
665 }
666
667 pub(crate) async fn open_vmo(
668 self: &Arc<Self>,
669 identifier: &[u8; 32],
670 ) -> Result<zx::Vmo, Error> {
671 loop {
672 let entry = match self.lookup(identifier)? {
673 CacheLookup::Ready(child) => return Ok(child),
674 CacheLookup::Pending(listener) => {
675 listener.await;
676 continue; }
678 CacheLookup::Missing(entry) => entry,
679 };
680
681 let key = entry.key();
682
683 let size = self
686 .mapping_session
687 .open(key, identifier)
688 .await
689 .context("FIDL error calling MappingSession.Open")?
690 .map_err(|e| {
691 Error::from(zx::Status::err_from_raw(e))
692 .context("MappingSession.Open failed for blob")
693 })?;
694
695 let vmo = self.pager.create_vmo(zx::VmoOptions::empty(), &self.port, key, size)?;
696 let vmo_name = format!("blob-{}", &Hash::from(*identifier).to_string()[..8]);
697 if let Ok(name) = zx::Name::new(&vmo_name) {
698 let _ = vmo.set_name(&name);
699 }
700
701 let first_child = vmo
704 .create_child(zx::VmoChildOptions::REFERENCE | zx::VmoChildOptions::NO_WRITE, 0, 0)
705 .map_err(|s| anyhow!("Failed to create child VMO: {}", s))?;
706
707 entry.commit(vmo, size);
708
709 return Ok(first_child);
710 }
711 }
712
713 fn on_zero_children(&self, blob: &Arc<CachedBlob>) {
714 let evicted = {
719 let mut state = self.state.lock();
720 if let Ok(info) = blob.vmo.info() {
721 if info.num_children > 0 {
722 blob.wait_for_zero_children();
725 return;
726 }
727 }
728 let is_current = matches!(
729 state.blob_states_by_key.get(&blob.vmo_key),
730 Some(BlobState::Ready(cached)) if Arc::ptr_eq(cached, blob)
731 );
732 if !is_current {
733 return;
734 }
735 state.unreferenced_lru.insert(blob.vmo_key, ());
736 state.evict_excess_unreferenced(self.cache_capacity)
737 };
738 drop(evicted);
739 }
740
741 fn create_merkle_verifier(
742 root_hash: &[u8; 32],
743 vmo_key: u64,
744 hashes: Box<[Hash]>,
745 read_alignment: usize,
746 ) -> Result<ReadSizedMerkleVerifier, Error> {
747 let hashes = if hashes.is_empty() { Box::new([Hash::from(*root_hash)]) } else { hashes };
752
753 match MerkleVerifier::new(Hash::from(*root_hash), hashes) {
754 Ok(verifier) => ReadSizedMerkleVerifier::new(verifier, read_alignment)
755 .map_err(|e| anyhow!("Failed to create ReadSizedMerkleVerifier: {e:?}")),
756 Err(e) => {
757 bail!("Failed to verify merkle leaves for key {vmo_key}: {e:?}");
758 }
759 }
760 }
761
762 fn report_pager_failure(&self, vmo: &zx::Vmo, range: Range<u64>, status: zx::Status) {
763 let pager_status = match status {
766 zx::Status::IO_DATA_INTEGRITY => zx::Status::IO_DATA_INTEGRITY,
767 zx::Status::NO_SPACE => zx::Status::NO_SPACE,
768 zx::Status::BUFFER_TOO_SMALL | zx::Status::FILE_BIG => zx::Status::BUFFER_TOO_SMALL,
769 zx::Status::IO
770 | zx::Status::IO_DATA_LOSS
771 | zx::Status::IO_INVALID
772 | zx::Status::IO_MISSED_DEADLINE
773 | zx::Status::IO_NOT_PRESENT
774 | zx::Status::IO_OVERRUN
775 | zx::Status::IO_REFUSED
776 | zx::Status::PEER_CLOSED => zx::Status::IO,
777 _ => zx::Status::BAD_STATE,
778 };
779
780 if let Err(error) = self.pager.op_range(zx::PagerOp::Fail(pager_status), vmo, range) {
783 log::error!(error:?; "Failed to report pager failure to kernel");
784 }
785 }
786}
787
788struct ChildPagesDelivery<'a> {
791 cache: &'a Cache,
792 child_vmo: Arc<ChildVmo>,
793 child_range: Range<u64>,
794 data: delivery::ChildData<'a>,
795 status: Option<zx::Status>,
796}
797
798impl<'a> ChildPagesDelivery<'a> {
799 fn new(cache: &'a Cache, data: delivery::ChildData<'a>) -> Result<Option<Self>, Error> {
802 let child_vmo = cache
803 .get_child_vmo(data.child_key)
804 .ok_or_else(|| anyhow!("Unknown child VMO {}", data.child_key))?;
805
806 let page_size = zx::system_get_page_size() as u64;
807 if data.child_target_offset % page_size != 0 {
808 bail!(
809 "ChildData child_target_offset must be page aligned: {}",
810 data.child_target_offset
811 );
812 }
813 if data.child_length == 0 || (data.child_length as u64) % page_size != 0 {
814 bail!(
815 "ChildData child_length must be non-zero and page aligned: {}",
816 data.child_length
817 );
818 }
819
820 let child_page_aligned_size = child_vmo.len.next_multiple_of(page_size);
821 let bounded_child_len = std::cmp::min(
822 data.child_length as u64,
823 child_page_aligned_size.saturating_sub(data.child_target_offset),
824 );
825 if bounded_child_len == 0 {
826 return Ok(None);
827 }
828 let child_range = data.child_target_offset..data.child_target_offset + bounded_child_len;
829 Ok(Some(Self { cache, child_vmo, child_range, data, status: Some(zx::Status::BAD_STATE) }))
830 }
831
832 fn supply_pages(&mut self, source_vmo: &zx::Vmo, source_offset: u64) -> Result<(), Error> {
835 match self.cache.pager.supply_pages(
836 &self.child_vmo.vmo,
837 self.child_range.clone(),
838 source_vmo,
839 source_offset,
840 ) {
841 Ok(()) => {
842 self.status = None;
843 Ok(())
844 }
845 Err(status) => {
846 self.status = Some(status);
847 bail!("Failed to supply child pages: {status:?}");
848 }
849 }
850 }
851
852 fn deliver(mut self) -> Result<(), Error> {
855 let page_size = zx::system_get_page_size() as u64;
856 let page_size_u32 = page_size as u32;
857 let bounded_child_len = self.child_range.end - self.child_range.start;
858
859 if self.data.length == 0 {
860 let transfer_vmo = self.cache.acquire_transfer_vmo()?;
862 self.supply_pages(&transfer_vmo, 0)?;
863 self.cache.release_transfer_vmo(transfer_vmo);
864 return Ok(());
865 }
866
867 if let Err(err) = self.cache.verify_parent_chunk(
868 self.child_vmo.parent_key,
869 self.data.parent_offset,
870 self.data.offset,
871 self.data.length,
872 self.data.payload.as_ref().map(|p| p.as_ptr_slice()),
873 ) {
874 self.status = Some(status_from_error(&err));
875 return Err(err);
876 }
877
878 if self.data.in_chunk_offset % page_size_u32 != 0 {
879 bail!("ChildData in_chunk_offset must be page aligned: {}", self.data.in_chunk_offset);
880 }
881 if self.data.in_chunk_offset.checked_add(bounded_child_len as u32).unwrap_or(u32::MAX)
882 > self.data.length
883 {
884 bail!("Child slice out of parent chunk bounds");
885 }
886 let source_offset = self.data.offset + self.data.in_chunk_offset;
887
888 if self.child_range.end > self.child_vmo.len {
890 let valid_in_slice =
891 self.child_vmo.len.saturating_sub(self.data.child_target_offset) as usize;
892 let bounded_usize = bounded_child_len as usize;
893 if valid_in_slice < bounded_usize {
894 let in_chunk = self.data.in_chunk_offset as usize;
895 self.data
896 .payload
897 .as_mut()
898 .unwrap()
899 .subslice_mut((in_chunk + valid_in_slice)..(in_chunk + bounded_usize))
900 .fill(0);
901 }
902 }
903
904 let vmo_offset = self.data.payload_region_offset + source_offset as u64;
905 self.supply_pages(&self.cache.delivery_vmo, vmo_offset)
906 }
907}
908
909impl Drop for ChildPagesDelivery<'_> {
910 fn drop(&mut self) {
911 if let Some(status) = self.status.take() {
912 self.cache.report_pager_failure(&self.child_vmo.vmo, self.child_range.clone(), status);
913 }
914 }
915}
916
917impl delivery::DeliveryQueueProvider for Cache {
918 fn deliver_pages(
919 &self,
920 key: u64,
921 target_offset: u64,
922 unverified_pages: UnverifiedPages<'_>,
923 ) -> Result<(), Error> {
924 let cached_blob = self
925 .get_by_key(key)
926 .ok_or_else(|| anyhow!("Unknown or expired key {key} in deliver_pages"))?;
927
928 let page_size = zx::system_get_page_size() as u64;
929 let page_aligned_size = cached_blob.len.div_ceil(page_size) * page_size;
930
931 let verifier = match cached_blob.merkle_verifier.get() {
932 Some(v) => v,
933 None => {
934 self.report_pager_failure(
939 &cached_blob.vmo,
940 0..page_aligned_size,
941 zx::Status::BAD_STATE,
942 );
943 bail!("Data received for uninitialized blob {}", key);
944 }
945 };
946
947 let chunk_len = unverified_pages.len_in_bytes() as u64;
948
949 let bounded_len = std::cmp::min(chunk_len, page_aligned_size.saturating_sub(target_offset));
954 let chunk_range = target_offset..target_offset + bounded_len;
955
956 let remaining_in_blob = cached_blob.len.saturating_sub(target_offset);
960 let unaligned_len = std::cmp::min(chunk_len, remaining_in_blob) as usize;
961 if let Err(e) = verifier.verify_aligned(
962 target_offset as usize,
963 unverified_pages.as_ptr_byte_slice(),
964 unaligned_len,
965 ) {
966 self.report_pager_failure(&cached_blob.vmo, chunk_range, zx::Status::IO_DATA_INTEGRITY);
967 bail!("Failed to verify payload for blob {}: {:?}", key, e);
968 }
969
970 if let Err(e) = self.pager.supply_pages(
971 &cached_blob.vmo,
972 chunk_range.clone(),
973 &self.delivery_vmo,
974 unverified_pages.delivery_offset(),
975 ) {
976 self.report_pager_failure(&cached_blob.vmo, chunk_range, e);
977 bail!("Failed to supply pages: {:?}", e);
978 }
979
980 Ok(())
981 }
982
983 fn register_blob(
984 &self,
985 key: u64,
986 leaf_data: PtrByteSlice<'_>,
987 read_alignment: usize,
988 ) -> Result<(), Error> {
989 if leaf_data.len() % HASH_SIZE != 0 {
990 bail!("RegisterBlob invalid leaf length must be a multiple of HASH_SIZE");
991 }
992
993 let hashes: Vec<Hash> = (0..(leaf_data.len() / HASH_SIZE))
994 .map(|i| {
995 let chunk = leaf_data.subslice(i * HASH_SIZE..(i + 1) * HASH_SIZE);
996 let mut hash_bytes = [0u8; HASH_SIZE];
997 chunk.copy_to_slice(&mut hash_bytes);
998 Hash::from(hash_bytes)
999 })
1000 .collect();
1001
1002 let mut state = self.state.lock();
1003 match state.blob_states_by_key.get_mut(&key) {
1004 Some(BlobState::Opening { root_hash, verifier, .. }) => {
1005 if verifier.is_some() {
1006 log::warn!(key;
1007 "RegisterBlob received for blob but it is already initialized"
1008 );
1009 return Ok(());
1010 }
1011 *verifier = Some(Self::create_merkle_verifier(
1012 root_hash,
1013 key,
1014 hashes.into_boxed_slice(),
1015 read_alignment,
1016 )?);
1017 Ok(())
1018 }
1019 Some(BlobState::Ready(cached)) => {
1020 if cached.merkle_verifier.get().is_some() {
1021 log::warn!(key;
1022 "RegisterBlob received for blob but it is already initialized"
1023 );
1024 return Ok(());
1025 }
1026 let verifier = Self::create_merkle_verifier(
1027 &cached.root_hash,
1028 key,
1029 hashes.into_boxed_slice(),
1030 read_alignment,
1031 )?;
1032 let _ = cached.merkle_verifier.set(verifier);
1033 Ok(())
1034 }
1035 None => {
1036 bail!("RegisterBlob received for unknown or expired key {key}");
1037 }
1038 }
1039 }
1040
1041 fn deliver_child_pages(&self, data: delivery::ChildData<'_>) -> Result<(), Error> {
1043 if let Some(delivery) = ChildPagesDelivery::new(self, data)? {
1044 delivery.deliver()?;
1045 }
1046 Ok(())
1047 }
1048
1049 fn deliver_child_inline_tail(
1053 &self,
1054 data: delivery::ChildInlineTail,
1055 receiver: &vmo_fifo::Receiver<mapping::RawDeliveryCommand>,
1056 ) -> Result<(), Error> {
1057 {
1058 let mut queue = self.inline_tail_queue.lock();
1059 if queue.busy {
1060 queue.pending.push_back(data);
1061 return Ok(());
1062 }
1063 queue.busy = true;
1064 }
1065
1066 receiver.will_maybe_reenter();
1070
1071 let mut current = data;
1072 loop {
1073 if let Err(error) = self.process_one_inline_tail(current) {
1074 log::warn!(error:?; "Failed to process ChildInlineTail");
1075 }
1076 let mut queue = self.inline_tail_queue.lock();
1077 if let Some(next) = queue.pending.pop_front() {
1078 current = next;
1079 } else {
1080 queue.busy = false;
1081 break;
1082 }
1083 }
1084 Ok(())
1085 }
1086}
1087
1088pub struct BlobPagerAndVerifier {
1096 _delivery_processor: delivery::DeliveryQueueProcessor,
1098 mapper_session: fblock::MapperSessionProxy,
1099 cache: Arc<Cache>,
1100 scope: fasync::Scope,
1101}
1102
1103impl BlobPagerAndVerifier {
1104 pub fn delivery_vmo(&self) -> &zx::Vmo {
1106 self.cache.delivery_vmo()
1107 }
1108
1109 pub fn clear_cache(&self) {
1111 let evicted = {
1112 let mut state = self.cache.state.lock();
1113 state.unreferenced_lru.clear();
1114 let unreferenced_keys: Vec<u64> = state
1115 .blob_states_by_key
1116 .iter()
1117 .filter_map(|(&key, blob_state)| match blob_state {
1118 BlobState::Ready(cached) => {
1119 if cached.vmo.info().map(|info| info.num_children == 0).unwrap_or(false) {
1120 Some(key)
1121 } else {
1122 None
1123 }
1124 }
1125 BlobState::Opening { .. } => None,
1126 })
1127 .collect();
1128 let mut evicted = Vec::with_capacity(unreferenced_keys.len());
1129 for key in unreferenced_keys {
1130 if let Some(BlobState::Ready(cached)) = state.blob_states_by_key.remove(&key) {
1131 if let hash_map::Entry::Occupied(entry) =
1132 state.keys_by_hash.entry(cached.root_hash)
1133 {
1134 if *entry.get() == key {
1135 entry.remove();
1136 }
1137 }
1138 evicted.push(cached);
1139 }
1140 }
1141 evicted
1142 };
1143 drop(evicted);
1144 }
1145
1146 pub async fn new(
1154 mapping_provider: &fmapping::MappingProviderProxy,
1155 mapper: &fblock::MapperProxy,
1156 ) -> Result<Self, Error> {
1157 Self::new_with_cache_capacity(mapping_provider, mapper, DEFAULT_CACHE_CAPACITY).await
1158 }
1159
1160 pub async fn new_with_cache_capacity(
1162 mapping_provider: &fmapping::MappingProviderProxy,
1163 mapper: &fblock::MapperProxy,
1164 cache_capacity: usize,
1165 ) -> Result<Self, Error> {
1166 let (mapping_session, session_server) =
1168 fidl::endpoints::create_proxy::<fmapping::MappingSessionMarker>();
1169 let mapping_vmo = mapping_provider
1170 .open_session(session_server)
1171 .await
1172 .context("FIDL error calling MappingProvider.OpenSession")?
1173 .map_err(|e| anyhow!("MappingProvider open_session failed: {e:?}"))?;
1174
1175 let port = zx::Port::create();
1177 let delivery_queue = zx::Vmo::create(mapping::DELIVERY_VMO_SIZE)
1178 .context("Failed to create delivery queue VMO")?;
1179 let delivery_vmo: zx::Vmo = delivery_queue
1180 .duplicate_handle(zx::Rights::SAME_RIGHTS)
1181 .context("Failed to duplicate delivery queue VMO")?;
1182 let delivery_queue_dup = delivery_queue.duplicate_handle(zx::Rights::SAME_RIGHTS)?;
1183 let receiver = vmo_fifo::Receiver::<mapping::RawDeliveryCommand>::new(
1184 delivery_queue,
1185 mapping::PENDING_DELIVERY_COMMANDS_CAPACITY,
1186 )
1187 .context("Failed to create delivery queue receiver")?;
1188 let pager = Arc::new(
1189 zx::Pager::create(zx::PagerOptions::empty()).context("Failed to create pager")?,
1190 );
1191 let port_dup = port.duplicate_handle(zx::Rights::SAME_RIGHTS)?;
1192 let (mapper_session, mapper_session_server) =
1193 fidl::endpoints::create_proxy::<fblock::MapperSessionMarker>();
1194 mapper
1195 .open_session(
1196 mapper_session_server,
1197 mapping_vmo,
1198 Some(port_dup),
1199 Some(delivery_queue_dup),
1200 )
1201 .await
1202 .context("FIDL error calling Mapper.OpenSession")?
1203 .map_err(|e| anyhow!("Mapper.OpenSession failed: {e:?}"))?;
1204
1205 let scope = fasync::Scope::new();
1206 let scope_handle = scope.to_handle();
1207 let cache = Arc::new(Cache::new(
1208 mapping_session,
1209 pager,
1210 port,
1211 delivery_vmo.duplicate_handle(zx::Rights::SAME_RIGHTS)?,
1212 scope_handle,
1213 cache_capacity,
1214 ));
1215 let _delivery_processor =
1216 delivery::DeliveryQueueProcessor::spawn(receiver, cache.clone(), delivery_vmo)?;
1217
1218 Ok(Self { _delivery_processor, mapper_session, cache, scope })
1219 }
1220
1221 pub async fn start_profile(
1223 &self,
1224 name: impl Into<String>,
1225 ) -> Result<ProfileRecording, zx::Status> {
1226 ProfileRecording::start(self.cache.clone(), &self.mapper_session, name.into()).await
1227 }
1228
1229 pub async fn record_and_replay_profile(
1232 &self,
1233 name: impl Into<String>,
1234 duration: zx::MonotonicDuration,
1235 ) {
1236 let name = name.into();
1237 let recording = match self.start_profile(name.clone()).await {
1238 Ok(recording) => recording,
1239 Err(status) => {
1240 log::warn!(status:?, name = name.as_str(); "Failed to start profile recording");
1241 return;
1242 }
1243 };
1244 self.scope.spawn(async move {
1245 fasync::Timer::new(duration).await;
1246 if let Err(status) = recording.stop().await {
1247 log::warn!(status:?, name = name.as_str(); "Failed to stop profile recording");
1248 }
1249 });
1250 }
1251
1252 pub async fn create_vmo(&self, identifier: &[u8; 32]) -> Result<zx::Vmo, Error> {
1254 let vmo = self.cache.open_vmo(identifier).await?;
1255 self.cache.record_open(identifier);
1256 Ok(vmo)
1257 }
1258
1259 pub async fn open_child_session(
1266 &self,
1267 identifier: &[u8; 32],
1268 mapping_vmo: zx::Vmo,
1269 session: fidl::endpoints::ServerEnd<fblock::MapperSessionMarker>,
1270 ) -> Result<(), zx::Status> {
1271 let parent_key = {
1272 let state = self.cache.state.lock();
1273 state.keys_by_hash.get(identifier).copied()
1274 }
1275 .ok_or(zx::Status::NOT_FOUND)?;
1276
1277 let child_port = zx::Port::create();
1278 let child_port_for_driver = child_port.duplicate_handle(zx::Rights::SAME_RIGHTS)?;
1279 let (driver_session_proxy, driver_session_server) =
1280 fidl::endpoints::create_proxy::<fblock::MapperSessionMarker>();
1281
1282 self.mapper_session
1283 .open_child_session(
1284 driver_session_server,
1285 mapping_vmo,
1286 parent_key,
1287 Some(child_port_for_driver),
1288 None,
1289 )
1290 .await
1291 .map_err(|_| zx::Status::PEER_CLOSED)?
1292 .map_err(zx::Status::err_from_raw)?;
1293
1294 let pager = self.cache.pager.clone();
1295 let cache = self.cache.clone();
1296 self.scope.spawn(async move {
1297 let mut stream = session.into_stream();
1298 let mut child_keys = HashSet::new();
1299 while let Ok(Some(request)) = stream.try_next().await {
1300 match request {
1301 fblock::MapperSessionRequest::CreateVmo { size, options: _, responder } => {
1302 let key = cache.state.lock().generate_key();
1303 let res = pager
1304 .create_vmo(zx::VmoOptions::empty(), &child_port, key, size)
1305 .and_then(|vmo| {
1306 let dup = vmo.duplicate_handle(zx::Rights::SAME_RIGHTS)?;
1307 cache.register_child_vmo(parent_key, key, dup, size);
1308 child_keys.insert(key);
1309 Ok((key, vmo))
1310 });
1311 let _ = responder.send(res.map_err(zx::Status::into_raw));
1312 }
1313 fblock::MapperSessionRequest::CloseVmo { key, .. } => {
1314 if child_keys.remove(&key) {
1315 cache.unregister_child_vmo(key);
1316 }
1317 }
1318 fblock::MapperSessionRequest::OpenChildSession { responder, .. } => {
1319 let _ = responder.send(Err(zx::Status::NOT_SUPPORTED.into_raw()));
1320 }
1321 fblock::MapperSessionRequest::RecordProfile { responder, .. } => {
1322 let _ = responder.send(Err(zx::Status::NOT_SUPPORTED.into_raw()));
1323 }
1324 fblock::MapperSessionRequest::Close { responder } => {
1325 let _ = driver_session_proxy.close().await;
1326 let _ = responder.send(Ok(()));
1327 break;
1328 }
1329 fblock::MapperSessionRequest::_UnknownMethod { .. } => {}
1330 }
1331 }
1332 for child_key in child_keys {
1333 cache.unregister_child_vmo(child_key);
1334 }
1335 });
1336
1337 Ok(())
1338 }
1339
1340 pub fn get_file_mapper_handler(
1344 self: &Arc<Self>,
1345 scope: vfs::execution_scope::ExecutionScope,
1346 ) -> Arc<vfs::service::Service> {
1347 let verifier = self.clone();
1348 vfs::service::host(move |mut stream: fmapping::FileMapperRequestStream| {
1349 use futures::TryStreamExt as _;
1350 let verifier = verifier.clone();
1351 let scope = scope.clone();
1352 async move {
1353 while let Some(request) = stream.try_next().await.unwrap_or_else(|error| {
1354 log::error!(error:?; "error reading FileMapper request");
1355 None
1356 }) {
1357 match request {
1358 fmapping::FileMapperRequest::OpenSession {
1359 file_token,
1360 mapping_vmo,
1361 session,
1362 responder,
1363 } => {
1364 let res = async {
1365 let (node, rights) = scope
1366 .token_registry()
1367 .get_owner_and_rights(file_token.into())?
1368 .ok_or(zx::Status::NOT_FOUND)?;
1369 if !rights.contains(fidl_fuchsia_io::Rights::READ_BYTES) {
1370 return Err(zx::Status::ACCESS_DENIED);
1371 }
1372 let vmo_blob = node
1373 .into_any()
1374 .downcast::<vmo_blob::VmoBlob>()
1375 .map_err(|_| zx::Status::INVALID_ARGS)?;
1376 verifier
1377 .open_child_session(vmo_blob.root_hash(), mapping_vmo, session)
1378 .await
1379 }
1380 .await;
1381 let _ = responder.send(res.map_err(zx::Status::into_raw));
1382 }
1383 fmapping::FileMapperRequest::_UnknownMethod { .. } => {}
1384 }
1385 }
1386 }
1387 })
1388 }
1389}
1390
1391#[cfg(test)]
1392mod tests {
1393 use super::*;
1394 use futures::TryStreamExt;
1395 use futures::channel::oneshot;
1396 use mapping::{DeliveryCommand, RawDeliveryCommand};
1397 use test_case::test_case;
1398 use vmo_fifo::SyncSender;
1399
1400 const TARGET_READ_AHEAD_SIZE: usize = mapping::TARGET_READ_AHEAD_SIZE as usize;
1401 const TEST_BLOB_SIZE: u64 = (TARGET_READ_AHEAD_SIZE * 2) as u64;
1402 const TEST_VMO_KEY: u64 = 1;
1403
1404 struct TestEnv {
1409 pager_and_verifier: Arc<BlobPagerAndVerifier>,
1410 mapping_task: fasync::Task<()>,
1411 mapper_task: fasync::Task<()>,
1412 close_signal: Option<oneshot::Receiver<()>>,
1413 delivery_vmo: zx::Vmo,
1414 pub valid_root: [u8; 32],
1415 pub valid_leaves: Vec<u8>,
1416 pub blob_data: Vec<u8>,
1417 }
1418
1419 impl TestEnv {
1420 async fn new(blob_size: u64) -> Self {
1421 let blob_data = vec![0x42u8; blob_size as usize];
1422 let (root, leaf_hashes) =
1423 fuchsia_merkle::MerkleRootBuilder::new(Vec::new()).complete(&blob_data);
1424 let expected_hash: [u8; 32] = root.into();
1425
1426 let mut flat_leaves = Vec::new();
1427 for hash in &leaf_hashes {
1428 flat_leaves.extend_from_slice(hash.as_bytes());
1429 }
1430
1431 let (mapping_proxy, mut mapping_stream) =
1432 fidl::endpoints::create_proxy_and_stream::<fmapping::MappingProviderMarker>();
1433
1434 let (close_tx, close_rx) = oneshot::channel();
1435 let mapping_task = fasync::Task::spawn(async move {
1436 let mut close_tx = Some(close_tx);
1437 if let Some(fmapping::MappingProviderRequest::OpenSession { session, responder }) =
1438 mapping_stream.try_next().await.expect("try_next failed")
1439 {
1440 let mapping_vmo = zx::Vmo::create(zx::system_get_page_size().into())
1441 .expect("zx::Vmo::create failed");
1442 responder.send(Ok(mapping_vmo)).expect("send failed");
1443
1444 let mut session_stream = session.into_stream();
1445 let mut open_calls = 0;
1446 while let Some(request) =
1447 session_stream.try_next().await.expect("try_next failed")
1448 {
1449 match request {
1450 fmapping::MappingSessionRequest::Open {
1451 key,
1452 identifier,
1453 responder,
1454 } => {
1455 assert_eq!(identifier, expected_hash);
1456 assert_eq!(key, TEST_VMO_KEY);
1457 open_calls += 1;
1458 assert_eq!(
1459 open_calls, 1,
1460 "Open should only be called once per identifier"
1461 );
1462 responder.send(Ok(blob_size)).expect("send failed");
1463 }
1464 fmapping::MappingSessionRequest::Close { key, responder } => {
1465 assert_eq!(key, TEST_VMO_KEY);
1466 responder.send(Ok(())).expect("send failed");
1467 if let Some(tx) = close_tx.take() {
1468 let _ = tx.send(());
1469 }
1470 }
1471 _ => {}
1472 }
1473 }
1474 }
1475 });
1476
1477 let (mapper_proxy, mut mapper_stream) =
1478 fidl::endpoints::create_proxy_and_stream::<fblock::MapperMarker>();
1479
1480 let (tx_delivery, rx_delivery) = oneshot::channel();
1481 let mapper_task = fasync::Task::spawn(async move {
1482 if let Some(fblock::MapperRequest::OpenSession {
1483 delivery_queue, responder, ..
1484 }) = mapper_stream.try_next().await.expect("try_next failed")
1485 {
1486 tx_delivery.send(delivery_queue).expect("send failed");
1487 responder.send(Ok(())).expect("send failed");
1488 }
1489 });
1490
1491 Self {
1492 pager_and_verifier: Arc::new(
1493 BlobPagerAndVerifier::new_with_cache_capacity(&mapping_proxy, &mapper_proxy, 0)
1494 .await
1495 .expect("BlobPagerAndVerifier::new failed"),
1496 ),
1497 mapping_task,
1498 mapper_task,
1499 close_signal: Some(close_rx),
1500 delivery_vmo: rx_delivery
1501 .await
1502 .expect("rx_delivery wait failed")
1503 .expect("delivery_vmo was None"),
1504 valid_root: expected_hash,
1505 valid_leaves: flat_leaves,
1506 blob_data,
1507 }
1508 }
1509
1510 async fn teardown(self) {
1511 drop(self.pager_and_verifier);
1512 self.mapping_task.await;
1513 self.mapper_task.await;
1514 }
1515 }
1516
1517 struct ExpectedReadThread {
1518 started_rx: Option<oneshot::Receiver<()>>,
1519 done_rx: oneshot::Receiver<()>,
1520 handle: std::thread::JoinHandle<()>,
1521 }
1522
1523 impl ExpectedReadThread {
1524 async fn wait_started(&mut self) {
1525 if let Some(rx) = self.started_rx.take() {
1526 rx.await.expect("reader thread failed to start");
1527 }
1528 }
1529
1530 async fn wait_and_verify(self) {
1531 self.done_rx.await.expect("reader thread panicked or hung");
1532 self.handle.join().expect("join failed");
1533 }
1534 }
1535
1536 fn spawn_reader_expect_error(
1537 vmo: &zx::Vmo,
1538 offset: u64,
1539 size: usize,
1540 expected_status: zx::Status,
1541 ) -> ExpectedReadThread {
1542 let vmo_clone =
1543 vmo.duplicate_handle(zx::Rights::SAME_RIGHTS).expect("duplicate_handle failed");
1544 let (started_tx, started_rx) = oneshot::channel();
1545 let (done_tx, done_rx) = oneshot::channel();
1546
1547 let handle = std::thread::spawn(move || {
1548 let mut buf = vec![0u8; size];
1549 let _ = started_tx.send(());
1550 let err = vmo_clone.read(&mut buf, offset).expect_err("read should fail");
1551 assert_eq!(err, expected_status);
1552 let _ = done_tx.send(());
1553 });
1554
1555 ExpectedReadThread { started_rx: Some(started_rx), done_rx, handle }
1556 }
1557
1558 #[fuchsia::test]
1559 async fn test_create_vmo() {
1560 let env = TestEnv::new(TEST_BLOB_SIZE).await;
1561 let vmo =
1562 env.pager_and_verifier.create_vmo(&env.valid_root).await.expect("Failed to create VMO");
1563 let size = vmo.get_size().expect("get_size failed");
1564
1565 let page_size = zx::system_get_page_size() as u64;
1567 let expected_pages = (TEST_BLOB_SIZE + page_size - 1) / page_size;
1568 assert_eq!(size, expected_pages * page_size);
1569
1570 drop(vmo);
1574
1575 env.teardown().await;
1576 }
1577
1578 #[fuchsia::test]
1579 async fn test_create_vmo_concurrent_access() {
1580 let env = TestEnv::new(TEST_BLOB_SIZE).await;
1581 let mut futures = vec![];
1582 for _ in 0..10 {
1583 let verifier = env.pager_and_verifier.clone();
1584 futures.push(fasync::Task::spawn(async move {
1585 verifier.create_vmo(&env.valid_root).await.expect("Failed to create VMO")
1586 }));
1587 }
1588 let vmos = futures::future::join_all(futures).await;
1589
1590 drop(vmos);
1591 env.teardown().await;
1592 }
1593
1594 #[fuchsia::test]
1595 async fn test_zero_children_eviction() {
1596 let mut env = TestEnv::new(TEST_BLOB_SIZE).await;
1597
1598 let child_vmo =
1599 env.pager_and_verifier.create_vmo(&env.valid_root).await.expect("create_vmo failed");
1600
1601 {
1602 let state = env.pager_and_verifier.cache.state.lock();
1603 assert_eq!(state.keys_by_hash.get(&env.valid_root), Some(&TEST_VMO_KEY));
1604 assert!(matches!(
1605 state.blob_states_by_key.get(&TEST_VMO_KEY),
1606 Some(BlobState::Ready(_))
1607 ));
1608 }
1609
1610 drop(child_vmo);
1611
1612 env.close_signal.take().expect("Missing signal").await.expect("Failed to close");
1615
1616 {
1617 let state = env.pager_and_verifier.cache.state.lock();
1618 assert!(state.keys_by_hash.get(&env.valid_root).is_none());
1619 assert!(state.blob_states_by_key.get(&TEST_VMO_KEY).is_none());
1620 }
1621
1622 env.teardown().await;
1623 }
1624
1625 #[fuchsia::test]
1626 async fn test_create_vmo_multiple_distinct_blobs() {
1627 use futures::StreamExt;
1628
1629 let (mapping_proxy, mut mapping_stream) =
1630 fidl::endpoints::create_proxy_and_stream::<fmapping::MappingProviderMarker>();
1631 let (mapper_proxy, mut mapper_stream) =
1632 fidl::endpoints::create_proxy_and_stream::<fblock::MapperMarker>();
1633
1634 let (close_tx, mut close_rx) = futures::channel::mpsc::unbounded();
1635 let mapping_task = fasync::Task::spawn(async move {
1636 if let Some(fmapping::MappingProviderRequest::OpenSession { session, responder }) =
1637 mapping_stream.try_next().await.expect("try_next failed")
1638 {
1639 let mapping_vmo = zx::Vmo::create(zx::system_get_page_size().into())
1640 .expect("zx::Vmo::create failed");
1641 responder.send(Ok(mapping_vmo)).expect("send failed");
1642
1643 let mut session_stream = session.into_stream();
1644 while let Some(request) = session_stream.try_next().await.expect("try_next failed")
1645 {
1646 match request {
1647 fmapping::MappingSessionRequest::Open { responder, .. } => {
1648 responder.send(Ok(8192)).expect("send failed");
1649 }
1650 fmapping::MappingSessionRequest::Close { key, responder } => {
1651 responder.send(Ok(())).expect("send failed");
1652 let _ = close_tx.unbounded_send(key);
1653 }
1654 _ => {}
1655 }
1656 }
1657 }
1658 });
1659
1660 let mapper_task = fasync::Task::spawn(async move {
1661 if let Some(fblock::MapperRequest::OpenSession { responder, .. }) =
1662 mapper_stream.try_next().await.expect("try_next failed")
1663 {
1664 responder.send(Ok(())).expect("send failed");
1665 }
1666 });
1667
1668 let pager_and_verifier = Arc::new(
1669 BlobPagerAndVerifier::new_with_cache_capacity(&mapping_proxy, &mapper_proxy, 0)
1670 .await
1671 .expect("BlobPagerAndVerifier::new failed"),
1672 );
1673
1674 let hash1: [u8; 32] = [0x11; 32];
1675 let hash2: [u8; 32] = [0x22; 32];
1676 let hash3: [u8; 32] = [0x33; 32];
1677
1678 let vmo1 = pager_and_verifier.create_vmo(&hash1).await.expect("create_vmo 1 failed");
1679 assert_eq!(
1680 vmo1.get_name().expect("get_name failed"),
1681 zx::Name::new("blob-11111111").expect("zx::Name::new failed")
1682 );
1683 let vmo2 = pager_and_verifier.create_vmo(&hash2).await.expect("create_vmo 2 failed");
1684 let vmo3 = pager_and_verifier.create_vmo(&hash3).await.expect("create_vmo 3 failed");
1685
1686 let (key1, key2, key3) = {
1687 let state = pager_and_verifier.cache.state.lock();
1688 let k1 = *state.keys_by_hash.get(&hash1).expect("hash1 missing");
1689 let k2 = *state.keys_by_hash.get(&hash2).expect("hash2 missing");
1690 let k3 = *state.keys_by_hash.get(&hash3).expect("hash3 missing");
1691 assert_ne!(k1, k2);
1692 assert_ne!(k2, k3);
1693 assert_ne!(k1, k3);
1694 assert!(matches!(state.blob_states_by_key.get(&k1), Some(BlobState::Ready(_))));
1695 assert!(matches!(state.blob_states_by_key.get(&k2), Some(BlobState::Ready(_))));
1696 assert!(matches!(state.blob_states_by_key.get(&k3), Some(BlobState::Ready(_))));
1697 (k1, k2, k3)
1698 };
1699
1700 drop(vmo2);
1702 let closed_key = close_rx.next().await.expect("expected close signal");
1703 assert_eq!(closed_key, key2);
1704
1705 {
1707 let state = pager_and_verifier.cache.state.lock();
1708 assert!(state.keys_by_hash.get(&hash2).is_none());
1709 assert!(state.blob_states_by_key.get(&key2).is_none());
1710 assert_eq!(state.keys_by_hash.get(&hash1), Some(&key1));
1711 assert_eq!(state.keys_by_hash.get(&hash3), Some(&key3));
1712 assert!(matches!(state.blob_states_by_key.get(&key1), Some(BlobState::Ready(_))));
1713 assert!(matches!(state.blob_states_by_key.get(&key3), Some(BlobState::Ready(_))));
1714 }
1715
1716 let vmo2_new = pager_and_verifier.create_vmo(&hash2).await.expect("re-create vmo 2 failed");
1718 {
1719 let state = pager_and_verifier.cache.state.lock();
1720 let k = *state.keys_by_hash.get(&hash2).expect("hash2 missing after re-open");
1721 assert_ne!(k, key2);
1722 assert!(matches!(state.blob_states_by_key.get(&k), Some(BlobState::Ready(_))));
1723 }
1724
1725 drop(vmo1);
1726 drop(vmo3);
1727 drop(vmo2_new);
1728
1729 drop(pager_and_verifier);
1730 mapping_task.await;
1731 mapper_task.await;
1732 }
1733
1734 #[fuchsia::test]
1735 async fn test_lru_cache_retains_and_evicts_blobs() {
1736 use futures::StreamExt;
1737
1738 let (mapping_proxy, mut mapping_stream) =
1739 fidl::endpoints::create_proxy_and_stream::<fmapping::MappingProviderMarker>();
1740 let (mapper_proxy, mut mapper_stream) =
1741 fidl::endpoints::create_proxy_and_stream::<fblock::MapperMarker>();
1742
1743 let (close_tx, mut close_rx) = futures::channel::mpsc::unbounded();
1744 let mapping_task = fasync::Task::spawn(async move {
1745 if let Some(fmapping::MappingProviderRequest::OpenSession { session, responder }) =
1746 mapping_stream.try_next().await.expect("try_next failed")
1747 {
1748 let mapping_vmo = zx::Vmo::create(zx::system_get_page_size().into())
1749 .expect("zx::Vmo::create failed");
1750 responder.send(Ok(mapping_vmo)).expect("send failed");
1751
1752 let mut session_stream = session.into_stream();
1753 while let Some(request) = session_stream.try_next().await.expect("try_next failed")
1754 {
1755 match request {
1756 fmapping::MappingSessionRequest::Open { responder, .. } => {
1757 responder.send(Ok(8192)).expect("send failed");
1758 }
1759 fmapping::MappingSessionRequest::Close { key, responder } => {
1760 responder.send(Ok(())).expect("send failed");
1761 let _ = close_tx.unbounded_send(key);
1762 }
1763 _ => {}
1764 }
1765 }
1766 }
1767 });
1768
1769 let mapper_task = fasync::Task::spawn(async move {
1770 if let Some(fblock::MapperRequest::OpenSession { responder, .. }) =
1771 mapper_stream.try_next().await.expect("try_next failed")
1772 {
1773 responder.send(Ok(())).expect("send failed");
1774 }
1775 });
1776
1777 let pager_and_verifier = Arc::new(
1779 BlobPagerAndVerifier::new_with_cache_capacity(&mapping_proxy, &mapper_proxy, 2)
1780 .await
1781 .expect("BlobPagerAndVerifier::new_with_cache_capacity failed"),
1782 );
1783
1784 let hash1: [u8; 32] = [0x11; 32];
1785 let hash2: [u8; 32] = [0x22; 32];
1786 let hash3: [u8; 32] = [0x33; 32];
1787
1788 let vmo1 = pager_and_verifier.create_vmo(&hash1).await.expect("create_vmo 1 failed");
1789 let vmo2 = pager_and_verifier.create_vmo(&hash2).await.expect("create_vmo 2 failed");
1790 let (key1, key2) = {
1791 let state = pager_and_verifier.cache.state.lock();
1792 (*state.keys_by_hash.get(&hash1).unwrap(), *state.keys_by_hash.get(&hash2).unwrap())
1793 };
1794
1795 drop(vmo1);
1797 drop(vmo2);
1798 while pager_and_verifier.cache.state.lock().unreferenced_lru.len() < 2 {
1799 fasync::Timer::new(std::time::Duration::from_millis(5)).await;
1800 }
1801 assert!(close_rx.try_recv().is_err());
1802
1803 let vmo1_reopened =
1805 pager_and_verifier.create_vmo(&hash1).await.expect("re-open vmo 1 failed");
1806 assert_eq!(pager_and_verifier.cache.state.lock().keys_by_hash.get(&hash1), Some(&key1));
1807 assert_eq!(pager_and_verifier.cache.state.lock().unreferenced_lru.len(), 1);
1808
1809 drop(vmo1_reopened);
1811 while pager_and_verifier.cache.state.lock().unreferenced_lru.len() < 2 {
1812 fasync::Timer::new(std::time::Duration::from_millis(5)).await;
1813 }
1814
1815 let vmo3 = pager_and_verifier.create_vmo(&hash3).await.expect("create_vmo 3 failed");
1817 drop(vmo3);
1818 let closed_key = close_rx.next().await.expect("expected close signal for evicted blob 2");
1819 assert_eq!(closed_key, key2);
1820 {
1821 let state = pager_and_verifier.cache.state.lock();
1822 assert!(state.keys_by_hash.get(&hash2).is_none());
1823 assert_eq!(state.keys_by_hash.get(&hash1), Some(&key1));
1824 assert!(state.keys_by_hash.get(&hash3).is_some());
1825 }
1826
1827 drop(pager_and_verifier);
1828 mapping_task.await;
1829 mapper_task.await;
1830 }
1831
1832 #[fuchsia::test]
1833 async fn test_cache_is_cleared_when_create_vmo_fails() {
1834 let (mapping_proxy, mut mapping_stream) =
1835 fidl::endpoints::create_proxy_and_stream::<fmapping::MappingProviderMarker>();
1836 let (mapper_proxy, mut mapper_stream) =
1837 fidl::endpoints::create_proxy_and_stream::<fblock::MapperMarker>();
1838
1839 let (mock_opened_tx, mock_opened_rx) = oneshot::channel();
1840 let mapping_task = fasync::Task::spawn(async move {
1841 let mut mock_opened_tx = Some(mock_opened_tx);
1842 if let Some(fmapping::MappingProviderRequest::OpenSession { session, responder }) =
1843 mapping_stream.try_next().await.expect("try_next failed")
1844 {
1845 let mapping_vmo = zx::Vmo::create(zx::system_get_page_size().into())
1846 .expect("zx::Vmo::create failed");
1847 responder.send(Ok(mapping_vmo)).expect("send failed");
1848 let mut session_stream = session.into_stream();
1849
1850 if let Some(fmapping::MappingSessionRequest::Open {
1851 responder: _responder, ..
1852 }) = session_stream.try_next().await.expect("try_next failed")
1853 {
1854 if let Some(tx) = mock_opened_tx.take() {
1856 let _ = tx.send(());
1857 }
1858
1859 let () = std::future::pending().await;
1861 }
1862 }
1863 });
1864
1865 let mapper_task = fasync::Task::spawn(async move {
1866 if let Some(fblock::MapperRequest::OpenSession { responder, .. }) =
1867 mapper_stream.try_next().await.expect("try_next failed")
1868 {
1869 responder.send(Ok(())).expect("send failed");
1870 }
1871 });
1872
1873 let pager_and_verifer = Arc::new(
1874 BlobPagerAndVerifier::new(&mapping_proxy, &mapper_proxy)
1875 .await
1876 .expect("BlobPagerAndVerifier::new failed"),
1877 );
1878
1879 let blob_data = vec![0x42u8; TEST_BLOB_SIZE as usize];
1880 let (root, _) = fuchsia_merkle::MerkleRootBuilder::new(Vec::new()).complete(&blob_data);
1881 let hash_val: [u8; 32] = root.into();
1882
1883 let verifier_clone = pager_and_verifer.clone();
1884
1885 let identifier = hash_val;
1886 let (abortable_future, abort_handle) = futures::future::abortable(async move {
1887 let _ = verifier_clone.create_vmo(&identifier).await;
1888 });
1889
1890 let identifier = &hash_val;
1891 let primary_task = fasync::Task::spawn(abortable_future);
1892
1893 mock_opened_rx.await.expect("Open exited abruptly");
1896 {
1897 let state = pager_and_verifer.cache.state.lock();
1898 assert_eq!(state.keys_by_hash.get(identifier), Some(&1));
1899 assert!(matches!(state.blob_states_by_key.get(&1), Some(BlobState::Opening { .. })));
1900 }
1901
1902 abort_handle.abort();
1904 let _ = primary_task.await;
1905
1906 {
1908 let state = pager_and_verifer.cache.state.lock();
1909 assert!(state.keys_by_hash.get(identifier).is_none());
1910 assert!(state.blob_states_by_key.get(&1).is_none());
1911 }
1912
1913 drop(pager_and_verifer);
1914 drop(mapping_task);
1915 drop(mapper_task);
1916 }
1917
1918 #[fuchsia::test]
1919 async fn test_create_vmo_error_clears_cache_and_unblocks_waiters() {
1920 let (mapping_proxy, mut mapping_stream) =
1921 fidl::endpoints::create_proxy_and_stream::<fmapping::MappingProviderMarker>();
1922 let (mapper_proxy, mut mapper_stream) =
1923 fidl::endpoints::create_proxy_and_stream::<fblock::MapperMarker>();
1924
1925 let (open_received_tx, open_received_rx) = oneshot::channel();
1926 let (reply_tx, reply_rx) = oneshot::channel();
1927
1928 let mapping_task = fasync::Task::spawn(async move {
1929 if let Some(fmapping::MappingProviderRequest::OpenSession { session, responder }) =
1930 mapping_stream.try_next().await.expect("try_next failed")
1931 {
1932 let mapping_vmo = zx::Vmo::create(zx::system_get_page_size().into())
1933 .expect("zx::Vmo::create failed");
1934 responder.send(Ok(mapping_vmo)).expect("send failed");
1935 let mut session_stream = session.into_stream();
1936
1937 if let Some(fmapping::MappingSessionRequest::Open { responder, .. }) =
1938 session_stream.try_next().await.expect("try_next failed")
1939 {
1940 open_received_tx.send(()).expect("send open_received failed");
1942
1943 reply_rx.await.expect("reply_rx failed");
1945 responder.send(Err(zx::Status::NOT_FOUND.into_raw())).expect("send failed");
1946 }
1947 }
1949 });
1950
1951 let mapper_task = fasync::Task::spawn(async move {
1952 if let Some(fblock::MapperRequest::OpenSession { responder, .. }) =
1953 mapper_stream.try_next().await.expect("try_next failed")
1954 {
1955 responder.send(Ok(())).expect("send failed");
1956 }
1957 });
1958
1959 let pager_and_verifier = Arc::new(
1960 BlobPagerAndVerifier::new(&mapping_proxy, &mapper_proxy)
1961 .await
1962 .expect("BlobPagerAndVerifier::new failed"),
1963 );
1964
1965 let hash: [u8; 32] = [0x55; 32];
1966
1967 let verifier1 = pager_and_verifier.clone();
1969 let primary_future = fasync::Task::spawn(async move { verifier1.create_vmo(&hash).await });
1970
1971 open_received_rx.await.expect("open_received_rx failed");
1973 {
1974 let state = pager_and_verifier.cache.state.lock();
1975 assert!(matches!(
1976 state.keys_by_hash.get(&hash).and_then(|k| state.blob_states_by_key.get(k)),
1977 Some(BlobState::Opening { .. })
1978 ));
1979 }
1980
1981 let verifier2 = pager_and_verifier.clone();
1983 let secondary_future =
1984 fasync::Task::spawn(async move { verifier2.create_vmo(&hash).await });
1985
1986 reply_tx.send(()).expect("reply_tx send failed");
1988
1989 let primary_err = primary_future.await.expect_err("expected primary create_vmo to fail");
1992 assert_eq!(primary_err.downcast_ref::<zx::Status>(), Some(&zx::Status::NOT_FOUND));
1993 assert!(secondary_future.await.is_err());
1994
1995 {
1997 let state = pager_and_verifier.cache.state.lock();
1998 assert!(state.keys_by_hash.get(&hash).is_none());
1999 assert!(state.blob_states_by_key.is_empty());
2000 }
2001
2002 drop(pager_and_verifier);
2003 drop(mapping_task);
2004 drop(mapper_task);
2005 }
2006
2007 #[fuchsia::test]
2008 async fn test_register_blob_arrives_before_open_completes() {
2009 let (mapping_proxy, mut mapping_stream) =
2013 fidl::endpoints::create_proxy_and_stream::<fmapping::MappingProviderMarker>();
2014 let (mapper_proxy, mut mapper_stream) =
2015 fidl::endpoints::create_proxy_and_stream::<fblock::MapperMarker>();
2016
2017 let blob_data = vec![0x42u8; TEST_BLOB_SIZE as usize];
2018 let (root, leaf_hashes) =
2019 fuchsia_merkle::MerkleRootBuilder::new(Vec::new()).complete(&blob_data);
2020 let expected_hash: [u8; 32] = root.into();
2021
2022 let mut flat_leaves = Vec::new();
2023 for hash in &leaf_hashes {
2024 flat_leaves.extend_from_slice(hash.as_bytes());
2025 }
2026
2027 let (tx_delivery, rx_delivery) = oneshot::channel();
2028 let (open_key_tx, open_key_rx) = oneshot::channel();
2029 let (resume_open_tx, resume_open_rx) = oneshot::channel();
2030 let (close_tx, close_rx) = oneshot::channel();
2031
2032 let mapping_task = fasync::Task::spawn(async move {
2033 let mut close_tx = Some(close_tx);
2034 let mut open_key_tx = Some(open_key_tx);
2035 let mut resume_open_rx = Some(resume_open_rx);
2036 if let Some(fmapping::MappingProviderRequest::OpenSession { session, responder }) =
2037 mapping_stream.try_next().await.expect("try_next failed")
2038 {
2039 let mapping_vmo = zx::Vmo::create(zx::system_get_page_size().into())
2040 .expect("zx::Vmo::create failed");
2041 responder.send(Ok(mapping_vmo)).expect("send failed");
2042
2043 let mut session_stream = session.into_stream();
2044 while let Some(request) = session_stream.try_next().await.expect("try_next failed")
2045 {
2046 match request {
2047 fmapping::MappingSessionRequest::Open { key, identifier, responder } => {
2048 assert_eq!(identifier, expected_hash);
2049 if let Some(tx) = open_key_tx.take() {
2051 tx.send(key).expect("open_key_tx failed");
2052 }
2053 if let Some(rx) = resume_open_rx.take() {
2054 rx.await.expect("resume_open_rx failed");
2055 }
2056 responder.send(Ok(TEST_BLOB_SIZE)).expect("send failed");
2057 }
2058 fmapping::MappingSessionRequest::Close { key: _, responder } => {
2059 responder.send(Ok(())).expect("send failed");
2060 if let Some(tx) = close_tx.take() {
2061 let _ = tx.send(());
2062 }
2063 }
2064 _ => {}
2065 }
2066 }
2067 }
2068 });
2069
2070 let mapper_task = fasync::Task::spawn(async move {
2071 if let Some(fblock::MapperRequest::OpenSession { delivery_queue, responder, .. }) =
2072 mapper_stream.try_next().await.expect("try_next failed")
2073 {
2074 tx_delivery.send(delivery_queue).expect("send failed");
2075 responder.send(Ok(())).expect("send failed");
2076 }
2077 });
2078
2079 let pager_and_verifier = Arc::new(
2080 BlobPagerAndVerifier::new_with_cache_capacity(&mapping_proxy, &mapper_proxy, 0)
2081 .await
2082 .expect("BlobPagerAndVerifier::new failed"),
2083 );
2084
2085 let delivery_vmo =
2086 rx_delivery.await.expect("rx_delivery wait failed").expect("delivery_vmo was None");
2087 let mut sender = SyncSender::<RawDeliveryCommand>::new(
2088 delivery_vmo
2089 .duplicate_handle(zx::Rights::SAME_RIGHTS)
2090 .expect("duplicate_handle failed"),
2091 zx::system_get_page_size() as usize,
2092 mapping::PENDING_DELIVERY_COMMANDS_CAPACITY,
2093 )
2094 .expect("SyncSender::new failed");
2095
2096 let verifier_clone = pager_and_verifier.clone();
2097 let create_task =
2098 fasync::Task::spawn(async move { verifier_clone.create_vmo(&expected_hash).await });
2099
2100 let key = open_key_rx.await.expect("open_key_rx failed");
2102
2103 let mut payload =
2105 sender.reserve_payload(flat_leaves.len()).expect("reserve_payload failed");
2106 payload.data().copy_from_slice(&flat_leaves);
2107 let raw_cmd: RawDeliveryCommand = DeliveryCommand::RegisterBlob {
2108 key: key as u64,
2109 offset: payload.offset(),
2110 length: flat_leaves.len() as u32,
2111 read_alignment: TARGET_READ_AHEAD_SIZE as u32,
2112 }
2113 .into();
2114 payload.commit(raw_cmd).expect("commit failed");
2115
2116 while !pager_and_verifier.cache.is_merkle_initialized(key) {
2118 fasync::Timer::new(std::time::Duration::from_millis(5)).await;
2119 }
2120
2121 resume_open_tx.send(()).expect("resume_open_tx failed");
2123 let vmo = create_task.await.expect("create_vmo failed");
2124
2125 let chunk = &blob_data[..TARGET_READ_AHEAD_SIZE];
2127 let mut data_payload = sender.reserve_payload(chunk.len()).expect("reserve_payload failed");
2128 data_payload.data().copy_from_slice(chunk);
2129 let data_cmd: RawDeliveryCommand = DeliveryCommand::Data {
2130 key: key as u64,
2131 offset: data_payload.offset(),
2132 length: chunk.len() as u32,
2133 target_offset: 0,
2134 }
2135 .into();
2136 data_payload.commit(data_cmd).expect("commit failed");
2137
2138 let mut read_buf = vec![0u8; TARGET_READ_AHEAD_SIZE];
2139 vmo.read(&mut read_buf, 0).expect("read failed");
2140 assert_eq!(read_buf, chunk);
2141
2142 drop(vmo);
2143 close_rx.await.expect("close_rx failed");
2144
2145 drop(pager_and_verifier);
2146 mapping_task.await;
2147 mapper_task.await;
2148 }
2149
2150 #[fuchsia::test]
2151 async fn test_delivery_register_blob_verification() {
2152 let env = TestEnv::new(TEST_BLOB_SIZE).await;
2153
2154 let _paged_vmo =
2155 env.pager_and_verifier.create_vmo(&env.valid_root).await.expect("create_vmo failed");
2156
2157 let mut sender = SyncSender::<RawDeliveryCommand>::new(
2158 env.delivery_vmo
2159 .duplicate_handle(zx::Rights::SAME_RIGHTS)
2160 .expect("duplicate_handle failed"),
2161 zx::system_get_page_size() as usize, mapping::PENDING_DELIVERY_COMMANDS_CAPACITY,
2163 )
2164 .expect("SyncSender::new failed");
2165
2166 let mut corrupted_leaves = env.valid_leaves.clone();
2168 corrupted_leaves[0] ^= 0xFF;
2169
2170 let mut bad_payload =
2171 sender.reserve_payload(corrupted_leaves.len()).expect("reserve_payload failed");
2172 bad_payload.data().copy_from_slice(&corrupted_leaves);
2173
2174 let bad_raw_cmd: RawDeliveryCommand = DeliveryCommand::RegisterBlob {
2175 key: TEST_VMO_KEY,
2176 offset: bad_payload.offset(),
2177 length: corrupted_leaves.len() as u32,
2178 read_alignment: TARGET_READ_AHEAD_SIZE as u32,
2179 }
2180 .into();
2181 bad_payload.commit(bad_raw_cmd).expect("commit failed");
2182
2183 fasync::Timer::new(std::time::Duration::from_millis(5)).await;
2185
2186 let blob =
2187 env.pager_and_verifier.cache.get_by_key(TEST_VMO_KEY).expect("get_by_key failed");
2188
2189 assert!(blob.merkle_verifier.get().is_none());
2191
2192 let mut payload =
2194 sender.reserve_payload(env.valid_leaves.len()).expect("reserve_payload failed");
2195 payload.data().copy_from_slice(&env.valid_leaves);
2196
2197 let raw_cmd: RawDeliveryCommand = DeliveryCommand::RegisterBlob {
2198 key: TEST_VMO_KEY,
2199 offset: payload.offset(),
2200 length: env.valid_leaves.len() as u32,
2201 read_alignment: TARGET_READ_AHEAD_SIZE as u32,
2202 }
2203 .into();
2204 payload.commit(raw_cmd).expect("commit failed");
2205
2206 while blob.merkle_verifier.get().is_none() {
2207 fasync::Timer::new(std::time::Duration::from_millis(5)).await;
2208 }
2209
2210 drop(_paged_vmo);
2211 env.teardown().await;
2212 }
2213
2214 #[fuchsia::test]
2215 async fn test_register_blob_invalid_commands() {
2216 let env = TestEnv::new(TEST_BLOB_SIZE).await;
2217
2218 let _paged_vmo =
2219 env.pager_and_verifier.create_vmo(&env.valid_root).await.expect("create_vmo failed");
2220
2221 let mut sender = SyncSender::<RawDeliveryCommand>::new(
2222 env.delivery_vmo
2223 .duplicate_handle(zx::Rights::SAME_RIGHTS)
2224 .expect("duplicate_handle failed"),
2225 std::mem::align_of::<RawDeliveryCommand>(),
2226 mapping::PENDING_DELIVERY_COMMANDS_CAPACITY,
2227 )
2228 .expect("SyncSender::new failed");
2229
2230 let blob =
2231 env.pager_and_verifier.cache.get_by_key(TEST_VMO_KEY).expect("get_by_key failed");
2232
2233 let mut invalid_key_payload =
2235 sender.reserve_payload(env.valid_leaves.len()).expect("reserve_payload failed");
2236 invalid_key_payload.data().copy_from_slice(&env.valid_leaves);
2237 let invalid_key_cmd: RawDeliveryCommand = DeliveryCommand::RegisterBlob {
2238 key: 9999 as u64,
2239 offset: invalid_key_payload.offset(),
2240 length: env.valid_leaves.len() as u32,
2241 read_alignment: TARGET_READ_AHEAD_SIZE as u32,
2242 }
2243 .into();
2244 invalid_key_payload.commit(invalid_key_cmd).expect("commit failed");
2245 fasync::Timer::new(std::time::Duration::from_millis(5)).await;
2246 assert!(blob.merkle_verifier.get().is_none());
2247
2248 let oob_payload = sender.reserve_payload(8).expect("reserve_payload failed");
2250 let oob_cmd: RawDeliveryCommand = DeliveryCommand::RegisterBlob {
2251 key: TEST_VMO_KEY,
2252 offset: u32::MAX - 4, length: 8,
2254 read_alignment: TARGET_READ_AHEAD_SIZE as u32,
2255 }
2256 .into();
2257 oob_payload.commit(oob_cmd).expect("commit failed");
2258 fasync::Timer::new(std::time::Duration::from_millis(5)).await;
2259 assert!(blob.merkle_verifier.get().is_none());
2260
2261 let invalid_len_payload = sender.reserve_payload(10).expect("reserve_payload failed");
2263 let invalid_len_cmd: RawDeliveryCommand = DeliveryCommand::RegisterBlob {
2264 key: TEST_VMO_KEY,
2265 offset: invalid_len_payload.offset(),
2266 length: 10,
2267 read_alignment: TARGET_READ_AHEAD_SIZE as u32,
2268 }
2269 .into();
2270 invalid_len_payload.commit(invalid_len_cmd).expect("commit failed");
2271 fasync::Timer::new(std::time::Duration::from_millis(5)).await;
2272 assert!(blob.merkle_verifier.get().is_none());
2273
2274 drop(_paged_vmo);
2275 env.teardown().await;
2276 }
2277
2278 #[fuchsia::test]
2279 async fn test_delivery_data_supplies_pages() {
2280 let env = TestEnv::new(TEST_BLOB_SIZE).await;
2281
2282 let paged_vmo =
2283 env.pager_and_verifier.create_vmo(&env.valid_root).await.expect("create_vmo failed");
2284
2285 let mut sender = SyncSender::<RawDeliveryCommand>::new(
2286 env.delivery_vmo
2287 .duplicate_handle(zx::Rights::SAME_RIGHTS)
2288 .expect("duplicate_handle failed"),
2289 zx::system_get_page_size() as usize, mapping::PENDING_DELIVERY_COMMANDS_CAPACITY,
2291 )
2292 .expect("SyncSender::new failed");
2293
2294 let mut payload =
2295 sender.reserve_payload(env.valid_leaves.len()).expect("reserve_payload failed");
2296 payload.data().copy_from_slice(&env.valid_leaves);
2297 let raw_cmd: RawDeliveryCommand = DeliveryCommand::RegisterBlob {
2298 key: TEST_VMO_KEY,
2299 offset: payload.offset(),
2300 length: env.valid_leaves.len() as u32,
2301 read_alignment: TARGET_READ_AHEAD_SIZE as u32,
2302 }
2303 .into();
2304 payload.commit(raw_cmd).expect("commit failed");
2305
2306 let blob =
2307 env.pager_and_verifier.cache.get_by_key(TEST_VMO_KEY).expect("get_by_key failed");
2308 while blob.merkle_verifier.get().is_none() {
2309 fasync::Timer::new(std::time::Duration::from_millis(5)).await;
2310 }
2311
2312 let test_payload = &env.blob_data[..TARGET_READ_AHEAD_SIZE];
2313
2314 let mut payload =
2315 sender.reserve_payload(test_payload.len()).expect("reserve_payload failed");
2316 payload.data().copy_from_slice(&test_payload);
2317
2318 let cmd: RawDeliveryCommand = DeliveryCommand::Data {
2319 key: TEST_VMO_KEY,
2320 target_offset: 0,
2321 length: test_payload.len() as u32,
2322 offset: payload.offset(),
2323 }
2324 .into();
2325 payload.commit(cmd).expect("commit failed");
2326
2327 let mut read_buf = vec![0u8; TARGET_READ_AHEAD_SIZE];
2328 paged_vmo.read(&mut read_buf, 0).expect("read paged_vmo failed");
2329 assert_eq!(read_buf, test_payload);
2330
2331 drop(paged_vmo);
2332 env.teardown().await;
2333 }
2334
2335 #[fuchsia::test]
2336 async fn test_delivery_data_corrupted() {
2337 let blob_size = TARGET_READ_AHEAD_SIZE as u64;
2340 let env = TestEnv::new(blob_size).await;
2341
2342 let paged_vmo =
2343 env.pager_and_verifier.create_vmo(&env.valid_root).await.expect("create_vmo failed");
2344
2345 let mut sender = SyncSender::<RawDeliveryCommand>::new(
2346 env.delivery_vmo
2347 .duplicate_handle(zx::Rights::SAME_RIGHTS)
2348 .expect("duplicate_handle failed"),
2349 zx::system_get_page_size() as usize,
2350 mapping::PENDING_DELIVERY_COMMANDS_CAPACITY,
2351 )
2352 .expect("SyncSender::new failed");
2353
2354 let mut payload =
2355 sender.reserve_payload(env.valid_leaves.len()).expect("reserve_payload failed");
2356 payload.data().copy_from_slice(&env.valid_leaves);
2357 let raw_cmd: RawDeliveryCommand = DeliveryCommand::RegisterBlob {
2358 key: TEST_VMO_KEY,
2359 offset: payload.offset(),
2360 length: env.valid_leaves.len() as u32,
2361 read_alignment: TARGET_READ_AHEAD_SIZE as u32,
2362 }
2363 .into();
2364 payload.commit(raw_cmd).expect("commit failed");
2365
2366 let blob =
2367 env.pager_and_verifier.cache.get_by_key(TEST_VMO_KEY).expect("get_by_key failed");
2368 while blob.merkle_verifier.get().is_none() {
2369 fasync::Timer::new(std::time::Duration::from_millis(5)).await;
2370 }
2371
2372 let mut corrupted_data = env.blob_data.clone();
2374 corrupted_data[0] ^= 0xFF;
2375
2376 let mut payload =
2377 sender.reserve_payload(corrupted_data.len()).expect("reserve_payload failed");
2378 payload.data().copy_from_slice(&corrupted_data);
2379 let raw_cmd: RawDeliveryCommand = DeliveryCommand::Data {
2380 key: TEST_VMO_KEY,
2381 offset: payload.offset(),
2382 length: corrupted_data.len() as u32,
2383 target_offset: 0,
2384 }
2385 .into();
2386
2387 let page_size = zx::system_get_page_size() as usize;
2390 let mut reader1 =
2391 spawn_reader_expect_error(&paged_vmo, 0, page_size, zx::Status::IO_DATA_INTEGRITY);
2392 let mut reader2 = spawn_reader_expect_error(
2393 &paged_vmo,
2394 page_size as u64,
2395 page_size,
2396 zx::Status::IO_DATA_INTEGRITY,
2397 );
2398
2399 reader1.wait_started().await;
2402 reader2.wait_started().await;
2403 fasync::Timer::new(std::time::Duration::from_millis(5)).await;
2404
2405 payload.commit(raw_cmd).expect("commit failed");
2408
2409 reader1.wait_and_verify().await;
2410 reader2.wait_and_verify().await;
2411
2412 drop(paged_vmo);
2413 env.teardown().await;
2414 }
2415
2416 #[fuchsia::test]
2417 async fn test_delivery_data_corrupted_chunk_preserves_supplied_pages() {
2418 let read_alignment = TARGET_READ_AHEAD_SIZE;
2419 let blob_size = (read_alignment * 2) as u64;
2420 let env = TestEnv::new(blob_size).await;
2421
2422 let paged_vmo =
2423 env.pager_and_verifier.create_vmo(&env.valid_root).await.expect("create_vmo failed");
2424
2425 let mut sender = SyncSender::<RawDeliveryCommand>::new(
2426 env.delivery_vmo
2427 .duplicate_handle(zx::Rights::SAME_RIGHTS)
2428 .expect("duplicate_handle failed"),
2429 zx::system_get_page_size() as usize,
2430 mapping::PENDING_DELIVERY_COMMANDS_CAPACITY,
2431 )
2432 .expect("SyncSender::new failed");
2433
2434 let mut payload =
2435 sender.reserve_payload(env.valid_leaves.len()).expect("reserve_payload failed");
2436 payload.data().copy_from_slice(&env.valid_leaves);
2437 let raw_cmd: RawDeliveryCommand = DeliveryCommand::RegisterBlob {
2438 key: TEST_VMO_KEY,
2439 offset: payload.offset(),
2440 length: env.valid_leaves.len() as u32,
2441 read_alignment: read_alignment as u32,
2442 }
2443 .into();
2444 payload.commit(raw_cmd).expect("commit failed");
2445
2446 let blob =
2447 env.pager_and_verifier.cache.get_by_key(TEST_VMO_KEY).expect("get_by_key failed");
2448 while blob.merkle_verifier.get().is_none() {
2449 fasync::Timer::new(std::time::Duration::from_millis(5)).await;
2450 }
2451
2452 let page_size = zx::system_get_page_size() as usize;
2453
2454 let paged_vmo_clone1 =
2457 paged_vmo.duplicate_handle(zx::Rights::SAME_RIGHTS).expect("duplicate_handle failed");
2458 let (tx1, rx1) = oneshot::channel();
2459 let expected_page0 = env.blob_data[..page_size].to_vec();
2460 let thread1 = std::thread::spawn(move || {
2461 let mut buf = vec![0u8; page_size];
2462 paged_vmo_clone1.read(&mut buf, 0).expect("read should succeed");
2463 assert_eq!(buf, expected_page0);
2464 let _ = tx1.send(());
2465 });
2466 fasync::Timer::new(std::time::Duration::from_millis(5)).await;
2467
2468 let valid_chunk = &env.blob_data[..read_alignment];
2469 let mut payload =
2470 sender.reserve_payload(valid_chunk.len()).expect("reserve_payload failed");
2471 payload.data().copy_from_slice(valid_chunk);
2472 let raw_cmd: RawDeliveryCommand = DeliveryCommand::Data {
2473 key: TEST_VMO_KEY,
2474 offset: payload.offset(),
2475 length: valid_chunk.len() as u32,
2476 target_offset: 0,
2477 }
2478 .into();
2479 payload.commit(raw_cmd).expect("commit failed");
2480
2481 rx1.await.expect("thread1 panicked or hung");
2482 thread1.join().expect("join failed");
2483
2484 let mut reader2 = spawn_reader_expect_error(
2486 &paged_vmo,
2487 read_alignment as u64,
2488 page_size,
2489 zx::Status::IO_DATA_INTEGRITY,
2490 );
2491 reader2.wait_started().await;
2492 fasync::Timer::new(std::time::Duration::from_millis(5)).await;
2493
2494 let mut corrupted_chunk = env.blob_data[read_alignment..].to_vec();
2496 corrupted_chunk[0] ^= 0xFF;
2497
2498 let mut payload =
2499 sender.reserve_payload(corrupted_chunk.len()).expect("reserve_payload failed");
2500 payload.data().copy_from_slice(&corrupted_chunk);
2501 let raw_cmd: RawDeliveryCommand = DeliveryCommand::Data {
2502 key: TEST_VMO_KEY,
2503 offset: payload.offset(),
2504 length: corrupted_chunk.len() as u32,
2505 target_offset: read_alignment as u64,
2506 }
2507 .into();
2508 payload.commit(raw_cmd).expect("commit failed");
2509
2510 reader2.wait_and_verify().await;
2511
2512 let mut buf = vec![0u8; page_size];
2514 paged_vmo.read(&mut buf, 0).expect("previously supplied page 0 must still be readable");
2515 assert_eq!(buf, env.blob_data[..page_size]);
2516
2517 drop(paged_vmo);
2518 env.teardown().await;
2519 }
2520
2521 #[fuchsia::test]
2522 async fn test_delivery_data_corrupted_multi_chunk_read() {
2523 let read_alignment = TARGET_READ_AHEAD_SIZE;
2524 let blob_size = (read_alignment * 3) as u64;
2525 let env = TestEnv::new(blob_size).await;
2526
2527 let paged_vmo =
2528 env.pager_and_verifier.create_vmo(&env.valid_root).await.expect("create_vmo failed");
2529
2530 let mut sender = SyncSender::<RawDeliveryCommand>::new(
2531 env.delivery_vmo
2532 .duplicate_handle(zx::Rights::SAME_RIGHTS)
2533 .expect("duplicate_handle failed"),
2534 zx::system_get_page_size() as usize,
2535 mapping::PENDING_DELIVERY_COMMANDS_CAPACITY,
2536 )
2537 .expect("SyncSender::new failed");
2538
2539 let mut payload =
2540 sender.reserve_payload(env.valid_leaves.len()).expect("reserve_payload failed");
2541 payload.data().copy_from_slice(&env.valid_leaves);
2542 let raw_cmd: RawDeliveryCommand = DeliveryCommand::RegisterBlob {
2543 key: TEST_VMO_KEY,
2544 offset: payload.offset(),
2545 length: env.valid_leaves.len() as u32,
2546 read_alignment: read_alignment as u32,
2547 }
2548 .into();
2549 payload.commit(raw_cmd).expect("commit failed");
2550
2551 let blob =
2552 env.pager_and_verifier.cache.get_by_key(TEST_VMO_KEY).expect("get_by_key failed");
2553 while blob.merkle_verifier.get().is_none() {
2554 fasync::Timer::new(std::time::Duration::from_millis(5)).await;
2555 }
2556
2557 let mut reader = spawn_reader_expect_error(
2563 &paged_vmo,
2564 0,
2565 blob_size as usize,
2566 zx::Status::IO_DATA_INTEGRITY,
2567 );
2568 reader.wait_started().await;
2569 fasync::Timer::new(std::time::Duration::from_millis(5)).await;
2570
2571 let valid_chunk1 = &env.blob_data[..read_alignment];
2573 let mut payload =
2574 sender.reserve_payload(valid_chunk1.len()).expect("reserve_payload failed");
2575 payload.data().copy_from_slice(valid_chunk1);
2576 let raw_cmd: RawDeliveryCommand = DeliveryCommand::Data {
2577 key: TEST_VMO_KEY,
2578 offset: payload.offset(),
2579 length: valid_chunk1.len() as u32,
2580 target_offset: 0,
2581 }
2582 .into();
2583 payload.commit(raw_cmd).expect("commit failed");
2584
2585 fasync::Timer::new(std::time::Duration::from_millis(5)).await;
2588
2589 let mut corrupted_chunk2 = env.blob_data[read_alignment..read_alignment * 2].to_vec();
2591 corrupted_chunk2[0] ^= 0xFF;
2592 let mut payload =
2593 sender.reserve_payload(corrupted_chunk2.len()).expect("reserve_payload failed");
2594 payload.data().copy_from_slice(&corrupted_chunk2);
2595 let raw_cmd: RawDeliveryCommand = DeliveryCommand::Data {
2596 key: TEST_VMO_KEY,
2597 offset: payload.offset(),
2598 length: corrupted_chunk2.len() as u32,
2599 target_offset: read_alignment as u64,
2600 }
2601 .into();
2602 payload.commit(raw_cmd).expect("commit failed");
2603
2604 reader.wait_and_verify().await;
2608
2609 drop(paged_vmo);
2610 env.teardown().await;
2611 }
2612
2613 #[fuchsia::test]
2614 async fn test_delivery_data_uninitialized() {
2615 let env = TestEnv::new(TEST_BLOB_SIZE).await;
2616
2617 let paged_vmo =
2618 env.pager_and_verifier.create_vmo(&env.valid_root).await.expect("create_vmo failed");
2619
2620 let mut sender = SyncSender::<RawDeliveryCommand>::new(
2621 env.delivery_vmo
2622 .duplicate_handle(zx::Rights::SAME_RIGHTS)
2623 .expect("duplicate_handle failed"),
2624 zx::system_get_page_size() as usize,
2625 mapping::PENDING_DELIVERY_COMMANDS_CAPACITY,
2626 )
2627 .expect("SyncSender::new failed");
2628
2629 let mut reader = spawn_reader_expect_error(&paged_vmo, 0, 8192, zx::Status::BAD_STATE);
2631 reader.wait_started().await;
2632 fasync::Timer::new(std::time::Duration::from_millis(5)).await;
2633
2634 let chunk = &env.blob_data[..8192];
2636 let mut payload = sender.reserve_payload(chunk.len()).expect("reserve_payload failed");
2637 payload.data().copy_from_slice(chunk);
2638 let raw_cmd: RawDeliveryCommand = DeliveryCommand::Data {
2639 key: TEST_VMO_KEY,
2640 offset: payload.offset(),
2641 length: chunk.len() as u32,
2642 target_offset: 0,
2643 }
2644 .into();
2645 payload.commit(raw_cmd).expect("commit failed");
2646
2647 reader.wait_and_verify().await;
2648
2649 drop(paged_vmo);
2650 env.teardown().await;
2651 }
2652
2653 #[test_case(TARGET_READ_AHEAD_SIZE; "read_alignment_128k")]
2654 #[test_case(96 * 1024; "read_alignment_96k")]
2655 #[fuchsia::test]
2656 async fn test_delivery_data_multiple_chunks(read_alignment: usize) {
2657 let env = TestEnv::new(TEST_BLOB_SIZE).await;
2658
2659 let paged_vmo =
2660 env.pager_and_verifier.create_vmo(&env.valid_root).await.expect("create_vmo failed");
2661
2662 let mut sender = SyncSender::<RawDeliveryCommand>::new(
2663 env.delivery_vmo
2664 .duplicate_handle(zx::Rights::SAME_RIGHTS)
2665 .expect("duplicate_handle failed"),
2666 zx::system_get_page_size() as usize,
2667 mapping::PENDING_DELIVERY_COMMANDS_CAPACITY,
2668 )
2669 .expect("SyncSender::new failed");
2670
2671 let mut payload =
2672 sender.reserve_payload(env.valid_leaves.len()).expect("reserve_payload failed");
2673 payload.data().copy_from_slice(&env.valid_leaves);
2674 let raw_cmd: RawDeliveryCommand = DeliveryCommand::RegisterBlob {
2675 key: TEST_VMO_KEY,
2676 offset: payload.offset(),
2677 length: env.valid_leaves.len() as u32,
2678 read_alignment: read_alignment as u32,
2679 }
2680 .into();
2681 payload.commit(raw_cmd).expect("commit failed");
2682
2683 let blob =
2684 env.pager_and_verifier.cache.get_by_key(TEST_VMO_KEY).expect("get_by_key failed");
2685 while blob.merkle_verifier.get().is_none() {
2686 fasync::Timer::new(std::time::Duration::from_millis(5)).await;
2687 }
2688
2689 let expected_data = env.blob_data.clone();
2690 let paged_vmo_clone =
2691 paged_vmo.duplicate_handle(zx::Rights::SAME_RIGHTS).expect("duplicate_handle failed");
2692
2693 let (tx, rx) = oneshot::channel();
2694 let thread = std::thread::spawn(move || {
2695 let mut buf = vec![0u8; expected_data.len()];
2696 paged_vmo_clone.read(&mut buf, 0).expect("failed to read from paged vmo");
2697 assert_eq!(buf, expected_data);
2698 let _ = tx.send(());
2699 });
2700
2701 for (i, chunk) in env.blob_data.chunks(read_alignment).enumerate() {
2703 let mut payload = sender.reserve_payload(chunk.len()).expect("reserve_payload failed");
2704 payload.data().copy_from_slice(chunk);
2705 let raw_cmd: RawDeliveryCommand = DeliveryCommand::Data {
2706 key: TEST_VMO_KEY,
2707 offset: payload.offset(),
2708 length: chunk.len() as u32,
2709 target_offset: (i * read_alignment) as u64,
2710 }
2711 .into();
2712 payload.commit(raw_cmd).expect("commit failed");
2713 }
2714
2715 rx.await.expect("reading thread panicked or hung");
2716 thread.join().expect("join failed");
2717
2718 drop(paged_vmo);
2719 env.teardown().await;
2720 }
2721
2722 #[fuchsia::test]
2723 async fn test_delivery_data_unaligned_blob_size() {
2724 let data_size = (TARGET_READ_AHEAD_SIZE + 1024) as u64; let env = TestEnv::new(data_size).await;
2726
2727 let paged_vmo =
2728 env.pager_and_verifier.create_vmo(&env.valid_root).await.expect("Failed to create VMO");
2729
2730 let mut sender = SyncSender::<RawDeliveryCommand>::new(
2731 env.delivery_vmo
2732 .duplicate_handle(zx::Rights::SAME_RIGHTS)
2733 .expect("duplicate_handle failed"),
2734 zx::system_get_page_size() as usize, mapping::PENDING_DELIVERY_COMMANDS_CAPACITY,
2736 )
2737 .expect("SyncSender::new failed");
2738
2739 let mut payload =
2740 sender.reserve_payload(env.valid_leaves.len()).expect("reserve_payload failed");
2741 payload.data().copy_from_slice(&env.valid_leaves);
2742 let raw_cmd: RawDeliveryCommand = DeliveryCommand::RegisterBlob {
2743 key: TEST_VMO_KEY,
2744 offset: payload.offset(),
2745 length: env.valid_leaves.len() as u32,
2746 read_alignment: TARGET_READ_AHEAD_SIZE as u32,
2747 }
2748 .into();
2749 payload.commit(raw_cmd).expect("commit failed");
2750
2751 let blob =
2752 env.pager_and_verifier.cache.get_by_key(TEST_VMO_KEY).expect("get_by_key failed");
2753 while blob.merkle_verifier.get().is_none() {
2754 fasync::Timer::new(std::time::Duration::from_millis(5)).await;
2755 }
2756
2757 let test_payload = env.blob_data.clone();
2758 assert_eq!(test_payload.len(), data_size as usize);
2759
2760 let chunk1 = &test_payload[..TARGET_READ_AHEAD_SIZE];
2761 let mut payload1 = sender.reserve_payload(chunk1.len()).expect("reserve_payload failed");
2762 payload1.data().copy_from_slice(chunk1);
2763 let off1 = payload1.offset();
2764 payload1
2765 .commit(
2766 DeliveryCommand::Data {
2767 key: TEST_VMO_KEY,
2768 target_offset: 0,
2769 length: chunk1.len() as u32,
2770 offset: off1,
2771 }
2772 .into(),
2773 )
2774 .expect("commit failed");
2775
2776 let chunk2 = &test_payload[TARGET_READ_AHEAD_SIZE..];
2777 let page_size = zx::system_get_page_size() as usize;
2778 let chunk2_len_aligned = chunk2.len().div_ceil(page_size) * page_size;
2779 let mut payload2 =
2780 sender.reserve_payload(chunk2_len_aligned).expect("reserve_payload failed");
2781 let payload2_data = payload2.data();
2782 payload2_data.subslice_mut(0..chunk2.len()).copy_from_slice(chunk2);
2783 payload2_data.subslice_mut(chunk2.len()..chunk2_len_aligned).fill(0);
2784
2785 let off2 = payload2.offset();
2786 payload2
2787 .commit(
2788 DeliveryCommand::Data {
2789 key: TEST_VMO_KEY,
2790 target_offset: TARGET_READ_AHEAD_SIZE as u64,
2791 length: chunk2_len_aligned as u32,
2792 offset: off2,
2793 }
2794 .into(),
2795 )
2796 .expect("commit failed");
2797
2798 let mut read_buf = vec![0u8; data_size as usize];
2799 paged_vmo.read(&mut read_buf, 0).expect("read paged_vmo failed");
2800 assert_eq!(read_buf, test_payload);
2801
2802 let page_size = zx::system_get_page_size() as u64;
2803 let out_of_bounds_offset = data_size.div_ceil(page_size) * page_size;
2805 let mut read_buf = vec![0u8; 1];
2807 let res = paged_vmo.read(&mut read_buf, out_of_bounds_offset);
2808 assert_eq!(res, Err(zx::Status::OUT_OF_RANGE));
2809
2810 drop(paged_vmo);
2811 env.teardown().await;
2812 }
2813
2814 #[fuchsia::test]
2815 async fn test_open_child_session() {
2816 let (mapping_proxy, mut mapping_stream) =
2817 fidl::endpoints::create_proxy_and_stream::<fmapping::MappingProviderMarker>();
2818 let (mapper_proxy, mut mapper_stream) =
2819 fidl::endpoints::create_proxy_and_stream::<fblock::MapperMarker>();
2820
2821 let _mapping_task = fasync::Task::spawn(async move {
2822 if let Some(fmapping::MappingProviderRequest::OpenSession { session, responder }) =
2823 mapping_stream.try_next().await.expect("try_next failed")
2824 {
2825 let mapping_vmo = zx::Vmo::create(zx::system_get_page_size().into())
2826 .expect("zx::Vmo::create failed");
2827 responder.send(Ok(mapping_vmo)).expect("send failed");
2828
2829 let mut session_stream = session.into_stream();
2830 while let Some(request) = session_stream.try_next().await.expect("try_next failed")
2831 {
2832 match request {
2833 fmapping::MappingSessionRequest::Open { responder, .. } => {
2834 responder.send(Ok(8192)).expect("send failed");
2835 }
2836 fmapping::MappingSessionRequest::Close { responder, .. } => {
2837 responder.send(Ok(())).expect("send failed");
2838 }
2839 _ => {}
2840 }
2841 }
2842 }
2843 });
2844
2845 let (child_key_tx, child_key_rx) = oneshot::channel();
2846 let _mapper_task = fasync::Task::spawn(async move {
2847 if let Some(fblock::MapperRequest::OpenSession { session, responder, .. }) =
2848 mapper_stream.try_next().await.expect("try_next failed")
2849 {
2850 responder.send(Ok(())).expect("send failed");
2851 let mut session_stream = session.into_stream();
2852 if let Some(fblock::MapperSessionRequest::OpenChildSession {
2853 parent_key,
2854 port,
2855 delivery_queue,
2856 responder,
2857 ..
2858 }) = session_stream.try_next().await.expect("try_next failed")
2859 {
2860 assert!(port.is_some());
2861 assert!(delivery_queue.is_none());
2862 child_key_tx.send(parent_key).expect("send failed");
2863 responder.send(Ok(())).expect("send failed");
2864 }
2865 }
2866 });
2867
2868 let pager_and_verifier = Arc::new(
2869 BlobPagerAndVerifier::new(&mapping_proxy, &mapper_proxy)
2870 .await
2871 .expect("BlobPagerAndVerifier::new failed"),
2872 );
2873
2874 let hash: [u8; 32] = [0x55; 32];
2875 let unknown_hash: [u8; 32] = [0x99; 32];
2876
2877 let (_client, server) = fidl::endpoints::create_endpoints::<fblock::MapperSessionMarker>();
2879 let mapping_vmo = zx::Vmo::create(4096).unwrap();
2880 assert_eq!(
2881 pager_and_verifier.open_child_session(&unknown_hash, mapping_vmo, server).await,
2882 Err(zx::Status::NOT_FOUND)
2883 );
2884
2885 let vmo = pager_and_verifier.create_vmo(&hash).await.expect("create_vmo failed");
2887 let (client_proxy, server) = fidl::endpoints::create_proxy::<fblock::MapperSessionMarker>();
2888 let mapping_vmo = zx::Vmo::create(4096).unwrap();
2889 pager_and_verifier
2890 .open_child_session(&hash, mapping_vmo, server)
2891 .await
2892 .expect("open_child_session failed");
2893
2894 let parent_key = child_key_rx.await.expect("failed to receive parent_key");
2895 assert_eq!(parent_key, TEST_VMO_KEY);
2896
2897 let (child_key, _child_vmo) = client_proxy
2898 .create_vmo(4096, fblock::CreateVmoOptions::empty())
2899 .await
2900 .expect("create_vmo fidl failed")
2901 .expect("create_vmo returned error");
2902 assert!(pager_and_verifier.cache.get_child_vmo(child_key).is_some());
2903
2904 client_proxy.close_vmo(child_key).expect("close_vmo fidl failed");
2905 while pager_and_verifier.cache.get_child_vmo(child_key).is_some() {
2906 fasync::Timer::new(std::time::Duration::from_millis(5)).await;
2907 }
2908 drop(vmo);
2909 }
2910
2911 #[fuchsia::test]
2912 async fn test_deliver_child_pages() {
2913 let env = TestEnv::new(32 * 1024).await;
2914 let _parent_vmo =
2915 env.pager_and_verifier.create_vmo(&env.valid_root).await.expect("create_vmo failed");
2916
2917 let mut sender = SyncSender::<RawDeliveryCommand>::new(
2918 env.delivery_vmo
2919 .duplicate_handle(zx::Rights::SAME_RIGHTS)
2920 .expect("duplicate_handle failed"),
2921 zx::system_get_page_size() as usize,
2922 mapping::PENDING_DELIVERY_COMMANDS_CAPACITY,
2923 )
2924 .expect("SyncSender::new failed");
2925
2926 let mut payload =
2928 sender.reserve_payload(env.valid_leaves.len()).expect("reserve_payload failed");
2929 payload.data().copy_from_slice(&env.valid_leaves);
2930 let off = payload.offset();
2931 payload
2932 .commit(
2933 DeliveryCommand::RegisterBlob {
2934 key: TEST_VMO_KEY,
2935 offset: off,
2936 length: env.valid_leaves.len() as u32,
2937 read_alignment: 32 * 1024,
2938 }
2939 .into(),
2940 )
2941 .expect("commit failed");
2942
2943 let blob =
2944 env.pager_and_verifier.cache.get_by_key(TEST_VMO_KEY).expect("get_by_key failed");
2945 while blob.merkle_verifier.get().is_none() {
2946 fasync::Timer::new(std::time::Duration::from_millis(5)).await;
2947 }
2948
2949 let child_port = zx::Port::create();
2950 let child_key = 77u64;
2951 let child_vmo = env
2952 .pager_and_verifier
2953 .cache
2954 .pager
2955 .create_vmo(zx::VmoOptions::empty(), &child_port, child_key, 100)
2956 .unwrap();
2957 env.pager_and_verifier.cache.register_child_vmo(
2958 TEST_VMO_KEY,
2959 child_key,
2960 child_vmo.duplicate_handle(zx::Rights::SAME_RIGHTS).unwrap(),
2961 100,
2962 );
2963
2964 let mut payload = sender.reserve_payload(32 * 1024).expect("reserve_payload failed");
2965 payload.data().copy_from_slice(&env.blob_data);
2966 let off = payload.offset();
2967 payload
2968 .commit(
2969 DeliveryCommand::ChildData {
2970 parent_offset: 0,
2971 offset: off,
2972 length: 32 * 1024,
2973 child_key,
2974 child_target_offset: 0,
2975 in_chunk_offset: 4096,
2976 child_length: 4096,
2977 }
2978 .into(),
2979 )
2980 .expect("commit failed");
2981
2982 let mut buf = vec![0u8; 4096];
2983 child_vmo.read(&mut buf, 0).expect("read child_vmo");
2984 assert_eq!(&buf[..100], &[0x42u8; 100]);
2985 assert_eq!(&buf[100..], &[0u8; 3996]);
2986
2987 env.teardown().await;
2988 }
2989
2990 #[fuchsia::test]
2991 async fn test_deliver_child_inline_tail_from_parent_vmo() {
2992 let env = TestEnv::new(32 * 1024).await;
2993 let _parent_vmo =
2994 env.pager_and_verifier.create_vmo(&env.valid_root).await.expect("create_vmo failed");
2995
2996 let mut sender = SyncSender::<RawDeliveryCommand>::new(
2997 env.delivery_vmo
2998 .duplicate_handle(zx::Rights::SAME_RIGHTS)
2999 .expect("duplicate_handle failed"),
3000 zx::system_get_page_size() as usize,
3001 mapping::PENDING_DELIVERY_COMMANDS_CAPACITY,
3002 )
3003 .expect("SyncSender::new failed");
3004
3005 let mut payload =
3007 sender.reserve_payload(env.valid_leaves.len()).expect("reserve_payload failed");
3008 payload.data().copy_from_slice(&env.valid_leaves);
3009 let off = payload.offset();
3010 payload
3011 .commit(
3012 DeliveryCommand::RegisterBlob {
3013 key: TEST_VMO_KEY,
3014 offset: off,
3015 length: env.valid_leaves.len() as u32,
3016 read_alignment: 32 * 1024,
3017 }
3018 .into(),
3019 )
3020 .expect("commit failed");
3021
3022 let blob =
3023 env.pager_and_verifier.cache.get_by_key(TEST_VMO_KEY).expect("get_by_key failed");
3024 while blob.merkle_verifier.get().is_none() {
3025 fasync::Timer::new(std::time::Duration::from_millis(5)).await;
3026 }
3027
3028 let child_key = 77u64;
3030 let child_port = zx::Port::create();
3031 let child_vmo = env
3032 .pager_and_verifier
3033 .cache
3034 .pager
3035 .create_vmo(zx::VmoOptions::empty(), &child_port, child_key, 100)
3036 .unwrap();
3037 env.pager_and_verifier.cache.register_child_vmo(
3038 TEST_VMO_KEY,
3039 child_key,
3040 child_vmo.duplicate_handle(zx::Rights::SAME_RIGHTS).unwrap(),
3041 100,
3042 );
3043
3044 sender
3048 .reserve_payload(0)
3049 .expect("reserve_payload failed")
3050 .commit(
3051 DeliveryCommand::ChildInlineTail {
3052 parent_byte_offset: 4096 + 500,
3053 child_key,
3054 child_target_offset: 0,
3055 tail_length: 100,
3056 }
3057 .into(),
3058 )
3059 .expect("commit failed");
3060
3061 let mut payload = sender.reserve_payload(32 * 1024).expect("reserve_payload failed");
3063 payload.data().copy_from_slice(&env.blob_data);
3064 let off = payload.offset();
3065 payload
3066 .commit(
3067 DeliveryCommand::Data {
3068 key: TEST_VMO_KEY,
3069 target_offset: 0,
3070 offset: off,
3071 length: 32 * 1024,
3072 }
3073 .into(),
3074 )
3075 .expect("commit failed");
3076
3077 let mut buf = vec![0u8; 4096];
3078 child_vmo.read(&mut buf, 0).expect("read child_vmo");
3079 assert_eq!(&buf[..100], &[0x42u8; 100]);
3080 assert_eq!(&buf[100..], &[0u8; 3996]);
3081
3082 env.teardown().await;
3083 }
3084
3085 #[fuchsia::test]
3086 async fn test_get_file_mapper_handler() {
3087 use vfs::ToObjectRequest as _;
3088 use vfs::file::StreamIoConnection;
3089
3090 let (mapping_proxy, mut mapping_stream) =
3091 fidl::endpoints::create_proxy_and_stream::<fmapping::MappingProviderMarker>();
3092 let (mapper_proxy, mut mapper_stream) =
3093 fidl::endpoints::create_proxy_and_stream::<fblock::MapperMarker>();
3094
3095 let _mapping_task = fasync::Task::spawn(async move {
3096 if let Some(fmapping::MappingProviderRequest::OpenSession { session, responder }) =
3097 mapping_stream.try_next().await.expect("try_next failed")
3098 {
3099 let mapping_vmo = zx::Vmo::create(zx::system_get_page_size().into())
3100 .expect("zx::Vmo::create failed");
3101 responder.send(Ok(mapping_vmo)).expect("send failed");
3102
3103 let mut session_stream = session.into_stream();
3104 while let Some(request) = session_stream.try_next().await.expect("try_next failed")
3105 {
3106 match request {
3107 fmapping::MappingSessionRequest::Open { responder, .. } => {
3108 responder.send(Ok(8192)).expect("send failed");
3109 }
3110 fmapping::MappingSessionRequest::Close { responder, .. } => {
3111 responder.send(Ok(())).expect("send failed");
3112 }
3113 _ => {}
3114 }
3115 }
3116 }
3117 });
3118
3119 let (child_key_tx, child_key_rx) = oneshot::channel();
3120 let _mapper_task = fasync::Task::spawn(async move {
3121 if let Some(fblock::MapperRequest::OpenSession { session, responder, .. }) =
3122 mapper_stream.try_next().await.expect("try_next failed")
3123 {
3124 responder.send(Ok(())).expect("send failed");
3125 let mut session_stream = session.into_stream();
3126 if let Some(fblock::MapperSessionRequest::OpenChildSession {
3127 parent_key,
3128 responder,
3129 ..
3130 }) = session_stream.try_next().await.expect("try_next failed")
3131 {
3132 child_key_tx.send(parent_key).expect("send failed");
3133 responder.send(Ok(())).expect("send failed");
3134 }
3135 }
3136 });
3137
3138 let pager_and_verifier = Arc::new(
3139 BlobPagerAndVerifier::new(&mapping_proxy, &mapper_proxy)
3140 .await
3141 .expect("BlobPagerAndVerifier::new failed"),
3142 );
3143
3144 let hash: [u8; 32] = [0x66; 32];
3145 let vmo = pager_and_verifier.create_vmo(&hash).await.expect("create_vmo failed");
3146
3147 let scope = vfs::execution_scope::ExecutionScope::new();
3148 let (file_mapper, file_mapper_server) =
3149 fidl::endpoints::create_proxy::<fmapping::FileMapperMarker>();
3150 fidl_fuchsia_io::Flags::PROTOCOL_SERVICE
3151 .to_object_request(file_mapper_server.into_channel())
3152 .handle(|object_request| {
3153 vfs::service::serve(
3154 pager_and_verifier.get_file_mapper_handler(scope.clone()),
3155 scope.clone(),
3156 &fidl_fuchsia_io::Flags::PROTOCOL_SERVICE,
3157 object_request,
3158 )
3159 });
3160
3161 let unregistered_token = zx::Event::create();
3163 let (_client, server) = fidl::endpoints::create_endpoints::<fblock::MapperSessionMarker>();
3164 assert_eq!(
3165 file_mapper
3166 .open_session(unregistered_token, zx::Vmo::create(4096).unwrap(), server)
3167 .await
3168 .unwrap(),
3169 Err(zx::Status::NOT_FOUND.into_raw())
3170 );
3171
3172 let vmo_blob =
3174 vmo_blob::VmoBlob::new(vmo.duplicate_handle(zx::Rights::SAME_RIGHTS).unwrap(), hash);
3175 let (no_read_proxy, no_read_server) =
3176 fidl::endpoints::create_proxy::<fidl_fuchsia_io::FileMarker>();
3177 let no_read_flags = fidl_fuchsia_io::Flags::PROTOCOL_FILE;
3178 let scope_clone = scope.clone();
3179 let vmo_blob_clone = vmo_blob.clone();
3180 scope.spawn(no_read_flags.to_object_request(no_read_server).handle_async(
3181 async move |object_request| {
3182 object_request
3183 .create_connection::<StreamIoConnection<_>, _>(
3184 scope_clone,
3185 vmo_blob_clone,
3186 no_read_flags,
3187 )
3188 .await
3189 },
3190 ));
3191 let no_read_token = zx::Event::from(
3192 no_read_proxy.get_token().await.unwrap().map_err(zx::Status::err_from_raw).unwrap(),
3193 );
3194 let (_client, server) = fidl::endpoints::create_endpoints::<fblock::MapperSessionMarker>();
3195 assert_eq!(
3196 file_mapper
3197 .open_session(no_read_token, zx::Vmo::create(4096).unwrap(), server)
3198 .await
3199 .unwrap(),
3200 Err(zx::Status::ACCESS_DENIED.into_raw())
3201 );
3202
3203 let other_file = vfs::file::vmo::read_only(b"not a vmo blob");
3205 let (other_proxy, other_server) =
3206 fidl::endpoints::create_proxy::<fidl_fuchsia_io::FileMarker>();
3207 fidl_fuchsia_io::PERM_READABLE.to_object_request(other_server).handle(|object_request| {
3208 vfs::file::serve(
3209 other_file,
3210 scope.clone(),
3211 &fidl_fuchsia_io::PERM_READABLE,
3212 object_request,
3213 )
3214 });
3215 let other_token = zx::Event::from(
3216 other_proxy.get_token().await.unwrap().map_err(zx::Status::err_from_raw).unwrap(),
3217 );
3218 let (_client, server) = fidl::endpoints::create_endpoints::<fblock::MapperSessionMarker>();
3219 assert_eq!(
3220 file_mapper
3221 .open_session(other_token, zx::Vmo::create(4096).unwrap(), server)
3222 .await
3223 .unwrap(),
3224 Err(zx::Status::INVALID_ARGS.into_raw())
3225 );
3226
3227 let (read_proxy, read_server) =
3229 fidl::endpoints::create_proxy::<fidl_fuchsia_io::FileMarker>();
3230 let read_flags = fidl_fuchsia_io::PERM_READABLE;
3231 let scope_clone = scope.clone();
3232 scope.spawn(read_flags.to_object_request(read_server).handle_async(
3233 async move |object_request| {
3234 object_request
3235 .create_connection::<StreamIoConnection<_>, _>(
3236 scope_clone,
3237 vmo_blob,
3238 read_flags,
3239 )
3240 .await
3241 },
3242 ));
3243 let valid_token = zx::Event::from(
3244 read_proxy.get_token().await.unwrap().map_err(zx::Status::err_from_raw).unwrap(),
3245 );
3246 let (client_proxy, server) = fidl::endpoints::create_proxy::<fblock::MapperSessionMarker>();
3247 file_mapper
3248 .open_session(valid_token, zx::Vmo::create(4096).unwrap(), server)
3249 .await
3250 .unwrap()
3251 .map_err(zx::Status::err_from_raw)
3252 .expect("open_session should succeed");
3253
3254 let parent_key = child_key_rx.await.expect("failed to receive parent_key");
3255 assert_eq!(parent_key, TEST_VMO_KEY);
3256
3257 let (child_key, _child_vmo) = client_proxy
3258 .create_vmo(4096, fblock::CreateVmoOptions::empty())
3259 .await
3260 .expect("create_vmo fidl failed")
3261 .expect("create_vmo returned error");
3262 assert!(pager_and_verifier.cache.get_child_vmo(child_key).is_some());
3263
3264 drop(vmo);
3265 }
3266
3267 #[fuchsia::test]
3268 async fn test_multiple_child_sessions_same_parent_blob() {
3269 let blob_size = 32 * 1024usize;
3270 let mut blob_data = vec![0u8; blob_size];
3271 blob_data[4096..8192].fill(0xAA);
3272 blob_data[8192..12288].fill(0xBB);
3273 let (root, leaf_hashes) =
3274 fuchsia_merkle::MerkleRootBuilder::new(Vec::new()).complete(&blob_data);
3275 let hash: [u8; 32] = root.into();
3276 let mut valid_leaves = Vec::new();
3277 for leaf in &leaf_hashes {
3278 valid_leaves.extend_from_slice(leaf.as_bytes());
3279 }
3280
3281 let (mapping_proxy, mut mapping_stream) =
3282 fidl::endpoints::create_proxy_and_stream::<fmapping::MappingProviderMarker>();
3283 let (mapper_proxy, mut mapper_stream) =
3284 fidl::endpoints::create_proxy_and_stream::<fblock::MapperMarker>();
3285
3286 let _mapping_task = fasync::Task::spawn(async move {
3287 if let Some(fmapping::MappingProviderRequest::OpenSession { session, responder }) =
3288 mapping_stream.try_next().await.expect("try_next failed")
3289 {
3290 let mapping_vmo = zx::Vmo::create(zx::system_get_page_size().into())
3291 .expect("zx::Vmo::create failed");
3292 responder.send(Ok(mapping_vmo)).expect("send failed");
3293
3294 let mut session_stream = session.into_stream();
3295 while let Some(request) = session_stream.try_next().await.expect("try_next failed")
3296 {
3297 match request {
3298 fmapping::MappingSessionRequest::Open { responder, .. } => {
3299 responder.send(Ok(blob_size as u64)).expect("send failed");
3300 }
3301 fmapping::MappingSessionRequest::Close { responder, .. } => {
3302 responder.send(Ok(())).expect("send failed");
3303 }
3304 _ => {}
3305 }
3306 }
3307 }
3308 });
3309
3310 let (tx_delivery, rx_delivery) = oneshot::channel();
3311 let (session_keys_tx, mut session_keys_rx) = futures::channel::mpsc::unbounded();
3312 let _mapper_task = fasync::Task::spawn(async move {
3313 if let Some(fblock::MapperRequest::OpenSession {
3314 session,
3315 delivery_queue,
3316 responder,
3317 ..
3318 }) = mapper_stream.try_next().await.expect("try_next failed")
3319 {
3320 tx_delivery.send(delivery_queue).expect("send failed");
3321 responder.send(Ok(())).expect("send failed");
3322 let mut session_stream = session.into_stream();
3323 while let Some(request) = session_stream.try_next().await.expect("try_next failed")
3324 {
3325 if let fblock::MapperSessionRequest::OpenChildSession {
3326 parent_key,
3327 responder,
3328 ..
3329 } = request
3330 {
3331 session_keys_tx.unbounded_send(parent_key).expect("unbounded_send failed");
3332 responder.send(Ok(())).expect("send failed");
3333 }
3334 }
3335 }
3336 });
3337
3338 let pager_and_verifier = Arc::new(
3339 BlobPagerAndVerifier::new(&mapping_proxy, &mapper_proxy)
3340 .await
3341 .expect("BlobPagerAndVerifier::new failed"),
3342 );
3343 let delivery_vmo =
3344 rx_delivery.await.expect("rx_delivery wait failed").expect("delivery_vmo was None");
3345 let _parent_vmo = pager_and_verifier.create_vmo(&hash).await.expect("create_vmo failed");
3346
3347 let mut sender = SyncSender::<RawDeliveryCommand>::new(
3348 delivery_vmo,
3349 zx::system_get_page_size() as usize,
3350 mapping::PENDING_DELIVERY_COMMANDS_CAPACITY,
3351 )
3352 .expect("SyncSender::new failed");
3353
3354 let mut payload =
3355 sender.reserve_payload(valid_leaves.len()).expect("reserve_payload failed");
3356 payload.data().copy_from_slice(&valid_leaves);
3357 let off = payload.offset();
3358 payload
3359 .commit(
3360 DeliveryCommand::RegisterBlob {
3361 key: TEST_VMO_KEY,
3362 offset: off,
3363 length: valid_leaves.len() as u32,
3364 read_alignment: blob_size as u32,
3365 }
3366 .into(),
3367 )
3368 .expect("commit failed");
3369
3370 let blob = pager_and_verifier.cache.get_by_key(TEST_VMO_KEY).expect("get_by_key failed");
3371 while blob.merkle_verifier.get().is_none() {
3372 fasync::Timer::new(std::time::Duration::from_millis(5)).await;
3373 }
3374
3375 let (session1_proxy, session1_server) =
3377 fidl::endpoints::create_proxy::<fblock::MapperSessionMarker>();
3378 pager_and_verifier
3379 .open_child_session(&hash, zx::Vmo::create(4096).expect("Vmo::create"), session1_server)
3380 .await
3381 .expect("open_child_session 1 failed");
3382 let session1_parent_key =
3383 futures::StreamExt::next(&mut session_keys_rx).await.expect("session1_key missing");
3384
3385 let (session2_proxy, session2_server) =
3386 fidl::endpoints::create_proxy::<fblock::MapperSessionMarker>();
3387 pager_and_verifier
3388 .open_child_session(&hash, zx::Vmo::create(4096).expect("Vmo::create"), session2_server)
3389 .await
3390 .expect("open_child_session 2 failed");
3391 let session2_parent_key =
3392 futures::StreamExt::next(&mut session_keys_rx).await.expect("session2_key missing");
3393
3394 assert_eq!(session1_parent_key, TEST_VMO_KEY);
3395 assert_eq!(session2_parent_key, TEST_VMO_KEY);
3396
3397 let (child_key1, vmo1) = session1_proxy
3399 .create_vmo(4096, fblock::CreateVmoOptions::empty())
3400 .await
3401 .expect("session1 create_vmo fidl failed")
3402 .expect("session1 create_vmo failed");
3403 let (child_key2, vmo2) = session2_proxy
3404 .create_vmo(4096, fblock::CreateVmoOptions::empty())
3405 .await
3406 .expect("session2 create_vmo fidl failed")
3407 .expect("session2 create_vmo failed");
3408 assert_ne!(child_key1, child_key2);
3409
3410 let mut payload1 = sender.reserve_payload(blob_size).expect("reserve_payload failed");
3412 payload1.data().copy_from_slice(&blob_data);
3413 let off1 = payload1.offset();
3414 payload1
3415 .commit(
3416 DeliveryCommand::ChildData {
3417 parent_offset: 0,
3418 offset: off1,
3419 length: blob_size as u32,
3420 child_key: child_key1,
3421 child_target_offset: 0,
3422 in_chunk_offset: 4096,
3423 child_length: 4096,
3424 }
3425 .into(),
3426 )
3427 .expect("commit 1 failed");
3428
3429 let mut payload2 = sender.reserve_payload(blob_size).expect("reserve_payload failed");
3430 payload2.data().copy_from_slice(&blob_data);
3431 let off2 = payload2.offset();
3432 payload2
3433 .commit(
3434 DeliveryCommand::ChildData {
3435 parent_offset: 0,
3436 offset: off2,
3437 length: blob_size as u32,
3438 child_key: child_key2,
3439 child_target_offset: 0,
3440 in_chunk_offset: 8192,
3441 child_length: 4096,
3442 }
3443 .into(),
3444 )
3445 .expect("commit 2 failed");
3446
3447 let mut buf1 = vec![0u8; 4096];
3448 vmo1.read(&mut buf1, 0).expect("vmo1 read failed");
3449 assert_eq!(buf1, vec![0xAAu8; 4096]);
3450
3451 let mut buf2 = vec![0u8; 4096];
3452 vmo2.read(&mut buf2, 0).expect("vmo2 read failed");
3453 assert_eq!(buf2, vec![0xBBu8; 4096]);
3454
3455 session2_proxy.close_vmo(child_key1).expect("close_vmo failed");
3457 session2_proxy.close_vmo(child_key2).expect("close_vmo failed");
3459 while pager_and_verifier.cache.get_child_vmo(child_key2).is_some() {
3460 fasync::Timer::new(std::time::Duration::from_millis(5)).await;
3461 }
3462 assert!(pager_and_verifier.cache.get_child_vmo(child_key1).is_some());
3463 }
3464}