1use super::{
6 ActiveRequests, DecodedRequest, DeviceInfo, FIFO_MAX_REQUESTS, HandleRequestResult,
7 IntoOrchestrator, OffsetMap, Operation, SessionHelper, TraceFlowId,
8};
9use crate::mapper::serve_mapper_session;
10use crate::verifier::Verifier;
11use anyhow::Error;
12use block_protocol::{BlockFifoRequest, BlockFifoResponse, ReadOptions, WriteFlags, WriteOptions};
13use fidl::endpoints::ServerEnd;
14use fidl_fuchsia_storage_block as fblock;
15use fidl_fuchsia_storage_block::DeviceFlag;
16use fuchsia_async as fasync;
17use fuchsia_sync::Mutex;
18use futures::future::{Fuse, FusedFuture, join};
19use futures::stream::FuturesUnordered;
20use futures::{FutureExt, StreamExt, select_biased};
21use mapping::reader::{BlockService, MAX_READ_BUFFER_SIZE};
22use std::borrow::Cow;
23use std::collections::VecDeque;
24use std::future::{Future, poll_fn};
25use std::mem::MaybeUninit;
26use std::pin::pin;
27use std::sync::{Arc, OnceLock};
28use std::task::{Poll, ready};
29use storage_device::buffer::{Buffer, OwnedBuffer};
30use storage_device::buffer_allocator::{BufferAllocator, BufferSource};
31
32pub trait Interface: Send + Sync + Unpin + 'static {
33 fn open_session(
62 &self,
63 session_manager: Arc<SessionManager<Self>>,
64 stream: fblock::SessionRequestStream,
65 offset_map: OffsetMap,
66 block_size: u32,
67 ) -> impl Future<Output = Result<(), Error>> + Send {
68 session_manager.serve_session(
70 stream,
71 offset_map,
72 self.get_info().max_transfer_blocks(),
73 block_size,
74 )
75 }
76
77 fn open_mapper_session(
80 session_manager: Arc<SessionManager<Self>>,
81 session: ServerEnd<fblock::MapperSessionMarker>,
82 mapping_vmo: zx::Vmo,
83 block_size: u32,
84 port: Option<zx::Port>,
85 delivery_queue: Option<zx::Vmo>,
86 ) -> Result<impl Future<Output = Result<(), Error>> + Send + 'static, zx::Status> {
87 let buffer_source = BufferSource::new(MAX_READ_BUFFER_SIZE * 16);
88 let vmo = buffer_source.vmo().clone();
89 let allocator = Arc::new(BufferAllocator::new(
90 std::cmp::max(block_size as usize, zx::system_get_page_size() as usize),
91 buffer_source,
92 ));
93 let scope = fasync::Scope::new();
94 let service: Arc<dyn BlockService> = Arc::new(AsyncBlockService::new_with_allocator(
95 session_manager.interface.clone(),
96 block_size,
97 allocator,
98 scope.to_handle(),
99 ));
100 let interface = session_manager.interface.clone();
101 let session_fut = serve_mapper_session(
102 Arc::new(move |mapping_vmo: &zx::Vmo, dq: zx::Vmo| {
103 interface.on_open_mapper_session(mapping_vmo, dq)
104 }),
105 service,
106 session,
107 mapping_vmo,
108 port,
109 delivery_queue,
110 )?;
111 Ok(async move {
112 session_manager.interface.on_attach_vmo(&vmo).await?;
113 let res = session_fut.await;
114 scope.cancel().await;
115 session_manager.interface.on_detach_vmo(&vmo);
116 res
117 })
118 }
119
120 fn on_open_mapper_session(
123 &self,
124 _mapping_vmo: &zx::Vmo,
125 delivery_queue: zx::Vmo,
126 ) -> Result<Verifier, zx::Status> {
127 Ok(Verifier::new(delivery_queue))
128 }
129
130 fn on_attach_vmo(&self, _vmo: &zx::Vmo) -> impl Future<Output = Result<(), zx::Status>> + Send {
134 async { Ok(()) }
135 }
136
137 fn on_detach_vmo(&self, _vmo: &zx::Vmo) {}
139
140 fn get_info(&self) -> Cow<'_, DeviceInfo>;
142
143 fn read(
150 &self,
151 device_block_offset: u64,
152 block_count: u32,
153 vmo: &Arc<zx::Vmo>,
154 vmo_offset: u64, opts: ReadOptions,
156 trace_flow_id: TraceFlowId,
157 ) -> impl Future<Output = Result<(), zx::Status>> + Send;
158
159 fn write(
166 &self,
167 device_block_offset: u64,
168 block_count: u32,
169 vmo: &Arc<zx::Vmo>,
170 vmo_offset: u64, opts: WriteOptions,
172 trace_flow_id: TraceFlowId,
173 ) -> impl Future<Output = Result<(), zx::Status>> + Send;
174
175 fn flush(
177 &self,
178 trace_flow_id: TraceFlowId,
179 ) -> impl Future<Output = Result<(), zx::Status>> + Send;
180
181 fn trim(
188 &self,
189 device_block_offset: u64,
190 block_count: u32,
191 trace_flow_id: TraceFlowId,
192 ) -> impl Future<Output = Result<(), zx::Status>> + Send;
193
194 fn get_volume_info(
196 &self,
197 ) -> impl Future<Output = Result<(fblock::VolumeManagerInfo, fblock::VolumeInfo), zx::Status>> + Send
198 {
199 async { Err(zx::Status::NOT_SUPPORTED) }
200 }
201
202 fn query_slices(
204 &self,
205 _start_slices: &[u64],
206 ) -> impl Future<Output = Result<Vec<fblock::VsliceRange>, zx::Status>> + Send {
207 async { Err(zx::Status::NOT_SUPPORTED) }
208 }
209
210 fn extend(
212 &self,
213 _start_slice: u64,
214 _slice_count: u64,
215 ) -> impl Future<Output = Result<(), zx::Status>> + Send {
216 async { Err(zx::Status::NOT_SUPPORTED) }
217 }
218
219 fn shrink(
221 &self,
222 _start_slice: u64,
223 _slice_count: u64,
224 ) -> impl Future<Output = Result<(), zx::Status>> + Send {
225 async { Err(zx::Status::NOT_SUPPORTED) }
226 }
227}
228
229pub struct PassthroughSession(fblock::SessionProxy);
231
232impl PassthroughSession {
233 pub fn new(proxy: fblock::SessionProxy) -> Self {
234 Self(proxy)
235 }
236
237 async fn handle_request(&self, request: fblock::SessionRequest) -> Result<(), Error> {
238 match request {
239 fblock::SessionRequest::GetFifo { responder } => {
240 responder.send(self.0.get_fifo().await?)?;
241 }
242 fblock::SessionRequest::AttachVmo { vmo, responder } => {
243 responder.send(self.0.attach_vmo(vmo).await?.as_ref().map_err(|s| *s))?;
244 }
245 fblock::SessionRequest::Close { responder } => {
246 responder.send(self.0.close().await?)?;
247 }
248 }
249 Ok(())
250 }
251
252 pub async fn serve(&self, mut stream: fblock::SessionRequestStream) -> Result<(), Error> {
254 while let Some(Ok(request)) = stream.next().await {
255 if let Err(error) = self.handle_request(request).await {
256 log::warn!(error:?; "FIDL error");
257 }
258 }
259 Ok(())
260 }
261}
262
263pub struct SessionManager<I: Interface + ?Sized> {
264 interface: Arc<I>,
265 active_requests: ActiveRequests<usize>,
266
267 buffer_allocator: OnceLock<BufferAllocator>,
270}
271
272impl<I: Interface + ?Sized> Drop for SessionManager<I> {
273 fn drop(&mut self) {
274 if let Some(allocator) = self.buffer_allocator.get() {
275 self.interface.on_detach_vmo(allocator.buffer_source().vmo());
276 }
277 }
278}
279
280impl<I: Interface + ?Sized> SessionManager<I> {
281 pub fn new(interface: Arc<I>) -> Self {
282 Self {
283 interface,
284 active_requests: ActiveRequests::default(),
285 buffer_allocator: OnceLock::new(),
286 }
287 }
288
289 pub fn interface(&self) -> &Arc<I> {
290 &self.interface
291 }
292
293 pub async fn serve_session(
295 self: Arc<Self>,
296 stream: fblock::SessionRequestStream,
297 offset_map: OffsetMap,
298 max_transfer_blocks: Option<std::num::NonZero<u32>>,
299 block_size: u32,
300 ) -> Result<(), Error> {
301 let (helper, fifo) =
302 SessionHelper::new(self.clone(), offset_map, max_transfer_blocks, block_size)?;
303 let session = Arc::new(Session {
304 helper: Arc::new(helper),
305 interface: self.interface.clone(),
306 close_callback: Mutex::new(None),
307 });
308
309 let (stop_sender, stop_receiver) = futures::channel::oneshot::channel();
310
311 let mut stream = stream.fuse();
312 let scope = fasync::Scope::new();
313 let session_clone = session.clone();
314 let mut fifo_task = scope
315 .spawn(async move {
316 if let Err(status) = session_clone.run_fifo(fifo, stop_receiver).await {
317 if status != zx::Status::PEER_CLOSED {
318 log::error!(status:?; "FIFO error");
319 }
320 }
321 })
322 .fuse();
323
324 scopeguard::defer! {
326 for (_, registered_vmo) in session.helper.take_vmos() {
327 self.interface.on_detach_vmo(®istered_vmo.vmo);
328 }
329 }
330
331 let mut closing = false;
332 let mut stop_sender = Some(stop_sender);
333
334 loop {
335 futures::select! {
336 maybe_req = if closing {
337 futures::future::pending().left_future()
338 } else {
339 stream.next().right_future()
340 } => {
341 if let Some(req) = maybe_req {
342 match session.helper.handle_request(req?).await? {
343 HandleRequestResult::Ok => {},
344 HandleRequestResult::Closed(callback) => {
345 *session.close_callback.lock() = Some(callback);
346 if let Some(sender) = stop_sender.take() {
348 let _ = sender.send(());
349 }
350 closing = true;
351 }
352 }
353 } else {
354 if let Some(sender) = stop_sender.take() {
356 let _ = sender.send(());
357 }
358 closing = true;
359 }
360 }
361 _ = fifo_task => break,
362 }
363 }
364 Ok(())
365 }
366}
367
368pub struct Session<I: Interface + ?Sized> {
369 interface: Arc<I>,
370 helper: Arc<SessionHelper<SessionManager<I>>>,
371 close_callback: Mutex<Option<Box<dyn FnOnce() + Send + 'static>>>,
372}
373
374impl<I: Interface + ?Sized> Session<I> {
375 async fn run_fifo(
377 &self,
378 fifo: zx::Fifo<BlockFifoRequest, BlockFifoResponse>,
379 stop_signal: futures::channel::oneshot::Receiver<()>,
380 ) -> Result<(), zx::Status> {
381 scopeguard::defer! {
382 self.helper.drop_active_requests(|session| *session == self as *const _ as usize);
385 }
386
387 let mut fifo = fasync::Fifo::from_fifo(fifo);
397 let (mut reader, mut writer) = fifo.async_io();
398 let mut requests = [MaybeUninit::<BlockFifoRequest>::uninit(); FIFO_MAX_REQUESTS];
399 let active_requests = &self.helper.session_manager().active_requests;
400 let mut active_request_futures = FuturesUnordered::new();
401 let mut responses = Vec::new();
402
403 let mut map_future = pin!(Fuse::terminated());
408 let mut pending_mappings: VecDeque<DecodedRequest> = VecDeque::new();
409
410 let mut stop_signal = pin!(stop_signal.fuse());
413 let mut is_closed = false;
414
415 loop {
416 let new_requests = {
417 let pending_requests = active_request_futures.len() + responses.len();
420
421 if is_closed
422 && pending_requests == 0
423 && map_future.is_terminated()
424 && pending_mappings.is_empty()
425 {
426 return Ok(());
427 }
428
429 let count = requests.len().saturating_sub(pending_requests);
430 let mut receive_requests = pin!(if count == 0 || is_closed {
431 Fuse::terminated()
432 } else {
433 reader.read_entries(&mut requests[..count]).fuse()
434 });
435 let mut send_responses = pin!(if responses.is_empty() {
436 Fuse::terminated()
437 } else {
438 poll_fn(|cx| -> Poll<Result<(), zx::Status>> {
439 match ready!(writer.try_write(cx, &responses[..])) {
440 Ok(written) => {
441 responses.drain(..written.get());
442 Poll::Ready(Ok(()))
443 }
444 Err(status) => Poll::Ready(Err(status)),
445 }
446 })
447 .fuse()
448 });
449
450 select_biased!(
453 res = send_responses => {
454 res?;
455 0
456 },
457 response = active_request_futures.select_next_some() => {
458 responses.extend(response);
459 0
460 }
461 result = map_future => {
462 match result {
463 Ok((request, remainder, commit_decompression_buffers)) => {
464 active_request_futures.push(self.process_fifo_request(
465 request,
466 commit_decompression_buffers,
467 ));
468 if let Some(remainder) = remainder {
469 map_future.set(
470 self.map_request_or_get_response(remainder).fuse()
471 );
472 }
473 }
474 Err(response) => responses.extend(response),
475 }
476 if map_future.is_terminated() {
477 if let Some(request) = pending_mappings.pop_front() {
478 map_future.set(self.map_request_or_get_response(request).fuse());
479 }
480 }
481 0
482 }
483 _ = stop_signal => {
484 is_closed = true;
485 0
486 }
487 count = receive_requests => {
488 count?.get()
489 }
490 )
491 };
492
493 for request in &mut requests[..new_requests] {
496 match self.helper.decode_fifo_request(self as *const _ as usize, unsafe {
497 request.assume_init_mut()
498 }) {
499 Ok(DecodedRequest {
500 operation: Operation::CloseVmo, vmo, request_id, ..
501 }) => {
502 if let Some(vmo) = vmo {
503 self.interface.on_detach_vmo(vmo.as_ref());
504 }
505 responses.extend(
506 active_requests
507 .complete_and_take_response(request_id, Ok(()))
508 .map(|(_, response)| response),
509 );
510 }
511 Ok(request) => {
512 if map_future.is_terminated() {
513 map_future.set(self.map_request_or_get_response(request).fuse());
514 } else {
515 pending_mappings.push_back(request);
516 }
517 }
518 Err(None) => {}
519 Err(Some(response)) => responses.push(response),
520 }
521 }
522 }
523 }
524
525 async fn map_request_or_get_response(
526 &self,
527 request: DecodedRequest,
528 ) -> Result<(DecodedRequest, Option<DecodedRequest>, bool), Option<BlockFifoResponse>> {
529 let request_id = request.request_id;
530 self.map_request(request).await.map_err(|status| {
531 self.helper
532 .orchestrator
533 .active_requests
534 .complete_and_take_response(request_id, Err(status))
535 .map(|(_, r)| r)
536 })
537 }
538
539 async fn map_request(
542 &self,
543 mut request: DecodedRequest,
544 ) -> Result<(DecodedRequest, Option<DecodedRequest>, bool), zx::Status> {
545 let mut active_requests;
546 let active_request;
547 let mut commit_decompression_buffers = false;
548 let flags = self.interface.get_info().as_ref().device_flags();
549 if !flags.contains(DeviceFlag::BARRIER_SUPPORT)
552 && request.operation.take_write_flag(WriteFlags::PRE_BARRIER)
553 {
554 if let Some(id) = request.trace_flow_id {
555 fuchsia_trace::async_instant!(
556 fuchsia_trace::Id::from(id.get()),
557 "storage",
558 "block_server::SimulatedBarrier",
559 "request_id" => request.request_id.0
560 );
561 }
562 self.interface.flush(request.trace_flow_id).await?;
563 }
564
565 match request.operation {
567 Operation::StartDecompressedRead {
568 required_buffer_size,
569 device_block_offset,
570 block_count,
571 options,
572 } => {
573 let allocator = match self.helper.session_manager().buffer_allocator.get() {
574 Some(a) => a,
575 None => {
576 let source = BufferSource::new(fblock::MAX_DECOMPRESSED_BYTES as usize);
579 self.interface.on_attach_vmo(&source.vmo()).await?;
580 let allocator = BufferAllocator::new(
581 std::cmp::max(
582 self.helper.block_size as usize,
583 zx::system_get_page_size() as usize,
584 ),
585 source,
586 );
587 self.helper.session_manager().buffer_allocator.set(allocator).unwrap();
588 self.helper.session_manager().buffer_allocator.get().unwrap()
589 }
590 };
591
592 if required_buffer_size > fblock::MAX_DECOMPRESSED_BYTES as usize {
593 return Err(zx::Status::OUT_OF_RANGE);
594 }
595
596 let buffer = allocator.allocate_buffer(required_buffer_size).await;
597 let vmo_offset = buffer.range().start as u64;
598
599 unsafe fn remove_lifetime(buffer: Buffer<'_>) -> Buffer<'static> {
603 unsafe { std::mem::transmute(buffer) }
604 }
605
606 active_requests = self.helper.session_manager().active_requests.0.lock();
607 active_request = &mut active_requests.requests[request.request_id.0];
608
609 active_request.decompression_info.as_mut().unwrap().buffer =
612 Some(unsafe { remove_lifetime(buffer) });
613
614 request.operation = Operation::Read {
615 device_block_offset,
616 block_count,
617 _unused: 0,
618 vmo_offset,
619 options,
620 };
621 request.vmo = Some(allocator.buffer_source().vmo().clone());
622
623 commit_decompression_buffers = true;
624 }
625 Operation::ContinueDecompressedRead {
626 offset,
627 device_block_offset,
628 block_count,
629 options,
630 } => {
631 active_requests = self.helper.session_manager().active_requests.0.lock();
632 active_request = &mut active_requests.requests[request.request_id.0];
633
634 let buffer =
635 active_request.decompression_info.as_ref().unwrap().buffer.as_ref().unwrap();
636
637 if offset >= buffer.len() as u64
639 || buffer.len() as u64 - offset
640 < block_count as u64 * self.helper.block_size as u64
641 {
642 return Err(zx::Status::OUT_OF_RANGE);
643 }
644
645 request.operation = Operation::Read {
646 device_block_offset,
647 block_count,
648 _unused: 0,
649 vmo_offset: buffer.range().start as u64 + offset,
650 options,
651 };
652
653 let allocator = self.helper.session_manager().buffer_allocator.get().unwrap();
654 request.vmo = Some(allocator.buffer_source().vmo().clone());
655 }
656 _ => {
657 active_requests = self.helper.session_manager().active_requests.0.lock();
658 active_request = &mut active_requests.requests[request.request_id.0];
659 }
660 }
661
662 self.helper
666 .map_request(request, active_request)
667 .map(|(request, remainder)| (request, remainder, commit_decompression_buffers))
668 }
669
670 async fn process_fifo_request(
672 &self,
673 DecodedRequest { request_id, operation, vmo, trace_flow_id }: DecodedRequest,
674 commit_decompression_buffers: bool,
675 ) -> Option<BlockFifoResponse> {
676 let mut needs_postflush = false;
677 let result = match operation {
678 Operation::Read { device_block_offset, block_count, _unused, vmo_offset, options } => {
679 join(
680 self.interface.read(
681 device_block_offset,
682 block_count,
683 vmo.as_ref().unwrap(),
684 vmo_offset,
685 options,
686 trace_flow_id,
687 ),
688 async {
689 if commit_decompression_buffers {
690 let (target_slice, buffer_slice, buffer_range) = {
691 let active_request = self
692 .helper
693 .session_manager()
694 .active_requests
695 .request(request_id);
696 let info = active_request.decompression_info.as_ref().unwrap();
697 (
698 info.uncompressed_slice(),
699 self.helper
700 .orchestrator
701 .buffer_allocator
702 .get()
703 .unwrap()
704 .buffer_source()
705 .slice(),
706 info.buffer.as_ref().unwrap().range(),
707 )
708 };
709 let vmar = fuchsia_runtime::vmar_root_self();
710 let addr = target_slice.addr();
712 let unaligned = addr % zx::system_get_page_size() as usize;
713 if let Err(error) = vmar.op_range(
714 zx::VmarOp::COMMIT,
715 addr - unaligned,
716 target_slice.len() + unaligned,
717 ) {
718 log::warn!(error:?; "Unable to commit target range");
719 }
720 if let Err(error) = vmar.op_range(
722 zx::VmarOp::PREFETCH,
723 buffer_slice.addr() + buffer_range.start,
724 buffer_range.len(),
725 ) {
726 log::warn!(
727 error:?,
728 buffer_range:?;
729 "Unable to prefetch source range",
730 );
731 }
732 }
733 },
734 )
735 .await
736 .0
737 }
738 Operation::Write {
739 device_block_offset,
740 block_count,
741 _unused,
742 vmo_offset,
743 mut options,
744 } => {
745 if options.flags.contains(WriteFlags::FORCE_ACCESS) {
748 let flags = self.interface.get_info().as_ref().device_flags();
749 if !flags.contains(DeviceFlag::FUA_SUPPORT) {
750 options.flags.remove(WriteFlags::FORCE_ACCESS);
751 needs_postflush = true;
752 }
753 }
754 self.interface
755 .write(
756 device_block_offset,
757 block_count,
758 vmo.as_ref().unwrap(),
759 vmo_offset,
760 options,
761 trace_flow_id,
762 )
763 .await
764 }
765 Operation::Flush => self.interface.flush(trace_flow_id).await,
766 Operation::Trim { device_block_offset, block_count } => {
767 self.interface.trim(device_block_offset, block_count, trace_flow_id).await
768 }
769 Operation::CloseVmo
770 | Operation::StartDecompressedRead { .. }
771 | Operation::ContinueDecompressedRead { .. } => {
772 unreachable!()
774 }
775 };
776 let response = self
777 .helper
778 .orchestrator
779 .active_requests
780 .complete_and_take_response(request_id, result)
781 .map(|(_, r)| r);
782 if let Some(mut response) = response {
783 if zx::Status::ok(response.status).is_ok() && needs_postflush {
785 if let Some(id) = trace_flow_id {
786 fuchsia_trace::async_instant!(
787 fuchsia_trace::Id::from(id.get()),
788 "storage",
789 "block_server::SimulatedFUA",
790 "request_id" => request_id.0
791 );
792 }
793 response.status =
794 zx::Status::result_into_raw(self.interface.flush(trace_flow_id).await);
795 }
796 Some(response)
797 } else {
798 response
799 }
800 }
801}
802
803impl<I: Interface + ?Sized> super::SessionManager for SessionManager<I> {
804 type Orchestrator = Self;
805
806 const SUPPORTS_DECOMPRESSION: bool = true;
807
808 type Session = usize;
810
811 fn session_eq(a: &usize, b: &usize) -> bool {
812 a == b
813 }
814
815 async fn on_attach_vmo(orchestrator: Arc<Self>, vmo: &Arc<zx::Vmo>) -> Result<(), zx::Status> {
816 I::on_attach_vmo(&orchestrator.interface, vmo).await
817 }
818
819 async fn open_session(
820 orchestrator: Arc<Self>,
821 stream: fblock::SessionRequestStream,
822 offset_map: OffsetMap,
823 block_size: u32,
824 ) -> Result<(), Error> {
825 I::open_session(
826 &orchestrator.interface,
827 orchestrator.clone(),
828 stream,
829 offset_map,
830 block_size,
831 )
832 .await
833 }
834
835 fn get_info(&self) -> Cow<'_, DeviceInfo> {
836 self.interface.get_info()
837 }
838
839 async fn get_volume_info(
840 &self,
841 ) -> Result<(fblock::VolumeManagerInfo, fblock::VolumeInfo), zx::Status> {
842 self.interface.get_volume_info().await
843 }
844
845 async fn query_slices(
846 &self,
847 start_slices: &[u64],
848 ) -> Result<Vec<fblock::VsliceRange>, zx::Status> {
849 self.interface.query_slices(start_slices).await
850 }
851
852 async fn extend(&self, start_slice: u64, slice_count: u64) -> Result<(), zx::Status> {
853 self.interface.extend(start_slice, slice_count).await
854 }
855
856 async fn shrink(&self, start_slice: u64, slice_count: u64) -> Result<(), zx::Status> {
857 self.interface.shrink(start_slice, slice_count).await
858 }
859
860 fn open_mapper_session(
861 orchestrator: Arc<Self>,
862 session: fidl::endpoints::ServerEnd<fblock::MapperSessionMarker>,
863 mapping_vmo: zx::Vmo,
864 block_size: u32,
865 port: Option<zx::Port>,
866 delivery_queue: Option<zx::Vmo>,
867 ) -> Result<impl Future<Output = Result<(), Error>> + Send, zx::Status> {
868 I::open_mapper_session(orchestrator, session, mapping_vmo, block_size, port, delivery_queue)
869 }
870
871 fn active_requests(&self) -> &ActiveRequests<Self::Session> {
872 return &self.active_requests;
873 }
874}
875
876impl<I: Interface + ?Sized> Drop for Session<I> {
877 fn drop(&mut self) {
878 let callback = std::mem::take(&mut *self.close_callback.lock());
879 if let Some(callback) = callback {
880 callback();
881 }
882 }
883}
884
885impl<I: Interface> IntoOrchestrator for Arc<I> {
886 type SM = SessionManager<I>;
887
888 fn into_orchestrator(self) -> Arc<Self::SM> {
889 Arc::new(SessionManager {
890 interface: self,
891 active_requests: ActiveRequests::default(),
892 buffer_allocator: OnceLock::new(),
893 })
894 }
895}
896
897pub struct AsyncBlockService<I: Interface + ?Sized> {
901 interface: Arc<I>,
902 allocator: Arc<BufferAllocator>,
903 block_size: u32,
904 scope: fasync::ScopeHandle,
905}
906
907impl<I: Interface + ?Sized> AsyncBlockService<I> {
908 pub async fn new(
909 interface: Arc<I>,
910 block_size: u32,
911 pool_capacity: usize,
912 scope: fasync::ScopeHandle,
913 ) -> Result<Self, zx::Status> {
914 let source = BufferSource::new(pool_capacity);
915 interface.on_attach_vmo(&source.vmo()).await?;
916 let allocator = Arc::new(BufferAllocator::new(
917 std::cmp::max(block_size as usize, zx::system_get_page_size() as usize),
918 source,
919 ));
920 Ok(Self { interface, allocator, block_size, scope })
921 }
922
923 pub fn new_with_allocator(
924 interface: Arc<I>,
925 block_size: u32,
926 allocator: Arc<BufferAllocator>,
927 scope: fasync::ScopeHandle,
928 ) -> Self {
929 Self { interface, allocator, block_size, scope }
930 }
931
932 pub fn interface(&self) -> &Arc<I> {
933 &self.interface
934 }
935
936 pub fn allocator(&self) -> &Arc<BufferAllocator> {
937 &self.allocator
938 }
939}
940
941impl<I: Interface + ?Sized> BlockService for AsyncBlockService<I> {
942 fn allocate_buffer(&self, max_len: usize) -> OwnedBuffer {
943 let max_len = std::cmp::min(
944 std::cmp::min(max_len, MAX_READ_BUFFER_SIZE),
945 self.allocator.buffer_source().size(),
946 );
947 self.allocator.allocate_buffer_sync_owned(max_len)
948 }
949
950 fn read_blocks(
951 &self,
952 device_offset: u64,
953 dest_buffer: OwnedBuffer,
954 on_complete: Box<dyn FnOnce(Result<OwnedBuffer, Error>) + Send>,
955 ) -> Result<(), Error> {
956 let block_size = self.block_size as u64;
957 let device_block_offset = device_offset / block_size;
958 let block_count = (dest_buffer.len() as u64 / block_size) as u32;
959
960 let vmo_offset = dest_buffer.range().start as u64;
961 let vmo = self.allocator.buffer_source().vmo().clone();
962 let interface = self.interface.clone();
963
964 self.scope.spawn(async move {
965 let res = interface
966 .read(
967 device_block_offset,
968 block_count,
969 &vmo,
970 vmo_offset,
971 ReadOptions::default(),
972 TraceFlowId::default(),
973 )
974 .await;
975 match res {
976 Ok(()) => on_complete(Ok(dest_buffer)),
977 Err(status) => on_complete(Err(anyhow::anyhow!("Read failed: {:?}", status))),
978 }
979 });
980
981 Ok(())
982 }
983}
984
985#[cfg(test)]
986mod tests {
987 use super::*;
988 use crate::BlockServer;
989 use fuchsia_async as fasync;
990 use mapping::Extents;
991 use mapping::reader::read_aligned_range;
992 use std::sync::atomic::{AtomicU64, Ordering};
993
994 struct FakeInterface {
995 data: Vec<u8>,
996 block_size: u32,
997 read_count: AtomicU64,
998 }
999
1000 impl FakeInterface {
1001 fn new(data: Vec<u8>, block_size: u32) -> Self {
1002 Self { data, block_size, read_count: AtomicU64::new(0) }
1003 }
1004 }
1005
1006 impl Interface for FakeInterface {
1007 fn on_open_mapper_session(
1008 &self,
1009 _mapping_vmo: &zx::Vmo,
1010 delivery_queue: zx::Vmo,
1011 ) -> Result<Verifier, zx::Status> {
1012 Ok(Verifier::new(delivery_queue))
1013 }
1014
1015 fn get_info(&self) -> Cow<'_, DeviceInfo> {
1016 Cow::Owned(DeviceInfo::Block(crate::BlockInfo {
1017 block_count: (self.data.len() / self.block_size as usize) as u64,
1018 max_transfer_blocks: None,
1019 device_flags: fblock::DeviceFlag::empty(),
1020 }))
1021 }
1022
1023 async fn read(
1024 &self,
1025 device_block_offset: u64,
1026 block_count: u32,
1027 vmo: &Arc<zx::Vmo>,
1028 vmo_offset: u64,
1029 _opts: ReadOptions,
1030 _trace_flow_id: TraceFlowId,
1031 ) -> Result<(), zx::Status> {
1032 self.read_count.fetch_add(1, Ordering::Relaxed);
1033 let byte_offset = (device_block_offset * self.block_size as u64) as usize;
1034 let byte_len = (block_count * self.block_size) as usize;
1035 let slice = &self.data[byte_offset..byte_offset + byte_len];
1036 vmo.write(slice, vmo_offset).map_err(|_| zx::Status::IO)?;
1037 Ok(())
1038 }
1039
1040 async fn write(
1041 &self,
1042 _device_block_offset: u64,
1043 _block_count: u32,
1044 _vmo: &Arc<zx::Vmo>,
1045 _vmo_offset: u64,
1046 _opts: WriteOptions,
1047 _trace_flow_id: TraceFlowId,
1048 ) -> Result<(), zx::Status> {
1049 Ok(())
1050 }
1051
1052 async fn flush(&self, _trace_flow_id: TraceFlowId) -> Result<(), zx::Status> {
1053 Ok(())
1054 }
1055
1056 async fn trim(
1057 &self,
1058 _device_block_offset: u64,
1059 _block_count: u32,
1060 _trace_flow_id: TraceFlowId,
1061 ) -> Result<(), zx::Status> {
1062 Ok(())
1063 }
1064 }
1065
1066 #[fasync::run_singlethreaded(test)]
1067 async fn test_async_block_service_read_aligned_range() {
1068 let block_size = 512;
1069 let test_data: Vec<u8> = (0..8192).map(|i| (i % 255) as u8).collect();
1070 let interface = Arc::new(FakeInterface::new(test_data.clone(), block_size));
1071 let scope = fasync::Scope::current();
1072
1073 let block_service = Arc::new(
1074 AsyncBlockService::new(interface, block_size, 16384, scope)
1075 .await
1076 .expect("Failed to create AsyncBlockService"),
1077 );
1078
1079 let encoded = (1u64 << 32) | 0u64;
1080 let extents = Extents::from_encoded([encoded], 0).unwrap();
1081 let service = block_service.clone();
1082 let (send, recv) = futures::channel::oneshot::channel();
1083 let send = std::sync::Mutex::new(Some(send));
1084 let read_buf = std::sync::Mutex::new(Vec::new());
1085
1086 read_aligned_range(&extents, 0..4096, &*service, move |buffer_result| {
1087 let buffer = buffer_result.unwrap();
1088 let mut read_guard = read_buf.lock().unwrap();
1089 buffer.as_ptr_slice().append_to(&mut read_guard);
1090 if read_guard.len() == 4096 {
1091 if let Some(s) = send.lock().unwrap().take() {
1092 let _ = s.send(read_guard.clone());
1093 }
1094 }
1095 std::ops::ControlFlow::Continue(())
1096 });
1097
1098 let result = recv.await.unwrap();
1099 assert_eq!(result, &test_data[0..4096]);
1100 }
1101
1102 #[fasync::run_singlethreaded(test)]
1103 async fn test_async_block_service_concurrent_reads_larger_than_pool_capacity() {
1104 let block_size = 512;
1105 let total_size = 65536; let test_data: Vec<u8> = (0..total_size).map(|i| (i % 251) as u8).collect();
1107 let interface = Arc::new(FakeInterface::new(test_data.clone(), block_size));
1108 let scope = fasync::Scope::current();
1109
1110 let pool_capacity = 8192;
1113 let source = BufferSource::new(pool_capacity);
1114 interface.on_attach_vmo(&source.vmo()).await.unwrap();
1115 let allocator = Arc::new(BufferAllocator::new(
1116 std::cmp::max(block_size as usize, zx::system_get_page_size() as usize),
1117 source,
1118 ));
1119 let block_service = Arc::new(AsyncBlockService::new_with_allocator(
1120 interface, block_size, allocator, scope,
1121 ));
1122
1123 let encoded = (16u64 << 32) | 0u64;
1124 let extents = Arc::new(Extents::from_encoded([encoded], 0).unwrap());
1125
1126 let ranges = [0..16384, 16384..32768, 32768..49152, 49152..65536];
1128 let mut receivers = Vec::new();
1129
1130 for range in ranges {
1131 let (send, recv) = futures::channel::oneshot::channel();
1132 let service = block_service.clone();
1133 let extents = extents.clone();
1134
1135 std::thread::spawn(move || {
1136 let send = std::sync::Mutex::new(Some(send));
1137 let read_buf = std::sync::Mutex::new(Vec::new());
1138 let target_len = (range.end - range.start) as usize;
1139
1140 read_aligned_range(&extents, range, &*service, move |buffer_result| {
1141 let buffer = buffer_result.unwrap();
1142 let mut read_guard = read_buf.lock().unwrap();
1143 buffer.as_ptr_slice().append_to(&mut read_guard);
1144 if read_guard.len() == target_len {
1145 if let Some(s) = send.lock().unwrap().take() {
1146 let _ = s.send(read_guard.clone());
1147 }
1148 }
1149 std::ops::ControlFlow::Continue(())
1150 });
1151 });
1152
1153 receivers.push(recv);
1154 }
1155
1156 let results = futures::future::join_all(receivers).await;
1157 for (i, res) in results.into_iter().enumerate() {
1158 let data = res.unwrap();
1159 let start = i * 16384;
1160 let end = start + 16384;
1161 assert_eq!(data, &test_data[start..end]);
1162 }
1163 }
1164
1165 #[fuchsia::test]
1166 async fn test_async_interface_mapper_hierarchical_session() {
1167 use assert_matches::assert_matches;
1168
1169 let block_size = 512;
1170 let test_data = vec![0xCDu8; 8192];
1171 let interface = Arc::new(FakeInterface::new(test_data.clone(), block_size));
1172 let block_server = BlockServer::new(block_size, interface.clone());
1173
1174 let (mapper_proxy, mapper_stream) =
1175 fidl::endpoints::create_proxy_and_stream::<fblock::MapperMarker>();
1176 let scope = fasync::Scope::new();
1177 scope.spawn(async move {
1178 let _ = block_server.handle_mapper_requests(mapper_stream).await;
1179 });
1180
1181 let (root_session_proxy, root_session_server) =
1183 fidl::endpoints::create_proxy::<fblock::MapperSessionMarker>();
1184 let root_mapping_vmo = zx::Vmo::create(65536).unwrap();
1185
1186 let partition_key = 500u64;
1187 let extents =
1188 mapping::Extents::try_new([mapping::Extent::new(0..4096, Some(4096))], 0).unwrap();
1189 let partition_extents: Vec<u64> = mapping::Extents::encode_extents(&extents).collect();
1190 let mut payload_bytes = Vec::new();
1191 for w in &partition_extents {
1192 payload_bytes.extend_from_slice(&w.to_le_bytes());
1193 }
1194 let cmd = mapping::RawMappingCommand {
1195 opcode: mapping::MAPPINGS_COMMAND,
1196 offset: 0,
1197 key: partition_key,
1198 stored_size: 4096,
1199 device_offset: 0,
1200 metadata_count: 0,
1201 extent_count: partition_extents.len() as u32,
1202 };
1203 let mut sender = vmo_fifo::SyncSender::<mapping::RawMappingCommand>::new(
1204 root_mapping_vmo.duplicate_handle(zx::Rights::SAME_RIGHTS).unwrap(),
1205 1024,
1206 256,
1207 )
1208 .unwrap();
1209 let mut payload_buf = sender.reserve_payload(payload_bytes.len()).unwrap();
1210 payload_buf.data().copy_from_slice(&payload_bytes);
1211 payload_buf.commit(cmd).unwrap();
1212
1213 let res = mapper_proxy
1214 .open_session(root_session_server, root_mapping_vmo, None, None)
1215 .await
1216 .unwrap();
1217 assert_matches!(res, Ok(()));
1218
1219 let pager = Arc::new(zx::Pager::create(zx::PagerOptions::empty()).unwrap());
1221 let port = zx::Port::create();
1222 let child_key = 2002u64;
1223 let paged_vmo = pager.create_vmo(zx::VmoOptions::empty(), &port, child_key, 4096).unwrap();
1224
1225 let child_mapping_vmo = zx::Vmo::create(65536).unwrap();
1226 let delivery_queue = zx::Vmo::create(65536).unwrap();
1227 let vmo_provider = Arc::new(blob_pager_and_verifier::TestVmoProvider::new(
1228 pager.clone(),
1229 delivery_queue.duplicate_handle(zx::Rights::SAME_RIGHTS).unwrap(),
1230 ));
1231 vmo_provider
1232 .register_vmo(child_key, paged_vmo.duplicate_handle(zx::Rights::SAME_RIGHTS).unwrap());
1233 let receiver = vmo_fifo::Receiver::<mapping::RawDeliveryCommand>::new(
1234 delivery_queue.duplicate_handle(zx::Rights::SAME_RIGHTS).unwrap(),
1235 mapping::PENDING_DELIVERY_COMMANDS_CAPACITY,
1236 )
1237 .unwrap();
1238 let _delivery_processor = blob_pager_and_verifier::DeliveryQueueProcessor::spawn(
1239 receiver,
1240 vmo_provider,
1241 delivery_queue.duplicate_handle(zx::Rights::SAME_RIGHTS).unwrap(),
1242 )
1243 .unwrap();
1244
1245 let extents =
1246 mapping::Extents::try_new([mapping::Extent::new(0..4096, Some(0))], 0).unwrap();
1247 let child_extents: Vec<u64> = mapping::Extents::encode_extents(&extents).collect();
1248 let mut child_payload_bytes = Vec::new();
1249 for w in &child_extents {
1250 child_payload_bytes.extend_from_slice(&w.to_le_bytes());
1251 }
1252 let child_cmd = mapping::RawMappingCommand {
1253 opcode: mapping::MAPPINGS_COMMAND,
1254 offset: 0,
1255 key: child_key,
1256 stored_size: 4096,
1257 device_offset: 0,
1258 metadata_count: 0,
1259 extent_count: child_extents.len() as u32,
1260 };
1261 let mut child_sender = vmo_fifo::SyncSender::<mapping::RawMappingCommand>::new(
1262 child_mapping_vmo.duplicate_handle(zx::Rights::SAME_RIGHTS).unwrap(),
1263 1024,
1264 256,
1265 )
1266 .unwrap();
1267 let mut child_payload_buf =
1268 child_sender.reserve_payload(child_payload_bytes.len()).unwrap();
1269 child_payload_buf.data().copy_from_slice(&child_payload_bytes);
1270 child_payload_buf.commit(child_cmd).unwrap();
1271
1272 let mut child_session = None;
1273 for _ in 0..100 {
1274 let (child_session_proxy, child_session_server) =
1275 fidl::endpoints::create_proxy::<fblock::MapperSessionMarker>();
1276 let child_res_raw = root_session_proxy
1277 .open_child_session(
1278 child_session_server,
1279 child_mapping_vmo.duplicate_handle(zx::Rights::SAME_RIGHTS).unwrap(),
1280 partition_key,
1281 Some(port.duplicate_handle(zx::Rights::SAME_RIGHTS).unwrap()),
1282 Some(delivery_queue.duplicate_handle(zx::Rights::SAME_RIGHTS).unwrap()),
1283 )
1284 .await
1285 .unwrap();
1286 if child_res_raw.is_ok() {
1287 child_session = Some(child_session_proxy);
1288 break;
1289 }
1290 fasync::Timer::new(std::time::Duration::from_millis(10)).await;
1291 }
1292 assert!(child_session.is_some());
1293
1294 let (tx, rx) = futures::channel::oneshot::channel();
1295 std::thread::spawn(move || {
1296 let mut buf = [0u8; 4096];
1297 paged_vmo.read(&mut buf, 0).expect("paged vmo read failed");
1298 let _ = tx.send(buf);
1299 });
1300
1301 let read_bytes = rx.await.unwrap();
1302 assert_eq!(read_bytes.len(), 4096);
1303 assert_eq!(read_bytes, &test_data[4096..8192]);
1304 }
1305
1306 #[fuchsia::test]
1307 async fn test_async_interface_mapper_child_session_closed_when_parent_closed() {
1308 use assert_matches::assert_matches;
1309 use fidl::endpoints::Proxy as _;
1310
1311 let block_size = 512;
1312 let test_data = vec![0u8; 8192];
1313 let interface = Arc::new(FakeInterface::new(test_data, block_size));
1314 let block_server = BlockServer::new(block_size, interface.clone());
1315
1316 let (mapper_proxy, mapper_stream) =
1317 fidl::endpoints::create_proxy_and_stream::<fblock::MapperMarker>();
1318 let scope = fasync::Scope::new();
1319 scope.spawn(async move {
1320 let _ = block_server.handle_mapper_requests(mapper_stream).await;
1321 });
1322
1323 let (root_session_proxy, root_session_server) =
1324 fidl::endpoints::create_proxy::<fblock::MapperSessionMarker>();
1325 let root_mapping_vmo = zx::Vmo::create(65536).unwrap();
1326
1327 let partition_key = 500u64;
1328 let extents =
1329 mapping::Extents::try_new([mapping::Extent::new(0..4096, Some(4096))], 0).unwrap();
1330 let partition_extents: Vec<u64> = mapping::Extents::encode_extents(&extents).collect();
1331 let mut payload_bytes = Vec::new();
1332 for w in &partition_extents {
1333 payload_bytes.extend_from_slice(&w.to_le_bytes());
1334 }
1335 let cmd = mapping::RawMappingCommand {
1336 opcode: mapping::MAPPINGS_COMMAND,
1337 offset: 0,
1338 key: partition_key,
1339 stored_size: 4096,
1340 device_offset: 0,
1341 metadata_count: 0,
1342 extent_count: partition_extents.len() as u32,
1343 };
1344 let mut sender = vmo_fifo::SyncSender::<mapping::RawMappingCommand>::new(
1345 root_mapping_vmo.duplicate_handle(zx::Rights::SAME_RIGHTS).unwrap(),
1346 1024,
1347 256,
1348 )
1349 .unwrap();
1350 let mut payload_buf = sender.reserve_payload(payload_bytes.len()).unwrap();
1351 payload_buf.data().copy_from_slice(&payload_bytes);
1352 payload_buf.commit(cmd).unwrap();
1353
1354 let res = mapper_proxy
1355 .open_session(root_session_server, root_mapping_vmo, None, None)
1356 .await
1357 .unwrap();
1358 assert_matches!(res, Ok(()));
1359
1360 let child_mapping_vmo = zx::Vmo::create(65536).unwrap();
1361 let mut child_session = None;
1362 for _ in 0..100 {
1363 let (child_session_proxy, child_session_server) =
1364 fidl::endpoints::create_proxy::<fblock::MapperSessionMarker>();
1365 let child_res_raw = root_session_proxy
1366 .open_child_session(
1367 child_session_server,
1368 child_mapping_vmo.duplicate_handle(zx::Rights::SAME_RIGHTS).unwrap(),
1369 partition_key,
1370 None,
1371 None,
1372 )
1373 .await
1374 .unwrap();
1375 if child_res_raw.is_ok() {
1376 child_session = Some(child_session_proxy);
1377 break;
1378 }
1379 fasync::Timer::new(std::time::Duration::from_millis(10)).await;
1380 }
1381 let child_session_proxy = child_session.expect("Failed to open child session");
1382
1383 root_session_proxy.close().await.unwrap().expect("Close parent session failed");
1384 child_session_proxy.on_closed().await.unwrap();
1385 }
1386}