gpt_component/
partition.rs1use crate::gpt::GptPartition;
5use anyhow::Error;
6use block_client::{ReadOptions, VmoId, WriteOptions};
7use block_server::async_interface::{PassthroughSession, SessionManager};
8use block_server::{DeviceInfo, OffsetMap};
9use fidl_fuchsia_storage_block as fblock;
10use fuchsia_async as fasync;
11
12use fuchsia_sync::Mutex;
13use std::borrow::Cow;
14use std::collections::BTreeMap;
15use std::num::NonZero;
16use std::sync::{Arc, Weak};
17
18pub struct VmoIdWrapper {
21 partition: Weak<GptPartition>,
22 vmo_id: VmoId,
23}
24
25impl std::ops::Deref for VmoIdWrapper {
26 type Target = VmoId;
27 fn deref(&self) -> &Self::Target {
28 &self.vmo_id
29 }
30}
31
32impl Drop for VmoIdWrapper {
33 fn drop(&mut self) {
34 let vmo_id = self.vmo_id.take().into_id();
38 if let Some(partition) = self.partition.upgrade() {
39 fasync::Task::spawn(async move {
40 if let Err(e) = partition.detach_vmo(VmoId::new(vmo_id)).await {
41 log::error!("detach_vmo failed: {:?}", e);
42 }
43 })
44 .detach();
45 }
46 }
47}
48
49pub struct PartitionBackend {
52 partition: Arc<GptPartition>,
53 vmo_keys_to_vmoids_map: Mutex<BTreeMap<usize, Arc<VmoIdWrapper>>>,
54 passthrough: bool,
55}
56
57impl block_server::async_interface::Interface for PartitionBackend {
58 async fn open_session(
59 &self,
60 session_manager: Arc<SessionManager<Self>>,
61 stream: fblock::SessionRequestStream,
62 offset_map: OffsetMap,
63 block_size: u32,
64 ) -> Result<(), Error> {
65 if !self.passthrough || !offset_map.is_empty() {
66 return session_manager.serve_session(stream, offset_map, block_size).await;
69 }
70 let (proxy, server_end) = fidl::endpoints::create_proxy::<fblock::SessionMarker>();
71 self.partition.open_passthrough_session(server_end);
72 let passthrough = PassthroughSession::new(proxy);
73 passthrough.serve(stream).await
74 }
75
76 async fn on_attach_vmo(&self, vmo: &zx::Vmo) -> Result<(), zx::Status> {
77 let key = std::ptr::from_ref(vmo) as usize;
78 let vmo_id = unsafe { self.partition.attach_vmo(vmo) }.await?;
81 self.vmo_keys_to_vmoids_map.lock().insert(
82 key,
83 Arc::new(VmoIdWrapper { partition: Arc::downgrade(&self.partition), vmo_id }),
84 );
85 Ok(())
86 }
87
88 fn on_detach_vmo(&self, vmo: &zx::Vmo) {
89 let key = std::ptr::from_ref(vmo) as usize;
92 self.vmo_keys_to_vmoids_map.lock().remove(&key);
93 }
94
95 fn get_info(&self) -> Cow<'_, DeviceInfo> {
96 Cow::Owned(self.partition.get_info())
97 }
98
99 async fn read(
100 &self,
101 device_block_offset: u64,
102 block_count: u32,
103 vmo: &Arc<zx::Vmo>,
104 vmo_offset: u64, opts: ReadOptions,
106 trace_flow_id: Option<NonZero<u64>>,
107 ) -> Result<(), zx::Status> {
108 let vmo_id = self.get_vmoid(vmo)?;
109 self.partition
110 .read(device_block_offset, block_count, &vmo_id, vmo_offset, opts, trace_flow_id)
111 .await
112 }
113
114 async fn write(
115 &self,
116 device_block_offset: u64,
117 length: u32,
118 vmo: &Arc<zx::Vmo>,
119 vmo_offset: u64, opts: WriteOptions,
121 trace_flow_id: Option<NonZero<u64>>,
122 ) -> Result<(), zx::Status> {
123 let vmo_id = self.get_vmoid(vmo)?;
124 self.partition
125 .write(device_block_offset, length, &vmo_id, vmo_offset, opts, trace_flow_id)
126 .await
127 }
128
129 async fn flush(&self, trace_flow_id: Option<NonZero<u64>>) -> Result<(), zx::Status> {
130 self.partition.flush(trace_flow_id).await
131 }
132
133 async fn trim(
134 &self,
135 device_block_offset: u64,
136 block_count: u32,
137 trace_flow_id: Option<NonZero<u64>>,
138 ) -> Result<(), zx::Status> {
139 self.partition.trim(device_block_offset, block_count, trace_flow_id).await
140 }
141}
142
143impl PartitionBackend {
144 #[cfg(test)]
145 pub fn vmo_count(&self) -> usize {
146 self.vmo_keys_to_vmoids_map.lock().len()
147 }
148
149 pub fn new(partition: Arc<GptPartition>, passthrough: bool) -> Arc<Self> {
150 Arc::new(Self {
151 partition,
152 vmo_keys_to_vmoids_map: Mutex::new(BTreeMap::new()),
153 passthrough,
154 })
155 }
156
157 pub fn update_info(&self, info: gpt::PartitionInfo) -> gpt::PartitionInfo {
159 self.partition.update_info(info)
160 }
161
162 fn get_vmoid(&self, vmo: &zx::Vmo) -> Result<Arc<VmoIdWrapper>, zx::Status> {
163 let key = std::ptr::from_ref(vmo) as usize;
164 self.vmo_keys_to_vmoids_map.lock().get(&key).map(Arc::clone).ok_or(zx::Status::NOT_FOUND)
165 }
166}