Skip to main content

fuchsia_storage_benchmarks/filesystems/
fxblob.rs

1// Copyright 2023 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use 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/// Config object for starting Fxblob instances.
20#[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            /*as_blob=*/ 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}