1use crate::verifier::Verifier;
6use crate::{
7 ActiveRequests, DecodedRequest, DeviceInfo, HandleRequestResult, IntoOrchestrator, KeyRegistry,
8 OffsetMap, Operation, RequestId, SessionHelper, TraceFlowId, WriteFlags,
9};
10use anyhow::Error;
11use block_protocol::{BlockFifoRequest, BlockFifoResponse};
12use fidl_fuchsia_storage_block as fblock;
13use fuchsia_sync::{Condvar, Mutex};
14use futures::TryStreamExt as _;
15use futures::stream::{AbortHandle, Abortable};
16use mapping::reader::BlockService;
17use std::borrow::{Borrow, Cow};
18use std::collections::{HashMap, VecDeque};
19use std::mem::MaybeUninit;
20use std::sync::{Arc, OnceLock, Weak};
21
22pub mod block_service;
23pub use block_service::DefaultCallbackBlockService;
24
25#[derive(Clone, Debug)]
27pub struct Request {
28 pub request_id: RequestId,
33 pub operation: Operation,
34 pub trace_flow_id: TraceFlowId,
35 pub vmo: Option<Arc<zx::Vmo>>,
37}
38
39pub trait Interface: Send + Sync + Unpin + 'static {
40 type Orchestrator: Borrow<SessionManager<Self>> + Send + Sync;
41
42 fn get_info(&self) -> Cow<'_, DeviceInfo>;
44
45 fn spawn_session(&self, session: Arc<Session<Self>>);
48
49 fn on_requests(&self, requests: &[Request]);
56
57 fn into_block_service(
61 self: Arc<Self>,
62 orchestrator: &Arc<Self::Orchestrator>,
63 ) -> Arc<dyn BlockService> {
64 Arc::new(DefaultCallbackBlockService::<Self>::new(orchestrator))
65 }
66
67 fn on_open_mapper_session(
70 &self,
71 _mapping_vmo: &zx::Vmo,
72 delivery_queue: zx::Vmo,
73 ) -> Result<Verifier, zx::Status> {
74 Ok(Verifier::new(delivery_queue))
75 }
76}
77
78const INTERNAL_REQUEST_FLAG: usize = 1 << 63;
83
84#[derive(Default)]
85struct InflightRequests {
86 count: usize,
88 callbacks: HashMap<RequestId, Box<dyn FnOnce(Result<(), zx::Status>) + Send>>,
90 next_internal_id: usize,
92}
93
94struct SessionManagerInner<I: Interface + ?Sized> {
95 open_sessions: HashMap<usize, Weak<Session<I>>>,
96}
97
98const FIFO_WAKE_SIGNAL: zx::Signals = zx::Signals::USER_0;
102
103const SHUTDOWN_SIGNAL: zx::Signals = zx::Signals::USER_1;
105
106pub struct SessionManager<I: Interface + ?Sized> {
107 interface: Arc<I>,
108 block_size: u32,
109 active_requests: ActiveRequests<Arc<Session<I>>>,
111 key_registry: KeyRegistry,
112 inflight_requests: Mutex<InflightRequests>,
113 no_inflight_requests_condvar: Condvar,
114 inner: Mutex<SessionManagerInner<I>>,
115 no_open_sessions_condvar: Condvar,
116 block_service: OnceLock<Arc<dyn BlockService>>,
117}
118
119impl<I: Interface + ?Sized> super::SessionManager for SessionManager<I> {
120 const SUPPORTS_DECOMPRESSION: bool = false;
121
122 type Orchestrator = I::Orchestrator;
123 type Session = Arc<Session<I>>;
124
125 fn session_eq(a: &Arc<Session<I>>, b: &Arc<Session<I>>) -> bool {
126 Arc::ptr_eq(a, b)
127 }
128
129 async fn on_attach_vmo(
130 _orchestrator: Arc<Self::Orchestrator>,
131 _vmo: &Arc<zx::Vmo>,
132 ) -> Result<(), zx::Status> {
133 Ok(())
134 }
135
136 async fn open_session(
141 orchestrator: Arc<Self::Orchestrator>,
142 mut stream: fblock::SessionRequestStream,
143 offset_map: OffsetMap,
144 block_size: u32,
145 ) -> Result<(), Error> {
146 let sm: &SessionManager<I> = orchestrator.as_ref().borrow();
147 let max_blocks = sm.get_info().max_transfer_blocks();
148 let (helper, fifo) =
149 SessionHelper::new(orchestrator.clone(), offset_map, max_blocks, block_size)?;
150 let (abort_handle, registration) = AbortHandle::new_pair();
151 let session = Arc::new(Session {
152 helper,
153 fifo,
154 queue: Mutex::default(),
155 abort_handle,
156 close_callback: Mutex::new(None),
157 });
158 let sm = orchestrator.as_ref().borrow();
159 sm.inner
160 .lock()
161 .open_sessions
162 .insert(Arc::as_ptr(&session) as usize, Arc::downgrade(&session));
163
164 sm.interface.spawn_session(session.clone());
165
166 let result = Abortable::new(
167 async {
168 while let Some(request) = stream.try_next().await? {
169 match session.helper.handle_request(request).await? {
170 HandleRequestResult::Ok => {}
171 HandleRequestResult::Closed(callback) => {
172 *session.close_callback.lock() = Some(callback);
173 break;
174 }
175 }
176 }
177 Ok(())
178 },
179 registration,
180 )
181 .await
182 .unwrap_or_else(|e| Err(e.into()));
183
184 let _ = session.fifo.signal(zx::Signals::empty(), SHUTDOWN_SIGNAL);
185
186 result
187 }
188
189 fn open_mapper_session(
190 orchestrator: Arc<Self::Orchestrator>,
191 session: fidl::endpoints::ServerEnd<fblock::MapperSessionMarker>,
192 mapping_vmo: zx::Vmo,
193 _block_size: u32,
194 port: Option<zx::Port>,
195 delivery_queue: Option<zx::Vmo>,
196 ) -> Result<impl Future<Output = Result<(), Error>> + Send, zx::Status> {
197 let sm: &SessionManager<I> = orchestrator.as_ref().borrow();
198 let service = sm.into_block_service(&orchestrator);
199 let interface = sm.interface.clone();
200 crate::mapper::serve_mapper_session(
201 Arc::new(move |mapping_vmo: &zx::Vmo, dq: zx::Vmo| {
202 interface.on_open_mapper_session(mapping_vmo, dq)
203 }),
204 service,
205 session,
206 mapping_vmo,
207 port,
208 delivery_queue,
209 )
210 }
211
212 fn get_info(&self) -> Cow<'_, super::DeviceInfo> {
213 self.interface.get_info()
214 }
215
216 fn active_requests(&self) -> &ActiveRequests<Arc<Session<I>>> {
217 &self.active_requests
218 }
219
220 fn key_registry(&self) -> &KeyRegistry {
221 &self.key_registry
222 }
223}
224
225impl<I: Interface + ?Sized> SessionManager<I> {
226 pub fn into_block_service(&self, orchestrator: &Arc<I::Orchestrator>) -> Arc<dyn BlockService> {
228 self.block_service
229 .get_or_init(|| self.interface.clone().into_block_service(orchestrator))
230 .clone()
231 }
232}
233
234impl<I: Interface + ?Sized> SessionManager<I> {
235 pub fn new(interface: Arc<I>, block_size: u32) -> Self
236 where
237 I: Sized,
238 {
239 Self {
240 interface,
241 block_size,
242 active_requests: ActiveRequests::default(),
243 key_registry: KeyRegistry::default(),
244 inflight_requests: Mutex::new(InflightRequests::default()),
245 no_inflight_requests_condvar: Condvar::new(),
246 inner: Mutex::new(SessionManagerInner { open_sessions: HashMap::new() }),
247 no_open_sessions_condvar: Condvar::new(),
248 block_service: OnceLock::new(),
249 }
250 }
251
252 pub fn block_size(&self) -> u32 {
253 self.block_size
254 }
255
256 pub fn complete_request(&self, request_id: RequestId, status: Result<(), zx::Status>) {
258 let (callback, notify) = {
259 let mut inflight = self.inflight_requests.lock();
260 let callback = if request_id.0 & INTERNAL_REQUEST_FLAG != 0 {
261 inflight.callbacks.remove(&request_id)
262 } else {
263 None
264 };
265 inflight.count -= 1;
266 let notify = inflight.count == 0;
267 (callback, notify)
268 };
269 if let Some(callback) = callback {
270 callback(status);
271 } else {
272 self.complete_unsubmitted_request(request_id, status);
273 }
274 if notify {
275 self.no_inflight_requests_condvar.notify_all();
276 }
277 }
278
279 fn submit_internal_request(
280 &self,
281 make_request: impl FnOnce(RequestId) -> Request,
282 callback: Box<dyn FnOnce(Result<(), zx::Status>) + Send>,
283 ) {
284 let req = {
285 let mut inflight = self.inflight_requests.lock();
286 let req_id = RequestId(inflight.next_internal_id | INTERNAL_REQUEST_FLAG);
287 inflight.next_internal_id += 1;
288 inflight.callbacks.insert(req_id, callback);
289 inflight.count += 1;
290 make_request(req_id)
291 };
292 self.interface.on_requests(&[req]);
293 }
294
295 fn submit_requests(&self, requests: &[Request]) {
296 self.inflight_requests.lock().count += requests.len();
297 self.interface.on_requests(requests);
298 }
299
300 fn wait_for_no_inflight_requests(&self) {
305 let mut guard = self.inflight_requests.lock();
306 self.no_inflight_requests_condvar.wait_while(&mut guard, |inflight| inflight.count > 0);
307 }
308
309 fn complete_unsubmitted_request(&self, request_id: RequestId, status: Result<(), zx::Status>) {
312 if let Some((session, response)) =
313 self.active_requests.complete_and_take_response(request_id, status)
314 {
315 session.send_response(response);
316 }
317 }
318
319 pub fn terminate(&self) {
321 {
322 #[allow(clippy::collection_is_never_read)]
325 let mut terminated_sessions = Vec::new();
326 for (_, session) in &self.inner.lock().open_sessions {
327 if let Some(session) = session.upgrade() {
328 session.terminate_async();
329 terminated_sessions.push(session);
330 }
331 }
332 }
333 let mut guard = self.inner.lock();
334 self.no_open_sessions_condvar.wait_while(&mut guard, |s| !s.open_sessions.is_empty());
335 }
336}
337
338pub struct Session<I: Interface + ?Sized> {
339 helper: SessionHelper<SessionManager<I>>,
340 fifo: zx::Fifo<BlockFifoRequest, BlockFifoResponse>,
341 queue: Mutex<SessionQueue>,
342 abort_handle: AbortHandle,
343 close_callback: Mutex<Option<Box<dyn FnOnce() + Send + 'static>>>,
344}
345
346#[derive(Default)]
347struct SessionQueue {
348 responses: VecDeque<BlockFifoResponse>,
349}
350
351pub const MAX_REQUESTS: usize = super::FIFO_MAX_REQUESTS;
352
353struct DecodedRequests {
354 requests: [MaybeUninit<Request>; MAX_REQUESTS],
355 count: usize,
356}
357
358impl Default for DecodedRequests {
359 fn default() -> Self {
360 Self { requests: [const { MaybeUninit::uninit() }; MAX_REQUESTS], count: 0 }
361 }
362}
363
364impl DecodedRequests {
365 fn push(&mut self, request: Request) {
366 assert!(self.count < MAX_REQUESTS);
367 self.requests[self.count].write(request);
370 self.count += 1;
371 }
372
373 fn is_empty(&self) -> bool {
374 self.count == 0
375 }
376
377 fn is_full(&self) -> bool {
378 self.count == MAX_REQUESTS
379 }
380
381 fn clear(&mut self) {
382 for i in 0..self.count {
383 unsafe { self.requests[i].assume_init_drop() };
385 }
386 self.count = 0;
387 }
388}
389
390impl Drop for DecodedRequests {
391 fn drop(&mut self) {
392 self.clear();
393 }
394}
395
396impl std::ops::Deref for DecodedRequests {
397 type Target = [Request];
398
399 fn deref(&self) -> &Self::Target {
400 unsafe { std::slice::from_raw_parts(self.requests[0].as_ptr(), self.count) }
402 }
403}
404
405impl std::ops::DerefMut for DecodedRequests {
406 fn deref_mut(&mut self) -> &mut Self::Target {
407 unsafe { std::slice::from_raw_parts_mut(self.requests[0].as_mut_ptr(), self.count) }
409 }
410}
411
412impl<I: Interface + ?Sized> Session<I> {
413 pub fn run(self: &Arc<Self>) {
416 self.fifo_loop();
417 self.abort_handle.abort();
418 self.helper.close_active_groups(|s| Arc::ptr_eq(s, self));
422 }
423
424 fn fifo_loop(self: &Arc<Self>) {
425 let mut requests = [MaybeUninit::uninit(); MAX_REQUESTS];
426
427 loop {
428 let is_queue_empty = {
430 let mut queue = self.queue.lock();
431 while !queue.responses.is_empty() {
432 let (front, _) = queue.responses.as_slices();
433 match self.fifo.write(front) {
434 Ok(count) => {
435 let full = count.get() < front.len();
436 queue.responses.drain(..count.get());
437 if full {
438 break;
439 }
440 }
441 Err(zx::Status::SHOULD_WAIT) => break,
442 Err(_) => return,
443 }
444 }
445 queue.responses.is_empty()
446 };
447
448 match self.fifo.read_uninit(&mut requests) {
450 Ok(valid_requests) => self.handle_requests(valid_requests.iter_mut()),
451 Err(zx::Status::SHOULD_WAIT) => {
452 let mut signals =
453 zx::Signals::OBJECT_READABLE | SHUTDOWN_SIGNAL | FIFO_WAKE_SIGNAL;
454 if !is_queue_empty {
455 signals |= zx::Signals::OBJECT_WRITABLE;
456 }
457 let Ok(signals) =
458 self.fifo.wait_one(signals, zx::MonotonicInstant::INFINITE).to_result()
459 else {
460 return;
461 };
462 if signals.contains(SHUTDOWN_SIGNAL) {
463 return;
464 }
465 if signals.contains(FIFO_WAKE_SIGNAL) {
467 let _ = self.fifo.signal(FIFO_WAKE_SIGNAL, zx::Signals::empty());
468 }
469 }
470 Err(_) => return,
471 }
472 }
473 }
474
475 fn pre_flush(self: &Arc<Self>, request_id: RequestId) -> Result<(), zx::Status> {
477 let trace_flow_id = {
478 let mut request = self.helper.session_manager().active_requests.request(request_id);
479 if let Some(id) = request.trace_flow_id {
480 fuchsia_trace::async_instant!(
481 fuchsia_trace::Id::from(id.get()),
482 c"storage",
483 c"block_server::SimulatedBarrier",
484 "request_id" => request_id.0
485 );
486 }
487 request.count += 1;
488 request.trace_flow_id
489 };
490 self.helper.session_manager().submit_requests(&[Request {
491 request_id,
492 operation: Operation::Flush,
493 trace_flow_id,
494 vmo: None,
495 }]);
496 self.helper.session_manager().wait_for_no_inflight_requests();
497 let status = self.helper.session_manager().active_requests.request(request_id).status;
498 match status {
499 Ok(()) => Ok(()),
500 Err(status) => {
501 self.helper.session_manager().complete_unsubmitted_request(request_id, Err(status));
503 Err(status)
504 }
505 }
506 }
507
508 fn post_flush(self: &Arc<Self>, request_id: RequestId, decoded_requests: &mut DecodedRequests) {
511 if !decoded_requests.is_empty() {
512 self.helper.session_manager().submit_requests(decoded_requests);
513 decoded_requests.clear();
514 }
515 self.helper.session_manager().wait_for_no_inflight_requests();
516 let request = self.helper.session_manager().active_requests.request(request_id);
517 match request.status {
518 Ok(()) => decoded_requests.push(Request {
519 request_id,
520 operation: Operation::Flush,
521 trace_flow_id: request.trace_flow_id,
522 vmo: None,
523 }),
524 Err(status) => {
525 drop(request);
526 self.helper.session_manager().complete_unsubmitted_request(request_id, Err(status))
527 }
528 }
529 }
530
531 fn handle_requests<'a>(
532 self: &Arc<Self>,
533 requests: impl Iterator<Item = &'a mut BlockFifoRequest>,
534 ) {
535 let manager = &self.helper.session_manager();
536 let mut decoded_requests = DecodedRequests::default();
537
538 for request in requests {
539 match self.helper.decode_fifo_request(self.clone(), request) {
540 Ok(DecodedRequest { operation: Operation::CloseVmo, request_id, .. }) => {
541 manager.complete_unsubmitted_request(request_id, Ok(()));
542 }
543 Ok(mut request) => {
544 let request_id = request.request_id;
545
546 if !manager
549 .interface
550 .get_info()
551 .device_flags()
552 .contains(fblock::DeviceFlag::BARRIER_SUPPORT)
553 && request.operation.take_write_flag(WriteFlags::PRE_BARRIER)
554 && self.pre_flush(request_id).is_err()
555 {
556 continue;
557 }
558 let simulate_fua = !manager
561 .interface
562 .get_info()
563 .device_flags()
564 .contains(fblock::DeviceFlag::FUA_SUPPORT)
565 && request.operation.take_write_flag(WriteFlags::FORCE_ACCESS);
566
567 if simulate_fua {
568 manager.active_requests.request(request_id).count += 1;
570 }
571
572 loop {
573 let result = self
574 .helper
575 .map_request(request, &mut manager.active_requests.request(request_id));
576 match result {
577 Ok((
578 DecodedRequest { request_id, operation, vmo, trace_flow_id },
579 remainder,
580 )) => {
581 decoded_requests.push(Request {
582 request_id,
583 operation,
584 trace_flow_id,
585 vmo,
586 });
587
588 if decoded_requests.is_full() {
589 manager.submit_requests(&*decoded_requests);
590 decoded_requests.clear();
591 }
592
593 if let Some(r) = remainder {
594 request = r;
595 } else {
596 break;
597 }
598 }
599 Err(status) => {
600 manager.complete_unsubmitted_request(request_id, Err(status));
601 break;
602 }
603 }
604 }
605
606 if simulate_fua {
607 self.post_flush(request_id, &mut decoded_requests);
608 }
609 }
610 Err(None) => {}
611 Err(Some(response)) => self.send_response(response),
612 }
613 }
614
615 if !decoded_requests.is_empty() {
616 manager.submit_requests(&decoded_requests);
617 }
618 }
619
620 fn send_response(&self, response: BlockFifoResponse) {
621 let mut queue = self.queue.lock();
622 if queue.responses.is_empty() {
623 match self.fifo.write_one(&response) {
624 Ok(()) => {
625 return;
626 }
627 Err(_) => {
628 let _ = self.fifo.signal(zx::Signals::empty(), FIFO_WAKE_SIGNAL);
630 }
631 }
632 }
633 queue.responses.push_back(response);
634 }
635
636 pub fn terminate_async(&self) {
639 let _ = self.fifo.signal(zx::Signals::empty(), SHUTDOWN_SIGNAL);
640 self.abort_handle.abort();
641 }
642}
643
644impl<I: Interface + ?Sized> Drop for Session<I> {
645 fn drop(&mut self) {
646 let callback = std::mem::take(&mut *self.close_callback.lock());
647 if let Some(callback) = callback {
648 callback();
649 }
650 let notify = {
651 let mut inner = self.helper.session_manager().inner.lock();
652 inner.open_sessions.remove(&(self as *const _ as usize));
653 inner.open_sessions.is_empty()
654 };
655 if notify {
656 self.helper.session_manager().no_open_sessions_condvar.notify_all();
657 }
658 }
659}
660
661impl<I: Interface + ?Sized> Drop for SessionManager<I> {
662 fn drop(&mut self) {
663 self.terminate();
664 }
665}
666
667impl<I: Interface<Orchestrator = SessionManager<I>>> IntoOrchestrator for Arc<SessionManager<I>> {
668 type SM = SessionManager<I>;
669
670 fn into_orchestrator(self) -> Arc<I::Orchestrator> {
671 self
672 }
673}
674
675#[cfg(test)]
676mod tests {
677 use super::*;
678 use crate::testing::MockInterface;
679 use block_protocol::{BlockFifoCommand, BlockFifoRequest, BlockFifoResponse};
680 use fidl::endpoints::create_proxy_and_stream;
681 use fidl_fuchsia_storage_block as fblock;
682 use fuchsia_async as fasync;
683
684 const BLOCK_SIZE: u32 = 512;
685
686 #[fuchsia::test]
687 async fn test_basic_request() {
688 let (tx, rx) = std::sync::mpsc::channel();
689 let interface = Arc::new(MockInterface::new(tx));
690 let session_manager = Arc::new(SessionManager::new(interface.clone(), BLOCK_SIZE));
691
692 let sm_clone = session_manager.clone();
693 let (proxy, stream) = create_proxy_and_stream::<fblock::BlockMarker>();
694 let _server_task = fasync::Task::spawn(async move {
695 let server = crate::BlockServer::new(BLOCK_SIZE, sm_clone);
696 server.handle_requests(stream).await.unwrap();
697 })
698 .detach();
699
700 let (session_proxy, session_server_end) =
701 fidl::endpoints::create_proxy::<fblock::SessionMarker>();
702 proxy.open_session(session_server_end).unwrap();
703
704 let fifo_handle = session_proxy.get_fifo().await.unwrap().unwrap();
705 let fifo: zx::Fifo<BlockFifoResponse, BlockFifoRequest> = zx::Fifo::from(fifo_handle);
706
707 let vmo = zx::Vmo::create(8192).unwrap();
708 let vmo_id = session_proxy
709 .attach_vmo(vmo.duplicate_handle(zx::Rights::SAME_RIGHTS).unwrap())
710 .await
711 .unwrap()
712 .unwrap();
713
714 let req = BlockFifoRequest {
715 command: BlockFifoCommand {
716 opcode: fblock::BlockOpcode::Read.into_primitive(),
717 ..Default::default()
718 },
719 reqid: 123,
720 group: 0,
721 vmoid: vmo_id.id,
722 length: 1,
723 vmo_offset: 0,
724 dev_offset: 0,
725 trace_flow_id: 0,
726 ..Default::default()
727 };
728 fifo.write(&[req]).unwrap();
729
730 let r = rx.recv().unwrap();
731 assert_eq!(r.request_id.0, 0);
732 assert!(matches!(r.operation, Operation::Read { .. }));
733
734 session_manager.complete_request(r.request_id, Ok(()));
735
736 let signals =
737 fifo.wait_one(zx::Signals::FIFO_READABLE, zx::MonotonicInstant::INFINITE).unwrap();
738 assert!(signals.contains(zx::Signals::FIFO_READABLE));
739
740 let mut resp = [BlockFifoResponse::default()];
741 fifo.read(&mut resp).unwrap();
742 assert_eq!(resp[0].reqid, 123);
743 assert_eq!(resp[0].status, zx::sys::ZX_OK);
744
745 std::mem::drop(proxy);
746 }
747 #[fuchsia::test]
748 async fn test_write_request() {
749 let (tx, rx) = std::sync::mpsc::channel();
750 let interface = Arc::new(MockInterface::new(tx));
751 let session_manager = Arc::new(SessionManager::new(interface.clone(), BLOCK_SIZE));
752
753 let sm_clone = session_manager.clone();
754 let (proxy, stream) = create_proxy_and_stream::<fblock::BlockMarker>();
755 let _server_task = fasync::Task::spawn(async move {
756 let server = crate::BlockServer::new(BLOCK_SIZE, sm_clone);
757 server.handle_requests(stream).await.unwrap();
758 })
759 .detach();
760
761 let (session_proxy, session_server_end) =
762 fidl::endpoints::create_proxy::<fblock::SessionMarker>();
763 proxy.open_session(session_server_end).unwrap();
764
765 let fifo_handle = session_proxy.get_fifo().await.unwrap().unwrap();
766 let fifo: zx::Fifo<BlockFifoResponse, BlockFifoRequest> = zx::Fifo::from(fifo_handle);
767
768 let vmo = zx::Vmo::create(8192).unwrap();
769 let vmo_id = session_proxy
770 .attach_vmo(vmo.duplicate_handle(zx::Rights::SAME_RIGHTS).unwrap())
771 .await
772 .unwrap()
773 .unwrap();
774
775 let req = BlockFifoRequest {
776 command: BlockFifoCommand {
777 opcode: fblock::BlockOpcode::Write.into_primitive(),
778 ..Default::default()
779 },
780 reqid: 124,
781 group: 0,
782 vmoid: vmo_id.id,
783 length: 1,
784 vmo_offset: 0,
785 dev_offset: 0,
786 trace_flow_id: 0,
787 ..Default::default()
788 };
789 fifo.write(&[req]).unwrap();
790
791 let r = rx.recv().unwrap();
792 assert_eq!(r.request_id.0, 0);
793 assert!(matches!(r.operation, Operation::Write { .. }));
794
795 session_manager.complete_request(r.request_id, Ok(()));
796
797 let signals =
798 fifo.wait_one(zx::Signals::FIFO_READABLE, zx::MonotonicInstant::INFINITE).unwrap();
799 assert!(signals.contains(zx::Signals::FIFO_READABLE));
800
801 let mut resp = [BlockFifoResponse::default()];
802 fifo.read(&mut resp).unwrap();
803 assert_eq!(resp[0].reqid, 124);
804 assert_eq!(resp[0].status, zx::sys::ZX_OK);
805 }
806
807 #[fuchsia::test]
808 async fn test_flush_request() {
809 let (tx, rx) = std::sync::mpsc::channel();
810 let interface = Arc::new(MockInterface::new(tx));
811 let session_manager = Arc::new(SessionManager::new(interface.clone(), BLOCK_SIZE));
812
813 let sm_clone = session_manager.clone();
814 let (proxy, stream) = create_proxy_and_stream::<fblock::BlockMarker>();
815 let _server_task = fasync::Task::spawn(async move {
816 let server = crate::BlockServer::new(BLOCK_SIZE, sm_clone);
817 server.handle_requests(stream).await.unwrap();
818 })
819 .detach();
820
821 let (session_proxy, session_server_end) =
822 fidl::endpoints::create_proxy::<fblock::SessionMarker>();
823 proxy.open_session(session_server_end).unwrap();
824
825 let fifo_handle = session_proxy.get_fifo().await.unwrap().unwrap();
826 let fifo: zx::Fifo<BlockFifoResponse, BlockFifoRequest> = zx::Fifo::from(fifo_handle);
827
828 let req = BlockFifoRequest {
829 command: BlockFifoCommand {
830 opcode: fblock::BlockOpcode::Flush.into_primitive(),
831 ..Default::default()
832 },
833 reqid: 125,
834 group: 0,
835 vmoid: fblock::VMOID_INVALID,
836 length: 0,
837 vmo_offset: 0,
838 dev_offset: 0,
839 trace_flow_id: 0,
840 ..Default::default()
841 };
842 fifo.write(&[req]).unwrap();
843
844 let r = rx.recv().unwrap();
845 assert_eq!(r.request_id.0, 0);
846 assert!(matches!(r.operation, Operation::Flush { .. }));
847
848 session_manager.complete_request(r.request_id, Ok(()));
849
850 let signals =
851 fifo.wait_one(zx::Signals::FIFO_READABLE, zx::MonotonicInstant::INFINITE).unwrap();
852 assert!(signals.contains(zx::Signals::FIFO_READABLE));
853
854 let mut resp = [BlockFifoResponse::default()];
855 fifo.read(&mut resp).unwrap();
856 assert_eq!(resp[0].reqid, 125);
857 assert_eq!(resp[0].status, zx::sys::ZX_OK);
858 }
859
860 #[fuchsia::test]
861 async fn test_trim_request() {
862 let (tx, rx) = std::sync::mpsc::channel();
863 let interface = Arc::new(MockInterface::new(tx));
864 let session_manager = Arc::new(SessionManager::new(interface.clone(), BLOCK_SIZE));
865
866 let sm_clone = session_manager.clone();
867 let (proxy, stream) = create_proxy_and_stream::<fblock::BlockMarker>();
868 let _server_task = fasync::Task::spawn(async move {
869 let server = crate::BlockServer::new(BLOCK_SIZE, sm_clone);
870 server.handle_requests(stream).await.unwrap();
871 })
872 .detach();
873
874 let (session_proxy, session_server_end) =
875 fidl::endpoints::create_proxy::<fblock::SessionMarker>();
876 proxy.open_session(session_server_end).unwrap();
877
878 let fifo_handle = session_proxy.get_fifo().await.unwrap().unwrap();
879 let fifo: zx::Fifo<BlockFifoResponse, BlockFifoRequest> = zx::Fifo::from(fifo_handle);
880
881 let req = BlockFifoRequest {
882 command: BlockFifoCommand {
883 opcode: fblock::BlockOpcode::Trim.into_primitive(),
884 ..Default::default()
885 },
886 reqid: 126,
887 group: 0,
888 vmoid: fblock::VMOID_INVALID,
889 length: 1,
890 vmo_offset: 0,
891 dev_offset: 0,
892 trace_flow_id: 0,
893 ..Default::default()
894 };
895 fifo.write(&[req]).unwrap();
896
897 let r = rx.recv().unwrap();
898 assert_eq!(r.request_id.0, 0);
899 assert!(matches!(r.operation, Operation::Trim { .. }));
900
901 session_manager.complete_request(r.request_id, Ok(()));
902
903 let signals =
904 fifo.wait_one(zx::Signals::FIFO_READABLE, zx::MonotonicInstant::INFINITE).unwrap();
905 assert!(signals.contains(zx::Signals::FIFO_READABLE));
906
907 let mut resp = [BlockFifoResponse::default()];
908 fifo.read(&mut resp).unwrap();
909 assert_eq!(resp[0].reqid, 126);
910 assert_eq!(resp[0].status, zx::sys::ZX_OK);
911 }
912
913 #[fuchsia::test]
914 async fn test_close_vmo() {
915 let (tx, rx) = std::sync::mpsc::channel();
916 let interface = Arc::new(MockInterface::new(tx));
917 let session_manager = Arc::new(SessionManager::new(interface.clone(), BLOCK_SIZE));
918
919 let sm_clone = session_manager.clone();
920 let (proxy, stream) = create_proxy_and_stream::<fblock::BlockMarker>();
921 let _server_task = fasync::Task::spawn(async move {
922 let server = crate::BlockServer::new(BLOCK_SIZE, sm_clone);
923 server.handle_requests(stream).await.unwrap();
924 })
925 .detach();
926
927 let (session_proxy, session_server_end) =
928 fidl::endpoints::create_proxy::<fblock::SessionMarker>();
929 proxy.open_session(session_server_end).unwrap();
930
931 let fifo_handle = session_proxy.get_fifo().await.unwrap().unwrap();
932 let fifo: zx::Fifo<BlockFifoResponse, BlockFifoRequest> = zx::Fifo::from(fifo_handle);
933
934 let vmo = zx::Vmo::create(8192).unwrap();
935 let vmo_id = session_proxy
936 .attach_vmo(vmo.duplicate_handle(zx::Rights::SAME_RIGHTS).unwrap())
937 .await
938 .unwrap()
939 .unwrap();
940
941 let req = BlockFifoRequest {
942 command: BlockFifoCommand {
943 opcode: fblock::BlockOpcode::CloseVmo.into_primitive(),
944 ..Default::default()
945 },
946 reqid: 127,
947 group: 0,
948 vmoid: vmo_id.id,
949 length: 0,
950 vmo_offset: 0,
951 dev_offset: 0,
952 trace_flow_id: 0,
953 ..Default::default()
954 };
955 fifo.write(&[req]).unwrap();
956
957 let signals =
958 fifo.wait_one(zx::Signals::FIFO_READABLE, zx::MonotonicInstant::INFINITE).unwrap();
959 assert!(signals.contains(zx::Signals::FIFO_READABLE));
960
961 let mut resp = [BlockFifoResponse::default()];
962 fifo.read(&mut resp).unwrap();
963 assert_eq!(resp[0].reqid, 127);
964 assert_eq!(resp[0].status, zx::sys::ZX_OK);
965
966 assert!(rx.try_recv().is_err());
968 }
969
970 #[fuchsia::test]
971 async fn test_error() {
972 let (tx, rx) = std::sync::mpsc::channel();
973 let interface = Arc::new(MockInterface::new(tx));
974 let session_manager = Arc::new(SessionManager::new(interface.clone(), BLOCK_SIZE));
975
976 let sm_clone = session_manager.clone();
977 let (proxy, stream) = create_proxy_and_stream::<fblock::BlockMarker>();
978 let _server_task = fasync::Task::spawn(async move {
979 let server = crate::BlockServer::new(BLOCK_SIZE, sm_clone);
980 server.handle_requests(stream).await.unwrap();
981 })
982 .detach();
983
984 let (session_proxy, session_server_end) =
985 fidl::endpoints::create_proxy::<fblock::SessionMarker>();
986 proxy.open_session(session_server_end).unwrap();
987
988 let fifo_handle = session_proxy.get_fifo().await.unwrap().unwrap();
989 let fifo: zx::Fifo<BlockFifoResponse, BlockFifoRequest> = zx::Fifo::from(fifo_handle);
990
991 let req = BlockFifoRequest {
992 command: BlockFifoCommand {
993 opcode: fblock::BlockOpcode::Flush.into_primitive(),
994 ..Default::default()
995 },
996 reqid: 128,
997 group: 0,
998 vmoid: fblock::VMOID_INVALID,
999 length: 0,
1000 vmo_offset: 0,
1001 dev_offset: 0,
1002 trace_flow_id: 0,
1003 ..Default::default()
1004 };
1005 fifo.write(&[req]).unwrap();
1006
1007 let r = rx.recv().unwrap();
1008 session_manager.complete_request(r.request_id, Err(zx::Status::IO));
1009
1010 let signals =
1011 fifo.wait_one(zx::Signals::FIFO_READABLE, zx::MonotonicInstant::INFINITE).unwrap();
1012 assert!(signals.contains(zx::Signals::FIFO_READABLE));
1013
1014 let mut resp = [BlockFifoResponse::default()];
1015 fifo.read(&mut resp).unwrap();
1016 assert_eq!(resp[0].reqid, 128);
1017 assert_eq!(resp[0].status, zx::sys::ZX_ERR_IO);
1018 }
1019
1020 #[fuchsia::test]
1021 async fn test_teardown_with_active_requests() {
1022 let (tx, rx) = std::sync::mpsc::channel();
1023 let interface = Arc::new(MockInterface::new(tx));
1024 let session_manager = Arc::new(SessionManager::new(interface.clone(), BLOCK_SIZE));
1025
1026 let sm_clone = session_manager.clone();
1027 let (proxy, stream) = create_proxy_and_stream::<fblock::BlockMarker>();
1028 let server_task = fasync::Task::spawn(async move {
1029 let server = crate::BlockServer::new(BLOCK_SIZE, sm_clone);
1030 server.handle_requests(stream).await.unwrap();
1031 });
1032
1033 let (session_proxy, session_server_end) =
1034 fidl::endpoints::create_proxy::<fblock::SessionMarker>();
1035 proxy.open_session(session_server_end).unwrap();
1036
1037 let fifo_handle = session_proxy.get_fifo().await.unwrap().unwrap();
1038 let fifo: zx::Fifo<BlockFifoResponse, BlockFifoRequest> = zx::Fifo::from(fifo_handle);
1039
1040 let vmo = zx::Vmo::create(8192).unwrap();
1041 let vmo_id = session_proxy
1042 .attach_vmo(vmo.duplicate_handle(zx::Rights::SAME_RIGHTS).unwrap())
1043 .await
1044 .unwrap()
1045 .unwrap();
1046
1047 let req = BlockFifoRequest {
1048 command: BlockFifoCommand {
1049 opcode: fblock::BlockOpcode::Read.into_primitive(),
1050 ..Default::default()
1051 },
1052 reqid: 129,
1053 group: 0,
1054 vmoid: vmo_id.id,
1055 length: 1,
1056 vmo_offset: 0,
1057 dev_offset: 0,
1058 trace_flow_id: 0,
1059 ..Default::default()
1060 };
1061 fifo.write(&[req]).unwrap();
1063 let r = rx.recv().unwrap();
1064
1065 drop(session_proxy);
1067 fasync::Timer::new(std::time::Duration::from_millis(50)).await;
1068
1069 session_manager.complete_request(r.request_id, Ok(()));
1071
1072 drop(proxy);
1073 fasync::unblock(move || session_manager.terminate()).await;
1074 server_task.await;
1075 }
1076
1077 #[fuchsia::test]
1078 async fn test_teardown_with_active_grouped_requests() {
1079 let (tx, rx) = std::sync::mpsc::channel();
1080 let interface = Arc::new(MockInterface::new(tx));
1081 let session_manager = Arc::new(SessionManager::new(interface.clone(), BLOCK_SIZE));
1082
1083 let sm_clone = session_manager.clone();
1084 let (proxy, stream) = create_proxy_and_stream::<fblock::BlockMarker>();
1085 let server_task = fasync::Task::spawn(async move {
1086 let server = crate::BlockServer::new(BLOCK_SIZE, sm_clone);
1087 server.handle_requests(stream).await.unwrap();
1088 });
1089
1090 let (session_proxy, session_server_end) =
1091 fidl::endpoints::create_proxy::<fblock::SessionMarker>();
1092 proxy.open_session(session_server_end).unwrap();
1093
1094 let fifo_handle = session_proxy.get_fifo().await.unwrap().unwrap();
1095 let fifo: zx::Fifo<BlockFifoResponse, BlockFifoRequest> = zx::Fifo::from(fifo_handle);
1096
1097 let vmo = zx::Vmo::create(8192).unwrap();
1098 let vmo_id = session_proxy
1099 .attach_vmo(vmo.duplicate_handle(zx::Rights::SAME_RIGHTS).unwrap())
1100 .await
1101 .unwrap()
1102 .unwrap();
1103
1104 let mut req = BlockFifoRequest {
1105 command: BlockFifoCommand {
1106 opcode: fblock::BlockOpcode::Read.into_primitive(),
1107 flags: fblock::BlockIoFlag::GROUP_ITEM.bits(),
1108 ..Default::default()
1109 },
1110 reqid: 1,
1111 group: 1,
1112 vmoid: vmo_id.id,
1113 length: 1,
1114 vmo_offset: 0,
1115 dev_offset: 0,
1116 trace_flow_id: 0,
1117 ..Default::default()
1118 };
1119
1120 fifo.write(&[req]).unwrap();
1122 req.reqid = 2;
1123 req.group = 2;
1124 fifo.write(&[req]).unwrap();
1125 let r1 = rx.recv().unwrap();
1126 let r2 = rx.recv().unwrap();
1127 req.reqid = 3;
1128 req.group = 2;
1129 fifo.write(&[req]).unwrap();
1130 let r3 = rx.recv().unwrap();
1131
1132 session_manager.complete_request(r1.request_id, Ok(()));
1137 session_manager.complete_request(r2.request_id, Ok(()));
1138
1139 drop(session_proxy);
1142 fasync::Timer::new(std::time::Duration::from_millis(50)).await;
1143
1144 session_manager.complete_request(r3.request_id, Ok(()));
1146
1147 drop(proxy);
1148
1149 fasync::unblock(move || session_manager.terminate()).await;
1150 server_task.await;
1151 }
1152
1153 #[fuchsia::test]
1154 async fn test_session_close_is_synchronous() {
1155 use futures::FutureExt as _;
1156
1157 let (tx, rx) = std::sync::mpsc::channel();
1158 let interface = Arc::new(MockInterface::new(tx));
1159 let session_manager = Arc::new(SessionManager::new(interface.clone(), BLOCK_SIZE));
1160
1161 let sm_clone = session_manager.clone();
1162 let (proxy, stream) = create_proxy_and_stream::<fblock::BlockMarker>();
1163 let server_task = fasync::Task::spawn(async move {
1164 let server = crate::BlockServer::new(BLOCK_SIZE, sm_clone);
1165 server.handle_requests(stream).await.unwrap();
1166 });
1167
1168 let (session_proxy, session_server_end) =
1169 fidl::endpoints::create_proxy::<fblock::SessionMarker>();
1170 proxy.open_session(session_server_end).unwrap();
1171
1172 let fifo_handle = session_proxy.get_fifo().await.unwrap().unwrap();
1173 let fifo: zx::Fifo<BlockFifoResponse, BlockFifoRequest> = zx::Fifo::from(fifo_handle);
1174
1175 let vmo = zx::Vmo::create(8192).unwrap();
1176 let vmo_id = session_proxy
1177 .attach_vmo(vmo.duplicate_handle(zx::Rights::SAME_RIGHTS).unwrap())
1178 .await
1179 .unwrap()
1180 .unwrap();
1181
1182 let req = BlockFifoRequest {
1183 command: BlockFifoCommand {
1184 opcode: fblock::BlockOpcode::Read.into_primitive(),
1185 ..Default::default()
1186 },
1187 reqid: 123,
1188 group: 0,
1189 vmoid: vmo_id.id,
1190 length: 1,
1191 vmo_offset: 0,
1192 dev_offset: 0,
1193 trace_flow_id: 0,
1194 ..Default::default()
1195 };
1196 fifo.write(&[req]).unwrap();
1197
1198 let r = rx.recv().unwrap();
1199
1200 let mut close_fut = std::pin::pin!(session_proxy.close().fuse());
1202 let mut timer_fut =
1203 std::pin::pin!(fasync::Timer::new(std::time::Duration::from_millis(100)).fuse());
1204 futures::select! {
1205 res = close_fut => panic!("close completed too early: {res:?}"),
1206 _ = timer_fut => {}
1207 }
1208
1209 session_manager.complete_request(r.request_id, Ok(()));
1210
1211 close_fut.await.unwrap().unwrap();
1213
1214 std::mem::drop(proxy);
1215 server_task.await;
1216 }
1217}