Skip to main content

fuchsia_storage_benchmarks/filesystems/
pkgdir.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, Blobfs, CacheClearableFilesystem, Fxblob};
6use async_trait::async_trait;
7use fidl::endpoints::DiscoverableProtocolMarker;
8use fidl_fuchsia_fxfs::{BlobCreatorProxy, BlobReaderProxy};
9use fidl_fuchsia_io as fio;
10use fuchsia_component_test::{Capability, ChildOptions, RealmBuilder, RealmInstance, Ref, Route};
11use futures::future::FutureExt;
12use std::path::Path;
13use storage_benchmarks::{BlockDeviceFactory, Filesystem, FilesystemConfig};
14/// Config object for starting a `PkgDirInstance`. The `PkgDirInstance` allows blob benchmarks to
15/// open and read a blob through its package directory as opposed to talking directly to the
16/// filesystem.
17#[derive(Clone)]
18pub struct PkgDirTest {
19    use_fxblob: bool,
20}
21
22impl PkgDirTest {
23    pub fn new_fxblob() -> Self {
24        PkgDirTest { use_fxblob: true }
25    }
26
27    pub fn new_blobfs() -> Self {
28        PkgDirTest { use_fxblob: false }
29    }
30}
31
32#[async_trait]
33impl FilesystemConfig for PkgDirTest {
34    type Filesystem = PkgDirInstance;
35
36    async fn start_filesystem(
37        &self,
38        block_device_factory: &dyn BlockDeviceFactory,
39    ) -> PkgDirInstance {
40        let fs = if self.use_fxblob {
41            Box::new(Fxblob::new().start_filesystem(block_device_factory).await)
42                as Box<dyn BlobFilesystem>
43        } else {
44            Box::new(Blobfs.start_filesystem(block_device_factory).await) as Box<dyn BlobFilesystem>
45        };
46
47        let (clone, server_end) = fidl::endpoints::create_proxy::<fio::DirectoryMarker>();
48        fs.exposed_dir()
49            .clone(server_end.into_channel().into())
50            .expect("connect to blob volume exposed dir");
51        let realm = PkgDirRealm::new(self.use_fxblob, clone).await;
52        PkgDirInstance { fs, realm, use_fxblob: self.use_fxblob }
53    }
54
55    fn name(&self) -> String {
56        let fs = if self.use_fxblob { "fxblob" } else { "blobfs" };
57        format!("{}-pkgdir", fs)
58    }
59}
60
61pub struct PkgDirInstance {
62    fs: Box<dyn BlobFilesystem>,
63    realm: PkgDirRealm,
64    use_fxblob: bool,
65}
66
67impl PkgDirInstance {
68    pub fn pkgdir_proxy(&self) -> fidl_test_pkgdir::PkgDirProxy {
69        self.realm.realm().root.connect_to_protocol_at_exposed_dir().unwrap()
70    }
71}
72
73#[async_trait]
74impl Filesystem for PkgDirInstance {
75    async fn shutdown(self) {
76        self.fs.shutdown_boxed().await
77    }
78
79    fn benchmark_dir(&self) -> &Path {
80        self.fs.benchmark_dir()
81    }
82}
83
84#[async_trait]
85impl CacheClearableFilesystem for PkgDirInstance {
86    async fn clear_cache(&mut self) {
87        self.fs.clear_cache().await;
88        let (clone, server_end) = fidl::endpoints::create_proxy::<fio::DirectoryMarker>();
89        self.fs
90            .exposed_dir()
91            .clone(server_end.into_channel().into())
92            .expect("connect to blob volume exposed dir");
93        self.realm = PkgDirRealm::new(self.use_fxblob, clone).await
94    }
95}
96
97#[async_trait]
98impl BlobFilesystem for PkgDirInstance {
99    fn blob_creator(&self) -> &BlobCreatorProxy {
100        self.fs.blob_creator()
101    }
102
103    fn blob_reader(&self) -> &BlobReaderProxy {
104        self.fs.blob_reader()
105    }
106
107    fn exposed_dir(&self) -> &fio::DirectoryProxy {
108        self.fs.exposed_dir()
109    }
110}
111
112pub struct PkgDirRealm {
113    pub realm: RealmInstance,
114}
115
116impl PkgDirRealm {
117    pub async fn new(fxblob: bool, exposed_dir: fio::DirectoryProxy) -> Self {
118        let builder = RealmBuilder::new().await.unwrap();
119        let pkgdir = builder
120            .add_child("pkgdir-component", "#meta/pkgdir-component.cm", ChildOptions::new())
121            .await
122            .unwrap();
123        builder.init_mutable_config_from_package(&pkgdir).await.unwrap();
124        let exposed_dir = vfs::pseudo_directory! {
125            "blob" => vfs::remote::remote_dir(exposed_dir),
126        };
127        let service_reflector = builder
128            .add_local_child(
129                "service_reflector",
130                move |handles| {
131                    let scope = vfs::execution_scope::ExecutionScope::new();
132                    vfs::directory::serve_on(
133                        exposed_dir.clone(),
134                        fio::PERM_READABLE,
135                        scope.clone(),
136                        handles.outgoing_dir,
137                    );
138                    async move {
139                        scope.wait().await;
140                        Ok(())
141                    }
142                    .boxed()
143                },
144                ChildOptions::new(),
145            )
146            .await
147            .unwrap();
148        builder
149            .add_route(
150                Route::new()
151                    .capability(Capability::protocol::<fidl_test_pkgdir::PkgDirMarker>())
152                    .from(&pkgdir)
153                    .to(Ref::parent()),
154            )
155            .await
156            .unwrap();
157        builder
158            .add_route(
159                Route::new()
160                    .capability(
161                        Capability::protocol::<fidl_fuchsia_tracing_provider::RegistryMarker>(),
162                    )
163                    .from(Ref::parent())
164                    .to(&pkgdir),
165            )
166            .await
167            .unwrap();
168        builder
169            .add_route(
170                Route::new()
171                    .capability(
172                        Capability::directory("blob-exec")
173                            .path("/blob/root")
174                            .rights(fio::R_STAR_DIR),
175                    )
176                    .from(&service_reflector)
177                    .to(&pkgdir),
178            )
179            .await
180            .unwrap();
181        let svc_path = if fxblob {
182            format!("/blob/svc/{}", fidl_fuchsia_fxfs::BlobReaderMarker::PROTOCOL_NAME)
183        } else {
184            format!("/blob/{}", fidl_fuchsia_fxfs::BlobReaderMarker::PROTOCOL_NAME)
185        };
186        builder
187            .add_route(
188                Route::new()
189                    .capability(
190                        Capability::protocol::<fidl_fuchsia_fxfs::BlobReaderMarker>()
191                            .path(svc_path),
192                    )
193                    .from(&service_reflector)
194                    .to(&pkgdir),
195            )
196            .await
197            .unwrap();
198        let realm = builder.build().await.expect("realm build failed");
199        Self { realm }
200    }
201
202    fn realm(&self) -> &RealmInstance {
203        &self.realm
204    }
205}