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