1use super::{
6 ActiveRequests, DecodedRequest, DeviceInfo, FIFO_MAX_REQUESTS, HandleRequestResult,
7 IntoOrchestrator, OffsetMap, Operation, SessionHelper, TraceFlowId,
8};
9use anyhow::Error;
10use block_protocol::{BlockFifoRequest, BlockFifoResponse, ReadOptions, WriteFlags, WriteOptions};
11use fidl_fuchsia_storage_block as fblock;
12use fidl_fuchsia_storage_block::DeviceFlag;
13use fuchsia_async as fasync;
14use fuchsia_sync::Mutex;
15use futures::future::{Fuse, FusedFuture, join};
16use futures::stream::FuturesUnordered;
17use futures::{FutureExt, StreamExt, select_biased};
18use mapping::reader::{BlockService, MAX_READ_BUFFER_SIZE};
19use std::borrow::Cow;
20use std::collections::VecDeque;
21use std::future::{Future, poll_fn};
22use std::mem::MaybeUninit;
23use std::pin::pin;
24use std::sync::{Arc, OnceLock};
25use std::task::{Poll, ready};
26use storage_device::buffer::{Buffer, OwnedBuffer};
27use storage_device::buffer_allocator::{BufferAllocator, BufferSource};
28
29pub trait Interface: Send + Sync + Unpin + 'static {
30 fn open_session(
59 &self,
60 session_manager: Arc<SessionManager<Self>>,
61 stream: fblock::SessionRequestStream,
62 offset_map: OffsetMap,
63 block_size: u32,
64 ) -> impl Future<Output = Result<(), Error>> + Send {
65 session_manager.serve_session(
67 stream,
68 offset_map,
69 self.get_info().max_transfer_blocks(),
70 block_size,
71 )
72 }
73
74 fn on_attach_vmo(&self, _vmo: &zx::Vmo) -> impl Future<Output = Result<(), zx::Status>> + Send {
78 async { Ok(()) }
79 }
80
81 fn on_detach_vmo(&self, _vmo: &zx::Vmo) {}
83
84 fn get_info(&self) -> Cow<'_, DeviceInfo>;
86
87 fn read(
94 &self,
95 device_block_offset: u64,
96 block_count: u32,
97 vmo: &Arc<zx::Vmo>,
98 vmo_offset: u64, opts: ReadOptions,
100 trace_flow_id: TraceFlowId,
101 ) -> impl Future<Output = Result<(), zx::Status>> + Send;
102
103 fn write(
110 &self,
111 device_block_offset: u64,
112 block_count: u32,
113 vmo: &Arc<zx::Vmo>,
114 vmo_offset: u64, opts: WriteOptions,
116 trace_flow_id: TraceFlowId,
117 ) -> impl Future<Output = Result<(), zx::Status>> + Send;
118
119 fn flush(
121 &self,
122 trace_flow_id: TraceFlowId,
123 ) -> impl Future<Output = Result<(), zx::Status>> + Send;
124
125 fn trim(
132 &self,
133 device_block_offset: u64,
134 block_count: u32,
135 trace_flow_id: TraceFlowId,
136 ) -> impl Future<Output = Result<(), zx::Status>> + Send;
137
138 fn get_volume_info(
140 &self,
141 ) -> impl Future<Output = Result<(fblock::VolumeManagerInfo, fblock::VolumeInfo), zx::Status>> + Send
142 {
143 async { Err(zx::Status::NOT_SUPPORTED) }
144 }
145
146 fn query_slices(
148 &self,
149 _start_slices: &[u64],
150 ) -> impl Future<Output = Result<Vec<fblock::VsliceRange>, zx::Status>> + Send {
151 async { Err(zx::Status::NOT_SUPPORTED) }
152 }
153
154 fn extend(
156 &self,
157 _start_slice: u64,
158 _slice_count: u64,
159 ) -> impl Future<Output = Result<(), zx::Status>> + Send {
160 async { Err(zx::Status::NOT_SUPPORTED) }
161 }
162
163 fn shrink(
165 &self,
166 _start_slice: u64,
167 _slice_count: u64,
168 ) -> impl Future<Output = Result<(), zx::Status>> + Send {
169 async { Err(zx::Status::NOT_SUPPORTED) }
170 }
171}
172
173pub struct PassthroughSession(fblock::SessionProxy);
175
176impl PassthroughSession {
177 pub fn new(proxy: fblock::SessionProxy) -> Self {
178 Self(proxy)
179 }
180
181 async fn handle_request(&self, request: fblock::SessionRequest) -> Result<(), Error> {
182 match request {
183 fblock::SessionRequest::GetFifo { responder } => {
184 responder.send(self.0.get_fifo().await?)?;
185 }
186 fblock::SessionRequest::AttachVmo { vmo, responder } => {
187 responder.send(self.0.attach_vmo(vmo).await?.as_ref().map_err(|s| *s))?;
188 }
189 fblock::SessionRequest::Close { responder } => {
190 responder.send(self.0.close().await?)?;
191 }
192 }
193 Ok(())
194 }
195
196 pub async fn serve(&self, mut stream: fblock::SessionRequestStream) -> Result<(), Error> {
198 while let Some(Ok(request)) = stream.next().await {
199 if let Err(error) = self.handle_request(request).await {
200 log::warn!(error:?; "FIDL error");
201 }
202 }
203 Ok(())
204 }
205}
206
207pub struct SessionManager<I: Interface + ?Sized> {
208 interface: Arc<I>,
209 active_requests: ActiveRequests<usize>,
210
211 buffer_allocator: OnceLock<BufferAllocator>,
214}
215
216impl<I: Interface + ?Sized> Drop for SessionManager<I> {
217 fn drop(&mut self) {
218 if let Some(allocator) = self.buffer_allocator.get() {
219 self.interface.on_detach_vmo(allocator.buffer_source().vmo());
220 }
221 }
222}
223
224impl<I: Interface + ?Sized> SessionManager<I> {
225 pub fn new(interface: Arc<I>) -> Self {
226 Self {
227 interface,
228 active_requests: ActiveRequests::default(),
229 buffer_allocator: OnceLock::new(),
230 }
231 }
232
233 pub fn interface(&self) -> &I {
234 self.interface.as_ref()
235 }
236
237 pub async fn serve_session(
239 self: Arc<Self>,
240 stream: fblock::SessionRequestStream,
241 offset_map: OffsetMap,
242 max_transfer_blocks: Option<std::num::NonZero<u32>>,
243 block_size: u32,
244 ) -> Result<(), Error> {
245 let (helper, fifo) =
246 SessionHelper::new(self.clone(), offset_map, max_transfer_blocks, block_size)?;
247 let session = Arc::new(Session {
248 helper: Arc::new(helper),
249 interface: self.interface.clone(),
250 close_callback: Mutex::new(None),
251 });
252
253 let (stop_sender, stop_receiver) = futures::channel::oneshot::channel();
254
255 let mut stream = stream.fuse();
256 let scope = fasync::Scope::new();
257 let session_clone = session.clone();
258 let mut fifo_task = scope
259 .spawn(async move {
260 if let Err(status) = session_clone.run_fifo(fifo, stop_receiver).await {
261 if status != zx::Status::PEER_CLOSED {
262 log::error!(status:?; "FIFO error");
263 }
264 }
265 })
266 .fuse();
267
268 scopeguard::defer! {
270 for (_, registered_vmo) in session.helper.take_vmos() {
271 self.interface.on_detach_vmo(®istered_vmo.vmo);
272 }
273 }
274
275 let mut closing = false;
276 let mut stop_sender = Some(stop_sender);
277
278 loop {
279 futures::select! {
280 maybe_req = if closing {
281 futures::future::pending().left_future()
282 } else {
283 stream.next().right_future()
284 } => {
285 if let Some(req) = maybe_req {
286 match session.helper.handle_request(req?).await? {
287 HandleRequestResult::Ok => {},
288 HandleRequestResult::Closed(callback) => {
289 *session.close_callback.lock() = Some(callback);
290 if let Some(sender) = stop_sender.take() {
292 let _ = sender.send(());
293 }
294 closing = true;
295 }
296 }
297 } else {
298 if let Some(sender) = stop_sender.take() {
300 let _ = sender.send(());
301 }
302 closing = true;
303 }
304 }
305 _ = fifo_task => break,
306 }
307 }
308 Ok(())
309 }
310}
311
312pub struct Session<I: Interface + ?Sized> {
313 interface: Arc<I>,
314 helper: Arc<SessionHelper<SessionManager<I>>>,
315 close_callback: Mutex<Option<Box<dyn FnOnce() + Send + 'static>>>,
316}
317
318impl<I: Interface + ?Sized> Session<I> {
319 async fn run_fifo(
321 &self,
322 fifo: zx::Fifo<BlockFifoRequest, BlockFifoResponse>,
323 stop_signal: futures::channel::oneshot::Receiver<()>,
324 ) -> Result<(), zx::Status> {
325 scopeguard::defer! {
326 self.helper.drop_active_requests(|session| *session == self as *const _ as usize);
329 }
330
331 let mut fifo = fasync::Fifo::from_fifo(fifo);
341 let (mut reader, mut writer) = fifo.async_io();
342 let mut requests = [MaybeUninit::<BlockFifoRequest>::uninit(); FIFO_MAX_REQUESTS];
343 let active_requests = &self.helper.session_manager().active_requests;
344 let mut active_request_futures = FuturesUnordered::new();
345 let mut responses = Vec::new();
346
347 let mut map_future = pin!(Fuse::terminated());
352 let mut pending_mappings: VecDeque<DecodedRequest> = VecDeque::new();
353
354 let mut stop_signal = pin!(stop_signal.fuse());
357 let mut is_closed = false;
358
359 loop {
360 let new_requests = {
361 let pending_requests = active_request_futures.len() + responses.len();
364
365 if is_closed
366 && pending_requests == 0
367 && map_future.is_terminated()
368 && pending_mappings.is_empty()
369 {
370 return Ok(());
371 }
372
373 let count = requests.len().saturating_sub(pending_requests);
374 let mut receive_requests = pin!(if count == 0 || is_closed {
375 Fuse::terminated()
376 } else {
377 reader.read_entries(&mut requests[..count]).fuse()
378 });
379 let mut send_responses = pin!(if responses.is_empty() {
380 Fuse::terminated()
381 } else {
382 poll_fn(|cx| -> Poll<Result<(), zx::Status>> {
383 match ready!(writer.try_write(cx, &responses[..])) {
384 Ok(written) => {
385 responses.drain(..written.get());
386 Poll::Ready(Ok(()))
387 }
388 Err(status) => Poll::Ready(Err(status)),
389 }
390 })
391 .fuse()
392 });
393
394 select_biased!(
397 res = send_responses => {
398 res?;
399 0
400 },
401 response = active_request_futures.select_next_some() => {
402 responses.extend(response);
403 0
404 }
405 result = map_future => {
406 match result {
407 Ok((request, remainder, commit_decompression_buffers)) => {
408 active_request_futures.push(self.process_fifo_request(
409 request,
410 commit_decompression_buffers,
411 ));
412 if let Some(remainder) = remainder {
413 map_future.set(
414 self.map_request_or_get_response(remainder).fuse()
415 );
416 }
417 }
418 Err(response) => responses.extend(response),
419 }
420 if map_future.is_terminated() {
421 if let Some(request) = pending_mappings.pop_front() {
422 map_future.set(self.map_request_or_get_response(request).fuse());
423 }
424 }
425 0
426 }
427 _ = stop_signal => {
428 is_closed = true;
429 0
430 }
431 count = receive_requests => {
432 count?.get()
433 }
434 )
435 };
436
437 for request in &mut requests[..new_requests] {
440 match self.helper.decode_fifo_request(self as *const _ as usize, unsafe {
441 request.assume_init_mut()
442 }) {
443 Ok(DecodedRequest {
444 operation: Operation::CloseVmo, vmo, request_id, ..
445 }) => {
446 if let Some(vmo) = vmo {
447 self.interface.on_detach_vmo(vmo.as_ref());
448 }
449 responses.extend(
450 active_requests
451 .complete_and_take_response(request_id, zx::Status::OK)
452 .map(|(_, response)| response),
453 );
454 }
455 Ok(request) => {
456 if map_future.is_terminated() {
457 map_future.set(self.map_request_or_get_response(request).fuse());
458 } else {
459 pending_mappings.push_back(request);
460 }
461 }
462 Err(None) => {}
463 Err(Some(response)) => responses.push(response),
464 }
465 }
466 }
467 }
468
469 async fn map_request_or_get_response(
470 &self,
471 request: DecodedRequest,
472 ) -> Result<(DecodedRequest, Option<DecodedRequest>, bool), Option<BlockFifoResponse>> {
473 let request_id = request.request_id;
474 self.map_request(request).await.map_err(|status| {
475 self.helper
476 .orchestrator
477 .active_requests
478 .complete_and_take_response(request_id, status)
479 .map(|(_, r)| r)
480 })
481 }
482
483 async fn map_request(
486 &self,
487 mut request: DecodedRequest,
488 ) -> Result<(DecodedRequest, Option<DecodedRequest>, bool), zx::Status> {
489 let mut active_requests;
490 let active_request;
491 let mut commit_decompression_buffers = false;
492 let flags = self.interface.get_info().as_ref().device_flags();
493 if !flags.contains(DeviceFlag::BARRIER_SUPPORT)
496 && request.operation.take_write_flag(WriteFlags::PRE_BARRIER)
497 {
498 if let Some(id) = request.trace_flow_id {
499 fuchsia_trace::async_instant!(
500 fuchsia_trace::Id::from(id.get()),
501 "storage",
502 "block_server::SimulatedBarrier",
503 "request_id" => request.request_id.0
504 );
505 }
506 self.interface.flush(request.trace_flow_id).await?;
507 }
508
509 match request.operation {
511 Operation::StartDecompressedRead {
512 required_buffer_size,
513 device_block_offset,
514 block_count,
515 options,
516 } => {
517 let allocator = match self.helper.session_manager().buffer_allocator.get() {
518 Some(a) => a,
519 None => {
520 let source = BufferSource::new(fblock::MAX_DECOMPRESSED_BYTES as usize);
523 self.interface.on_attach_vmo(&source.vmo()).await?;
524 let allocator = BufferAllocator::new(
525 std::cmp::max(
526 self.helper.block_size as usize,
527 zx::system_get_page_size() as usize,
528 ),
529 source,
530 );
531 self.helper.session_manager().buffer_allocator.set(allocator).unwrap();
532 self.helper.session_manager().buffer_allocator.get().unwrap()
533 }
534 };
535
536 if required_buffer_size > fblock::MAX_DECOMPRESSED_BYTES as usize {
537 return Err(zx::Status::OUT_OF_RANGE);
538 }
539
540 let buffer = allocator.allocate_buffer(required_buffer_size).await;
541 let vmo_offset = buffer.range().start as u64;
542
543 unsafe fn remove_lifetime(buffer: Buffer<'_>) -> Buffer<'static> {
547 unsafe { std::mem::transmute(buffer) }
548 }
549
550 active_requests = self.helper.session_manager().active_requests.0.lock();
551 active_request = &mut active_requests.requests[request.request_id.0];
552
553 active_request.decompression_info.as_mut().unwrap().buffer =
556 Some(unsafe { remove_lifetime(buffer) });
557
558 request.operation = Operation::Read {
559 device_block_offset,
560 block_count,
561 _unused: 0,
562 vmo_offset,
563 options,
564 };
565 request.vmo = Some(allocator.buffer_source().vmo().clone());
566
567 commit_decompression_buffers = true;
568 }
569 Operation::ContinueDecompressedRead {
570 offset,
571 device_block_offset,
572 block_count,
573 options,
574 } => {
575 active_requests = self.helper.session_manager().active_requests.0.lock();
576 active_request = &mut active_requests.requests[request.request_id.0];
577
578 let buffer =
579 active_request.decompression_info.as_ref().unwrap().buffer.as_ref().unwrap();
580
581 if offset >= buffer.len() as u64
583 || buffer.len() as u64 - offset
584 < block_count as u64 * self.helper.block_size as u64
585 {
586 return Err(zx::Status::OUT_OF_RANGE);
587 }
588
589 request.operation = Operation::Read {
590 device_block_offset,
591 block_count,
592 _unused: 0,
593 vmo_offset: buffer.range().start as u64 + offset,
594 options,
595 };
596
597 let allocator = self.helper.session_manager().buffer_allocator.get().unwrap();
598 request.vmo = Some(allocator.buffer_source().vmo().clone());
599 }
600 _ => {
601 active_requests = self.helper.session_manager().active_requests.0.lock();
602 active_request = &mut active_requests.requests[request.request_id.0];
603 }
604 }
605
606 self.helper
610 .map_request(request, active_request)
611 .map(|(request, remainder)| (request, remainder, commit_decompression_buffers))
612 }
613
614 async fn process_fifo_request(
616 &self,
617 DecodedRequest { request_id, operation, vmo, trace_flow_id }: DecodedRequest,
618 commit_decompression_buffers: bool,
619 ) -> Option<BlockFifoResponse> {
620 let mut needs_postflush = false;
621 let result = match operation {
622 Operation::Read { device_block_offset, block_count, _unused, vmo_offset, options } => {
623 join(
624 self.interface.read(
625 device_block_offset,
626 block_count,
627 vmo.as_ref().unwrap(),
628 vmo_offset,
629 options,
630 trace_flow_id,
631 ),
632 async {
633 if commit_decompression_buffers {
634 let (target_slice, buffer_slice, buffer_range) = {
635 let active_request = self
636 .helper
637 .session_manager()
638 .active_requests
639 .request(request_id);
640 let info = active_request.decompression_info.as_ref().unwrap();
641 (
642 info.uncompressed_slice(),
643 self.helper
644 .orchestrator
645 .buffer_allocator
646 .get()
647 .unwrap()
648 .buffer_source()
649 .slice(),
650 info.buffer.as_ref().unwrap().range(),
651 )
652 };
653 let vmar = fuchsia_runtime::vmar_root_self();
654 let addr = target_slice.addr();
656 let unaligned = addr % zx::system_get_page_size() as usize;
657 if let Err(error) = vmar.op_range(
658 zx::VmarOp::COMMIT,
659 addr - unaligned,
660 target_slice.len() + unaligned,
661 ) {
662 log::warn!(error:?; "Unable to commit target range");
663 }
664 if let Err(error) = vmar.op_range(
666 zx::VmarOp::PREFETCH,
667 buffer_slice.addr() + buffer_range.start,
668 buffer_range.len(),
669 ) {
670 log::warn!(
671 error:?,
672 buffer_range:?;
673 "Unable to prefetch source range",
674 );
675 }
676 }
677 },
678 )
679 .await
680 .0
681 }
682 Operation::Write {
683 device_block_offset,
684 block_count,
685 _unused,
686 vmo_offset,
687 mut options,
688 } => {
689 if options.flags.contains(WriteFlags::FORCE_ACCESS) {
692 let flags = self.interface.get_info().as_ref().device_flags();
693 if !flags.contains(DeviceFlag::FUA_SUPPORT) {
694 options.flags.remove(WriteFlags::FORCE_ACCESS);
695 needs_postflush = true;
696 }
697 }
698 self.interface
699 .write(
700 device_block_offset,
701 block_count,
702 vmo.as_ref().unwrap(),
703 vmo_offset,
704 options,
705 trace_flow_id,
706 )
707 .await
708 }
709 Operation::Flush => self.interface.flush(trace_flow_id).await,
710 Operation::Trim { device_block_offset, block_count } => {
711 self.interface.trim(device_block_offset, block_count, trace_flow_id).await
712 }
713 Operation::CloseVmo
714 | Operation::StartDecompressedRead { .. }
715 | Operation::ContinueDecompressedRead { .. } => {
716 unreachable!()
718 }
719 };
720 let response = self
721 .helper
722 .orchestrator
723 .active_requests
724 .complete_and_take_response(request_id, result.into())
725 .map(|(_, r)| r);
726 if let Some(mut response) = response {
727 if zx::Status::from_raw(response.status) == zx::Status::OK && needs_postflush {
729 if let Some(id) = trace_flow_id {
730 fuchsia_trace::async_instant!(
731 fuchsia_trace::Id::from(id.get()),
732 "storage",
733 "block_server::SimulatedFUA",
734 "request_id" => request_id.0
735 );
736 }
737 response.status =
738 zx::Status::from(self.interface.flush(trace_flow_id).await).into_raw();
739 }
740 Some(response)
741 } else {
742 response
743 }
744 }
745}
746
747impl<I: Interface + ?Sized> super::SessionManager for SessionManager<I> {
748 type Orchestrator = Self;
749
750 const SUPPORTS_DECOMPRESSION: bool = true;
751
752 type Session = usize;
754
755 fn session_eq(a: &usize, b: &usize) -> bool {
756 a == b
757 }
758
759 async fn on_attach_vmo(orchestrator: Arc<Self>, vmo: &Arc<zx::Vmo>) -> Result<(), zx::Status> {
760 I::on_attach_vmo(&orchestrator.interface, vmo).await
761 }
762
763 async fn open_session(
764 orchestrator: Arc<Self>,
765 stream: fblock::SessionRequestStream,
766 offset_map: OffsetMap,
767 block_size: u32,
768 ) -> Result<(), Error> {
769 I::open_session(
770 &orchestrator.interface,
771 orchestrator.clone(),
772 stream,
773 offset_map,
774 block_size,
775 )
776 .await
777 }
778
779 fn get_info(&self) -> Cow<'_, DeviceInfo> {
780 self.interface.get_info()
781 }
782
783 async fn get_volume_info(
784 &self,
785 ) -> Result<(fblock::VolumeManagerInfo, fblock::VolumeInfo), zx::Status> {
786 self.interface.get_volume_info().await
787 }
788
789 async fn query_slices(
790 &self,
791 start_slices: &[u64],
792 ) -> Result<Vec<fblock::VsliceRange>, zx::Status> {
793 self.interface.query_slices(start_slices).await
794 }
795
796 async fn extend(&self, start_slice: u64, slice_count: u64) -> Result<(), zx::Status> {
797 self.interface.extend(start_slice, slice_count).await
798 }
799
800 async fn shrink(&self, start_slice: u64, slice_count: u64) -> Result<(), zx::Status> {
801 self.interface.shrink(start_slice, slice_count).await
802 }
803
804 fn active_requests(&self) -> &ActiveRequests<Self::Session> {
805 return &self.active_requests;
806 }
807}
808
809impl<I: Interface + ?Sized> Drop for Session<I> {
810 fn drop(&mut self) {
811 let callback = std::mem::take(&mut *self.close_callback.lock());
812 if let Some(callback) = callback {
813 callback();
814 }
815 }
816}
817
818impl<I: Interface> IntoOrchestrator for Arc<I> {
819 type SM = SessionManager<I>;
820
821 fn into_orchestrator(self) -> Arc<Self::SM> {
822 Arc::new(SessionManager {
823 interface: self,
824 active_requests: ActiveRequests::default(),
825 buffer_allocator: OnceLock::new(),
826 })
827 }
828}
829
830pub struct AsyncBlockService<I: Interface> {
834 interface: Arc<I>,
835 allocator: Arc<BufferAllocator>,
836 block_size: u32,
837 scope: fasync::ScopeHandle,
838}
839
840impl<I: Interface> AsyncBlockService<I> {
841 pub async fn new(
842 interface: Arc<I>,
843 block_size: u32,
844 pool_capacity: usize,
845 scope: fasync::ScopeHandle,
846 ) -> Result<Self, zx::Status> {
847 let source = BufferSource::new(pool_capacity);
848 interface.on_attach_vmo(&source.vmo()).await?;
849 let allocator = Arc::new(BufferAllocator::new(
850 std::cmp::max(block_size as usize, zx::system_get_page_size() as usize),
851 source,
852 ));
853 Ok(Self { interface, allocator, block_size, scope })
854 }
855
856 pub fn new_with_allocator(
857 interface: Arc<I>,
858 block_size: u32,
859 allocator: Arc<BufferAllocator>,
860 scope: fasync::ScopeHandle,
861 ) -> Self {
862 Self { interface, allocator, block_size, scope }
863 }
864
865 pub fn interface(&self) -> &Arc<I> {
866 &self.interface
867 }
868
869 pub fn allocator(&self) -> &Arc<BufferAllocator> {
870 &self.allocator
871 }
872}
873
874impl<I: Interface> BlockService for AsyncBlockService<I> {
875 fn allocate_buffer(&self, max_len: usize) -> OwnedBuffer {
876 let max_len = std::cmp::min(
877 std::cmp::min(max_len, MAX_READ_BUFFER_SIZE),
878 self.allocator.buffer_source().size(),
879 );
880 self.allocator.allocate_buffer_sync_owned(max_len)
881 }
882
883 fn read_blocks(
884 &self,
885 device_offset: u64,
886 dest_buffer: OwnedBuffer,
887 on_complete: Box<dyn FnOnce(Result<OwnedBuffer, Error>) + Send>,
888 ) -> Result<(), Error> {
889 let block_size = self.block_size as u64;
890 let device_block_offset = device_offset / block_size;
891 let block_count = (dest_buffer.len() as u64 / block_size) as u32;
892
893 let vmo_offset = dest_buffer.range().start as u64;
894 let vmo = self.allocator.buffer_source().vmo().clone();
895 let interface = self.interface.clone();
896
897 self.scope.spawn(async move {
898 let res = interface
899 .read(
900 device_block_offset,
901 block_count,
902 &vmo,
903 vmo_offset,
904 ReadOptions::default(),
905 TraceFlowId::default(),
906 )
907 .await;
908 match res {
909 Ok(()) => on_complete(Ok(dest_buffer)),
910 Err(status) => on_complete(Err(anyhow::anyhow!("Read failed: {:?}", status))),
911 }
912 });
913
914 Ok(())
915 }
916}
917
918#[cfg(test)]
919mod tests {
920 use super::*;
921 use fuchsia_async as fasync;
922 use mapping::Extents;
923 use mapping::reader::read_aligned_range;
924 use std::sync::atomic::{AtomicU64, Ordering};
925
926 struct FakeInterface {
927 data: Vec<u8>,
928 block_size: u32,
929 read_count: AtomicU64,
930 }
931
932 impl FakeInterface {
933 fn new(data: Vec<u8>, block_size: u32) -> Self {
934 Self { data, block_size, read_count: AtomicU64::new(0) }
935 }
936 }
937
938 impl Interface for FakeInterface {
939 fn get_info(&self) -> Cow<'_, DeviceInfo> {
940 Cow::Owned(DeviceInfo::Block(crate::BlockInfo {
941 block_count: (self.data.len() / self.block_size as usize) as u64,
942 max_transfer_blocks: None,
943 device_flags: fblock::DeviceFlag::empty(),
944 }))
945 }
946
947 async fn read(
948 &self,
949 device_block_offset: u64,
950 block_count: u32,
951 vmo: &Arc<zx::Vmo>,
952 vmo_offset: u64,
953 _opts: ReadOptions,
954 _trace_flow_id: TraceFlowId,
955 ) -> Result<(), zx::Status> {
956 self.read_count.fetch_add(1, Ordering::Relaxed);
957 let byte_offset = (device_block_offset * self.block_size as u64) as usize;
958 let byte_len = (block_count * self.block_size) as usize;
959 let slice = &self.data[byte_offset..byte_offset + byte_len];
960 vmo.write(slice, vmo_offset).map_err(|_| zx::Status::IO)?;
961 Ok(())
962 }
963
964 async fn write(
965 &self,
966 _device_block_offset: u64,
967 _block_count: u32,
968 _vmo: &Arc<zx::Vmo>,
969 _vmo_offset: u64,
970 _opts: WriteOptions,
971 _trace_flow_id: TraceFlowId,
972 ) -> Result<(), zx::Status> {
973 Ok(())
974 }
975
976 async fn flush(&self, _trace_flow_id: TraceFlowId) -> Result<(), zx::Status> {
977 Ok(())
978 }
979
980 async fn trim(
981 &self,
982 _device_block_offset: u64,
983 _block_count: u32,
984 _trace_flow_id: TraceFlowId,
985 ) -> Result<(), zx::Status> {
986 Ok(())
987 }
988 }
989
990 #[fasync::run_singlethreaded(test)]
991 async fn test_async_block_service_read_aligned_range() {
992 let block_size = 512;
993 let test_data: Vec<u8> = (0..8192).map(|i| (i % 255) as u8).collect();
994 let interface = Arc::new(FakeInterface::new(test_data.clone(), block_size));
995 let scope = fasync::Scope::current();
996
997 let block_service = Arc::new(
998 AsyncBlockService::new(interface, block_size, 16384, scope)
999 .await
1000 .expect("Failed to create AsyncBlockService"),
1001 );
1002
1003 let encoded = (1u64 << 32) | 0u64;
1004 let extents = Extents::from_encoded(&[encoded]).unwrap();
1005 let service = block_service.clone();
1006 let (send, recv) = futures::channel::oneshot::channel();
1007 let send = std::sync::Mutex::new(Some(send));
1008 let read_buf = std::sync::Mutex::new(Vec::new());
1009
1010 read_aligned_range(&extents, 0..4096, &*service, move |buffer_result| {
1011 let buffer = buffer_result.unwrap();
1012 let mut read_guard = read_buf.lock().unwrap();
1013 buffer.as_ptr_slice().append_to(&mut read_guard);
1014 if read_guard.len() == 4096 {
1015 if let Some(s) = send.lock().unwrap().take() {
1016 let _ = s.send(read_guard.clone());
1017 }
1018 }
1019 std::ops::ControlFlow::Continue(())
1020 });
1021
1022 let result = recv.await.unwrap();
1023 assert_eq!(result, &test_data[0..4096]);
1024 }
1025
1026 #[fasync::run_singlethreaded(test)]
1027 async fn test_async_block_service_concurrent_reads_larger_than_pool_capacity() {
1028 let block_size = 512;
1029 let total_size = 65536; let test_data: Vec<u8> = (0..total_size).map(|i| (i % 251) as u8).collect();
1031 let interface = Arc::new(FakeInterface::new(test_data.clone(), block_size));
1032 let scope = fasync::Scope::current();
1033
1034 let pool_capacity = 8192;
1037 let source = BufferSource::new(pool_capacity);
1038 interface.on_attach_vmo(&source.vmo()).await.unwrap();
1039 let allocator = Arc::new(BufferAllocator::new(
1040 std::cmp::max(block_size as usize, zx::system_get_page_size() as usize),
1041 source,
1042 ));
1043 let block_service = Arc::new(AsyncBlockService::new_with_allocator(
1044 interface, block_size, allocator, scope,
1045 ));
1046
1047 let encoded = (16u64 << 32) | 0u64;
1048 let extents = Arc::new(Extents::from_encoded(&[encoded]).unwrap());
1049
1050 let ranges = [0..16384, 16384..32768, 32768..49152, 49152..65536];
1052 let mut receivers = Vec::new();
1053
1054 for range in ranges {
1055 let (send, recv) = futures::channel::oneshot::channel();
1056 let service = block_service.clone();
1057 let extents = extents.clone();
1058
1059 std::thread::spawn(move || {
1060 let send = std::sync::Mutex::new(Some(send));
1061 let read_buf = std::sync::Mutex::new(Vec::new());
1062 let target_len = (range.end - range.start) as usize;
1063
1064 read_aligned_range(&extents, range, &*service, move |buffer_result| {
1065 let buffer = buffer_result.unwrap();
1066 let mut read_guard = read_buf.lock().unwrap();
1067 buffer.as_ptr_slice().append_to(&mut read_guard);
1068 if read_guard.len() == target_len {
1069 if let Some(s) = send.lock().unwrap().take() {
1070 let _ = s.send(read_guard.clone());
1071 }
1072 }
1073 std::ops::ControlFlow::Continue(())
1074 });
1075 });
1076
1077 receivers.push(recv);
1078 }
1079
1080 let results = futures::future::join_all(receivers).await;
1081 for (i, res) in results.into_iter().enumerate() {
1082 let data = res.unwrap();
1083 let start = i * 16384;
1084 let end = start + 16384;
1085 assert_eq!(data, &test_data[start..end]);
1086 }
1087 }
1088}