fuchsia_storage_benchmarks/filesystems/
fxblob.rs1use crate::filesystems::{BlobFilesystem, FsManagementFilesystemInstance};
6use async_trait::async_trait;
7use blob_pager_and_verifier::BlobPagerAndVerifier;
8use fidl_fuchsia_fxfs::{BlobCreatorMarker, BlobCreatorProxy, BlobReaderMarker, BlobReaderProxy};
9use fidl_fuchsia_io as fio;
10use fidl_fuchsia_storage_block as fblock;
11use fidl_fuchsia_storage_mapping as fmapping;
12use fuchsia_component::client::{connect_to_protocol_at_dir_root, connect_to_protocol_at_dir_svc};
13use fuchsia_merkle::Hash;
14use std::path::Path;
15use storage_benchmarks::{
16 BlockDeviceConfig, BlockDeviceFactory, CacheClearableFilesystem, Filesystem, FilesystemConfig,
17};
18
19#[derive(Clone, Default)]
21pub struct Fxblob {
22 use_driver_blob_paging: bool,
23}
24
25impl Fxblob {
26 pub fn new() -> Self {
27 Self { use_driver_blob_paging: false }
28 }
29
30 pub fn with_driver_paging() -> Self {
31 Self { use_driver_blob_paging: true }
32 }
33}
34
35#[async_trait]
36impl FilesystemConfig for Fxblob {
37 type Filesystem = FxblobInstance;
38
39 async fn start_filesystem(
40 &self,
41 block_device_factory: &dyn BlockDeviceFactory,
42 ) -> FxblobInstance {
43 let block_device = block_device_factory
44 .create_block_device(&BlockDeviceConfig {
45 requires_fvm: false,
46 use_zxcrypt: false,
47 volume_size: Some(104 * 1024 * 1024),
48 })
49 .await;
50 let fxblob = FsManagementFilesystemInstance::new(
51 || fs_management::Fxfs { allow_type3_blobs: true, ..Default::default() },
52 block_device,
53 None,
54 true,
55 )
56 .await;
57 let blob_creator =
58 connect_to_protocol_at_dir_svc::<BlobCreatorMarker>(fxblob.exposed_dir())
59 .expect("failed to connect to the BlobCreator protocol");
60 let blob_reader = connect_to_protocol_at_dir_svc::<BlobReaderMarker>(fxblob.exposed_dir())
61 .expect("failed to connect to the BlobReader protocol");
62 let pager_and_verifier = if self.use_driver_blob_paging {
63 Some(FxblobInstance::create_pager_and_verifier(&fxblob).await)
64 } else {
65 None
66 };
67 FxblobInstance { blob_creator, blob_reader, pager_and_verifier, fxblob }
68 }
69
70 fn name(&self) -> String {
71 if self.use_driver_blob_paging { "fxblob_driver".to_owned() } else { "fxblob".to_owned() }
72 }
73}
74
75pub struct FxblobInstance {
76 blob_creator: BlobCreatorProxy,
77 blob_reader: BlobReaderProxy,
78 pager_and_verifier: Option<BlobPagerAndVerifier>,
79 fxblob: FsManagementFilesystemInstance,
80}
81
82pub struct ErofsMount {
83 root_dir: fio::DirectoryProxy,
84 _parent_vmo: zx::Vmo,
85 shutdown_tx: Option<futures::channel::oneshot::Sender<()>>,
86 thread: Option<std::thread::JoinHandle<()>>,
87}
88
89impl ErofsMount {
90 pub fn root_dir(&self) -> &fio::DirectoryProxy {
91 &self.root_dir
92 }
93}
94
95impl Drop for ErofsMount {
96 fn drop(&mut self) {
97 if let Some(tx) = self.shutdown_tx.take() {
98 let _ = tx.send(());
99 }
100 if let Some(thread) = self.thread.take() {
101 let _ = thread.join();
102 }
103 }
104}
105
106impl FxblobInstance {
107 async fn create_pager_and_verifier(
108 fxblob: &FsManagementFilesystemInstance,
109 ) -> BlobPagerAndVerifier {
110 let mapping_provider =
111 connect_to_protocol_at_dir_svc::<fmapping::MappingProviderMarker>(fxblob.exposed_dir())
112 .expect("failed to connect to the MappingProvider protocol");
113 let block_proxy = fxblob
114 .block_device
115 .connector()
116 .connect_block()
117 .expect("failed to connect to block device")
118 .into_proxy();
119 let (mapper, mapper_server) = fidl::endpoints::create_proxy::<fblock::MapperMarker>();
120 block_proxy
121 .connect_mapper(mapper_server)
122 .await
123 .expect("FIDL error on ConnectMapper")
124 .expect("ConnectMapper failed");
125 BlobPagerAndVerifier::new(&mapping_provider, &mapper)
126 .await
127 .expect("failed to initialize BlobPagerAndVerifier")
128 }
129
130 pub fn connect_to_debug(&self) -> fidl_fuchsia_fxfs::DebugProxy {
131 connect_to_protocol_at_dir_root::<fidl_fuchsia_fxfs::DebugMarker>(
132 self.fxblob.exposed_services_dir(),
133 )
134 .expect("failed to connect to Debug protocol")
135 }
136
137 pub async fn mount_erofs(&self, blob_hash: &Hash, file_offset: u64) -> ErofsMount {
138 let parent_vmo = self.get_vmo(blob_hash).await;
139 let backing_vmo = if file_offset > 0 {
140 let vmo_size = parent_vmo.get_size().expect("failed to get parent VMO size");
141 parent_vmo
142 .create_child(zx::VmoChildOptions::SLICE, file_offset, vmo_size - file_offset)
143 .expect("failed to create child SLICE of parent VMO")
144 } else {
145 parent_vmo
146 .duplicate_handle(zx::Rights::SAME_RIGHTS)
147 .expect("failed to duplicate parent VMO")
148 };
149
150 let (root_dir, root_server) = fidl::endpoints::create_proxy::<fio::DirectoryMarker>();
151 let (shutdown_tx, shutdown_rx) = futures::channel::oneshot::channel::<()>();
152 let thread = std::thread::spawn(move || {
153 let mut executor = fuchsia_async::LocalExecutor::default();
154 executor.run_singlethreaded(async move {
155 let erofs_pager = std::sync::Arc::new(
156 erofs_component::ErofsPager::new().expect("failed to create ErofsPager"),
157 );
158 erofs_component::ErofsVolume::serve(
159 backing_vmo,
160 erofs_pager.clone(),
161 fio::PERM_READABLE,
162 root_server,
163 )
164 .expect("failed to serve ErofsVolume");
165 let _ = shutdown_rx.await;
166 erofs_pager.unregister_all();
167 });
168 });
169
170 ErofsMount {
171 root_dir,
172 _parent_vmo: parent_vmo,
173 shutdown_tx: Some(shutdown_tx),
174 thread: Some(thread),
175 }
176 }
177}
178
179#[async_trait]
180impl Filesystem for FxblobInstance {
181 async fn shutdown(self) {
182 drop(self.pager_and_verifier);
183 self.fxblob.shutdown().await
184 }
185
186 fn benchmark_dir(&self) -> &Path {
187 self.fxblob.benchmark_dir()
188 }
189}
190
191#[async_trait]
192impl CacheClearableFilesystem for FxblobInstance {
193 async fn clear_cache(&mut self) {
194 let use_driver_blob_paging = self.pager_and_verifier.take().is_some();
195 let () = self.fxblob.clear_cache().await;
196 self.blob_creator =
197 connect_to_protocol_at_dir_svc::<BlobCreatorMarker>(self.fxblob.exposed_dir())
198 .expect("failed to connect to the BlobCreator protocol");
199 self.blob_reader =
200 connect_to_protocol_at_dir_svc::<BlobReaderMarker>(self.fxblob.exposed_dir())
201 .expect("failed to connect to the BlobReader protocol");
202 if use_driver_blob_paging {
203 self.pager_and_verifier = Some(Self::create_pager_and_verifier(&self.fxblob).await);
204 }
205 }
206}
207
208#[async_trait]
209impl BlobFilesystem for FxblobInstance {
210 async fn get_vmo(&self, name: &Hash) -> zx::Vmo {
211 if let Some(pager) = &self.pager_and_verifier {
212 pager.create_vmo(&**name).await.expect("failed to get vmo from BlobPagerAndVerifier")
213 } else {
214 self.blob_reader()
215 .get_vmo(&*name)
216 .await
217 .expect("transport error on BlobReader.GetVmo")
218 .expect("failed to get vmo")
219 }
220 }
221
222 fn blob_creator(&self) -> &BlobCreatorProxy {
223 &self.blob_creator
224 }
225
226 fn blob_reader(&self) -> &BlobReaderProxy {
227 &self.blob_reader
228 }
229
230 fn exposed_dir(&self) -> &fio::DirectoryProxy {
231 self.fxblob.exposed_dir()
232 }
233}
234
235#[cfg(test)]
236mod tests {
237 use super::Fxblob;
238 use crate::filesystems::testing::check_blob_filesystem;
239
240 #[fuchsia::test]
241 async fn start_fxblob_new() {
242 check_blob_filesystem(Fxblob::new()).await;
243 }
244}