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