1use anyhow::{Context, Error};
6use async_trait::async_trait;
7use fidl_fuchsia_storage_block as fblock;
8use fuchsia_async as fasync;
9use futures::lock::Mutex as AsyncMutex;
10use fxfs::filesystem::LayerPager;
11use fxfs::object_handle::{LayerObject, ObjectHandle, ReadObjectHandle};
12use fxfs::object_store::{DataObjectHandle, FileExtent, ObjectStore};
13use fxfs_crypto::UnwrappedKey;
14use mapping::{
15 Extent, Extents, MAPPING_VMO_SIZE, MappingCommand, PENDING_COMMANDS_CAPACITY, RawMappingCommand,
16};
17use std::sync::Arc;
18use std::sync::atomic::{AtomicBool, AtomicU64, Ordering};
19use storage_device::buffer::{BufferFuture, MutableBufferRef};
20use storage_units::BlockSize;
21use vmo_fifo::AsyncSender;
22use zx;
23
24struct MappedVmo {
25 vmo: zx::Vmo,
26 vaddr: usize,
27 len: usize,
28}
29
30impl MappedVmo {
31 fn new(vmo: zx::Vmo, len: usize) -> Result<Self, zx::Status> {
32 let page_size = zx::system_get_page_size() as usize;
33 let aligned_len = len.next_multiple_of(page_size);
34 let vaddr = if aligned_len > 0 {
35 fuchsia_runtime::vmar_root_self().map(
36 0,
37 &vmo,
38 0,
39 aligned_len,
40 zx::VmarFlags::PERM_READ,
41 )?
42 } else {
43 0
44 };
45 Ok(Self { vmo, vaddr, len })
46 }
47
48 fn as_slice(&self) -> &[u8] {
49 if self.vaddr == 0 || self.len == 0 {
50 &[]
51 } else {
52 unsafe { std::slice::from_raw_parts(self.vaddr as *const u8, self.len) }
58 }
59 }
60
61 fn has_io_error(&self) -> bool {
62 self.vmo
63 .wait_one(zx::Signals::USER_0, zx::MonotonicInstant::INFINITE_PAST)
64 .to_result()
65 .is_ok()
66 }
67
68 fn purge_cached_data(&self) {
69 if self.len > 0 {
70 let _ = self.vmo.op_range(zx::VmoOp::DONT_NEED, 0, self.len as u64);
73 }
74 }
75}
76
77impl Drop for MappedVmo {
78 fn drop(&mut self) {
79 if self.vaddr != 0 {
80 let page_size = zx::system_get_page_size() as usize;
81 let aligned_len = self.len.next_multiple_of(page_size);
82 unsafe {
84 let _ = fuchsia_runtime::vmar_root_self().unmap(self.vaddr, aligned_len);
85 }
86 }
87 }
88}
89
90struct PagedLayerObject {
91 handle: DataObjectHandle<ObjectStore>,
92 mapped: MappedVmo,
93 sender: Arc<AsyncMutex<AsyncSender<RawMappingCommand>>>,
94 scope: fasync::ScopeHandle,
95 key: u64,
96 closed: AtomicBool,
97}
98
99impl ObjectHandle for PagedLayerObject {
100 fn object_id(&self) -> u64 {
101 self.handle.object_id()
102 }
103
104 fn block_size(&self) -> BlockSize {
105 self.handle.block_size()
106 }
107
108 fn allocate_buffer(&self, size: usize) -> BufferFuture<'_> {
109 self.handle.allocate_buffer(size)
110 }
111
112 fn set_trace(&self, v: bool) {
113 self.handle.set_trace(v)
114 }
115}
116
117#[async_trait]
118impl ReadObjectHandle for PagedLayerObject {
119 async fn read_aligned(&self, offset: u64, buf: MutableBufferRef<'_>) -> Result<usize, Error> {
120 self.handle.read_aligned(offset, buf).await
121 }
122
123 fn get_size(&self) -> u64 {
124 self.handle.get_size()
125 }
126}
127
128#[async_trait]
129impl LayerObject for PagedLayerObject {
130 fn as_slice(&self) -> Option<&[u8]> {
131 Some(self.mapped.as_slice())
132 }
133
134 fn has_io_error(&self) -> bool {
135 self.mapped.has_io_error()
136 }
137
138 fn purge_cached_data(&self) {
139 self.mapped.purge_cached_data();
140 }
141
142 async fn close(&self) {
143 if !self.closed.swap(true, Ordering::Relaxed) {
144 let mut sender = self.sender.lock().await;
145 let _ = sender.push(MappingCommand::CloseBlob { key: self.key }.into()).await;
146 }
147 }
148}
149
150impl Drop for PagedLayerObject {
151 fn drop(&mut self) {
152 if !*self.closed.get_mut() {
155 let sender = self.sender.clone();
156 let key = self.key;
157 self.scope.spawn(async move {
158 let mut sender = sender.lock().await;
159 let _ = sender.push(MappingCommand::CloseBlob { key }.into()).await;
160 });
161 }
162 }
163}
164
165pub struct LayerPagerImpl {
167 mapper_session: fblock::MapperSessionProxy,
168 sender: Arc<AsyncMutex<AsyncSender<RawMappingCommand>>>,
169 scope: fasync::Scope,
170 next_key: AtomicU64,
171}
172
173impl LayerPagerImpl {
174 pub async fn new(mapper_proxy: &fblock::MapperProxy) -> Result<Self, Error> {
175 let mapping_vmo = zx::Vmo::create(MAPPING_VMO_SIZE)?;
176 let sender = AsyncSender::<RawMappingCommand>::new(
177 mapping_vmo.duplicate_handle(zx::Rights::SAME_RIGHTS)?,
178 8,
179 PENDING_COMMANDS_CAPACITY,
180 )?;
181
182 let (mapper_session, mapper_session_server) = fidl::endpoints::create_proxy();
183 mapper_proxy
184 .open_session(mapper_session_server, mapping_vmo, None, None)
185 .await
186 .context("FIDL error on Mapper.OpenSession")?
187 .map_err(zx::Status::err_from_raw)
188 .context("Failed to open mapper session")?;
189
190 Ok(Self {
191 mapper_session,
192 sender: Arc::new(AsyncMutex::new(sender)),
193 scope: fasync::Scope::new_with_name("layer_pager"),
194 next_key: AtomicU64::new(1),
195 })
196 }
197
198 async fn register_layer(
199 &self,
200 size: u64,
201 extents: &[FileExtent],
202 raw_key: Option<&[u8]>,
203 ) -> Result<(u64, zx::Vmo), Error> {
204 let key = self.next_key.fetch_add(1, Ordering::Relaxed);
205
206 let mut mapping_extents = Vec::with_capacity(extents.len());
207 let mut current_offset = 0u64;
208 for ext in extents {
209 if ext.logical_offset() > current_offset {
210 mapping_extents.push(Extent::try_new(current_offset..ext.logical_offset(), None)?);
211 }
212 mapping_extents
213 .push(Extent::try_new(ext.logical_range(), Some(ext.device_range().start))?);
214 current_offset = ext.logical_range().end;
215 }
216 let aligned_size = size.next_multiple_of(mapping::BLOCK_SIZE);
217 if current_offset < aligned_size {
218 mapping_extents.push(Extent::try_new(current_offset..aligned_size, None)?);
219 }
220 let data_extents = Extents::try_new(&mapping_extents, 0)?;
221 let extent_count = mapping_extents.len() as u32;
222 let encrypted = raw_key.is_some();
223 let key_bytes_len = if encrypted { 32 } else { 0 };
224 let allocation_size = (extent_count as usize * 8) + key_bytes_len;
225
226 if allocation_size > 0 {
227 let mut sender = self.sender.lock().await;
228 let mut payload = sender.reserve_payload(allocation_size).await?;
229 let offset_in_vmo = payload.offset();
230
231 let extent_bytes = extent_count as usize * 8;
232 for (mut chunk, val) in payload
233 .data()
234 .subslice_mut(0..extent_bytes)
235 .chunks_mut(8)
236 .zip(Extents::encode_extents(&data_extents))
237 {
238 chunk.copy_from_slice(&val.to_le_bytes());
239 }
240
241 if let Some(k) = raw_key {
242 payload.data().subslice_mut(extent_bytes..extent_bytes + 32).copy_from_slice(k);
243 }
244
245 let command = MappingCommand::Mappings {
246 key,
247 offset: offset_in_vmo as u32,
248 stored_size: size,
249 device_offset: 0,
250 metadata_count: 0,
251 extent_count,
252 encrypted,
253 };
254 payload.commit(command.into()).await?;
255 }
256
257 let vmo = self
258 .mapper_session
259 .create_vmo(key, size, fblock::CreateVmoOptions::SUPPLY_ZEROES_ON_ERROR)
260 .await
261 .context("FIDL error calling MapperSession.CreateVmo")?
262 .map_err(zx::Status::err_from_raw)
263 .context("MapperSession.CreateVmo returned error")?;
264
265 Ok((key, vmo))
266 }
267}
268
269#[async_trait]
270impl LayerPager for LayerPagerImpl {
271 async fn open_layer(
272 &self,
273 handle: DataObjectHandle<ObjectStore>,
274 unwrapped_key: Option<UnwrappedKey>,
275 ) -> Result<Arc<dyn LayerObject>, Error> {
276 let size = handle.get_size();
277 if size == 0 || handle.block_size() > BlockSize::SIZE_4KIB {
278 return Ok(Arc::new(handle) as Arc<dyn LayerObject>);
279 }
280 let extents = handle.device_extents().await?;
281 let (key, vmo) = self
282 .register_layer(size, &extents, unwrapped_key.as_deref().map(|k| k.as_slice()))
283 .await?;
284 drop(unwrapped_key);
285 let mapped = MappedVmo::new(vmo, size as usize).context("Failed to map layer VMO")?;
286 Ok(Arc::new(PagedLayerObject {
287 handle,
288 mapped,
289 sender: self.sender.clone(),
290 scope: self.scope.to_handle(),
291 key,
292 closed: AtomicBool::new(false),
293 }) as Arc<dyn LayerObject>)
294 }
295}
296
297#[cfg(test)]
298mod tests {
299 use super::*;
300
301 #[fuchsia::test]
302 fn test_mapped_vmo_io_error_signal() {
303 let vmo = zx::Vmo::create(4096).unwrap();
304 vmo.write(&[0x42u8; 4096], 0).unwrap();
305 let vmo_dup = vmo.duplicate_handle(zx::Rights::SAME_RIGHTS).unwrap();
306
307 let mapped = MappedVmo::new(vmo, 4096).unwrap();
308 assert_eq!(mapped.as_slice(), &[0x42u8; 4096]);
309 assert!(!mapped.has_io_error());
310
311 vmo_dup.signal(zx::Signals::empty(), zx::Signals::USER_0).unwrap();
312 assert!(mapped.has_io_error());
313 }
314}