1mod delivery;
40mod profile;
41
42pub use delivery::{
43 DeliveryQueueProcessor, DeliveryQueueProvider, TestVmoProvider, UnverifiedPages,
44};
45pub use profile::ProfileRecording;
46
47use anyhow::{Context, Error, anyhow, bail};
48use event_listener as _;
49use fidl_fuchsia_storage_block as fblock;
50use fidl_fuchsia_storage_mapping as fmapping;
51use fuchsia_async as fasync;
52use fuchsia_hash::{HASH_SIZE, Hash};
53use fuchsia_merkle::{MerkleVerifier, ReadSizedMerkleVerifier};
54use fuchsia_sync::Mutex;
55use std::collections::{HashMap, HashSet, hash_map};
56use std::ops::Range;
57use std::sync::{Arc, OnceLock, Weak};
58use storage_ptr_slice::PtrByteSlice;
59use zx;
60
61struct ZeroChildrenReceiver {
64 blob: OnceLock<Weak<CachedBlob>>,
65}
66
67impl fasync::PacketReceiver for ZeroChildrenReceiver {
68 fn receive_packet(&self, packet: zx::Packet) {
69 if let zx::PacketContents::SignalOne(signals) = packet.contents() {
70 if signals.observed().contains(zx::Signals::VMO_ZERO_CHILDREN) {
71 if let Some(cached_blob) = self.blob.get().and_then(|w| w.upgrade()) {
72 if let Some(cache) = cached_blob.cache.upgrade() {
73 cache.on_zero_children(&cached_blob);
74 }
75 }
76 }
77 }
78 }
79}
80
81struct CachedBlob {
89 vmo: zx::Vmo,
92 root_hash: [u8; 32],
94 cache: Weak<Cache>,
97 vmo_key: u64,
100 len: u64,
102 registration: fasync::ReceiverRegistration<ZeroChildrenReceiver>,
104 merkle_verifier: OnceLock<ReadSizedMerkleVerifier>,
106}
107
108impl CachedBlob {
109 fn create_child(&self) -> Result<zx::Vmo, zx::Status> {
110 self.vmo.create_child(zx::VmoChildOptions::REFERENCE | zx::VmoChildOptions::NO_WRITE, 0, 0)
111 }
112
113 fn wait_for_zero_children(&self) {
114 let _ = self.vmo.wait_async(
115 fasync::EHandle::local().port(),
116 self.registration.key(),
117 zx::Signals::VMO_ZERO_CHILDREN,
118 zx::WaitAsyncOpts::empty(),
119 );
120 }
121}
122
123impl Drop for CachedBlob {
124 fn drop(&mut self) {
125 if let Some(cache) = self.cache.upgrade() {
126 let session = cache.mapping_session.clone();
127 let vmo_key = self.vmo_key;
128 cache.scope.spawn(async move {
129 let _ = session.close(vmo_key).await;
130 });
131 }
132 }
133}
134
135enum BlobState {
136 Opening {
140 root_hash: [u8; 32],
141 event: Arc<event_listener::Event>,
142 verifier: Option<ReadSizedMerkleVerifier>,
143 },
144 Ready(Arc<CachedBlob>),
147}
148
149pub(crate) struct ActiveRecording {
150 pub(crate) opened_hashes: HashSet<Hash>,
152 pub(crate) hash_by_key: HashMap<u64, Hash>,
160}
161
162struct CacheState {
163 next_key: u64,
164 keys_by_hash: HashMap<[u8; 32], u64>,
166 blob_states_by_key: HashMap<u64, BlobState>,
167 recording: Option<ActiveRecording>,
168}
169
170impl Default for CacheState {
171 fn default() -> Self {
172 Self {
173 next_key: 1,
174 keys_by_hash: HashMap::default(),
175 blob_states_by_key: HashMap::default(),
176 recording: None,
177 }
178 }
179}
180
181impl CacheState {
182 fn generate_key(&mut self) -> u64 {
183 let key = self.next_key;
184 self.next_key += 1;
185 key
186 }
187}
188
189struct PendingEntry {
195 cache: Arc<Cache>,
196 key: u64,
197}
198
199impl PendingEntry {
200 fn key(&self) -> u64 {
201 self.key
202 }
203
204 fn commit(self, vmo: zx::Vmo, size: u64) -> Arc<CachedBlob> {
207 let zero_children_receiver = ZeroChildrenReceiver { blob: OnceLock::new() };
208 let zero_children_registration =
209 fasync::EHandle::local().register_receiver(zero_children_receiver);
210
211 let (cached, event) = {
212 let mut state = self.cache.state.lock();
213 let (root_hash, event, verifier) = match state.blob_states_by_key.remove(&self.key) {
214 Some(BlobState::Opening { root_hash, event, verifier }) => {
215 (root_hash, event, verifier)
216 }
217 _ => {
218 unreachable!("Blob for key {} was unexpectedly not in Opening state", self.key)
219 }
220 };
221
222 let merkle_verifier = OnceLock::new();
223 if let Some(verifier) = verifier {
224 let _ = merkle_verifier.set(verifier);
225 }
226
227 let cached = Arc::new(CachedBlob {
228 vmo,
229 root_hash,
230 cache: Arc::downgrade(&self.cache),
231 vmo_key: self.key,
232 len: size,
233 registration: zero_children_registration,
234 merkle_verifier,
235 });
236
237 cached
238 .registration
239 .receiver()
240 .blob
241 .set(Arc::downgrade(&cached))
242 .expect("Failed to bind CachedBlob to ZeroChildrenReceiver: already initialized");
243
244 state.blob_states_by_key.insert(self.key, BlobState::Ready(cached.clone()));
245 if let Some(recording) = state.recording.as_mut() {
246 recording.hash_by_key.insert(self.key, Hash::from(root_hash));
247 }
248
249 (cached, event)
250 };
251
252 cached.wait_for_zero_children();
253 event.notify(usize::MAX);
254 cached
255 }
256}
257
258impl Drop for PendingEntry {
259 fn drop(&mut self) {
260 let event = {
261 let mut state = self.cache.state.lock();
262 match state.blob_states_by_key.get(&self.key) {
263 Some(BlobState::Ready(_)) => return,
265 Some(BlobState::Opening { .. }) => {
266 if let Some(BlobState::Opening { root_hash, event, .. }) =
267 state.blob_states_by_key.remove(&self.key)
268 {
269 state.keys_by_hash.remove(&root_hash);
270 event
271 } else {
272 return;
273 }
274 }
275 None => {
276 log::error!(
277 key = self.key;
278 "PendingEntry::drop: key unexpectedly absent from cache"
279 );
280 return;
281 }
282 }
283 };
284
285 let session = self.cache.mapping_session.clone();
291 let key = self.key;
292 self.cache.scope.spawn(async move {
293 let _ = session.close(key).await;
294 });
295
296 event.notify(usize::MAX);
298 }
299}
300
301enum CacheLookup {
303 Ready(zx::Vmo),
305 Pending(event_listener::EventListener),
308 Missing(PendingEntry),
311}
312
313pub(crate) struct Cache {
315 state: Mutex<CacheState>,
316 pub(crate) mapping_session: fmapping::MappingSessionProxy,
317 pager: Arc<zx::Pager>,
318 port: zx::Port,
319 delivery_vmo: zx::Vmo,
320 pub(crate) scope: fasync::ScopeHandle,
321}
322
323impl Cache {
324 fn new(
325 mapping_session: fmapping::MappingSessionProxy,
326 pager: Arc<zx::Pager>,
327 port: zx::Port,
328 delivery_vmo: zx::Vmo,
329 scope: fasync::ScopeHandle,
330 ) -> Self {
331 Self {
332 state: Mutex::new(CacheState::default()),
333 mapping_session,
334 pager,
335 port,
336 delivery_vmo,
337 scope,
338 }
339 }
340
341 fn delivery_vmo(&self) -> &zx::Vmo {
342 &self.delivery_vmo
343 }
344
345 fn get_by_key(&self, key: u64) -> Option<Arc<CachedBlob>> {
346 let state = self.state.lock();
347 match state.blob_states_by_key.get(&key) {
348 Some(BlobState::Ready(cached)) => Some(cached.clone()),
349 _ => None,
350 }
351 }
352
353 #[cfg(test)]
354 fn is_merkle_initialized(&self, key: u64) -> bool {
355 let state = self.state.lock();
356 match state.blob_states_by_key.get(&key) {
357 Some(BlobState::Opening { verifier, .. }) => verifier.is_some(),
358 Some(BlobState::Ready(blob)) => blob.merkle_verifier.get().is_some(),
359 None => false,
360 }
361 }
362
363 pub(crate) fn start_recording(&self) -> Result<(), zx::Status> {
364 let mut state = self.state.lock();
365 if state.recording.is_some() {
366 return Err(zx::Status::BAD_STATE);
367 }
368 let hash_by_key =
369 state.keys_by_hash.iter().map(|(&hash, &key)| (key, Hash::from(hash))).collect();
370 state.recording = Some(ActiveRecording { opened_hashes: HashSet::new(), hash_by_key });
371 Ok(())
372 }
373
374 fn record_open(&self, identifier: &[u8; 32]) {
375 let mut state = self.state.lock();
376 if let Some(recording) = state.recording.as_mut() {
377 recording.opened_hashes.insert(Hash::from(*identifier));
378 }
379 }
380
381 pub(crate) fn take_recording(&self) -> Option<ActiveRecording> {
382 self.state.lock().recording.take()
383 }
384
385 pub(crate) fn abort_recording(&self) {
386 self.state.lock().recording = None;
387 }
388
389 fn lookup(self: &Arc<Self>, identifier: &[u8; 32]) -> Result<CacheLookup, Error> {
397 let mut state = self.state.lock();
398 if let Some(&key) = state.keys_by_hash.get(identifier) {
399 match state.blob_states_by_key.get(&key) {
400 Some(BlobState::Ready(cached)) => {
401 let child = cached
402 .create_child()
403 .map_err(|s| anyhow!("Failed to create child VMO: {s}"))?;
404 return Ok(CacheLookup::Ready(child));
405 }
406 Some(BlobState::Opening { event, .. }) => {
407 return Ok(CacheLookup::Pending(event.listen()));
408 }
409 None => unreachable!("keys_by_hash pointed to non-existent key {key}"),
410 }
411 }
412
413 let event = Arc::new(event_listener::Event::new());
414 let key = state.generate_key();
415 state.keys_by_hash.insert(*identifier, key);
416 state
417 .blob_states_by_key
418 .insert(key, BlobState::Opening { root_hash: *identifier, event, verifier: None });
419 Ok(CacheLookup::Missing(PendingEntry { cache: self.clone(), key }))
420 }
421
422 pub(crate) async fn open_vmo(
423 self: &Arc<Self>,
424 identifier: &[u8; 32],
425 ) -> Result<zx::Vmo, Error> {
426 loop {
427 let entry = match self.lookup(identifier)? {
428 CacheLookup::Ready(child) => return Ok(child),
429 CacheLookup::Pending(listener) => {
430 listener.await;
431 continue; }
433 CacheLookup::Missing(entry) => entry,
434 };
435
436 let key = entry.key();
437
438 let size = self
441 .mapping_session
442 .open(key, identifier)
443 .await
444 .context("FIDL error calling MappingSession.Open")?
445 .map_err(|e| {
446 Error::from(zx::Status::err_from_raw(e))
447 .context("MappingSession.Open failed for blob")
448 })?;
449
450 let vmo = self.pager.create_vmo(zx::VmoOptions::empty(), &self.port, key, size)?;
451 let vmo_name = format!("blob-{}", &Hash::from(*identifier).to_string()[..8]);
452 if let Ok(name) = zx::Name::new(&vmo_name) {
453 let _ = vmo.set_name(&name);
454 }
455
456 let first_child = vmo
459 .create_child(zx::VmoChildOptions::REFERENCE | zx::VmoChildOptions::NO_WRITE, 0, 0)
460 .map_err(|s| anyhow!("Failed to create child VMO: {}", s))?;
461
462 entry.commit(vmo, size);
463
464 return Ok(first_child);
465 }
466 }
467
468 fn on_zero_children(&self, blob: &Arc<CachedBlob>) {
469 let mut state = self.state.lock();
474 if let Ok(info) = blob.vmo.info() {
475 if info.num_children > 0 {
476 blob.wait_for_zero_children();
479 return;
480 }
481 }
482 if let hash_map::Entry::Occupied(entry) = state.keys_by_hash.entry(blob.root_hash) {
484 if *entry.get() == blob.vmo_key {
485 entry.remove();
486 }
487 }
488 if let hash_map::Entry::Occupied(entry) = state.blob_states_by_key.entry(blob.vmo_key) {
490 if let BlobState::Ready(cached) = entry.get() {
491 if Arc::ptr_eq(cached, blob) {
492 entry.remove();
493 }
494 }
495 }
496 }
497
498 fn create_merkle_verifier(
499 root_hash: &[u8; 32],
500 vmo_key: u64,
501 hashes: Box<[Hash]>,
502 read_alignment: usize,
503 ) -> Result<ReadSizedMerkleVerifier, Error> {
504 let hashes = if hashes.is_empty() { Box::new([Hash::from(*root_hash)]) } else { hashes };
509
510 match MerkleVerifier::new(Hash::from(*root_hash), hashes) {
511 Ok(verifier) => ReadSizedMerkleVerifier::new(verifier, read_alignment)
512 .map_err(|e| anyhow!("Failed to create ReadSizedMerkleVerifier: {e:?}")),
513 Err(e) => {
514 bail!("Failed to verify merkle leaves for key {vmo_key}: {e:?}");
515 }
516 }
517 }
518
519 fn report_pager_failure(&self, vmo: &zx::Vmo, range: Range<u64>, status: zx::Status) {
520 let pager_status = match status {
523 zx::Status::IO_DATA_INTEGRITY => zx::Status::IO_DATA_INTEGRITY,
524 zx::Status::NO_SPACE => zx::Status::NO_SPACE,
525 zx::Status::BUFFER_TOO_SMALL | zx::Status::FILE_BIG => zx::Status::BUFFER_TOO_SMALL,
526 zx::Status::IO
527 | zx::Status::IO_DATA_LOSS
528 | zx::Status::IO_INVALID
529 | zx::Status::IO_MISSED_DEADLINE
530 | zx::Status::IO_NOT_PRESENT
531 | zx::Status::IO_OVERRUN
532 | zx::Status::IO_REFUSED
533 | zx::Status::PEER_CLOSED => zx::Status::IO,
534 _ => zx::Status::BAD_STATE,
535 };
536
537 if let Err(error) = self.pager.op_range(zx::PagerOp::Fail(pager_status), vmo, range) {
540 log::error!(error:?; "Failed to report pager failure to kernel");
541 }
542 }
543}
544
545impl delivery::DeliveryQueueProvider for Cache {
546 fn deliver_pages(
547 &self,
548 key: u64,
549 target_offset: u64,
550 unverified_pages: UnverifiedPages<'_>,
551 ) -> Result<(), Error> {
552 let cached_blob = self
553 .get_by_key(key)
554 .ok_or_else(|| anyhow!("Unknown or expired key {key} in deliver_pages"))?;
555
556 let page_size = zx::system_get_page_size() as u64;
557 let page_aligned_size = cached_blob.len.div_ceil(page_size) * page_size;
558
559 let verifier = match cached_blob.merkle_verifier.get() {
560 Some(v) => v,
561 None => {
562 self.report_pager_failure(
567 &cached_blob.vmo,
568 0..page_aligned_size,
569 zx::Status::BAD_STATE,
570 );
571 bail!("Data received for uninitialized blob {}", key);
572 }
573 };
574
575 let chunk_len = unverified_pages.len_in_bytes() as u64;
576
577 let bounded_len = std::cmp::min(chunk_len, page_aligned_size.saturating_sub(target_offset));
582 let chunk_range = target_offset..target_offset + bounded_len;
583
584 let remaining_in_blob = cached_blob.len.saturating_sub(target_offset);
588 let unaligned_len = std::cmp::min(chunk_len, remaining_in_blob) as usize;
589 if let Err(e) = verifier.verify_aligned(
590 target_offset as usize,
591 unverified_pages.as_ptr_byte_slice(),
592 unaligned_len,
593 ) {
594 self.report_pager_failure(&cached_blob.vmo, chunk_range, zx::Status::IO_DATA_INTEGRITY);
595 bail!("Failed to verify payload for blob {}: {:?}", key, e);
596 }
597
598 if let Err(e) = self.pager.supply_pages(
599 &cached_blob.vmo,
600 chunk_range.clone(),
601 &self.delivery_vmo,
602 unverified_pages.delivery_offset(),
603 ) {
604 self.report_pager_failure(&cached_blob.vmo, chunk_range, e);
605 bail!("Failed to supply pages: {:?}", e);
606 }
607
608 Ok(())
609 }
610
611 fn register_blob(
612 &self,
613 key: u64,
614 leaf_data: PtrByteSlice<'_>,
615 read_alignment: usize,
616 ) -> Result<(), Error> {
617 if leaf_data.len() % HASH_SIZE != 0 {
618 bail!("RegisterBlob invalid leaf length must be a multiple of HASH_SIZE");
619 }
620
621 let hashes: Vec<Hash> = (0..(leaf_data.len() / HASH_SIZE))
622 .map(|i| {
623 let chunk = leaf_data.subslice(i * HASH_SIZE..(i + 1) * HASH_SIZE);
624 let mut hash_bytes = [0u8; HASH_SIZE];
625 chunk.copy_to_slice(&mut hash_bytes);
626 Hash::from(hash_bytes)
627 })
628 .collect();
629
630 let mut state = self.state.lock();
631 match state.blob_states_by_key.get_mut(&key) {
632 Some(BlobState::Opening { root_hash, verifier, .. }) => {
633 if verifier.is_some() {
634 log::warn!(key;
635 "RegisterBlob received for blob but it is already initialized"
636 );
637 return Ok(());
638 }
639 *verifier = Some(Self::create_merkle_verifier(
640 root_hash,
641 key,
642 hashes.into_boxed_slice(),
643 read_alignment,
644 )?);
645 Ok(())
646 }
647 Some(BlobState::Ready(cached)) => {
648 if cached.merkle_verifier.get().is_some() {
649 log::warn!(key;
650 "RegisterBlob received for blob but it is already initialized"
651 );
652 return Ok(());
653 }
654 let verifier = Self::create_merkle_verifier(
655 &cached.root_hash,
656 key,
657 hashes.into_boxed_slice(),
658 read_alignment,
659 )?;
660 let _ = cached.merkle_verifier.set(verifier);
661 Ok(())
662 }
663 None => {
664 bail!("RegisterBlob received for unknown or expired key {key}");
665 }
666 }
667 }
668}
669
670pub struct BlobPagerAndVerifier {
678 _delivery_processor: delivery::DeliveryQueueProcessor,
680 mapper_session: fblock::MapperSessionProxy,
681 cache: Arc<Cache>,
682 scope: fasync::Scope,
683}
684
685impl BlobPagerAndVerifier {
686 pub fn delivery_vmo(&self) -> &zx::Vmo {
688 self.cache.delivery_vmo()
689 }
690
691 pub async fn new(
699 mapping_provider: &fmapping::MappingProviderProxy,
700 mapper: &fblock::MapperProxy,
701 ) -> Result<Self, Error> {
702 let (mapping_session, session_server) =
704 fidl::endpoints::create_proxy::<fmapping::MappingSessionMarker>();
705 let mapping_vmo = mapping_provider
706 .open_session(session_server)
707 .await
708 .context("FIDL error calling MappingProvider.OpenSession")?
709 .map_err(|e| anyhow!("MappingProvider open_session failed: {e:?}"))?;
710
711 let port = zx::Port::create();
713 let delivery_queue = zx::Vmo::create(mapping::DELIVERY_VMO_SIZE)
714 .context("Failed to create delivery queue VMO")?;
715 let delivery_vmo: zx::Vmo = delivery_queue
716 .duplicate_handle(zx::Rights::SAME_RIGHTS)
717 .context("Failed to duplicate delivery queue VMO")?;
718 let delivery_queue_dup = delivery_queue.duplicate_handle(zx::Rights::SAME_RIGHTS)?;
719 let receiver = vmo_fifo::Receiver::<mapping::RawDeliveryCommand>::new(
720 delivery_queue,
721 mapping::PENDING_DELIVERY_COMMANDS_CAPACITY,
722 )
723 .context("Failed to create delivery queue receiver")?;
724 let pager = Arc::new(
725 zx::Pager::create(zx::PagerOptions::empty()).context("Failed to create pager")?,
726 );
727 let port_dup = port.duplicate_handle(zx::Rights::SAME_RIGHTS)?;
728 let (mapper_session, mapper_session_server) =
729 fidl::endpoints::create_proxy::<fblock::MapperSessionMarker>();
730 mapper
731 .open_session(
732 mapper_session_server,
733 mapping_vmo,
734 Some(port_dup),
735 Some(delivery_queue_dup),
736 )
737 .await
738 .context("FIDL error calling Mapper.OpenSession")?
739 .map_err(|e| anyhow!("Mapper.OpenSession failed: {e:?}"))?;
740
741 let scope = fasync::Scope::new();
742 let scope_handle = scope.to_handle();
743 let cache = Arc::new(Cache::new(
744 mapping_session,
745 pager,
746 port,
747 delivery_vmo.duplicate_handle(zx::Rights::SAME_RIGHTS)?,
748 scope_handle,
749 ));
750 let _delivery_processor =
751 delivery::DeliveryQueueProcessor::spawn(receiver, cache.clone(), delivery_vmo)?;
752
753 Ok(Self { _delivery_processor, mapper_session, cache, scope })
754 }
755
756 pub async fn start_profile(
758 &self,
759 name: impl Into<String>,
760 ) -> Result<ProfileRecording, zx::Status> {
761 ProfileRecording::start(self.cache.clone(), &self.mapper_session, name.into()).await
762 }
763
764 pub async fn record_and_replay_profile(
767 &self,
768 name: impl Into<String>,
769 duration: zx::MonotonicDuration,
770 ) {
771 let name = name.into();
772 let recording = match self.start_profile(name.clone()).await {
773 Ok(recording) => recording,
774 Err(status) => {
775 log::warn!(status:?, name = name.as_str(); "Failed to start profile recording");
776 return;
777 }
778 };
779 self.scope.spawn(async move {
780 fasync::Timer::new(duration).await;
781 if let Err(status) = recording.stop().await {
782 log::warn!(status:?, name = name.as_str(); "Failed to stop profile recording");
783 }
784 });
785 }
786
787 pub async fn create_vmo(&self, identifier: &[u8; 32]) -> Result<zx::Vmo, Error> {
789 let vmo = self.cache.open_vmo(identifier).await?;
790 self.cache.record_open(identifier);
791 Ok(vmo)
792 }
793}
794
795#[cfg(test)]
796mod tests {
797 use super::*;
798 use futures::TryStreamExt;
799 use futures::channel::oneshot;
800 use mapping::{DeliveryCommand, RawDeliveryCommand};
801 use test_case::test_case;
802 use vmo_fifo::SyncSender;
803
804 const TARGET_READ_AHEAD_SIZE: usize = mapping::TARGET_READ_AHEAD_SIZE as usize;
805 const TEST_BLOB_SIZE: u64 = (TARGET_READ_AHEAD_SIZE * 2) as u64;
806 const TEST_VMO_KEY: u64 = 1;
807
808 struct TestEnv {
813 pager_and_verifier: Arc<BlobPagerAndVerifier>,
814 mapping_task: fasync::Task<()>,
815 mapper_task: fasync::Task<()>,
816 close_signal: Option<oneshot::Receiver<()>>,
817 delivery_vmo: zx::Vmo,
818 pub valid_root: [u8; 32],
819 pub valid_leaves: Vec<u8>,
820 pub blob_data: Vec<u8>,
821 }
822
823 impl TestEnv {
824 async fn new(blob_size: u64) -> Self {
825 let blob_data = vec![0x42u8; blob_size as usize];
826 let (root, leaf_hashes) =
827 fuchsia_merkle::MerkleRootBuilder::new(Vec::new()).complete(&blob_data);
828 let expected_hash: [u8; 32] = root.into();
829
830 let mut flat_leaves = Vec::new();
831 for hash in &leaf_hashes {
832 flat_leaves.extend_from_slice(hash.as_bytes());
833 }
834
835 let (mapping_proxy, mut mapping_stream) =
836 fidl::endpoints::create_proxy_and_stream::<fmapping::MappingProviderMarker>();
837
838 let (close_tx, close_rx) = oneshot::channel();
839 let mapping_task = fasync::Task::spawn(async move {
840 let mut close_tx = Some(close_tx);
841 if let Some(fmapping::MappingProviderRequest::OpenSession { session, responder }) =
842 mapping_stream.try_next().await.expect("try_next failed")
843 {
844 let mapping_vmo = zx::Vmo::create(zx::system_get_page_size().into())
845 .expect("zx::Vmo::create failed");
846 responder.send(Ok(mapping_vmo)).expect("send failed");
847
848 let mut session_stream = session.into_stream();
849 let mut open_calls = 0;
850 while let Some(request) =
851 session_stream.try_next().await.expect("try_next failed")
852 {
853 match request {
854 fmapping::MappingSessionRequest::Open {
855 key,
856 identifier,
857 responder,
858 } => {
859 assert_eq!(identifier, expected_hash);
860 assert_eq!(key, TEST_VMO_KEY);
861 open_calls += 1;
862 assert_eq!(
863 open_calls, 1,
864 "Open should only be called once per identifier"
865 );
866 responder.send(Ok(blob_size)).expect("send failed");
867 }
868 fmapping::MappingSessionRequest::Close { key, responder } => {
869 assert_eq!(key, TEST_VMO_KEY);
870 responder.send(Ok(())).expect("send failed");
871 if let Some(tx) = close_tx.take() {
872 let _ = tx.send(());
873 }
874 }
875 _ => {}
876 }
877 }
878 }
879 });
880
881 let (mapper_proxy, mut mapper_stream) =
882 fidl::endpoints::create_proxy_and_stream::<fblock::MapperMarker>();
883
884 let (tx_delivery, rx_delivery) = oneshot::channel();
885 let mapper_task = fasync::Task::spawn(async move {
886 if let Some(fblock::MapperRequest::OpenSession {
887 delivery_queue, responder, ..
888 }) = mapper_stream.try_next().await.expect("try_next failed")
889 {
890 tx_delivery.send(delivery_queue).expect("send failed");
891 responder.send(Ok(())).expect("send failed");
892 }
893 });
894
895 Self {
896 pager_and_verifier: Arc::new(
897 BlobPagerAndVerifier::new(&mapping_proxy, &mapper_proxy)
898 .await
899 .expect("BlobPagerAndVerifier::new failed"),
900 ),
901 mapping_task,
902 mapper_task,
903 close_signal: Some(close_rx),
904 delivery_vmo: rx_delivery
905 .await
906 .expect("rx_delivery wait failed")
907 .expect("delivery_vmo was None"),
908 valid_root: expected_hash,
909 valid_leaves: flat_leaves,
910 blob_data,
911 }
912 }
913
914 async fn teardown(self) {
915 drop(self.pager_and_verifier);
916 self.mapping_task.await;
917 self.mapper_task.await;
918 }
919 }
920
921 struct ExpectedReadThread {
922 started_rx: Option<oneshot::Receiver<()>>,
923 done_rx: oneshot::Receiver<()>,
924 handle: std::thread::JoinHandle<()>,
925 }
926
927 impl ExpectedReadThread {
928 async fn wait_started(&mut self) {
929 if let Some(rx) = self.started_rx.take() {
930 rx.await.expect("reader thread failed to start");
931 }
932 }
933
934 async fn wait_and_verify(self) {
935 self.done_rx.await.expect("reader thread panicked or hung");
936 self.handle.join().expect("join failed");
937 }
938 }
939
940 fn spawn_reader_expect_error(
941 vmo: &zx::Vmo,
942 offset: u64,
943 size: usize,
944 expected_status: zx::Status,
945 ) -> ExpectedReadThread {
946 let vmo_clone =
947 vmo.duplicate_handle(zx::Rights::SAME_RIGHTS).expect("duplicate_handle failed");
948 let (started_tx, started_rx) = oneshot::channel();
949 let (done_tx, done_rx) = oneshot::channel();
950
951 let handle = std::thread::spawn(move || {
952 let mut buf = vec![0u8; size];
953 let _ = started_tx.send(());
954 let err = vmo_clone.read(&mut buf, offset).expect_err("read should fail");
955 assert_eq!(err, expected_status);
956 let _ = done_tx.send(());
957 });
958
959 ExpectedReadThread { started_rx: Some(started_rx), done_rx, handle }
960 }
961
962 #[fuchsia::test]
963 async fn test_create_vmo() {
964 let env = TestEnv::new(TEST_BLOB_SIZE).await;
965 let vmo =
966 env.pager_and_verifier.create_vmo(&env.valid_root).await.expect("Failed to create VMO");
967 let size = vmo.get_size().expect("get_size failed");
968
969 let page_size = zx::system_get_page_size() as u64;
971 let expected_pages = (TEST_BLOB_SIZE + page_size - 1) / page_size;
972 assert_eq!(size, expected_pages * page_size);
973
974 drop(vmo);
978
979 env.teardown().await;
980 }
981
982 #[fuchsia::test]
983 async fn test_create_vmo_concurrent_access() {
984 let env = TestEnv::new(TEST_BLOB_SIZE).await;
985 let mut futures = vec![];
986 for _ in 0..10 {
987 let verifier = env.pager_and_verifier.clone();
988 futures.push(fasync::Task::spawn(async move {
989 verifier.create_vmo(&env.valid_root).await.expect("Failed to create VMO")
990 }));
991 }
992 let vmos = futures::future::join_all(futures).await;
993
994 drop(vmos);
995 env.teardown().await;
996 }
997
998 #[fuchsia::test]
999 async fn test_zero_children_eviction() {
1000 let mut env = TestEnv::new(TEST_BLOB_SIZE).await;
1001
1002 let child_vmo =
1003 env.pager_and_verifier.create_vmo(&env.valid_root).await.expect("create_vmo failed");
1004
1005 {
1006 let state = env.pager_and_verifier.cache.state.lock();
1007 assert_eq!(state.keys_by_hash.get(&env.valid_root), Some(&TEST_VMO_KEY));
1008 assert!(matches!(
1009 state.blob_states_by_key.get(&TEST_VMO_KEY),
1010 Some(BlobState::Ready(_))
1011 ));
1012 }
1013
1014 drop(child_vmo);
1015
1016 env.close_signal.take().expect("Missing signal").await.expect("Failed to close");
1019
1020 {
1021 let state = env.pager_and_verifier.cache.state.lock();
1022 assert!(state.keys_by_hash.get(&env.valid_root).is_none());
1023 assert!(state.blob_states_by_key.get(&TEST_VMO_KEY).is_none());
1024 }
1025
1026 env.teardown().await;
1027 }
1028
1029 #[fuchsia::test]
1030 async fn test_create_vmo_multiple_distinct_blobs() {
1031 use futures::StreamExt;
1032
1033 let (mapping_proxy, mut mapping_stream) =
1034 fidl::endpoints::create_proxy_and_stream::<fmapping::MappingProviderMarker>();
1035 let (mapper_proxy, mut mapper_stream) =
1036 fidl::endpoints::create_proxy_and_stream::<fblock::MapperMarker>();
1037
1038 let (close_tx, mut close_rx) = futures::channel::mpsc::unbounded();
1039 let mapping_task = fasync::Task::spawn(async move {
1040 if let Some(fmapping::MappingProviderRequest::OpenSession { session, responder }) =
1041 mapping_stream.try_next().await.expect("try_next failed")
1042 {
1043 let mapping_vmo = zx::Vmo::create(zx::system_get_page_size().into())
1044 .expect("zx::Vmo::create failed");
1045 responder.send(Ok(mapping_vmo)).expect("send failed");
1046
1047 let mut session_stream = session.into_stream();
1048 while let Some(request) = session_stream.try_next().await.expect("try_next failed")
1049 {
1050 match request {
1051 fmapping::MappingSessionRequest::Open { responder, .. } => {
1052 responder.send(Ok(8192)).expect("send failed");
1053 }
1054 fmapping::MappingSessionRequest::Close { key, responder } => {
1055 responder.send(Ok(())).expect("send failed");
1056 let _ = close_tx.unbounded_send(key);
1057 }
1058 _ => {}
1059 }
1060 }
1061 }
1062 });
1063
1064 let mapper_task = fasync::Task::spawn(async move {
1065 if let Some(fblock::MapperRequest::OpenSession { responder, .. }) =
1066 mapper_stream.try_next().await.expect("try_next failed")
1067 {
1068 responder.send(Ok(())).expect("send failed");
1069 }
1070 });
1071
1072 let pager_and_verifier = Arc::new(
1073 BlobPagerAndVerifier::new(&mapping_proxy, &mapper_proxy)
1074 .await
1075 .expect("BlobPagerAndVerifier::new failed"),
1076 );
1077
1078 let hash1: [u8; 32] = [0x11; 32];
1079 let hash2: [u8; 32] = [0x22; 32];
1080 let hash3: [u8; 32] = [0x33; 32];
1081
1082 let vmo1 = pager_and_verifier.create_vmo(&hash1).await.expect("create_vmo 1 failed");
1083 assert_eq!(
1084 vmo1.get_name().expect("get_name failed"),
1085 zx::Name::new("blob-11111111").expect("zx::Name::new failed")
1086 );
1087 let vmo2 = pager_and_verifier.create_vmo(&hash2).await.expect("create_vmo 2 failed");
1088 let vmo3 = pager_and_verifier.create_vmo(&hash3).await.expect("create_vmo 3 failed");
1089
1090 let (key1, key2, key3) = {
1091 let state = pager_and_verifier.cache.state.lock();
1092 let k1 = *state.keys_by_hash.get(&hash1).expect("hash1 missing");
1093 let k2 = *state.keys_by_hash.get(&hash2).expect("hash2 missing");
1094 let k3 = *state.keys_by_hash.get(&hash3).expect("hash3 missing");
1095 assert_ne!(k1, k2);
1096 assert_ne!(k2, k3);
1097 assert_ne!(k1, k3);
1098 assert!(matches!(state.blob_states_by_key.get(&k1), Some(BlobState::Ready(_))));
1099 assert!(matches!(state.blob_states_by_key.get(&k2), Some(BlobState::Ready(_))));
1100 assert!(matches!(state.blob_states_by_key.get(&k3), Some(BlobState::Ready(_))));
1101 (k1, k2, k3)
1102 };
1103
1104 drop(vmo2);
1106 let closed_key = close_rx.next().await.expect("expected close signal");
1107 assert_eq!(closed_key, key2);
1108
1109 {
1111 let state = pager_and_verifier.cache.state.lock();
1112 assert!(state.keys_by_hash.get(&hash2).is_none());
1113 assert!(state.blob_states_by_key.get(&key2).is_none());
1114 assert_eq!(state.keys_by_hash.get(&hash1), Some(&key1));
1115 assert_eq!(state.keys_by_hash.get(&hash3), Some(&key3));
1116 assert!(matches!(state.blob_states_by_key.get(&key1), Some(BlobState::Ready(_))));
1117 assert!(matches!(state.blob_states_by_key.get(&key3), Some(BlobState::Ready(_))));
1118 }
1119
1120 let vmo2_new = pager_and_verifier.create_vmo(&hash2).await.expect("re-create vmo 2 failed");
1122 {
1123 let state = pager_and_verifier.cache.state.lock();
1124 let k = *state.keys_by_hash.get(&hash2).expect("hash2 missing after re-open");
1125 assert_ne!(k, key2);
1126 assert!(matches!(state.blob_states_by_key.get(&k), Some(BlobState::Ready(_))));
1127 }
1128
1129 drop(vmo1);
1130 drop(vmo3);
1131 drop(vmo2_new);
1132
1133 drop(pager_and_verifier);
1134 mapping_task.await;
1135 mapper_task.await;
1136 }
1137
1138 #[fuchsia::test]
1139 async fn test_cache_is_cleared_when_create_vmo_fails() {
1140 let (mapping_proxy, mut mapping_stream) =
1141 fidl::endpoints::create_proxy_and_stream::<fmapping::MappingProviderMarker>();
1142 let (mapper_proxy, mut mapper_stream) =
1143 fidl::endpoints::create_proxy_and_stream::<fblock::MapperMarker>();
1144
1145 let (mock_opened_tx, mock_opened_rx) = oneshot::channel();
1146 let mapping_task = fasync::Task::spawn(async move {
1147 let mut mock_opened_tx = Some(mock_opened_tx);
1148 if let Some(fmapping::MappingProviderRequest::OpenSession { session, responder }) =
1149 mapping_stream.try_next().await.expect("try_next failed")
1150 {
1151 let mapping_vmo = zx::Vmo::create(zx::system_get_page_size().into())
1152 .expect("zx::Vmo::create failed");
1153 responder.send(Ok(mapping_vmo)).expect("send failed");
1154 let mut session_stream = session.into_stream();
1155
1156 if let Some(fmapping::MappingSessionRequest::Open {
1157 responder: _responder, ..
1158 }) = session_stream.try_next().await.expect("try_next failed")
1159 {
1160 if let Some(tx) = mock_opened_tx.take() {
1162 let _ = tx.send(());
1163 }
1164
1165 let () = std::future::pending().await;
1167 }
1168 }
1169 });
1170
1171 let mapper_task = fasync::Task::spawn(async move {
1172 if let Some(fblock::MapperRequest::OpenSession { responder, .. }) =
1173 mapper_stream.try_next().await.expect("try_next failed")
1174 {
1175 responder.send(Ok(())).expect("send failed");
1176 }
1177 });
1178
1179 let pager_and_verifer = Arc::new(
1180 BlobPagerAndVerifier::new(&mapping_proxy, &mapper_proxy)
1181 .await
1182 .expect("BlobPagerAndVerifier::new failed"),
1183 );
1184
1185 let blob_data = vec![0x42u8; TEST_BLOB_SIZE as usize];
1186 let (root, _) = fuchsia_merkle::MerkleRootBuilder::new(Vec::new()).complete(&blob_data);
1187 let hash_val: [u8; 32] = root.into();
1188
1189 let verifier_clone = pager_and_verifer.clone();
1190
1191 let identifier = hash_val;
1192 let (abortable_future, abort_handle) = futures::future::abortable(async move {
1193 let _ = verifier_clone.create_vmo(&identifier).await;
1194 });
1195
1196 let identifier = &hash_val;
1197 let primary_task = fasync::Task::spawn(abortable_future);
1198
1199 mock_opened_rx.await.expect("Open exited abruptly");
1202 {
1203 let state = pager_and_verifer.cache.state.lock();
1204 assert_eq!(state.keys_by_hash.get(identifier), Some(&1));
1205 assert!(matches!(state.blob_states_by_key.get(&1), Some(BlobState::Opening { .. })));
1206 }
1207
1208 abort_handle.abort();
1210 let _ = primary_task.await;
1211
1212 {
1214 let state = pager_and_verifer.cache.state.lock();
1215 assert!(state.keys_by_hash.get(identifier).is_none());
1216 assert!(state.blob_states_by_key.get(&1).is_none());
1217 }
1218
1219 drop(pager_and_verifer);
1220 drop(mapping_task);
1221 drop(mapper_task);
1222 }
1223
1224 #[fuchsia::test]
1225 async fn test_create_vmo_error_clears_cache_and_unblocks_waiters() {
1226 let (mapping_proxy, mut mapping_stream) =
1227 fidl::endpoints::create_proxy_and_stream::<fmapping::MappingProviderMarker>();
1228 let (mapper_proxy, mut mapper_stream) =
1229 fidl::endpoints::create_proxy_and_stream::<fblock::MapperMarker>();
1230
1231 let (open_received_tx, open_received_rx) = oneshot::channel();
1232 let (reply_tx, reply_rx) = oneshot::channel();
1233
1234 let mapping_task = fasync::Task::spawn(async move {
1235 if let Some(fmapping::MappingProviderRequest::OpenSession { session, responder }) =
1236 mapping_stream.try_next().await.expect("try_next failed")
1237 {
1238 let mapping_vmo = zx::Vmo::create(zx::system_get_page_size().into())
1239 .expect("zx::Vmo::create failed");
1240 responder.send(Ok(mapping_vmo)).expect("send failed");
1241 let mut session_stream = session.into_stream();
1242
1243 if let Some(fmapping::MappingSessionRequest::Open { responder, .. }) =
1244 session_stream.try_next().await.expect("try_next failed")
1245 {
1246 open_received_tx.send(()).expect("send open_received failed");
1248
1249 reply_rx.await.expect("reply_rx failed");
1251 responder.send(Err(zx::Status::NOT_FOUND.into_raw())).expect("send failed");
1252 }
1253 }
1255 });
1256
1257 let mapper_task = fasync::Task::spawn(async move {
1258 if let Some(fblock::MapperRequest::OpenSession { responder, .. }) =
1259 mapper_stream.try_next().await.expect("try_next failed")
1260 {
1261 responder.send(Ok(())).expect("send failed");
1262 }
1263 });
1264
1265 let pager_and_verifier = Arc::new(
1266 BlobPagerAndVerifier::new(&mapping_proxy, &mapper_proxy)
1267 .await
1268 .expect("BlobPagerAndVerifier::new failed"),
1269 );
1270
1271 let hash: [u8; 32] = [0x55; 32];
1272
1273 let verifier1 = pager_and_verifier.clone();
1275 let primary_future = fasync::Task::spawn(async move { verifier1.create_vmo(&hash).await });
1276
1277 open_received_rx.await.expect("open_received_rx failed");
1279 {
1280 let state = pager_and_verifier.cache.state.lock();
1281 assert!(matches!(
1282 state.keys_by_hash.get(&hash).and_then(|k| state.blob_states_by_key.get(k)),
1283 Some(BlobState::Opening { .. })
1284 ));
1285 }
1286
1287 let verifier2 = pager_and_verifier.clone();
1289 let secondary_future =
1290 fasync::Task::spawn(async move { verifier2.create_vmo(&hash).await });
1291
1292 reply_tx.send(()).expect("reply_tx send failed");
1294
1295 let primary_err = primary_future.await.expect_err("expected primary create_vmo to fail");
1298 assert_eq!(primary_err.downcast_ref::<zx::Status>(), Some(&zx::Status::NOT_FOUND));
1299 assert!(secondary_future.await.is_err());
1300
1301 {
1303 let state = pager_and_verifier.cache.state.lock();
1304 assert!(state.keys_by_hash.get(&hash).is_none());
1305 assert!(state.blob_states_by_key.is_empty());
1306 }
1307
1308 drop(pager_and_verifier);
1309 drop(mapping_task);
1310 drop(mapper_task);
1311 }
1312
1313 #[fuchsia::test]
1314 async fn test_register_blob_arrives_before_open_completes() {
1315 let (mapping_proxy, mut mapping_stream) =
1319 fidl::endpoints::create_proxy_and_stream::<fmapping::MappingProviderMarker>();
1320 let (mapper_proxy, mut mapper_stream) =
1321 fidl::endpoints::create_proxy_and_stream::<fblock::MapperMarker>();
1322
1323 let blob_data = vec![0x42u8; TEST_BLOB_SIZE as usize];
1324 let (root, leaf_hashes) =
1325 fuchsia_merkle::MerkleRootBuilder::new(Vec::new()).complete(&blob_data);
1326 let expected_hash: [u8; 32] = root.into();
1327
1328 let mut flat_leaves = Vec::new();
1329 for hash in &leaf_hashes {
1330 flat_leaves.extend_from_slice(hash.as_bytes());
1331 }
1332
1333 let (tx_delivery, rx_delivery) = oneshot::channel();
1334 let (open_key_tx, open_key_rx) = oneshot::channel();
1335 let (resume_open_tx, resume_open_rx) = oneshot::channel();
1336 let (close_tx, close_rx) = oneshot::channel();
1337
1338 let mapping_task = fasync::Task::spawn(async move {
1339 let mut close_tx = Some(close_tx);
1340 let mut open_key_tx = Some(open_key_tx);
1341 let mut resume_open_rx = Some(resume_open_rx);
1342 if let Some(fmapping::MappingProviderRequest::OpenSession { session, responder }) =
1343 mapping_stream.try_next().await.expect("try_next failed")
1344 {
1345 let mapping_vmo = zx::Vmo::create(zx::system_get_page_size().into())
1346 .expect("zx::Vmo::create failed");
1347 responder.send(Ok(mapping_vmo)).expect("send failed");
1348
1349 let mut session_stream = session.into_stream();
1350 while let Some(request) = session_stream.try_next().await.expect("try_next failed")
1351 {
1352 match request {
1353 fmapping::MappingSessionRequest::Open { key, identifier, responder } => {
1354 assert_eq!(identifier, expected_hash);
1355 if let Some(tx) = open_key_tx.take() {
1357 tx.send(key).expect("open_key_tx failed");
1358 }
1359 if let Some(rx) = resume_open_rx.take() {
1360 rx.await.expect("resume_open_rx failed");
1361 }
1362 responder.send(Ok(TEST_BLOB_SIZE)).expect("send failed");
1363 }
1364 fmapping::MappingSessionRequest::Close { key: _, responder } => {
1365 responder.send(Ok(())).expect("send failed");
1366 if let Some(tx) = close_tx.take() {
1367 let _ = tx.send(());
1368 }
1369 }
1370 _ => {}
1371 }
1372 }
1373 }
1374 });
1375
1376 let mapper_task = fasync::Task::spawn(async move {
1377 if let Some(fblock::MapperRequest::OpenSession { delivery_queue, responder, .. }) =
1378 mapper_stream.try_next().await.expect("try_next failed")
1379 {
1380 tx_delivery.send(delivery_queue).expect("send failed");
1381 responder.send(Ok(())).expect("send failed");
1382 }
1383 });
1384
1385 let pager_and_verifier = Arc::new(
1386 BlobPagerAndVerifier::new(&mapping_proxy, &mapper_proxy)
1387 .await
1388 .expect("BlobPagerAndVerifier::new failed"),
1389 );
1390
1391 let delivery_vmo =
1392 rx_delivery.await.expect("rx_delivery wait failed").expect("delivery_vmo was None");
1393 let mut sender = SyncSender::<RawDeliveryCommand>::new(
1394 delivery_vmo
1395 .duplicate_handle(zx::Rights::SAME_RIGHTS)
1396 .expect("duplicate_handle failed"),
1397 zx::system_get_page_size() as usize,
1398 mapping::PENDING_DELIVERY_COMMANDS_CAPACITY,
1399 )
1400 .expect("SyncSender::new failed");
1401
1402 let verifier_clone = pager_and_verifier.clone();
1403 let create_task =
1404 fasync::Task::spawn(async move { verifier_clone.create_vmo(&expected_hash).await });
1405
1406 let key = open_key_rx.await.expect("open_key_rx failed");
1408
1409 let mut payload =
1411 sender.reserve_payload(flat_leaves.len()).expect("reserve_payload failed");
1412 payload.data().copy_from_slice(&flat_leaves);
1413 let raw_cmd: RawDeliveryCommand = DeliveryCommand::RegisterBlob {
1414 key: key as u64,
1415 offset: payload.offset(),
1416 length: flat_leaves.len() as u32,
1417 read_alignment: TARGET_READ_AHEAD_SIZE as u32,
1418 }
1419 .into();
1420 payload.commit(raw_cmd).expect("commit failed");
1421
1422 while !pager_and_verifier.cache.is_merkle_initialized(key) {
1424 fasync::Timer::new(std::time::Duration::from_millis(5)).await;
1425 }
1426
1427 resume_open_tx.send(()).expect("resume_open_tx failed");
1429 let vmo = create_task.await.expect("create_vmo failed");
1430
1431 let chunk = &blob_data[..TARGET_READ_AHEAD_SIZE];
1433 let mut data_payload = sender.reserve_payload(chunk.len()).expect("reserve_payload failed");
1434 data_payload.data().copy_from_slice(chunk);
1435 let data_cmd: RawDeliveryCommand = DeliveryCommand::Data {
1436 key: key as u64,
1437 offset: data_payload.offset(),
1438 length: chunk.len() as u32,
1439 target_offset: 0,
1440 }
1441 .into();
1442 data_payload.commit(data_cmd).expect("commit failed");
1443
1444 let mut read_buf = vec![0u8; TARGET_READ_AHEAD_SIZE];
1445 vmo.read(&mut read_buf, 0).expect("read failed");
1446 assert_eq!(read_buf, chunk);
1447
1448 drop(vmo);
1449 close_rx.await.expect("close_rx failed");
1450
1451 drop(pager_and_verifier);
1452 mapping_task.await;
1453 mapper_task.await;
1454 }
1455
1456 #[fuchsia::test]
1457 async fn test_delivery_register_blob_verification() {
1458 let env = TestEnv::new(TEST_BLOB_SIZE).await;
1459
1460 let _paged_vmo =
1461 env.pager_and_verifier.create_vmo(&env.valid_root).await.expect("create_vmo failed");
1462
1463 let mut sender = SyncSender::<RawDeliveryCommand>::new(
1464 env.delivery_vmo
1465 .duplicate_handle(zx::Rights::SAME_RIGHTS)
1466 .expect("duplicate_handle failed"),
1467 zx::system_get_page_size() as usize, mapping::PENDING_DELIVERY_COMMANDS_CAPACITY,
1469 )
1470 .expect("SyncSender::new failed");
1471
1472 let mut corrupted_leaves = env.valid_leaves.clone();
1474 corrupted_leaves[0] ^= 0xFF;
1475
1476 let mut bad_payload =
1477 sender.reserve_payload(corrupted_leaves.len()).expect("reserve_payload failed");
1478 bad_payload.data().copy_from_slice(&corrupted_leaves);
1479
1480 let bad_raw_cmd: RawDeliveryCommand = DeliveryCommand::RegisterBlob {
1481 key: TEST_VMO_KEY,
1482 offset: bad_payload.offset(),
1483 length: corrupted_leaves.len() as u32,
1484 read_alignment: TARGET_READ_AHEAD_SIZE as u32,
1485 }
1486 .into();
1487 bad_payload.commit(bad_raw_cmd).expect("commit failed");
1488
1489 fasync::Timer::new(std::time::Duration::from_millis(5)).await;
1491
1492 let blob =
1493 env.pager_and_verifier.cache.get_by_key(TEST_VMO_KEY).expect("get_by_key failed");
1494
1495 assert!(blob.merkle_verifier.get().is_none());
1497
1498 let mut payload =
1500 sender.reserve_payload(env.valid_leaves.len()).expect("reserve_payload failed");
1501 payload.data().copy_from_slice(&env.valid_leaves);
1502
1503 let raw_cmd: RawDeliveryCommand = DeliveryCommand::RegisterBlob {
1504 key: TEST_VMO_KEY,
1505 offset: payload.offset(),
1506 length: env.valid_leaves.len() as u32,
1507 read_alignment: TARGET_READ_AHEAD_SIZE as u32,
1508 }
1509 .into();
1510 payload.commit(raw_cmd).expect("commit failed");
1511
1512 while blob.merkle_verifier.get().is_none() {
1513 fasync::Timer::new(std::time::Duration::from_millis(5)).await;
1514 }
1515
1516 drop(_paged_vmo);
1517 env.teardown().await;
1518 }
1519
1520 #[fuchsia::test]
1521 async fn test_register_blob_invalid_commands() {
1522 let env = TestEnv::new(TEST_BLOB_SIZE).await;
1523
1524 let _paged_vmo =
1525 env.pager_and_verifier.create_vmo(&env.valid_root).await.expect("create_vmo failed");
1526
1527 let mut sender = SyncSender::<RawDeliveryCommand>::new(
1528 env.delivery_vmo
1529 .duplicate_handle(zx::Rights::SAME_RIGHTS)
1530 .expect("duplicate_handle failed"),
1531 std::mem::align_of::<RawDeliveryCommand>(),
1532 mapping::PENDING_DELIVERY_COMMANDS_CAPACITY,
1533 )
1534 .expect("SyncSender::new failed");
1535
1536 let blob =
1537 env.pager_and_verifier.cache.get_by_key(TEST_VMO_KEY).expect("get_by_key failed");
1538
1539 let mut invalid_key_payload =
1541 sender.reserve_payload(env.valid_leaves.len()).expect("reserve_payload failed");
1542 invalid_key_payload.data().copy_from_slice(&env.valid_leaves);
1543 let invalid_key_cmd: RawDeliveryCommand = DeliveryCommand::RegisterBlob {
1544 key: 9999 as u64,
1545 offset: invalid_key_payload.offset(),
1546 length: env.valid_leaves.len() as u32,
1547 read_alignment: TARGET_READ_AHEAD_SIZE as u32,
1548 }
1549 .into();
1550 invalid_key_payload.commit(invalid_key_cmd).expect("commit failed");
1551 fasync::Timer::new(std::time::Duration::from_millis(5)).await;
1552 assert!(blob.merkle_verifier.get().is_none());
1553
1554 let oob_payload = sender.reserve_payload(8).expect("reserve_payload failed");
1556 let oob_cmd: RawDeliveryCommand = DeliveryCommand::RegisterBlob {
1557 key: TEST_VMO_KEY,
1558 offset: u32::MAX - 4, length: 8,
1560 read_alignment: TARGET_READ_AHEAD_SIZE as u32,
1561 }
1562 .into();
1563 oob_payload.commit(oob_cmd).expect("commit failed");
1564 fasync::Timer::new(std::time::Duration::from_millis(5)).await;
1565 assert!(blob.merkle_verifier.get().is_none());
1566
1567 let invalid_len_payload = sender.reserve_payload(10).expect("reserve_payload failed");
1569 let invalid_len_cmd: RawDeliveryCommand = DeliveryCommand::RegisterBlob {
1570 key: TEST_VMO_KEY,
1571 offset: invalid_len_payload.offset(),
1572 length: 10,
1573 read_alignment: TARGET_READ_AHEAD_SIZE as u32,
1574 }
1575 .into();
1576 invalid_len_payload.commit(invalid_len_cmd).expect("commit failed");
1577 fasync::Timer::new(std::time::Duration::from_millis(5)).await;
1578 assert!(blob.merkle_verifier.get().is_none());
1579
1580 drop(_paged_vmo);
1581 env.teardown().await;
1582 }
1583
1584 #[fuchsia::test]
1585 async fn test_delivery_data_supplies_pages() {
1586 let env = TestEnv::new(TEST_BLOB_SIZE).await;
1587
1588 let paged_vmo =
1589 env.pager_and_verifier.create_vmo(&env.valid_root).await.expect("create_vmo failed");
1590
1591 let mut sender = SyncSender::<RawDeliveryCommand>::new(
1592 env.delivery_vmo
1593 .duplicate_handle(zx::Rights::SAME_RIGHTS)
1594 .expect("duplicate_handle failed"),
1595 zx::system_get_page_size() as usize, mapping::PENDING_DELIVERY_COMMANDS_CAPACITY,
1597 )
1598 .expect("SyncSender::new failed");
1599
1600 let mut payload =
1601 sender.reserve_payload(env.valid_leaves.len()).expect("reserve_payload failed");
1602 payload.data().copy_from_slice(&env.valid_leaves);
1603 let raw_cmd: RawDeliveryCommand = DeliveryCommand::RegisterBlob {
1604 key: TEST_VMO_KEY,
1605 offset: payload.offset(),
1606 length: env.valid_leaves.len() as u32,
1607 read_alignment: TARGET_READ_AHEAD_SIZE as u32,
1608 }
1609 .into();
1610 payload.commit(raw_cmd).expect("commit failed");
1611
1612 let blob =
1613 env.pager_and_verifier.cache.get_by_key(TEST_VMO_KEY).expect("get_by_key failed");
1614 while blob.merkle_verifier.get().is_none() {
1615 fasync::Timer::new(std::time::Duration::from_millis(5)).await;
1616 }
1617
1618 let test_payload = &env.blob_data[..TARGET_READ_AHEAD_SIZE];
1619
1620 let mut payload =
1621 sender.reserve_payload(test_payload.len()).expect("reserve_payload failed");
1622 payload.data().copy_from_slice(&test_payload);
1623
1624 let cmd: RawDeliveryCommand = DeliveryCommand::Data {
1625 key: TEST_VMO_KEY,
1626 target_offset: 0,
1627 length: test_payload.len() as u32,
1628 offset: payload.offset(),
1629 }
1630 .into();
1631 payload.commit(cmd).expect("commit failed");
1632
1633 let mut read_buf = vec![0u8; TARGET_READ_AHEAD_SIZE];
1634 paged_vmo.read(&mut read_buf, 0).expect("read paged_vmo failed");
1635 assert_eq!(read_buf, test_payload);
1636
1637 drop(paged_vmo);
1638 env.teardown().await;
1639 }
1640
1641 #[fuchsia::test]
1642 async fn test_delivery_data_corrupted() {
1643 let blob_size = TARGET_READ_AHEAD_SIZE as u64;
1646 let env = TestEnv::new(blob_size).await;
1647
1648 let paged_vmo =
1649 env.pager_and_verifier.create_vmo(&env.valid_root).await.expect("create_vmo failed");
1650
1651 let mut sender = SyncSender::<RawDeliveryCommand>::new(
1652 env.delivery_vmo
1653 .duplicate_handle(zx::Rights::SAME_RIGHTS)
1654 .expect("duplicate_handle failed"),
1655 zx::system_get_page_size() as usize,
1656 mapping::PENDING_DELIVERY_COMMANDS_CAPACITY,
1657 )
1658 .expect("SyncSender::new failed");
1659
1660 let mut payload =
1661 sender.reserve_payload(env.valid_leaves.len()).expect("reserve_payload failed");
1662 payload.data().copy_from_slice(&env.valid_leaves);
1663 let raw_cmd: RawDeliveryCommand = DeliveryCommand::RegisterBlob {
1664 key: TEST_VMO_KEY,
1665 offset: payload.offset(),
1666 length: env.valid_leaves.len() as u32,
1667 read_alignment: TARGET_READ_AHEAD_SIZE as u32,
1668 }
1669 .into();
1670 payload.commit(raw_cmd).expect("commit failed");
1671
1672 let blob =
1673 env.pager_and_verifier.cache.get_by_key(TEST_VMO_KEY).expect("get_by_key failed");
1674 while blob.merkle_verifier.get().is_none() {
1675 fasync::Timer::new(std::time::Duration::from_millis(5)).await;
1676 }
1677
1678 let mut corrupted_data = env.blob_data.clone();
1680 corrupted_data[0] ^= 0xFF;
1681
1682 let mut payload =
1683 sender.reserve_payload(corrupted_data.len()).expect("reserve_payload failed");
1684 payload.data().copy_from_slice(&corrupted_data);
1685 let raw_cmd: RawDeliveryCommand = DeliveryCommand::Data {
1686 key: TEST_VMO_KEY,
1687 offset: payload.offset(),
1688 length: corrupted_data.len() as u32,
1689 target_offset: 0,
1690 }
1691 .into();
1692
1693 let page_size = zx::system_get_page_size() as usize;
1696 let mut reader1 =
1697 spawn_reader_expect_error(&paged_vmo, 0, page_size, zx::Status::IO_DATA_INTEGRITY);
1698 let mut reader2 = spawn_reader_expect_error(
1699 &paged_vmo,
1700 page_size as u64,
1701 page_size,
1702 zx::Status::IO_DATA_INTEGRITY,
1703 );
1704
1705 reader1.wait_started().await;
1708 reader2.wait_started().await;
1709 fasync::Timer::new(std::time::Duration::from_millis(5)).await;
1710
1711 payload.commit(raw_cmd).expect("commit failed");
1714
1715 reader1.wait_and_verify().await;
1716 reader2.wait_and_verify().await;
1717
1718 drop(paged_vmo);
1719 env.teardown().await;
1720 }
1721
1722 #[fuchsia::test]
1723 async fn test_delivery_data_corrupted_chunk_preserves_supplied_pages() {
1724 let read_alignment = TARGET_READ_AHEAD_SIZE;
1725 let blob_size = (read_alignment * 2) as u64;
1726 let env = TestEnv::new(blob_size).await;
1727
1728 let paged_vmo =
1729 env.pager_and_verifier.create_vmo(&env.valid_root).await.expect("create_vmo failed");
1730
1731 let mut sender = SyncSender::<RawDeliveryCommand>::new(
1732 env.delivery_vmo
1733 .duplicate_handle(zx::Rights::SAME_RIGHTS)
1734 .expect("duplicate_handle failed"),
1735 zx::system_get_page_size() as usize,
1736 mapping::PENDING_DELIVERY_COMMANDS_CAPACITY,
1737 )
1738 .expect("SyncSender::new failed");
1739
1740 let mut payload =
1741 sender.reserve_payload(env.valid_leaves.len()).expect("reserve_payload failed");
1742 payload.data().copy_from_slice(&env.valid_leaves);
1743 let raw_cmd: RawDeliveryCommand = DeliveryCommand::RegisterBlob {
1744 key: TEST_VMO_KEY,
1745 offset: payload.offset(),
1746 length: env.valid_leaves.len() as u32,
1747 read_alignment: read_alignment as u32,
1748 }
1749 .into();
1750 payload.commit(raw_cmd).expect("commit failed");
1751
1752 let blob =
1753 env.pager_and_verifier.cache.get_by_key(TEST_VMO_KEY).expect("get_by_key failed");
1754 while blob.merkle_verifier.get().is_none() {
1755 fasync::Timer::new(std::time::Duration::from_millis(5)).await;
1756 }
1757
1758 let page_size = zx::system_get_page_size() as usize;
1759
1760 let paged_vmo_clone1 =
1763 paged_vmo.duplicate_handle(zx::Rights::SAME_RIGHTS).expect("duplicate_handle failed");
1764 let (tx1, rx1) = oneshot::channel();
1765 let expected_page0 = env.blob_data[..page_size].to_vec();
1766 let thread1 = std::thread::spawn(move || {
1767 let mut buf = vec![0u8; page_size];
1768 paged_vmo_clone1.read(&mut buf, 0).expect("read should succeed");
1769 assert_eq!(buf, expected_page0);
1770 let _ = tx1.send(());
1771 });
1772 fasync::Timer::new(std::time::Duration::from_millis(5)).await;
1773
1774 let valid_chunk = &env.blob_data[..read_alignment];
1775 let mut payload =
1776 sender.reserve_payload(valid_chunk.len()).expect("reserve_payload failed");
1777 payload.data().copy_from_slice(valid_chunk);
1778 let raw_cmd: RawDeliveryCommand = DeliveryCommand::Data {
1779 key: TEST_VMO_KEY,
1780 offset: payload.offset(),
1781 length: valid_chunk.len() as u32,
1782 target_offset: 0,
1783 }
1784 .into();
1785 payload.commit(raw_cmd).expect("commit failed");
1786
1787 rx1.await.expect("thread1 panicked or hung");
1788 thread1.join().expect("join failed");
1789
1790 let mut reader2 = spawn_reader_expect_error(
1792 &paged_vmo,
1793 read_alignment as u64,
1794 page_size,
1795 zx::Status::IO_DATA_INTEGRITY,
1796 );
1797 reader2.wait_started().await;
1798 fasync::Timer::new(std::time::Duration::from_millis(5)).await;
1799
1800 let mut corrupted_chunk = env.blob_data[read_alignment..].to_vec();
1802 corrupted_chunk[0] ^= 0xFF;
1803
1804 let mut payload =
1805 sender.reserve_payload(corrupted_chunk.len()).expect("reserve_payload failed");
1806 payload.data().copy_from_slice(&corrupted_chunk);
1807 let raw_cmd: RawDeliveryCommand = DeliveryCommand::Data {
1808 key: TEST_VMO_KEY,
1809 offset: payload.offset(),
1810 length: corrupted_chunk.len() as u32,
1811 target_offset: read_alignment as u64,
1812 }
1813 .into();
1814 payload.commit(raw_cmd).expect("commit failed");
1815
1816 reader2.wait_and_verify().await;
1817
1818 let mut buf = vec![0u8; page_size];
1820 paged_vmo.read(&mut buf, 0).expect("previously supplied page 0 must still be readable");
1821 assert_eq!(buf, env.blob_data[..page_size]);
1822
1823 drop(paged_vmo);
1824 env.teardown().await;
1825 }
1826
1827 #[fuchsia::test]
1828 async fn test_delivery_data_corrupted_multi_chunk_read() {
1829 let read_alignment = TARGET_READ_AHEAD_SIZE;
1830 let blob_size = (read_alignment * 3) as u64;
1831 let env = TestEnv::new(blob_size).await;
1832
1833 let paged_vmo =
1834 env.pager_and_verifier.create_vmo(&env.valid_root).await.expect("create_vmo failed");
1835
1836 let mut sender = SyncSender::<RawDeliveryCommand>::new(
1837 env.delivery_vmo
1838 .duplicate_handle(zx::Rights::SAME_RIGHTS)
1839 .expect("duplicate_handle failed"),
1840 zx::system_get_page_size() as usize,
1841 mapping::PENDING_DELIVERY_COMMANDS_CAPACITY,
1842 )
1843 .expect("SyncSender::new failed");
1844
1845 let mut payload =
1846 sender.reserve_payload(env.valid_leaves.len()).expect("reserve_payload failed");
1847 payload.data().copy_from_slice(&env.valid_leaves);
1848 let raw_cmd: RawDeliveryCommand = DeliveryCommand::RegisterBlob {
1849 key: TEST_VMO_KEY,
1850 offset: payload.offset(),
1851 length: env.valid_leaves.len() as u32,
1852 read_alignment: read_alignment as u32,
1853 }
1854 .into();
1855 payload.commit(raw_cmd).expect("commit failed");
1856
1857 let blob =
1858 env.pager_and_verifier.cache.get_by_key(TEST_VMO_KEY).expect("get_by_key failed");
1859 while blob.merkle_verifier.get().is_none() {
1860 fasync::Timer::new(std::time::Duration::from_millis(5)).await;
1861 }
1862
1863 let mut reader = spawn_reader_expect_error(
1869 &paged_vmo,
1870 0,
1871 blob_size as usize,
1872 zx::Status::IO_DATA_INTEGRITY,
1873 );
1874 reader.wait_started().await;
1875 fasync::Timer::new(std::time::Duration::from_millis(5)).await;
1876
1877 let valid_chunk1 = &env.blob_data[..read_alignment];
1879 let mut payload =
1880 sender.reserve_payload(valid_chunk1.len()).expect("reserve_payload failed");
1881 payload.data().copy_from_slice(valid_chunk1);
1882 let raw_cmd: RawDeliveryCommand = DeliveryCommand::Data {
1883 key: TEST_VMO_KEY,
1884 offset: payload.offset(),
1885 length: valid_chunk1.len() as u32,
1886 target_offset: 0,
1887 }
1888 .into();
1889 payload.commit(raw_cmd).expect("commit failed");
1890
1891 fasync::Timer::new(std::time::Duration::from_millis(5)).await;
1894
1895 let mut corrupted_chunk2 = env.blob_data[read_alignment..read_alignment * 2].to_vec();
1897 corrupted_chunk2[0] ^= 0xFF;
1898 let mut payload =
1899 sender.reserve_payload(corrupted_chunk2.len()).expect("reserve_payload failed");
1900 payload.data().copy_from_slice(&corrupted_chunk2);
1901 let raw_cmd: RawDeliveryCommand = DeliveryCommand::Data {
1902 key: TEST_VMO_KEY,
1903 offset: payload.offset(),
1904 length: corrupted_chunk2.len() as u32,
1905 target_offset: read_alignment as u64,
1906 }
1907 .into();
1908 payload.commit(raw_cmd).expect("commit failed");
1909
1910 reader.wait_and_verify().await;
1914
1915 drop(paged_vmo);
1916 env.teardown().await;
1917 }
1918
1919 #[fuchsia::test]
1920 async fn test_delivery_data_uninitialized() {
1921 let env = TestEnv::new(TEST_BLOB_SIZE).await;
1922
1923 let paged_vmo =
1924 env.pager_and_verifier.create_vmo(&env.valid_root).await.expect("create_vmo failed");
1925
1926 let mut sender = SyncSender::<RawDeliveryCommand>::new(
1927 env.delivery_vmo
1928 .duplicate_handle(zx::Rights::SAME_RIGHTS)
1929 .expect("duplicate_handle failed"),
1930 zx::system_get_page_size() as usize,
1931 mapping::PENDING_DELIVERY_COMMANDS_CAPACITY,
1932 )
1933 .expect("SyncSender::new failed");
1934
1935 let mut reader = spawn_reader_expect_error(&paged_vmo, 0, 8192, zx::Status::BAD_STATE);
1937 reader.wait_started().await;
1938 fasync::Timer::new(std::time::Duration::from_millis(5)).await;
1939
1940 let chunk = &env.blob_data[..8192];
1942 let mut payload = sender.reserve_payload(chunk.len()).expect("reserve_payload failed");
1943 payload.data().copy_from_slice(chunk);
1944 let raw_cmd: RawDeliveryCommand = DeliveryCommand::Data {
1945 key: TEST_VMO_KEY,
1946 offset: payload.offset(),
1947 length: chunk.len() as u32,
1948 target_offset: 0,
1949 }
1950 .into();
1951 payload.commit(raw_cmd).expect("commit failed");
1952
1953 reader.wait_and_verify().await;
1954
1955 drop(paged_vmo);
1956 env.teardown().await;
1957 }
1958
1959 #[test_case(TARGET_READ_AHEAD_SIZE; "read_alignment_128k")]
1960 #[test_case(96 * 1024; "read_alignment_96k")]
1961 #[fuchsia::test]
1962 async fn test_delivery_data_multiple_chunks(read_alignment: usize) {
1963 let env = TestEnv::new(TEST_BLOB_SIZE).await;
1964
1965 let paged_vmo =
1966 env.pager_and_verifier.create_vmo(&env.valid_root).await.expect("create_vmo failed");
1967
1968 let mut sender = SyncSender::<RawDeliveryCommand>::new(
1969 env.delivery_vmo
1970 .duplicate_handle(zx::Rights::SAME_RIGHTS)
1971 .expect("duplicate_handle failed"),
1972 zx::system_get_page_size() as usize,
1973 mapping::PENDING_DELIVERY_COMMANDS_CAPACITY,
1974 )
1975 .expect("SyncSender::new failed");
1976
1977 let mut payload =
1978 sender.reserve_payload(env.valid_leaves.len()).expect("reserve_payload failed");
1979 payload.data().copy_from_slice(&env.valid_leaves);
1980 let raw_cmd: RawDeliveryCommand = DeliveryCommand::RegisterBlob {
1981 key: TEST_VMO_KEY,
1982 offset: payload.offset(),
1983 length: env.valid_leaves.len() as u32,
1984 read_alignment: read_alignment as u32,
1985 }
1986 .into();
1987 payload.commit(raw_cmd).expect("commit failed");
1988
1989 let blob =
1990 env.pager_and_verifier.cache.get_by_key(TEST_VMO_KEY).expect("get_by_key failed");
1991 while blob.merkle_verifier.get().is_none() {
1992 fasync::Timer::new(std::time::Duration::from_millis(5)).await;
1993 }
1994
1995 let expected_data = env.blob_data.clone();
1996 let paged_vmo_clone =
1997 paged_vmo.duplicate_handle(zx::Rights::SAME_RIGHTS).expect("duplicate_handle failed");
1998
1999 let (tx, rx) = oneshot::channel();
2000 let thread = std::thread::spawn(move || {
2001 let mut buf = vec![0u8; expected_data.len()];
2002 paged_vmo_clone.read(&mut buf, 0).expect("failed to read from paged vmo");
2003 assert_eq!(buf, expected_data);
2004 let _ = tx.send(());
2005 });
2006
2007 for (i, chunk) in env.blob_data.chunks(read_alignment).enumerate() {
2009 let mut payload = sender.reserve_payload(chunk.len()).expect("reserve_payload failed");
2010 payload.data().copy_from_slice(chunk);
2011 let raw_cmd: RawDeliveryCommand = DeliveryCommand::Data {
2012 key: TEST_VMO_KEY,
2013 offset: payload.offset(),
2014 length: chunk.len() as u32,
2015 target_offset: (i * read_alignment) as u64,
2016 }
2017 .into();
2018 payload.commit(raw_cmd).expect("commit failed");
2019 }
2020
2021 rx.await.expect("reading thread panicked or hung");
2022 thread.join().expect("join failed");
2023
2024 drop(paged_vmo);
2025 env.teardown().await;
2026 }
2027
2028 #[fuchsia::test]
2029 async fn test_delivery_data_unaligned_blob_size() {
2030 let data_size = (TARGET_READ_AHEAD_SIZE + 1024) as u64; let env = TestEnv::new(data_size).await;
2032
2033 let paged_vmo =
2034 env.pager_and_verifier.create_vmo(&env.valid_root).await.expect("Failed to create VMO");
2035
2036 let mut sender = SyncSender::<RawDeliveryCommand>::new(
2037 env.delivery_vmo
2038 .duplicate_handle(zx::Rights::SAME_RIGHTS)
2039 .expect("duplicate_handle failed"),
2040 zx::system_get_page_size() as usize, mapping::PENDING_DELIVERY_COMMANDS_CAPACITY,
2042 )
2043 .expect("SyncSender::new failed");
2044
2045 let mut payload =
2046 sender.reserve_payload(env.valid_leaves.len()).expect("reserve_payload failed");
2047 payload.data().copy_from_slice(&env.valid_leaves);
2048 let raw_cmd: RawDeliveryCommand = DeliveryCommand::RegisterBlob {
2049 key: TEST_VMO_KEY,
2050 offset: payload.offset(),
2051 length: env.valid_leaves.len() as u32,
2052 read_alignment: TARGET_READ_AHEAD_SIZE as u32,
2053 }
2054 .into();
2055 payload.commit(raw_cmd).expect("commit failed");
2056
2057 let blob =
2058 env.pager_and_verifier.cache.get_by_key(TEST_VMO_KEY).expect("get_by_key failed");
2059 while blob.merkle_verifier.get().is_none() {
2060 fasync::Timer::new(std::time::Duration::from_millis(5)).await;
2061 }
2062
2063 let test_payload = env.blob_data.clone();
2064 assert_eq!(test_payload.len(), data_size as usize);
2065
2066 let chunk1 = &test_payload[..TARGET_READ_AHEAD_SIZE];
2067 let mut payload1 = sender.reserve_payload(chunk1.len()).expect("reserve_payload failed");
2068 payload1.data().copy_from_slice(chunk1);
2069 let off1 = payload1.offset();
2070 payload1
2071 .commit(
2072 DeliveryCommand::Data {
2073 key: TEST_VMO_KEY,
2074 target_offset: 0,
2075 length: chunk1.len() as u32,
2076 offset: off1,
2077 }
2078 .into(),
2079 )
2080 .expect("commit failed");
2081
2082 let chunk2 = &test_payload[TARGET_READ_AHEAD_SIZE..];
2083 let page_size = zx::system_get_page_size() as usize;
2084 let chunk2_len_aligned = chunk2.len().div_ceil(page_size) * page_size;
2085 let mut payload2 =
2086 sender.reserve_payload(chunk2_len_aligned).expect("reserve_payload failed");
2087 let payload2_data = payload2.data();
2088 payload2_data.subslice_mut(0..chunk2.len()).copy_from_slice(chunk2);
2089 payload2_data.subslice_mut(chunk2.len()..chunk2_len_aligned).fill(0);
2090
2091 let off2 = payload2.offset();
2092 payload2
2093 .commit(
2094 DeliveryCommand::Data {
2095 key: TEST_VMO_KEY,
2096 target_offset: TARGET_READ_AHEAD_SIZE as u64,
2097 length: chunk2_len_aligned as u32,
2098 offset: off2,
2099 }
2100 .into(),
2101 )
2102 .expect("commit failed");
2103
2104 let mut read_buf = vec![0u8; data_size as usize];
2105 paged_vmo.read(&mut read_buf, 0).expect("read paged_vmo failed");
2106 assert_eq!(read_buf, test_payload);
2107
2108 let page_size = zx::system_get_page_size() as u64;
2109 let out_of_bounds_offset = data_size.div_ceil(page_size) * page_size;
2111 let mut read_buf = vec![0u8; 1];
2113 let res = paged_vmo.read(&mut read_buf, out_of_bounds_offset);
2114 assert_eq!(res, Err(zx::Status::OUT_OF_RANGE));
2115
2116 drop(paged_vmo);
2117 env.teardown().await;
2118 }
2119}