Skip to main content

block_server/
async_interface.rs

1// Copyright 2024 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use super::{
6    ActiveRequests, DecodedRequest, DeviceInfo, FIFO_MAX_REQUESTS, HandleRequestResult,
7    IntoOrchestrator, KeyRegistry, 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    /// Runs `stream` to completion.
34    ///
35    /// `offset_map` is provided by the client, and is used to remap requests. The extents in
36    /// `offset_map` are already validated to be within the range of the partition (as determined by
37    /// the [`PartitionInfo::block_count`] field). The implementation is expected to apply these
38    /// mappings to all FIFO requests, and to ensure all FIFO requests fit within the logical
39    /// extents of the offset map. Note that the default implementation does this for you, and that
40    /// is correct for most implementations.
41    ///
42    /// Implementors can override this method if they want to create a passthrough session instead
43    /// (and can use [`PassthroughSession`] below to do so). Generally, a passthrough session would
44    /// open a session to its underlying device with an offset map applied
45    /// (`fuchsia.storage.block.Block/OpenSessionWithOptions`), which remaps and restricts
46    /// requests to the range the partition should have access to.
47    ///
48    /// Nested mappings (i.e. the case when `offset_map` is non-empty, but the implementation
49    /// creates a passthrough session with its own mapping) would need to be composed by the
50    /// implementation. At this time, no implementations of passthrough sessions support nested
51    /// mappings, but we can add support as needed.
52    ///
53    /// If the implementor uses a [`PassthroughSession`], the following Interface methods
54    /// will not be called, and can be stubbed out:
55    ///   - on_attach_vmo
56    ///   - on_detach_vmo
57    ///   - read
58    ///   - write
59    ///   - flush
60    ///   - trim
61    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        // By default, serve the session rather than forwarding it.
69        session_manager.serve_session(
70            stream,
71            offset_map,
72            self.get_info().max_transfer_blocks(),
73            block_size,
74        )
75    }
76
77    /// Opens a mapper session. Implementations that serve mapper requests directly or
78    /// forward them can implement this method.
79    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            scopeguard::defer! {
114                session_manager.interface.on_detach_vmo(&vmo);
115            }
116            let res = session_fut.await;
117            scope.cancel().await;
118            res
119        })
120    }
121
122    /// Called when a new mapper session is opened.
123    /// Returns the [`Verifier`] for page delivery.
124    fn on_open_mapper_session(
125        &self,
126        _mapping_vmo: &zx::Vmo,
127        delivery_queue: zx::Vmo,
128    ) -> Result<Verifier, zx::Status> {
129        Ok(Verifier::new(delivery_queue))
130    }
131
132    /// Called whenever a VMO is attached, prior to the VMO's usage in any other methods. Whilst
133    /// the VMO is attached, `vmo` will keep the same address so it is safe to use the pointer
134    /// value (as, say, a key into a HashMap).
135    fn on_attach_vmo(&self, _vmo: &zx::Vmo) -> impl Future<Output = Result<(), zx::Status>> + Send {
136        async { Ok(()) }
137    }
138
139    /// Called whenever a VMO is detached.
140    fn on_detach_vmo(&self, _vmo: &zx::Vmo) {}
141
142    /// Called to get block/partition information.
143    fn get_info(&self) -> Cow<'_, DeviceInfo>;
144
145    /// Called for a request to read bytes.
146    ///
147    /// Implementations are responsible for checking that the request block range
148    /// (`[device_block_offset, device_block_offset + block_count)`) falls within valid
149    /// device/partition bounds, and returning `Err(zx::Status::OUT_OF_RANGE)` if it is out of
150    /// bounds.
151    fn read(
152        &self,
153        device_block_offset: u64,
154        block_count: u32,
155        vmo: &Arc<zx::Vmo>,
156        vmo_offset: u64, // *bytes* not blocks
157        opts: ReadOptions,
158        trace_flow_id: TraceFlowId,
159    ) -> impl Future<Output = Result<(), zx::Status>> + Send;
160
161    /// Called for a request to write bytes.
162    ///
163    /// Implementations are responsible for checking that the request block range
164    /// (`[device_block_offset, device_block_offset + block_count)`) falls within valid
165    /// device/partition bounds, and returning `Err(zx::Status::OUT_OF_RANGE)` if it is out of
166    /// bounds.
167    fn write(
168        &self,
169        device_block_offset: u64,
170        block_count: u32,
171        vmo: &Arc<zx::Vmo>,
172        vmo_offset: u64, // *bytes* not blocks
173        opts: WriteOptions,
174        trace_flow_id: TraceFlowId,
175    ) -> impl Future<Output = Result<(), zx::Status>> + Send;
176
177    /// Called to flush the device.
178    fn flush(
179        &self,
180        trace_flow_id: TraceFlowId,
181    ) -> impl Future<Output = Result<(), zx::Status>> + Send;
182
183    /// Called to trim a region.
184    ///
185    /// Implementations are responsible for checking that the request block range
186    /// (`[device_block_offset, device_block_offset + block_count)`) falls within valid
187    /// device/partition bounds, and returning `Err(zx::Status::OUT_OF_RANGE)` if it is out of
188    /// bounds.
189    fn trim(
190        &self,
191        device_block_offset: u64,
192        block_count: u32,
193        trace_flow_id: TraceFlowId,
194    ) -> impl Future<Output = Result<(), zx::Status>> + Send;
195
196    /// Called to handle the GetVolumeInfo FIDL call.
197    fn get_volume_info(
198        &self,
199    ) -> impl Future<Output = Result<(fblock::VolumeManagerInfo, fblock::VolumeInfo), zx::Status>> + Send
200    {
201        async { Err(zx::Status::NOT_SUPPORTED) }
202    }
203
204    /// Called to handle the QuerySlices FIDL call.
205    fn query_slices(
206        &self,
207        _start_slices: &[u64],
208    ) -> impl Future<Output = Result<Vec<fblock::VsliceRange>, zx::Status>> + Send {
209        async { Err(zx::Status::NOT_SUPPORTED) }
210    }
211
212    /// Called to handle the Extend FIDL call.
213    fn extend(
214        &self,
215        _start_slice: u64,
216        _slice_count: u64,
217    ) -> impl Future<Output = Result<(), zx::Status>> + Send {
218        async { Err(zx::Status::NOT_SUPPORTED) }
219    }
220
221    /// Called to handle the Shrink FIDL call.
222    fn shrink(
223        &self,
224        _start_slice: u64,
225        _slice_count: u64,
226    ) -> impl Future<Output = Result<(), zx::Status>> + Send {
227        async { Err(zx::Status::NOT_SUPPORTED) }
228    }
229}
230
231/// A helper object to run a passthrough (proxy) session.
232pub struct PassthroughSession(fblock::SessionProxy);
233
234impl PassthroughSession {
235    pub fn new(proxy: fblock::SessionProxy) -> Self {
236        Self(proxy)
237    }
238
239    async fn handle_request(&self, request: fblock::SessionRequest) -> Result<(), Error> {
240        match request {
241            fblock::SessionRequest::GetFifo { responder } => {
242                responder.send(self.0.get_fifo().await?)?;
243            }
244            fblock::SessionRequest::AttachVmo { vmo, responder } => {
245                responder.send(self.0.attach_vmo(vmo).await?.as_ref().map_err(|s| *s))?;
246            }
247            fblock::SessionRequest::RegisterKey { key_token, responder } => {
248                responder.send(self.0.register_key(key_token).await?)?;
249            }
250            fblock::SessionRequest::Close { responder } => {
251                responder.send(self.0.close().await?)?;
252            }
253        }
254        Ok(())
255    }
256
257    /// Runs `stream` until completion.
258    pub async fn serve(&self, mut stream: fblock::SessionRequestStream) -> Result<(), Error> {
259        while let Some(Ok(request)) = stream.next().await {
260            if let Err(error) = self.handle_request(request).await {
261                log::warn!(error:?; "FIDL error");
262            }
263        }
264        Ok(())
265    }
266}
267
268pub struct SessionManager<I: Interface + ?Sized> {
269    interface: Arc<I>,
270    active_requests: ActiveRequests<usize>,
271    key_registry: KeyRegistry,
272
273    // NOTE: This must be dropped *after* `active_requests` because we store `Buffer<'_>` with an
274    // erased ('static) lifetime in `ActiveRequest`.
275    buffer_allocator: OnceLock<BufferAllocator>,
276}
277
278impl<I: Interface + ?Sized> Drop for SessionManager<I> {
279    fn drop(&mut self) {
280        if let Some(allocator) = self.buffer_allocator.get() {
281            self.interface.on_detach_vmo(allocator.buffer_source().vmo());
282        }
283    }
284}
285
286impl<I: Interface + ?Sized> SessionManager<I> {
287    pub fn new(interface: Arc<I>) -> Self {
288        Self {
289            interface,
290            active_requests: ActiveRequests::default(),
291            key_registry: KeyRegistry::default(),
292            buffer_allocator: OnceLock::new(),
293        }
294    }
295
296    pub fn interface(&self) -> &Arc<I> {
297        &self.interface
298    }
299
300    /// Runs `stream` until completion.
301    pub async fn serve_session(
302        self: Arc<Self>,
303        stream: fblock::SessionRequestStream,
304        offset_map: OffsetMap,
305        max_transfer_blocks: Option<std::num::NonZero<u32>>,
306        block_size: u32,
307    ) -> Result<(), Error> {
308        let (helper, fifo) =
309            SessionHelper::new(self.clone(), offset_map, max_transfer_blocks, block_size)?;
310        let session = Arc::new(Session {
311            helper: Arc::new(helper),
312            interface: self.interface.clone(),
313            close_callback: Mutex::new(None),
314        });
315
316        let (stop_sender, stop_receiver) = futures::channel::oneshot::channel();
317
318        let mut stream = stream.fuse();
319        let scope = fasync::Scope::new();
320        let session_clone = session.clone();
321        let mut fifo_task = scope
322            .spawn(async move {
323                if let Err(status) = session_clone.run_fifo(fifo, stop_receiver).await {
324                    if status != zx::Status::PEER_CLOSED {
325                        log::error!(status:?; "FIFO error");
326                    }
327                }
328            })
329            .fuse();
330
331        // Make sure we detach VMOs when we go out of scope.
332        scopeguard::defer! {
333            for (_, registered_vmo) in session.helper.take_vmos() {
334                self.interface.on_detach_vmo(&registered_vmo.vmo);
335            }
336        }
337
338        let mut closing = false;
339        let mut stop_sender = Some(stop_sender);
340
341        loop {
342            futures::select! {
343                maybe_req = if closing {
344                    futures::future::pending().left_future()
345                } else {
346                    stream.next().right_future()
347                } => {
348                    if let Some(req) = maybe_req {
349                        match session.helper.handle_request(req?).await? {
350                            HandleRequestResult::Ok => {},
351                            HandleRequestResult::Closed(callback) => {
352                                *session.close_callback.lock() = Some(callback);
353                                // Client explicitly closed stream, stop processing.
354                                if let Some(sender) = stop_sender.take() {
355                                    let _ = sender.send(());
356                                }
357                                closing = true;
358                            }
359                        }
360                    } else {
361                        // Client end of stream dropped, stop processing.
362                        if let Some(sender) = stop_sender.take() {
363                            let _ = sender.send(());
364                        }
365                        closing = true;
366                    }
367                }
368                _ = fifo_task => break,
369            }
370        }
371        Ok(())
372    }
373}
374
375pub struct Session<I: Interface + ?Sized> {
376    interface: Arc<I>,
377    helper: Arc<SessionHelper<SessionManager<I>>>,
378    close_callback: Mutex<Option<Box<dyn FnOnce() + Send + 'static>>>,
379}
380
381impl<I: Interface + ?Sized> Session<I> {
382    // A task loop for receiving and responding to FIFO requests.
383    async fn run_fifo(
384        &self,
385        fifo: zx::Fifo<BlockFifoRequest, BlockFifoResponse>,
386        stop_signal: futures::channel::oneshot::Receiver<()>,
387    ) -> Result<(), zx::Status> {
388        scopeguard::defer! {
389            // Ensure that we always clean up active requests for this session upon FIFO
390            // termination.
391            self.helper.drop_active_requests(|session| *session == self as *const _ as usize);
392        }
393
394        // The FIFO has to be processed by a single task due to implementation constraints on
395        // fuchsia_async::Fifo.  Thus, we use an event loop to drive the FIFO.  FIFO reads and
396        // writes can happen in batch, and request processing is parallel.
397        //
398        // The general flow is:
399        //  - Read messages from the FIFO, write into `requests`.
400        //  - Read `requests`, decode them, and spawn a task to process them in `active_requests`,
401        //    which will eventually write them into `responses`.
402        //  - Read `responses` and write out to the FIFO.
403        let mut fifo = fasync::Fifo::from_fifo(fifo);
404        let (mut reader, mut writer) = fifo.async_io();
405        let mut requests = [MaybeUninit::<BlockFifoRequest>::uninit(); FIFO_MAX_REQUESTS];
406        let active_requests = &self.helper.session_manager().active_requests;
407        let mut active_request_futures = FuturesUnordered::new();
408        let mut responses = Vec::new();
409
410        // We map requests using a single future `map_future`.  `pending_mappings` is used to queue
411        // up requests that need to be mapped.  This will serialise how mappings occur which might
412        // make updating mapping caches simpler.  If this proves to be a performance issue, we can
413        // optimise it.
414        let mut map_future = pin!(Fuse::terminated());
415        let mut pending_mappings: VecDeque<DecodedRequest> = VecDeque::new();
416
417        // When `stop_signal` is received, we stop reading from the FIFO and wait for in-flight
418        // tasks to complete.
419        let mut stop_signal = pin!(stop_signal.fuse());
420        let mut is_closed = false;
421
422        loop {
423            let new_requests = {
424                // We provide some flow control by limiting how many in-flight requests we will
425                // allow.
426                let pending_requests = active_request_futures.len() + responses.len();
427
428                if is_closed
429                    && pending_requests == 0
430                    && map_future.is_terminated()
431                    && pending_mappings.is_empty()
432                {
433                    return Ok(());
434                }
435
436                let count = requests.len().saturating_sub(pending_requests);
437                let mut receive_requests = pin!(if count == 0 || is_closed {
438                    Fuse::terminated()
439                } else {
440                    reader.read_entries(&mut requests[..count]).fuse()
441                });
442                let mut send_responses = pin!(if responses.is_empty() {
443                    Fuse::terminated()
444                } else {
445                    poll_fn(|cx| -> Poll<Result<(), zx::Status>> {
446                        match ready!(writer.try_write(cx, &responses[..])) {
447                            Ok(written) => {
448                                responses.drain(..written.get());
449                                Poll::Ready(Ok(()))
450                            }
451                            Err(status) => Poll::Ready(Err(status)),
452                        }
453                    })
454                    .fuse()
455                });
456
457                // Order is important here.  We want to prioritize sending results on the FIFO and
458                // processing FIFO messages over receiving new ones, to provide flow control.
459                select_biased!(
460                    res = send_responses => {
461                        res?;
462                        0
463                    },
464                    response = active_request_futures.select_next_some() => {
465                        responses.extend(response);
466                        0
467                    }
468                    result = map_future => {
469                        match result {
470                            Ok((request, remainder, commit_decompression_buffers)) => {
471                                active_request_futures.push(self.process_fifo_request(
472                                    request,
473                                    commit_decompression_buffers,
474                                ));
475                                if let Some(remainder) = remainder {
476                                    map_future.set(
477                                        self.map_request_or_get_response(remainder).fuse()
478                                    );
479                                }
480                            }
481                            Err(response) => responses.extend(response),
482                        }
483                        if map_future.is_terminated() {
484                            if let Some(request) = pending_mappings.pop_front() {
485                                map_future.set(self.map_request_or_get_response(request).fuse());
486                            }
487                        }
488                        0
489                    }
490                    _ = stop_signal => {
491                        is_closed = true;
492                        0
493                    }
494                    count = receive_requests => {
495                        count?.get()
496                    }
497                )
498            };
499
500            // NB: It is very important that there are no `await`s for the rest of the loop body, as
501            // otherwise active requests might become stalled.
502            for request in &mut requests[..new_requests] {
503                match self.helper.decode_fifo_request(self as *const _ as usize, unsafe {
504                    request.assume_init_mut()
505                }) {
506                    Ok(DecodedRequest {
507                        operation: Operation::CloseVmo, vmo, request_id, ..
508                    }) => {
509                        if let Some(vmo) = vmo {
510                            self.interface.on_detach_vmo(vmo.as_ref());
511                        }
512                        responses.extend(
513                            active_requests
514                                .complete_and_take_response(request_id, Ok(()))
515                                .map(|(_, response)| response),
516                        );
517                    }
518                    Ok(request) => {
519                        if map_future.is_terminated() {
520                            map_future.set(self.map_request_or_get_response(request).fuse());
521                        } else {
522                            pending_mappings.push_back(request);
523                        }
524                    }
525                    Err(None) => {}
526                    Err(Some(response)) => responses.push(response),
527                }
528            }
529        }
530    }
531
532    async fn map_request_or_get_response(
533        &self,
534        request: DecodedRequest,
535    ) -> Result<(DecodedRequest, Option<DecodedRequest>, bool), Option<BlockFifoResponse>> {
536        let request_id = request.request_id;
537        self.map_request(request).await.map_err(|status| {
538            self.helper
539                .orchestrator
540                .active_requests
541                .complete_and_take_response(request_id, Err(status))
542                .map(|(_, r)| r)
543        })
544    }
545
546    // NOTE: The implementation of this currently assumes that we are only processing a single map
547    // request at a time.
548    async fn map_request(
549        &self,
550        mut request: DecodedRequest,
551    ) -> Result<(DecodedRequest, Option<DecodedRequest>, bool), zx::Status> {
552        let mut active_requests;
553        let active_request;
554        let mut commit_decompression_buffers = false;
555        let flags = self.interface.get_info().as_ref().device_flags();
556        // Strip the PRE_BARRIER flag if we don't support it, and simulate the barrier with a
557        // pre-flush.
558        if !flags.contains(DeviceFlag::BARRIER_SUPPORT)
559            && request.operation.take_write_flag(WriteFlags::PRE_BARRIER)
560        {
561            if let Some(id) = request.trace_flow_id {
562                fuchsia_trace::async_instant!(
563                    fuchsia_trace::Id::from(id.get()),
564                    "storage",
565                    "block_server::SimulatedBarrier",
566                    "request_id" => request.request_id.0
567                );
568            }
569            self.interface.flush(request.trace_flow_id).await?;
570        }
571
572        // Handle decompressed read operations by turning them into regular read operations.
573        match request.operation {
574            Operation::StartDecompressedRead {
575                required_buffer_size,
576                device_block_offset,
577                block_count,
578                options,
579            } => {
580                let allocator = match self.helper.session_manager().buffer_allocator.get() {
581                    Some(a) => a,
582                    None => {
583                        // This isn't racy because there should only be one `map_request` future
584                        // running at any one time.
585                        let source = BufferSource::new(fblock::MAX_DECOMPRESSED_BYTES as usize);
586                        self.interface.on_attach_vmo(&source.vmo()).await?;
587                        let allocator = BufferAllocator::new(
588                            std::cmp::max(
589                                self.helper.block_size as usize,
590                                zx::system_get_page_size() as usize,
591                            ),
592                            source,
593                        );
594                        self.helper.session_manager().buffer_allocator.set(allocator).unwrap();
595                        self.helper.session_manager().buffer_allocator.get().unwrap()
596                    }
597                };
598
599                if required_buffer_size > fblock::MAX_DECOMPRESSED_BYTES as usize {
600                    return Err(zx::Status::OUT_OF_RANGE);
601                }
602
603                let buffer = allocator.allocate_buffer(required_buffer_size).await;
604                let vmo_offset = buffer.range().start as u64;
605
606                // # Safety
607                //
608                // See below.
609                unsafe fn remove_lifetime(buffer: Buffer<'_>) -> Buffer<'static> {
610                    unsafe { std::mem::transmute(buffer) }
611                }
612
613                active_requests = self.helper.session_manager().active_requests.0.lock();
614                active_request = &mut active_requests.requests[request.request_id.0];
615
616                // SAFETY: We guarantee that `buffer_allocator` is dropped after `active_requests`,
617                // so this should be safe.
618                active_request.decompression_info.as_mut().unwrap().buffer =
619                    Some(unsafe { remove_lifetime(buffer) });
620
621                request.operation = Operation::Read {
622                    device_block_offset,
623                    block_count,
624                    _unused: 0,
625                    vmo_offset,
626                    options,
627                };
628                request.vmo = Some(allocator.buffer_source().vmo().clone());
629
630                commit_decompression_buffers = true;
631            }
632            Operation::ContinueDecompressedRead {
633                offset,
634                device_block_offset,
635                block_count,
636                options,
637            } => {
638                active_requests = self.helper.session_manager().active_requests.0.lock();
639                active_request = &mut active_requests.requests[request.request_id.0];
640
641                let buffer =
642                    active_request.decompression_info.as_ref().unwrap().buffer.as_ref().unwrap();
643
644                // Make sure this read won't overflow our buffer.
645                if offset >= buffer.len() as u64
646                    || buffer.len() as u64 - offset
647                        < block_count as u64 * self.helper.block_size as u64
648                {
649                    return Err(zx::Status::OUT_OF_RANGE);
650                }
651
652                request.operation = Operation::Read {
653                    device_block_offset,
654                    block_count,
655                    _unused: 0,
656                    vmo_offset: buffer.range().start as u64 + offset,
657                    options,
658                };
659
660                let allocator = self.helper.session_manager().buffer_allocator.get().unwrap();
661                request.vmo = Some(allocator.buffer_source().vmo().clone());
662            }
663            _ => {
664                active_requests = self.helper.session_manager().active_requests.0.lock();
665                active_request = &mut active_requests.requests[request.request_id.0];
666            }
667        }
668
669        // NB: We propagate the FORCE_ACCESS flag to *both* request and remainder, even if we're
670        // using simulated FUA.  However, in `process_fifo_request`, we'll only do the post-flush
671        // once the last request completes.
672        self.helper
673            .map_request(request, active_request)
674            .map(|(request, remainder)| (request, remainder, commit_decompression_buffers))
675    }
676
677    /// Processes a fifo request.
678    async fn process_fifo_request(
679        &self,
680        DecodedRequest { request_id, operation, vmo, trace_flow_id }: DecodedRequest,
681        commit_decompression_buffers: bool,
682    ) -> Option<BlockFifoResponse> {
683        let mut needs_postflush = false;
684        let result = match operation {
685            Operation::Read { device_block_offset, block_count, _unused, vmo_offset, options } => {
686                join(
687                    self.interface.read(
688                        device_block_offset,
689                        block_count,
690                        vmo.as_ref().unwrap(),
691                        vmo_offset,
692                        options,
693                        trace_flow_id,
694                    ),
695                    async {
696                        if commit_decompression_buffers {
697                            let (target_slice, buffer_slice, buffer_range) = {
698                                let active_request = self
699                                    .helper
700                                    .session_manager()
701                                    .active_requests
702                                    .request(request_id);
703                                let info = active_request.decompression_info.as_ref().unwrap();
704                                (
705                                    info.uncompressed_slice(),
706                                    self.helper
707                                        .orchestrator
708                                        .buffer_allocator
709                                        .get()
710                                        .unwrap()
711                                        .buffer_source()
712                                        .slice(),
713                                    info.buffer.as_ref().unwrap().range(),
714                                )
715                            };
716                            let vmar = fuchsia_runtime::vmar_root_self();
717                            // The target slice might not be page aligned.
718                            let addr = target_slice.addr();
719                            let unaligned = addr % zx::system_get_page_size() as usize;
720                            if let Err(error) = vmar.op_range(
721                                zx::VmarOp::COMMIT,
722                                addr - unaligned,
723                                target_slice.len() + unaligned,
724                            ) {
725                                log::warn!(error:?; "Unable to commit target range");
726                            }
727                            // But the buffer range should be.
728                            if let Err(error) = vmar.op_range(
729                                zx::VmarOp::PREFETCH,
730                                buffer_slice.addr() + buffer_range.start,
731                                buffer_range.len(),
732                            ) {
733                                log::warn!(
734                                    error:?,
735                                    buffer_range:?;
736                                    "Unable to prefetch source range",
737                                );
738                            }
739                        }
740                    },
741                )
742                .await
743                .0
744            }
745            Operation::Write {
746                device_block_offset,
747                block_count,
748                _unused,
749                vmo_offset,
750                mut options,
751            } => {
752                // Strip the FORCE_ACCESS flag if we don't support it, and simulate the FUA with a
753                // post-flush.
754                if options.flags.contains(WriteFlags::FORCE_ACCESS) {
755                    let flags = self.interface.get_info().as_ref().device_flags();
756                    if !flags.contains(DeviceFlag::FUA_SUPPORT) {
757                        options.flags.remove(WriteFlags::FORCE_ACCESS);
758                        needs_postflush = true;
759                    }
760                }
761                self.interface
762                    .write(
763                        device_block_offset,
764                        block_count,
765                        vmo.as_ref().unwrap(),
766                        vmo_offset,
767                        options,
768                        trace_flow_id,
769                    )
770                    .await
771            }
772            Operation::Flush => self.interface.flush(trace_flow_id).await,
773            Operation::Trim { device_block_offset, block_count } => {
774                self.interface.trim(device_block_offset, block_count, trace_flow_id).await
775            }
776            Operation::CloseVmo
777            | Operation::StartDecompressedRead { .. }
778            | Operation::ContinueDecompressedRead { .. } => {
779                // Handled in main request loop
780                unreachable!()
781            }
782        };
783        let response = self
784            .helper
785            .orchestrator
786            .active_requests
787            .complete_and_take_response(request_id, result)
788            .map(|(_, r)| r);
789        if let Some(mut response) = response {
790            // Only do the post-flush on the very last request, and only if successful.
791            if zx::Status::ok(response.status).is_ok() && needs_postflush {
792                if let Some(id) = trace_flow_id {
793                    fuchsia_trace::async_instant!(
794                        fuchsia_trace::Id::from(id.get()),
795                        "storage",
796                        "block_server::SimulatedFUA",
797                        "request_id" => request_id.0
798                    );
799                }
800                response.status =
801                    zx::Status::result_into_raw(self.interface.flush(trace_flow_id).await);
802            }
803            Some(response)
804        } else {
805            response
806        }
807    }
808}
809
810impl<I: Interface + ?Sized> super::SessionManager for SessionManager<I> {
811    type Orchestrator = Self;
812
813    const SUPPORTS_DECOMPRESSION: bool = true;
814
815    // We don't need the session, we just need something unique to identify the session.
816    type Session = usize;
817
818    fn session_eq(a: &usize, b: &usize) -> bool {
819        a == b
820    }
821
822    async fn on_attach_vmo(orchestrator: Arc<Self>, vmo: &Arc<zx::Vmo>) -> Result<(), zx::Status> {
823        I::on_attach_vmo(&orchestrator.interface, vmo).await
824    }
825
826    async fn open_session(
827        orchestrator: Arc<Self>,
828        stream: fblock::SessionRequestStream,
829        offset_map: OffsetMap,
830        block_size: u32,
831    ) -> Result<(), Error> {
832        I::open_session(
833            &orchestrator.interface,
834            orchestrator.clone(),
835            stream,
836            offset_map,
837            block_size,
838        )
839        .await
840    }
841
842    fn get_info(&self) -> Cow<'_, DeviceInfo> {
843        self.interface.get_info()
844    }
845
846    async fn get_volume_info(
847        &self,
848    ) -> Result<(fblock::VolumeManagerInfo, fblock::VolumeInfo), zx::Status> {
849        self.interface.get_volume_info().await
850    }
851
852    async fn query_slices(
853        &self,
854        start_slices: &[u64],
855    ) -> Result<Vec<fblock::VsliceRange>, zx::Status> {
856        self.interface.query_slices(start_slices).await
857    }
858
859    async fn extend(&self, start_slice: u64, slice_count: u64) -> Result<(), zx::Status> {
860        self.interface.extend(start_slice, slice_count).await
861    }
862
863    async fn shrink(&self, start_slice: u64, slice_count: u64) -> Result<(), zx::Status> {
864        self.interface.shrink(start_slice, slice_count).await
865    }
866
867    fn open_mapper_session(
868        orchestrator: Arc<Self>,
869        session: fidl::endpoints::ServerEnd<fblock::MapperSessionMarker>,
870        mapping_vmo: zx::Vmo,
871        block_size: u32,
872        port: Option<zx::Port>,
873        delivery_queue: Option<zx::Vmo>,
874    ) -> Result<impl Future<Output = Result<(), Error>> + Send, zx::Status> {
875        I::open_mapper_session(orchestrator, session, mapping_vmo, block_size, port, delivery_queue)
876    }
877
878    fn active_requests(&self) -> &ActiveRequests<Self::Session> {
879        return &self.active_requests;
880    }
881
882    fn key_registry(&self) -> &KeyRegistry {
883        &self.key_registry
884    }
885}
886
887impl<I: Interface + ?Sized> Drop for Session<I> {
888    fn drop(&mut self) {
889        let callback = std::mem::take(&mut *self.close_callback.lock());
890        if let Some(callback) = callback {
891            callback();
892        }
893    }
894}
895
896impl<I: Interface> IntoOrchestrator for Arc<I> {
897    type SM = SessionManager<I>;
898
899    fn into_orchestrator(self) -> Arc<Self::SM> {
900        Arc::new(SessionManager::new(self))
901    }
902}
903
904/// A generic adapter that presents any [`async_interface::Interface`] backend as a
905/// [`BlockService`], using [`BufferAllocator`] for concurrent read buffer management and
906/// [`fasync::ScopeHandle`] for thread-safe task spawning.
907pub struct AsyncBlockService<I: Interface + ?Sized> {
908    interface: Arc<I>,
909    allocator: Arc<BufferAllocator>,
910    block_size: u32,
911    max_transfer_bytes: usize,
912    scope: fasync::ScopeHandle,
913}
914
915impl<I: Interface + ?Sized> AsyncBlockService<I> {
916    pub async fn new(
917        interface: Arc<I>,
918        block_size: u32,
919        pool_capacity: usize,
920        scope: fasync::ScopeHandle,
921    ) -> Result<Self, zx::Status> {
922        let source = BufferSource::new(pool_capacity);
923        interface.on_attach_vmo(&source.vmo()).await?;
924        let allocator = Arc::new(BufferAllocator::new(
925            std::cmp::max(block_size as usize, zx::system_get_page_size() as usize),
926            source,
927        ));
928        Ok(Self::new_with_allocator(interface, block_size, allocator, scope))
929    }
930
931    pub fn new_with_allocator(
932        interface: Arc<I>,
933        block_size: u32,
934        allocator: Arc<BufferAllocator>,
935        scope: fasync::ScopeHandle,
936    ) -> Self {
937        let max_transfer_bytes = interface
938            .get_info()
939            .max_transfer_blocks()
940            .map(|blocks| {
941                let bytes = (blocks.get() as usize).saturating_mul(block_size as usize);
942                std::cmp::max(
943                    bytes & !(mapping::BLOCK_SIZE as usize - 1),
944                    mapping::BLOCK_SIZE as usize,
945                )
946            })
947            .unwrap_or(MAX_READ_BUFFER_SIZE);
948        Self { interface, allocator, block_size, max_transfer_bytes, scope }
949    }
950
951    pub fn interface(&self) -> &Arc<I> {
952        &self.interface
953    }
954
955    pub fn allocator(&self) -> &Arc<BufferAllocator> {
956        &self.allocator
957    }
958}
959
960impl<I: Interface + ?Sized> BlockService for AsyncBlockService<I> {
961    fn allocate_buffer(&self, max_len: usize) -> OwnedBuffer {
962        let max_len = max_len
963            .min(MAX_READ_BUFFER_SIZE)
964            .min(self.max_transfer_bytes)
965            .min(self.allocator.buffer_source().size());
966        self.allocator.allocate_buffer_sync_owned(max_len)
967    }
968
969    fn read_blocks(
970        &self,
971        device_offset: u64,
972        dest_buffer: OwnedBuffer,
973        on_complete: Box<dyn FnOnce(Result<OwnedBuffer, Error>) + Send>,
974    ) -> Result<(), Error> {
975        let block_size = self.block_size as u64;
976        let device_block_offset = device_offset / block_size;
977        let block_count = (dest_buffer.len() as u64 / block_size) as u32;
978
979        let vmo_offset = dest_buffer.range().start as u64;
980        let vmo = self.allocator.buffer_source().vmo().clone();
981        let interface = self.interface.clone();
982
983        self.scope.spawn(async move {
984            let res = interface
985                .read(
986                    device_block_offset,
987                    block_count,
988                    &vmo,
989                    vmo_offset,
990                    ReadOptions::default(),
991                    TraceFlowId::default(),
992                )
993                .await;
994            match res {
995                Ok(()) => on_complete(Ok(dest_buffer)),
996                Err(status) => on_complete(Err(anyhow::anyhow!("Read failed: {:?}", status))),
997            }
998        });
999
1000        Ok(())
1001    }
1002}
1003
1004#[cfg(test)]
1005mod tests {
1006    use super::*;
1007    use crate::BlockServer;
1008    use fuchsia_async as fasync;
1009    use mapping::Extents;
1010    use mapping::reader::read_aligned_range;
1011    use std::sync::atomic::{AtomicU64, Ordering};
1012
1013    struct FakeInterface {
1014        data: Vec<u8>,
1015        block_size: u32,
1016        read_count: AtomicU64,
1017    }
1018
1019    impl FakeInterface {
1020        fn new(data: Vec<u8>, block_size: u32) -> Self {
1021            Self { data, block_size, read_count: AtomicU64::new(0) }
1022        }
1023    }
1024
1025    impl Interface for FakeInterface {
1026        fn on_open_mapper_session(
1027            &self,
1028            _mapping_vmo: &zx::Vmo,
1029            delivery_queue: zx::Vmo,
1030        ) -> Result<Verifier, zx::Status> {
1031            Ok(Verifier::new(delivery_queue))
1032        }
1033
1034        fn get_info(&self) -> Cow<'_, DeviceInfo> {
1035            Cow::Owned(DeviceInfo::Block(crate::BlockInfo {
1036                block_count: (self.data.len() / self.block_size as usize) as u64,
1037                max_transfer_blocks: None,
1038                device_flags: fblock::DeviceFlag::empty(),
1039            }))
1040        }
1041
1042        async fn read(
1043            &self,
1044            device_block_offset: u64,
1045            block_count: u32,
1046            vmo: &Arc<zx::Vmo>,
1047            vmo_offset: u64,
1048            _opts: ReadOptions,
1049            _trace_flow_id: TraceFlowId,
1050        ) -> Result<(), zx::Status> {
1051            self.read_count.fetch_add(1, Ordering::Relaxed);
1052            let byte_offset = (device_block_offset * self.block_size as u64) as usize;
1053            let byte_len = (block_count * self.block_size) as usize;
1054            let slice = &self.data[byte_offset..byte_offset + byte_len];
1055            vmo.write(slice, vmo_offset).map_err(|_| zx::Status::IO)?;
1056            Ok(())
1057        }
1058
1059        async fn write(
1060            &self,
1061            _device_block_offset: u64,
1062            _block_count: u32,
1063            _vmo: &Arc<zx::Vmo>,
1064            _vmo_offset: u64,
1065            _opts: WriteOptions,
1066            _trace_flow_id: TraceFlowId,
1067        ) -> Result<(), zx::Status> {
1068            Ok(())
1069        }
1070
1071        async fn flush(&self, _trace_flow_id: TraceFlowId) -> Result<(), zx::Status> {
1072            Ok(())
1073        }
1074
1075        async fn trim(
1076            &self,
1077            _device_block_offset: u64,
1078            _block_count: u32,
1079            _trace_flow_id: TraceFlowId,
1080        ) -> Result<(), zx::Status> {
1081            Ok(())
1082        }
1083    }
1084
1085    #[fasync::run_singlethreaded(test)]
1086    async fn test_async_block_service_read_aligned_range() {
1087        let block_size = 512;
1088        let test_data: Vec<u8> = (0..8192).map(|i| (i % 255) as u8).collect();
1089        let interface = Arc::new(FakeInterface::new(test_data.clone(), block_size));
1090        let scope = fasync::Scope::current();
1091
1092        let block_service = Arc::new(
1093            AsyncBlockService::new(interface, block_size, 16384, scope)
1094                .await
1095                .expect("Failed to create AsyncBlockService"),
1096        );
1097
1098        let encoded = (1u64 << 32) | 0u64;
1099        let extents = Extents::from_encoded([encoded], 0).unwrap();
1100        let service = block_service.clone();
1101        let (send, recv) = futures::channel::oneshot::channel();
1102        let send = std::sync::Mutex::new(Some(send));
1103        let read_buf = std::sync::Mutex::new(Vec::new());
1104
1105        read_aligned_range(&extents, 0..4096, &*service, move |buffer_result| {
1106            let buffer = buffer_result.unwrap();
1107            let mut read_guard = read_buf.lock().unwrap();
1108            buffer.as_ptr_slice().append_to(&mut read_guard);
1109            if read_guard.len() == 4096 {
1110                if let Some(s) = send.lock().unwrap().take() {
1111                    let _ = s.send(read_guard.clone());
1112                }
1113            }
1114            std::ops::ControlFlow::Continue(())
1115        });
1116
1117        let result = recv.await.unwrap();
1118        assert_eq!(result, &test_data[0..4096]);
1119    }
1120
1121    #[fasync::run_singlethreaded(test)]
1122    async fn test_async_block_service_concurrent_reads_larger_than_pool_capacity() {
1123        let block_size = 512;
1124        let total_size = 65536; // 16 * 4096 bytes
1125        let test_data: Vec<u8> = (0..total_size).map(|i| (i % 251) as u8).collect();
1126        let interface = Arc::new(FakeInterface::new(test_data.clone(), block_size));
1127        let scope = fasync::Scope::current();
1128
1129        // Pool capacity is 8192 bytes (2 * 4096 bytes), while total concurrent reads
1130        // request 65536 bytes.
1131        let pool_capacity = 8192;
1132        let source = BufferSource::new(pool_capacity);
1133        interface.on_attach_vmo(&source.vmo()).await.unwrap();
1134        let allocator = Arc::new(BufferAllocator::new(
1135            std::cmp::max(block_size as usize, zx::system_get_page_size() as usize),
1136            source,
1137        ));
1138        let block_service = Arc::new(AsyncBlockService::new_with_allocator(
1139            interface, block_size, allocator, scope,
1140        ));
1141
1142        let encoded = (16u64 << 32) | 0u64;
1143        let extents = Arc::new(Extents::from_encoded([encoded], 0).unwrap());
1144
1145        // Spawn 4 concurrent read requests on background threads, each requesting 16384 bytes.
1146        let ranges = [0..16384, 16384..32768, 32768..49152, 49152..65536];
1147        let mut receivers = Vec::new();
1148
1149        for range in ranges {
1150            let (send, recv) = futures::channel::oneshot::channel();
1151            let service = block_service.clone();
1152            let extents = extents.clone();
1153
1154            std::thread::spawn(move || {
1155                let send = std::sync::Mutex::new(Some(send));
1156                let read_buf = std::sync::Mutex::new(Vec::new());
1157                let target_len = (range.end - range.start) as usize;
1158
1159                read_aligned_range(&extents, range, &*service, move |buffer_result| {
1160                    let buffer = buffer_result.unwrap();
1161                    let mut read_guard = read_buf.lock().unwrap();
1162                    buffer.as_ptr_slice().append_to(&mut read_guard);
1163                    if read_guard.len() == target_len {
1164                        if let Some(s) = send.lock().unwrap().take() {
1165                            let _ = s.send(read_guard.clone());
1166                        }
1167                    }
1168                    std::ops::ControlFlow::Continue(())
1169                });
1170            });
1171
1172            receivers.push(recv);
1173        }
1174
1175        let results = futures::future::join_all(receivers).await;
1176        for (i, res) in results.into_iter().enumerate() {
1177            let data = res.unwrap();
1178            let start = i * 16384;
1179            let end = start + 16384;
1180            assert_eq!(data, &test_data[start..end]);
1181        }
1182    }
1183
1184    #[fuchsia::test]
1185    async fn test_async_interface_mapper_hierarchical_session() {
1186        use assert_matches::assert_matches;
1187
1188        let block_size = 512;
1189        let test_data = vec![0xCDu8; 8192];
1190        let interface = Arc::new(FakeInterface::new(test_data.clone(), block_size));
1191        let block_server = BlockServer::new(block_size, interface.clone());
1192
1193        let (mapper_proxy, mapper_stream) =
1194            fidl::endpoints::create_proxy_and_stream::<fblock::MapperMarker>();
1195        let scope = fasync::Scope::new();
1196        scope.spawn(async move {
1197            let _ = block_server.handle_mapper_requests(mapper_stream).await;
1198        });
1199
1200        // 1. Open root intermediate mapper session without pager.
1201        let (root_session_proxy, root_session_server) =
1202            fidl::endpoints::create_proxy::<fblock::MapperSessionMarker>();
1203        let root_mapping_vmo = zx::Vmo::create(65536).unwrap();
1204
1205        let partition_key = 500u64;
1206        let extents =
1207            mapping::Extents::try_new([mapping::Extent::new(0..4096, Some(4096))], 0).unwrap();
1208        let partition_extents: Vec<u64> = mapping::Extents::encode_extents(&extents).collect();
1209        let mut payload_bytes = Vec::new();
1210        for w in &partition_extents {
1211            payload_bytes.extend_from_slice(&w.to_le_bytes());
1212        }
1213        let cmd = mapping::RawMappingCommand {
1214            opcode: mapping::MAPPINGS_COMMAND,
1215            offset: 0,
1216            key: partition_key,
1217            stored_size: 4096,
1218            device_offset: 0,
1219            metadata_count: 0,
1220            extent_count: partition_extents.len() as u32,
1221        };
1222        let mut sender = vmo_fifo::SyncSender::<mapping::RawMappingCommand>::new(
1223            root_mapping_vmo.duplicate_handle(zx::Rights::SAME_RIGHTS).unwrap(),
1224            1024,
1225            256,
1226        )
1227        .unwrap();
1228        let mut payload_buf = sender.reserve_payload(payload_bytes.len()).unwrap();
1229        payload_buf.data().copy_from_slice(&payload_bytes);
1230        payload_buf.commit(cmd).unwrap();
1231
1232        let res = mapper_proxy
1233            .open_session(root_session_server, root_mapping_vmo, None, None)
1234            .await
1235            .unwrap();
1236        assert_matches!(res, Ok(()));
1237
1238        // 2. Open child session with pager through partition key 500.
1239        let pager = Arc::new(zx::Pager::create(zx::PagerOptions::empty()).unwrap());
1240        let port = zx::Port::create();
1241        let child_key = 2002u64;
1242        let paged_vmo = pager.create_vmo(zx::VmoOptions::empty(), &port, child_key, 4096).unwrap();
1243
1244        let child_mapping_vmo = zx::Vmo::create(65536).unwrap();
1245        let delivery_queue = zx::Vmo::create(65536).unwrap();
1246        let vmo_provider = Arc::new(blob_pager_and_verifier::TestVmoProvider::new(
1247            pager.clone(),
1248            delivery_queue.duplicate_handle(zx::Rights::SAME_RIGHTS).unwrap(),
1249        ));
1250        vmo_provider
1251            .register_vmo(child_key, paged_vmo.duplicate_handle(zx::Rights::SAME_RIGHTS).unwrap());
1252        let receiver = vmo_fifo::Receiver::<mapping::RawDeliveryCommand>::new(
1253            delivery_queue.duplicate_handle(zx::Rights::SAME_RIGHTS).unwrap(),
1254            mapping::PENDING_DELIVERY_COMMANDS_CAPACITY,
1255        )
1256        .unwrap();
1257        let _delivery_processor = blob_pager_and_verifier::DeliveryQueueProcessor::spawn(
1258            receiver,
1259            vmo_provider,
1260            delivery_queue.duplicate_handle(zx::Rights::SAME_RIGHTS).unwrap(),
1261        )
1262        .unwrap();
1263
1264        let extents =
1265            mapping::Extents::try_new([mapping::Extent::new(0..4096, Some(0))], 0).unwrap();
1266        let child_extents: Vec<u64> = mapping::Extents::encode_extents(&extents).collect();
1267        let mut child_payload_bytes = Vec::new();
1268        for w in &child_extents {
1269            child_payload_bytes.extend_from_slice(&w.to_le_bytes());
1270        }
1271        let child_cmd = mapping::RawMappingCommand {
1272            opcode: mapping::MAPPINGS_COMMAND,
1273            offset: 0,
1274            key: child_key,
1275            stored_size: 4096,
1276            device_offset: 0,
1277            metadata_count: 0,
1278            extent_count: child_extents.len() as u32,
1279        };
1280        let mut child_sender = vmo_fifo::SyncSender::<mapping::RawMappingCommand>::new(
1281            child_mapping_vmo.duplicate_handle(zx::Rights::SAME_RIGHTS).unwrap(),
1282            1024,
1283            256,
1284        )
1285        .unwrap();
1286        let mut child_payload_buf =
1287            child_sender.reserve_payload(child_payload_bytes.len()).unwrap();
1288        child_payload_buf.data().copy_from_slice(&child_payload_bytes);
1289        child_payload_buf.commit(child_cmd).unwrap();
1290
1291        let mut child_session = None;
1292        for _ in 0..100 {
1293            let (child_session_proxy, child_session_server) =
1294                fidl::endpoints::create_proxy::<fblock::MapperSessionMarker>();
1295            let child_res_raw = root_session_proxy
1296                .open_child_session(
1297                    child_session_server,
1298                    child_mapping_vmo.duplicate_handle(zx::Rights::SAME_RIGHTS).unwrap(),
1299                    partition_key,
1300                    Some(port.duplicate_handle(zx::Rights::SAME_RIGHTS).unwrap()),
1301                    Some(delivery_queue.duplicate_handle(zx::Rights::SAME_RIGHTS).unwrap()),
1302                )
1303                .await
1304                .unwrap();
1305            if child_res_raw.is_ok() {
1306                child_session = Some(child_session_proxy);
1307                break;
1308            }
1309            fasync::Timer::new(std::time::Duration::from_millis(10)).await;
1310        }
1311        assert!(child_session.is_some());
1312
1313        let (tx, rx) = futures::channel::oneshot::channel();
1314        std::thread::spawn(move || {
1315            let mut buf = [0u8; 4096];
1316            paged_vmo.read(&mut buf, 0).expect("paged vmo read failed");
1317            let _ = tx.send(buf);
1318        });
1319
1320        let read_bytes = rx.await.unwrap();
1321        assert_eq!(read_bytes.len(), 4096);
1322        assert_eq!(read_bytes, &test_data[4096..8192]);
1323    }
1324
1325    #[fuchsia::test]
1326    async fn test_async_interface_mapper_child_session_closed_when_parent_closed() {
1327        use assert_matches::assert_matches;
1328        use fidl::endpoints::Proxy as _;
1329
1330        let block_size = 512;
1331        let test_data = vec![0u8; 8192];
1332        let interface = Arc::new(FakeInterface::new(test_data, block_size));
1333        let block_server = BlockServer::new(block_size, interface.clone());
1334
1335        let (mapper_proxy, mapper_stream) =
1336            fidl::endpoints::create_proxy_and_stream::<fblock::MapperMarker>();
1337        let scope = fasync::Scope::new();
1338        scope.spawn(async move {
1339            let _ = block_server.handle_mapper_requests(mapper_stream).await;
1340        });
1341
1342        let (root_session_proxy, root_session_server) =
1343            fidl::endpoints::create_proxy::<fblock::MapperSessionMarker>();
1344        let root_mapping_vmo = zx::Vmo::create(65536).unwrap();
1345
1346        let partition_key = 500u64;
1347        let extents =
1348            mapping::Extents::try_new([mapping::Extent::new(0..4096, Some(4096))], 0).unwrap();
1349        let partition_extents: Vec<u64> = mapping::Extents::encode_extents(&extents).collect();
1350        let mut payload_bytes = Vec::new();
1351        for w in &partition_extents {
1352            payload_bytes.extend_from_slice(&w.to_le_bytes());
1353        }
1354        let cmd = mapping::RawMappingCommand {
1355            opcode: mapping::MAPPINGS_COMMAND,
1356            offset: 0,
1357            key: partition_key,
1358            stored_size: 4096,
1359            device_offset: 0,
1360            metadata_count: 0,
1361            extent_count: partition_extents.len() as u32,
1362        };
1363        let mut sender = vmo_fifo::SyncSender::<mapping::RawMappingCommand>::new(
1364            root_mapping_vmo.duplicate_handle(zx::Rights::SAME_RIGHTS).unwrap(),
1365            1024,
1366            256,
1367        )
1368        .unwrap();
1369        let mut payload_buf = sender.reserve_payload(payload_bytes.len()).unwrap();
1370        payload_buf.data().copy_from_slice(&payload_bytes);
1371        payload_buf.commit(cmd).unwrap();
1372
1373        let res = mapper_proxy
1374            .open_session(root_session_server, root_mapping_vmo, None, None)
1375            .await
1376            .unwrap();
1377        assert_matches!(res, Ok(()));
1378
1379        let child_mapping_vmo = zx::Vmo::create(65536).unwrap();
1380        let mut child_session = None;
1381        for _ in 0..100 {
1382            let (child_session_proxy, child_session_server) =
1383                fidl::endpoints::create_proxy::<fblock::MapperSessionMarker>();
1384            let child_res_raw = root_session_proxy
1385                .open_child_session(
1386                    child_session_server,
1387                    child_mapping_vmo.duplicate_handle(zx::Rights::SAME_RIGHTS).unwrap(),
1388                    partition_key,
1389                    None,
1390                    None,
1391                )
1392                .await
1393                .unwrap();
1394            if child_res_raw.is_ok() {
1395                child_session = Some(child_session_proxy);
1396                break;
1397            }
1398            fasync::Timer::new(std::time::Duration::from_millis(10)).await;
1399        }
1400        let child_session_proxy = child_session.expect("Failed to open child session");
1401
1402        root_session_proxy.close().await.unwrap().expect("Close parent session failed");
1403        child_session_proxy.on_closed().await.unwrap();
1404    }
1405}