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