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 std::borrow::Cow;
19use std::collections::VecDeque;
20use std::future::{Future, poll_fn};
21use std::mem::MaybeUninit;
22use std::pin::pin;
23use std::sync::{Arc, OnceLock};
24use std::task::{Poll, ready};
25use storage_device::buffer::Buffer;
26use storage_device::buffer_allocator::{BufferAllocator, BufferSource};
27
28pub trait Interface: Send + Sync + Unpin + 'static {
29 fn open_session(
58 &self,
59 session_manager: Arc<SessionManager<Self>>,
60 stream: fblock::SessionRequestStream,
61 offset_map: OffsetMap,
62 block_size: u32,
63 ) -> impl Future<Output = Result<(), Error>> + Send {
64 session_manager.serve_session(
66 stream,
67 offset_map,
68 self.get_info().max_transfer_blocks(),
69 block_size,
70 )
71 }
72
73 fn on_attach_vmo(&self, _vmo: &zx::Vmo) -> impl Future<Output = Result<(), zx::Status>> + Send {
77 async { Ok(()) }
78 }
79
80 fn on_detach_vmo(&self, _vmo: &zx::Vmo) {}
82
83 fn get_info(&self) -> Cow<'_, DeviceInfo>;
85
86 fn read(
93 &self,
94 device_block_offset: u64,
95 block_count: u32,
96 vmo: &Arc<zx::Vmo>,
97 vmo_offset: u64, opts: ReadOptions,
99 trace_flow_id: TraceFlowId,
100 ) -> impl Future<Output = Result<(), zx::Status>> + Send;
101
102 fn write(
109 &self,
110 device_block_offset: u64,
111 block_count: u32,
112 vmo: &Arc<zx::Vmo>,
113 vmo_offset: u64, opts: WriteOptions,
115 trace_flow_id: TraceFlowId,
116 ) -> impl Future<Output = Result<(), zx::Status>> + Send;
117
118 fn flush(
120 &self,
121 trace_flow_id: TraceFlowId,
122 ) -> impl Future<Output = Result<(), zx::Status>> + Send;
123
124 fn trim(
131 &self,
132 device_block_offset: u64,
133 block_count: u32,
134 trace_flow_id: TraceFlowId,
135 ) -> impl Future<Output = Result<(), zx::Status>> + Send;
136
137 fn get_volume_info(
139 &self,
140 ) -> impl Future<Output = Result<(fblock::VolumeManagerInfo, fblock::VolumeInfo), zx::Status>> + Send
141 {
142 async { Err(zx::Status::NOT_SUPPORTED) }
143 }
144
145 fn query_slices(
147 &self,
148 _start_slices: &[u64],
149 ) -> impl Future<Output = Result<Vec<fblock::VsliceRange>, zx::Status>> + Send {
150 async { Err(zx::Status::NOT_SUPPORTED) }
151 }
152
153 fn extend(
155 &self,
156 _start_slice: u64,
157 _slice_count: u64,
158 ) -> impl Future<Output = Result<(), zx::Status>> + Send {
159 async { Err(zx::Status::NOT_SUPPORTED) }
160 }
161
162 fn shrink(
164 &self,
165 _start_slice: u64,
166 _slice_count: u64,
167 ) -> impl Future<Output = Result<(), zx::Status>> + Send {
168 async { Err(zx::Status::NOT_SUPPORTED) }
169 }
170}
171
172pub struct PassthroughSession(fblock::SessionProxy);
174
175impl PassthroughSession {
176 pub fn new(proxy: fblock::SessionProxy) -> Self {
177 Self(proxy)
178 }
179
180 async fn handle_request(&self, request: fblock::SessionRequest) -> Result<(), Error> {
181 match request {
182 fblock::SessionRequest::GetFifo { responder } => {
183 responder.send(self.0.get_fifo().await?)?;
184 }
185 fblock::SessionRequest::AttachVmo { vmo, responder } => {
186 responder.send(self.0.attach_vmo(vmo).await?.as_ref().map_err(|s| *s))?;
187 }
188 fblock::SessionRequest::Close { responder } => {
189 responder.send(self.0.close().await?)?;
190 }
191 }
192 Ok(())
193 }
194
195 pub async fn serve(&self, mut stream: fblock::SessionRequestStream) -> Result<(), Error> {
197 while let Some(Ok(request)) = stream.next().await {
198 if let Err(error) = self.handle_request(request).await {
199 log::warn!(error:?; "FIDL error");
200 }
201 }
202 Ok(())
203 }
204}
205
206pub struct SessionManager<I: Interface + ?Sized> {
207 interface: Arc<I>,
208 active_requests: ActiveRequests<usize>,
209
210 buffer_allocator: OnceLock<BufferAllocator>,
213}
214
215impl<I: Interface + ?Sized> Drop for SessionManager<I> {
216 fn drop(&mut self) {
217 if let Some(allocator) = self.buffer_allocator.get() {
218 self.interface.on_detach_vmo(allocator.buffer_source().vmo());
219 }
220 }
221}
222
223impl<I: Interface + ?Sized> SessionManager<I> {
224 pub fn new(interface: Arc<I>) -> Self {
225 Self {
226 interface,
227 active_requests: ActiveRequests::default(),
228 buffer_allocator: OnceLock::new(),
229 }
230 }
231
232 pub fn interface(&self) -> &I {
233 self.interface.as_ref()
234 }
235
236 pub async fn serve_session(
238 self: Arc<Self>,
239 stream: fblock::SessionRequestStream,
240 offset_map: OffsetMap,
241 max_transfer_blocks: Option<std::num::NonZero<u32>>,
242 block_size: u32,
243 ) -> Result<(), Error> {
244 let (helper, fifo) =
245 SessionHelper::new(self.clone(), offset_map, max_transfer_blocks, block_size)?;
246 let session = Arc::new(Session {
247 helper: Arc::new(helper),
248 interface: self.interface.clone(),
249 close_callback: Mutex::new(None),
250 });
251
252 let (stop_sender, stop_receiver) = futures::channel::oneshot::channel();
253
254 let mut stream = stream.fuse();
255 let scope = fasync::Scope::new();
256 let session_clone = session.clone();
257 let mut fifo_task = scope
258 .spawn(async move {
259 if let Err(status) = session_clone.run_fifo(fifo, stop_receiver).await {
260 if status != zx::Status::PEER_CLOSED {
261 log::error!(status:?; "FIFO error");
262 }
263 }
264 })
265 .fuse();
266
267 scopeguard::defer! {
269 for (_, (vmo, _)) in session.helper.take_vmos() {
270 self.interface.on_detach_vmo(&vmo);
271 }
272 }
273
274 let mut closing = false;
275 let mut stop_sender = Some(stop_sender);
276
277 loop {
278 futures::select! {
279 maybe_req = if closing {
280 futures::future::pending().left_future()
281 } else {
282 stream.next().right_future()
283 } => {
284 if let Some(req) = maybe_req {
285 match session.helper.handle_request(req?).await? {
286 HandleRequestResult::Ok => {},
287 HandleRequestResult::Closed(callback) => {
288 *session.close_callback.lock() = Some(callback);
289 if let Some(sender) = stop_sender.take() {
291 let _ = sender.send(());
292 }
293 closing = true;
294 }
295 }
296 } else {
297 if let Some(sender) = stop_sender.take() {
299 let _ = sender.send(());
300 }
301 closing = true;
302 }
303 }
304 _ = fifo_task => break,
305 }
306 }
307 Ok(())
308 }
309}
310
311pub struct Session<I: Interface + ?Sized> {
312 interface: Arc<I>,
313 helper: Arc<SessionHelper<SessionManager<I>>>,
314 close_callback: Mutex<Option<Box<dyn FnOnce() + Send + 'static>>>,
315}
316
317impl<I: Interface + ?Sized> Session<I> {
318 async fn run_fifo(
320 &self,
321 fifo: zx::Fifo<BlockFifoRequest, BlockFifoResponse>,
322 stop_signal: futures::channel::oneshot::Receiver<()>,
323 ) -> Result<(), zx::Status> {
324 scopeguard::defer! {
325 self.helper.drop_active_requests(|session| *session == self as *const _ as usize);
328 }
329
330 let mut fifo = fasync::Fifo::from_fifo(fifo);
340 let (mut reader, mut writer) = fifo.async_io();
341 let mut requests = [MaybeUninit::<BlockFifoRequest>::uninit(); FIFO_MAX_REQUESTS];
342 let active_requests = &self.helper.session_manager().active_requests;
343 let mut active_request_futures = FuturesUnordered::new();
344 let mut responses = Vec::new();
345
346 let mut map_future = pin!(Fuse::terminated());
351 let mut pending_mappings: VecDeque<DecodedRequest> = VecDeque::new();
352
353 let mut stop_signal = pin!(stop_signal.fuse());
356 let mut is_closed = false;
357
358 loop {
359 let new_requests = {
360 let pending_requests = active_request_futures.len() + responses.len();
363
364 if is_closed
365 && pending_requests == 0
366 && map_future.is_terminated()
367 && pending_mappings.is_empty()
368 {
369 return Ok(());
370 }
371
372 let count = requests.len().saturating_sub(pending_requests);
373 let mut receive_requests = pin!(if count == 0 || is_closed {
374 Fuse::terminated()
375 } else {
376 reader.read_entries(&mut requests[..count]).fuse()
377 });
378 let mut send_responses = pin!(if responses.is_empty() {
379 Fuse::terminated()
380 } else {
381 poll_fn(|cx| -> Poll<Result<(), zx::Status>> {
382 match ready!(writer.try_write(cx, &responses[..])) {
383 Ok(written) => {
384 responses.drain(..written);
385 Poll::Ready(Ok(()))
386 }
387 Err(status) => Poll::Ready(Err(status)),
388 }
389 })
390 .fuse()
391 });
392
393 select_biased!(
396 res = send_responses => {
397 res?;
398 0
399 },
400 response = active_request_futures.select_next_some() => {
401 responses.extend(response);
402 0
403 }
404 result = map_future => {
405 match result {
406 Ok((request, remainder, commit_decompression_buffers)) => {
407 active_request_futures.push(self.process_fifo_request(
408 request,
409 commit_decompression_buffers,
410 ));
411 if let Some(remainder) = remainder {
412 map_future.set(
413 self.map_request_or_get_response(remainder).fuse()
414 );
415 }
416 }
417 Err(response) => responses.extend(response),
418 }
419 if map_future.is_terminated() {
420 if let Some(request) = pending_mappings.pop_front() {
421 map_future.set(self.map_request_or_get_response(request).fuse());
422 }
423 }
424 0
425 }
426 _ = stop_signal => {
427 is_closed = true;
428 0
429 }
430 count = receive_requests => {
431 count?
432 }
433 )
434 };
435
436 for request in &mut requests[..new_requests] {
439 match self.helper.decode_fifo_request(self as *const _ as usize, unsafe {
440 request.assume_init_mut()
441 }) {
442 Ok(DecodedRequest {
443 operation: Operation::CloseVmo, vmo, request_id, ..
444 }) => {
445 if let Some(vmo) = vmo {
446 self.interface.on_detach_vmo(vmo.as_ref());
447 }
448 responses.extend(
449 active_requests
450 .complete_and_take_response(request_id, zx::Status::OK)
451 .map(|(_, response)| response),
452 );
453 }
454 Ok(request) => {
455 if map_future.is_terminated() {
456 map_future.set(self.map_request_or_get_response(request).fuse());
457 } else {
458 pending_mappings.push_back(request);
459 }
460 }
461 Err(None) => {}
462 Err(Some(response)) => responses.push(response),
463 }
464 }
465 }
466 }
467
468 async fn map_request_or_get_response(
469 &self,
470 request: DecodedRequest,
471 ) -> Result<(DecodedRequest, Option<DecodedRequest>, bool), Option<BlockFifoResponse>> {
472 let request_id = request.request_id;
473 self.map_request(request).await.map_err(|status| {
474 self.helper
475 .orchestrator
476 .active_requests
477 .complete_and_take_response(request_id, status)
478 .map(|(_, r)| r)
479 })
480 }
481
482 async fn map_request(
485 &self,
486 mut request: DecodedRequest,
487 ) -> Result<(DecodedRequest, Option<DecodedRequest>, bool), zx::Status> {
488 let mut active_requests;
489 let active_request;
490 let mut commit_decompression_buffers = false;
491 let flags = self.interface.get_info().as_ref().device_flags();
492 if !flags.contains(DeviceFlag::BARRIER_SUPPORT)
495 && request.operation.take_write_flag(WriteFlags::PRE_BARRIER)
496 {
497 if let Some(id) = request.trace_flow_id {
498 fuchsia_trace::async_instant!(
499 fuchsia_trace::Id::from(id.get()),
500 "storage",
501 "block_server::SimulatedBarrier",
502 "request_id" => request.request_id.0
503 );
504 }
505 self.interface.flush(request.trace_flow_id).await?;
506 }
507
508 match request.operation {
510 Operation::StartDecompressedRead {
511 required_buffer_size,
512 device_block_offset,
513 block_count,
514 options,
515 } => {
516 let allocator = match self.helper.session_manager().buffer_allocator.get() {
517 Some(a) => a,
518 None => {
519 let source = BufferSource::new(fblock::MAX_DECOMPRESSED_BYTES as usize);
522 self.interface.on_attach_vmo(&source.vmo()).await?;
523 let allocator = BufferAllocator::new(
524 std::cmp::max(
525 self.helper.block_size as usize,
526 zx::system_get_page_size() as usize,
527 ),
528 source,
529 );
530 self.helper.session_manager().buffer_allocator.set(allocator).unwrap();
531 self.helper.session_manager().buffer_allocator.get().unwrap()
532 }
533 };
534
535 if required_buffer_size > fblock::MAX_DECOMPRESSED_BYTES as usize {
536 return Err(zx::Status::OUT_OF_RANGE);
537 }
538
539 let buffer = allocator.allocate_buffer(required_buffer_size).await;
540 let vmo_offset = buffer.range().start as u64;
541
542 unsafe fn remove_lifetime(buffer: Buffer<'_>) -> Buffer<'static> {
546 unsafe { std::mem::transmute(buffer) }
547 }
548
549 active_requests = self.helper.session_manager().active_requests.0.lock();
550 active_request = &mut active_requests.requests[request.request_id.0];
551
552 active_request.decompression_info.as_mut().unwrap().buffer =
555 Some(unsafe { remove_lifetime(buffer) });
556
557 request.operation = Operation::Read {
558 device_block_offset,
559 block_count,
560 _unused: 0,
561 vmo_offset,
562 options,
563 };
564 request.vmo = Some(allocator.buffer_source().vmo().clone());
565
566 commit_decompression_buffers = true;
567 }
568 Operation::ContinueDecompressedRead {
569 offset,
570 device_block_offset,
571 block_count,
572 options,
573 } => {
574 active_requests = self.helper.session_manager().active_requests.0.lock();
575 active_request = &mut active_requests.requests[request.request_id.0];
576
577 let buffer =
578 active_request.decompression_info.as_ref().unwrap().buffer.as_ref().unwrap();
579
580 if offset >= buffer.len() as u64
582 || buffer.len() as u64 - offset
583 < block_count as u64 * self.helper.block_size as u64
584 {
585 return Err(zx::Status::OUT_OF_RANGE);
586 }
587
588 request.operation = Operation::Read {
589 device_block_offset,
590 block_count,
591 _unused: 0,
592 vmo_offset: buffer.range().start as u64 + offset,
593 options,
594 };
595
596 let allocator = self.helper.session_manager().buffer_allocator.get().unwrap();
597 request.vmo = Some(allocator.buffer_source().vmo().clone());
598 }
599 _ => {
600 active_requests = self.helper.session_manager().active_requests.0.lock();
601 active_request = &mut active_requests.requests[request.request_id.0];
602 }
603 }
604
605 self.helper
609 .map_request(request, active_request)
610 .map(|(request, remainder)| (request, remainder, commit_decompression_buffers))
611 }
612
613 async fn process_fifo_request(
615 &self,
616 DecodedRequest { request_id, operation, vmo, trace_flow_id }: DecodedRequest,
617 commit_decompression_buffers: bool,
618 ) -> Option<BlockFifoResponse> {
619 let mut needs_postflush = false;
620 let result = match operation {
621 Operation::Read { device_block_offset, block_count, _unused, vmo_offset, options } => {
622 join(
623 self.interface.read(
624 device_block_offset,
625 block_count,
626 vmo.as_ref().unwrap(),
627 vmo_offset,
628 options,
629 trace_flow_id,
630 ),
631 async {
632 if commit_decompression_buffers {
633 let (target_slice, buffer_slice, buffer_range) = {
634 let active_request = self
635 .helper
636 .session_manager()
637 .active_requests
638 .request(request_id);
639 let info = active_request.decompression_info.as_ref().unwrap();
640 (
641 info.uncompressed_slice(),
642 self.helper
643 .orchestrator
644 .buffer_allocator
645 .get()
646 .unwrap()
647 .buffer_source()
648 .slice(),
649 info.buffer.as_ref().unwrap().range(),
650 )
651 };
652 let vmar = fuchsia_runtime::vmar_root_self();
653 let addr = target_slice.addr();
655 let unaligned = addr % zx::system_get_page_size() as usize;
656 if let Err(error) = vmar.op_range(
657 zx::VmarOp::COMMIT,
658 addr - unaligned,
659 target_slice.len() + unaligned,
660 ) {
661 log::warn!(error:?; "Unable to commit target range");
662 }
663 if let Err(error) = vmar.op_range(
665 zx::VmarOp::PREFETCH,
666 buffer_slice.addr() + buffer_range.start,
667 buffer_range.len(),
668 ) {
669 log::warn!(
670 error:?,
671 buffer_range:?;
672 "Unable to prefetch source range",
673 );
674 }
675 }
676 },
677 )
678 .await
679 .0
680 }
681 Operation::Write {
682 device_block_offset,
683 block_count,
684 _unused,
685 vmo_offset,
686 mut options,
687 } => {
688 if options.flags.contains(WriteFlags::FORCE_ACCESS) {
691 let flags = self.interface.get_info().as_ref().device_flags();
692 if !flags.contains(DeviceFlag::FUA_SUPPORT) {
693 options.flags.remove(WriteFlags::FORCE_ACCESS);
694 needs_postflush = true;
695 }
696 }
697 self.interface
698 .write(
699 device_block_offset,
700 block_count,
701 vmo.as_ref().unwrap(),
702 vmo_offset,
703 options,
704 trace_flow_id,
705 )
706 .await
707 }
708 Operation::Flush => self.interface.flush(trace_flow_id).await,
709 Operation::Trim { device_block_offset, block_count } => {
710 self.interface.trim(device_block_offset, block_count, trace_flow_id).await
711 }
712 Operation::CloseVmo
713 | Operation::StartDecompressedRead { .. }
714 | Operation::ContinueDecompressedRead { .. } => {
715 unreachable!()
717 }
718 };
719 let response = self
720 .helper
721 .orchestrator
722 .active_requests
723 .complete_and_take_response(request_id, result.into())
724 .map(|(_, r)| r);
725 if let Some(mut response) = response {
726 if zx::Status::from_raw(response.status) == zx::Status::OK && needs_postflush {
728 if let Some(id) = trace_flow_id {
729 fuchsia_trace::async_instant!(
730 fuchsia_trace::Id::from(id.get()),
731 "storage",
732 "block_server::SimulatedFUA",
733 "request_id" => request_id.0
734 );
735 }
736 response.status =
737 zx::Status::from(self.interface.flush(trace_flow_id).await).into_raw();
738 }
739 Some(response)
740 } else {
741 response
742 }
743 }
744}
745
746impl<I: Interface + ?Sized> super::SessionManager for SessionManager<I> {
747 type Orchestrator = Self;
748
749 const SUPPORTS_DECOMPRESSION: bool = true;
750
751 type Session = usize;
753
754 fn session_eq(a: &usize, b: &usize) -> bool {
755 a == b
756 }
757
758 async fn on_attach_vmo(orchestrator: Arc<Self>, vmo: &Arc<zx::Vmo>) -> Result<(), zx::Status> {
759 I::on_attach_vmo(&orchestrator.interface, vmo).await
760 }
761
762 async fn open_session(
763 orchestrator: Arc<Self>,
764 stream: fblock::SessionRequestStream,
765 offset_map: OffsetMap,
766 block_size: u32,
767 ) -> Result<(), Error> {
768 I::open_session(
769 &orchestrator.interface,
770 orchestrator.clone(),
771 stream,
772 offset_map,
773 block_size,
774 )
775 .await
776 }
777
778 fn get_info(&self) -> Cow<'_, DeviceInfo> {
779 self.interface.get_info()
780 }
781
782 async fn get_volume_info(
783 &self,
784 ) -> Result<(fblock::VolumeManagerInfo, fblock::VolumeInfo), zx::Status> {
785 self.interface.get_volume_info().await
786 }
787
788 async fn query_slices(
789 &self,
790 start_slices: &[u64],
791 ) -> Result<Vec<fblock::VsliceRange>, zx::Status> {
792 self.interface.query_slices(start_slices).await
793 }
794
795 async fn extend(&self, start_slice: u64, slice_count: u64) -> Result<(), zx::Status> {
796 self.interface.extend(start_slice, slice_count).await
797 }
798
799 async fn shrink(&self, start_slice: u64, slice_count: u64) -> Result<(), zx::Status> {
800 self.interface.shrink(start_slice, slice_count).await
801 }
802
803 fn active_requests(&self) -> &ActiveRequests<Self::Session> {
804 return &self.active_requests;
805 }
806}
807
808impl<I: Interface + ?Sized> Drop for Session<I> {
809 fn drop(&mut self) {
810 let callback = std::mem::take(&mut *self.close_callback.lock());
811 if let Some(callback) = callback {
812 callback();
813 }
814 }
815}
816
817impl<I: Interface> IntoOrchestrator for Arc<I> {
818 type SM = SessionManager<I>;
819
820 fn into_orchestrator(self) -> Arc<Self::SM> {
821 Arc::new(SessionManager {
822 interface: self,
823 active_requests: ActiveRequests::default(),
824 buffer_allocator: OnceLock::new(),
825 })
826 }
827}