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.start_filesystem(block_device_factory).await) as Box<dyn BlobFilesystem>
42        } else {
43            Box::new(Blobfs.start_filesystem(block_device_factory).await) as Box<dyn BlobFilesystem>
44        };
45
46        let (clone, server_end) = fidl::endpoints::create_proxy::<fio::DirectoryMarker>();
47        fs.exposed_dir()
48            .clone(server_end.into_channel().into())
49            .expect("connect to blob volume exposed dir");
50        let realm = PkgDirRealm::new(self.use_fxblob, clone).await;
51        PkgDirInstance { fs, realm, use_fxblob: self.use_fxblob }
52    }
53
54    fn name(&self) -> String {
55        let fs = if self.use_fxblob { "fxblob" } else { "blobfs" };
56        format!("{}-pkgdir", fs)
57    }
58}
59
60pub struct PkgDirInstance {
61    fs: Box<dyn BlobFilesystem>,
62    realm: PkgDirRealm,
63    use_fxblob: bool,
64}
65
66impl PkgDirInstance {
67    pub fn pkgdir_proxy(&self) -> fidl_test_pkgdir::PkgDirProxy {
68        self.realm.realm().root.connect_to_protocol_at_exposed_dir().unwrap()
69    }
70}
71
72#[async_trait]
73impl Filesystem for PkgDirInstance {
74    async fn shutdown(self) {
75        self.fs.shutdown_boxed().await
76    }
77
78    fn benchmark_dir(&self) -> &Path {
79        self.fs.benchmark_dir()
80    }
81}
82
83#[async_trait]
84impl CacheClearableFilesystem for PkgDirInstance {
85    async fn clear_cache(&mut self) {
86        self.fs.clear_cache().await;
87        let (clone, server_end) = fidl::endpoints::create_proxy::<fio::DirectoryMarker>();
88        self.fs
89            .exposed_dir()
90            .clone(server_end.into_channel().into())
91            .expect("connect to blob volume exposed dir");
92        self.realm = PkgDirRealm::new(self.use_fxblob, clone).await
93    }
94}
95
96#[async_trait]
97impl BlobFilesystem for PkgDirInstance {
98    fn blob_creator(&self) -> &BlobCreatorProxy {
99        self.fs.blob_creator()
100    }
101
102    fn blob_reader(&self) -> &BlobReaderProxy {
103        self.fs.blob_reader()
104    }
105
106    fn exposed_dir(&self) -> &fio::DirectoryProxy {
107        self.fs.exposed_dir()
108    }
109}
110
111pub struct PkgDirRealm {
112    pub realm: RealmInstance,
113}
114
115impl PkgDirRealm {
116    pub async fn new(fxblob: bool, exposed_dir: fio::DirectoryProxy) -> Self {
117        let builder = RealmBuilder::new().await.unwrap();
118        let pkgdir = builder
119            .add_child("pkgdir-component", "#meta/pkgdir-component.cm", ChildOptions::new())
120            .await
121            .unwrap();
122        builder.init_mutable_config_from_package(&pkgdir).await.unwrap();
123        let exposed_dir = vfs::pseudo_directory! {
124            "blob" => vfs::remote::remote_dir(exposed_dir),
125        };
126        let service_reflector = builder
127            .add_local_child(
128                "service_reflector",
129                move |handles| {
130                    let scope = vfs::execution_scope::ExecutionScope::new();
131                    vfs::directory::serve_on(
132                        exposed_dir.clone(),
133                        fio::PERM_READABLE,
134                        scope.clone(),
135                        handles.outgoing_dir,
136                    );
137                    async move {
138                        scope.wait().await;
139                        Ok(())
140                    }
141                    .boxed()
142                },
143                ChildOptions::new(),
144            )
145            .await
146            .unwrap();
147        builder
148            .add_route(
149                Route::new()
150                    .capability(Capability::protocol::<fidl_test_pkgdir::PkgDirMarker>())
151                    .from(&pkgdir)
152                    .to(Ref::parent()),
153            )
154            .await
155            .unwrap();
156        builder
157            .add_route(
158                Route::new()
159                    .capability(
160                        Capability::protocol::<fidl_fuchsia_tracing_provider::RegistryMarker>(),
161                    )
162                    .from(Ref::parent())
163                    .to(&pkgdir),
164            )
165            .await
166            .unwrap();
167        builder
168            .add_route(
169                Route::new()
170                    .capability(
171                        Capability::directory("blob-exec")
172                            .path("/blob/root")
173                            .rights(fio::R_STAR_DIR),
174                    )
175                    .from(&service_reflector)
176                    .to(&pkgdir),
177            )
178            .await
179            .unwrap();
180        let svc_path = if fxblob {
181            format!("/blob/svc/{}", fidl_fuchsia_fxfs::BlobReaderMarker::PROTOCOL_NAME)
182        } else {
183            format!("/blob/{}", fidl_fuchsia_fxfs::BlobReaderMarker::PROTOCOL_NAME)
184        };
185        builder
186            .add_route(
187                Route::new()
188                    .capability(
189                        Capability::protocol::<fidl_fuchsia_fxfs::BlobReaderMarker>()
190                            .path(svc_path),
191                    )
192                    .from(&service_reflector)
193                    .to(&pkgdir),
194            )
195            .await
196            .unwrap();
197        let realm = builder.build().await.expect("realm build failed");
198        Self { realm }
199    }
200
201    fn realm(&self) -> &RealmInstance {
202        &self.realm
203    }
204}