fuchsia_storage_benchmarks/filesystems/
mod.rs
1use async_trait::async_trait;
6use delivery_blob::{CompressionMode, Type1Blob};
7use fidl::endpoints::ClientEnd;
8use fidl_fuchsia_fs_startup::{CreateOptions, MountOptions};
9use fidl_fuchsia_fxfs::CryptMarker;
10use fidl_fuchsia_io as fio;
11use fs_management::filesystem::{ServingMultiVolumeFilesystem, ServingSingleVolumeFilesystem};
12use fs_management::FSConfig;
13use fuchsia_merkle::Hash;
14use std::path::Path;
15use std::sync::Arc;
16use storage_benchmarks::block_device::BlockDevice;
17use storage_benchmarks::{CacheClearableFilesystem, Filesystem};
18
19mod blobfs;
20mod f2fs;
21mod fxblob;
22pub mod fxfs;
23mod memfs;
24mod minfs;
25mod pkgdir;
26#[cfg(test)]
27mod testing;
28
29pub use blobfs::Blobfs;
30pub use f2fs::F2fs;
31pub use fxblob::Fxblob;
32pub use fxfs::Fxfs;
33pub use memfs::Memfs;
34pub use minfs::Minfs;
35pub use pkgdir::{PkgDirInstance, PkgDirTest};
36
37const MOUNT_PATH: &str = "/benchmark";
38
39pub struct DeliveryBlob {
41 pub data: Vec<u8>,
42 pub name: Hash,
43}
44
45impl DeliveryBlob {
46 pub fn new(data: Vec<u8>, mode: CompressionMode) -> Self {
47 let name = fuchsia_merkle::from_slice(&data).root();
48 Self { data: Type1Blob::generate(&data, mode), name }
49 }
50}
51
52#[async_trait]
54pub trait BlobFilesystem: CacheClearableFilesystem {
55 async fn write_blob(&self, blob: &DeliveryBlob);
60
61 async fn get_vmo(&self, blob: &DeliveryBlob) -> zx::Vmo;
64
65 fn exposed_dir(&self) -> &fio::DirectoryProxy;
67}
68
69enum FsType {
70 SingleVolume(ServingSingleVolumeFilesystem),
71 MultiVolume(ServingMultiVolumeFilesystem),
72}
73
74pub type CryptClientFn = Arc<dyn Fn() -> ClientEnd<CryptMarker> + Send + Sync>;
75
76pub struct FsManagementFilesystemInstance {
77 fs: fs_management::filesystem::Filesystem,
78 crypt_client_fn: Option<CryptClientFn>,
79 serving_filesystem: Option<FsType>,
80 as_blob: bool,
81 _block_device: Box<dyn BlockDevice>,
83}
84
85impl FsManagementFilesystemInstance {
86 pub async fn new<FSC: FSConfig>(
87 config: FSC,
88 block_device: Box<dyn BlockDevice>,
89 crypt_client_fn: Option<CryptClientFn>,
90 as_blob: bool,
91 ) -> Self {
92 let mut fs = fs_management::filesystem::Filesystem::from_boxed_config(
93 block_device.connector(),
94 Box::new(config),
95 );
96 fs.format().await.expect("Failed to format the filesystem");
97 let serving_filesystem = if fs.config().is_multi_volume() {
98 let mut serving_filesystem =
99 fs.serve_multi_volume().await.expect("Failed to start the filesystem");
100 let vol = serving_filesystem
101 .create_volume(
102 "default",
103 CreateOptions::default(),
104 MountOptions {
105 crypt: crypt_client_fn.as_ref().map(|f| f()),
106 as_blob: Some(as_blob),
107 ..MountOptions::default()
108 },
109 )
110 .await
111 .expect("Failed to create volume");
112 vol.bind_to_path(MOUNT_PATH).expect("Failed to bind the volume");
113 FsType::MultiVolume(serving_filesystem)
114 } else {
115 let mut serving_filesystem = fs.serve().await.expect("Failed to start the filesystem");
116 serving_filesystem.bind_to_path(MOUNT_PATH).expect("Failed to bind the filesystem");
117 FsType::SingleVolume(serving_filesystem)
118 };
119 Self {
120 fs,
121 crypt_client_fn,
122 serving_filesystem: Some(serving_filesystem),
123 _block_device: block_device,
124 as_blob,
125 }
126 }
127
128 fn exposed_dir(&self) -> &fio::DirectoryProxy {
129 let fs = self.serving_filesystem.as_ref().unwrap();
130 match fs {
131 FsType::SingleVolume(serving_filesystem) => serving_filesystem.exposed_dir(),
132 FsType::MultiVolume(serving_filesystem) => {
133 serving_filesystem.volume("default").unwrap().exposed_dir()
134 }
135 }
136 }
137
138 fn exposed_services_dir(&self) -> &fio::DirectoryProxy {
141 let fs = self.serving_filesystem.as_ref().unwrap();
142 match fs {
143 FsType::SingleVolume(serving_filesystem) => serving_filesystem.exposed_dir(),
144 FsType::MultiVolume(serving_filesystem) => serving_filesystem.exposed_dir(),
145 }
146 }
147}
148
149#[async_trait]
150impl Filesystem for FsManagementFilesystemInstance {
151 async fn shutdown(mut self) {
152 if let Some(fs) = self.serving_filesystem.take() {
153 match fs {
154 FsType::SingleVolume(fs) => fs.shutdown().await.expect("Failed to stop filesystem"),
155 FsType::MultiVolume(fs) => fs.shutdown().await.expect("Failed to stop filesystem"),
156 }
157 }
158 }
159
160 fn benchmark_dir(&self) -> &Path {
161 Path::new(MOUNT_PATH)
162 }
163}
164
165#[async_trait]
166impl CacheClearableFilesystem for FsManagementFilesystemInstance {
167 async fn clear_cache(&mut self) {
168 let serving_filesystem = self.serving_filesystem.take().unwrap();
170 let serving_filesystem = match serving_filesystem {
171 FsType::SingleVolume(serving_filesystem) => {
172 serving_filesystem.shutdown().await.expect("Failed to stop the filesystem");
173 let mut serving_filesystem =
174 self.fs.serve().await.expect("Failed to start the filesystem");
175 serving_filesystem.bind_to_path(MOUNT_PATH).expect("Failed to bind the filesystem");
176 FsType::SingleVolume(serving_filesystem)
177 }
178 FsType::MultiVolume(serving_filesystem) => {
179 serving_filesystem.shutdown().await.expect("Failed to stop the filesystem");
180 let mut serving_filesystem =
181 self.fs.serve_multi_volume().await.expect("Failed to start the filesystem");
182 let vol = serving_filesystem
183 .open_volume(
184 "default",
185 MountOptions {
186 crypt: self.crypt_client_fn.as_ref().map(|f| f()),
187 as_blob: Some(self.as_blob),
188 ..MountOptions::default()
189 },
190 )
191 .await
192 .expect("Failed to create volume");
193 vol.bind_to_path(MOUNT_PATH).expect("Failed to bind the volume");
194 FsType::MultiVolume(serving_filesystem)
195 }
196 };
197 self.serving_filesystem = Some(serving_filesystem);
198 }
199}