fuchsia_storage_benchmarks/filesystems/
mod.rs1use async_trait::async_trait;
6use blob_writer::BlobWriter;
7use delivery_blob::{CompressionMode, Type1Blob};
8use fidl::endpoints::ClientEnd;
9use fidl_fuchsia_fs_startup::{CreateOptions, MountOptions};
10use fidl_fuchsia_fxfs::{BlobCreatorProxy, BlobReaderProxy, CryptMarker};
11use fidl_fuchsia_io as fio;
12use fs_management::FSConfig;
13use fs_management::filesystem::{
14 Filesystem as FsManagementFilesystem, ServingMultiVolumeFilesystem,
15 ServingSingleVolumeFilesystem, ServingVolume,
16};
17use fuchsia_merkle::Hash;
18use std::path::Path;
19use std::sync::Arc;
20use storage_benchmarks::block_device::BlockDevice;
21use storage_benchmarks::{CacheClearableFilesystem, Filesystem};
22
23mod blobfs;
24mod f2fs;
25mod fxblob;
26pub mod fxfs;
27mod memfs;
28mod minfs;
29mod pkgdir;
30#[cfg(test)]
31mod testing;
32
33pub use blobfs::Blobfs;
34pub use f2fs::F2fs;
35pub use fxblob::Fxblob;
36pub use fxfs::Fxfs;
37pub use memfs::Memfs;
38pub use minfs::Minfs;
39pub use pkgdir::{PkgDirInstance, PkgDirTest};
40
41const MOUNT_PATH: &str = "/benchmark";
42
43pub struct DeliveryBlob {
45 pub data: Vec<u8>,
46 pub name: Hash,
47}
48
49impl DeliveryBlob {
50 pub fn new(data: Vec<u8>, mode: CompressionMode) -> Self {
51 let name = fuchsia_merkle::root_from_slice(&data);
52 Self { data: Type1Blob::generate(&data, mode), name }
53 }
54}
55
56#[async_trait]
58pub trait BlobFilesystem: CacheClearableFilesystem {
59 async fn write_blob(&self, blob: &DeliveryBlob) {
61 let writer_client_end = self
62 .blob_creator()
63 .create(&blob.name.into(), false)
64 .await
65 .expect("transport error on BlobCreator.Create")
66 .expect("failed to create blob");
67 let writer = writer_client_end.into_proxy();
68 let mut blob_writer = BlobWriter::create(writer, blob.data.len() as u64)
69 .await
70 .expect("failed to create BlobWriter");
71 blob_writer.write(&blob.data).await.unwrap();
72 }
73
74 async fn get_vmo(&self, name: &Hash) -> zx::Vmo {
76 self.blob_reader()
77 .get_vmo(&*name)
78 .await
79 .expect("transport error on BlobReader.GetVmo")
80 .expect("failed to get vmo")
81 }
82
83 fn blob_creator(&self) -> &BlobCreatorProxy;
85
86 fn blob_reader(&self) -> &BlobReaderProxy;
88
89 fn exposed_dir(&self) -> &fio::DirectoryProxy;
91}
92
93enum FsType {
94 SingleVolume(ServingSingleVolumeFilesystem),
95 MultiVolume(ServingMultiVolumeFilesystem, ServingVolume),
96}
97
98pub type CryptClientFn = Arc<dyn Fn() -> ClientEnd<CryptMarker> + Send + Sync>;
99
100pub struct FsManagementFilesystemInstance {
101 config_creator: Box<dyn Fn() -> Box<dyn FSConfig> + Send + Sync>,
102 crypt_client_fn: Option<CryptClientFn>,
103 serving_filesystem: Option<FsType>,
104 as_blob: bool,
105 block_device: Box<dyn BlockDevice>,
107}
108
109impl FsManagementFilesystemInstance {
110 pub async fn new<FSC: FSConfig>(
111 config_creator: impl (Fn() -> FSC) + Send + Sync + 'static,
112 block_device: Box<dyn BlockDevice>,
113 crypt_client_fn: Option<CryptClientFn>,
114 as_blob: bool,
115 ) -> Self {
116 let config_creator = Box::new(move || Box::new(config_creator()) as Box<dyn FSConfig>);
117 let mut fs =
118 FsManagementFilesystem::from_boxed_config(block_device.connector(), config_creator());
119 fs.format().await.expect("Failed to format the filesystem");
120 let serving_filesystem = if fs.config().is_multi_volume() {
121 let serving_filesystem =
122 fs.serve_multi_volume().await.expect("Failed to start the filesystem");
123 let mut vol = serving_filesystem
124 .create_volume(
125 "default",
126 CreateOptions::default(),
127 MountOptions {
128 crypt: crypt_client_fn.as_ref().map(|f| f()),
129 as_blob: Some(as_blob),
130 ..MountOptions::default()
131 },
132 )
133 .await
134 .expect("Failed to create volume");
135 vol.bind_to_path(MOUNT_PATH).expect("Failed to bind the volume");
136 FsType::MultiVolume(serving_filesystem, vol)
137 } else {
138 let mut serving_filesystem = fs.serve().await.expect("Failed to start the filesystem");
139 serving_filesystem.bind_to_path(MOUNT_PATH).expect("Failed to bind the filesystem");
140 FsType::SingleVolume(serving_filesystem)
141 };
142 Self {
143 config_creator,
144 crypt_client_fn,
145 serving_filesystem: Some(serving_filesystem),
146 as_blob,
147 block_device,
148 }
149 }
150
151 fn exposed_dir(&self) -> &fio::DirectoryProxy {
152 let fs = self.serving_filesystem.as_ref().unwrap();
153 match fs {
154 FsType::SingleVolume(serving_filesystem) => serving_filesystem.exposed_dir(),
155 FsType::MultiVolume(_, serving_volume) => serving_volume.exposed_dir(),
156 }
157 }
158
159 fn exposed_services_dir(&self) -> &fio::DirectoryProxy {
162 let fs = self.serving_filesystem.as_ref().unwrap();
163 match fs {
164 FsType::SingleVolume(serving_filesystem) => serving_filesystem.exposed_dir(),
165 FsType::MultiVolume(serving_filesystem, _) => serving_filesystem.exposed_dir(),
166 }
167 }
168
169 fn fs(&self) -> FsManagementFilesystem {
170 FsManagementFilesystem::from_boxed_config(
171 self.block_device.connector(),
172 (self.config_creator)(),
173 )
174 }
175}
176
177#[async_trait]
178impl Filesystem for FsManagementFilesystemInstance {
179 async fn shutdown(mut self) {
180 if let Some(fs) = self.serving_filesystem.take() {
181 match fs {
182 FsType::SingleVolume(fs) => fs.shutdown().await.expect("Failed to stop filesystem"),
183 FsType::MultiVolume(fs, vol) => {
184 vol.shutdown().await.expect("Failed to stop volume");
185 fs.shutdown().await.expect("Failed to stop filesystem")
186 }
187 }
188 }
189 }
190
191 fn benchmark_dir(&self) -> &Path {
192 Path::new(MOUNT_PATH)
193 }
194}
195
196#[async_trait]
197impl CacheClearableFilesystem for FsManagementFilesystemInstance {
198 async fn clear_cache(&mut self) {
199 let serving_filesystem = self.serving_filesystem.take().unwrap();
201 let serving_filesystem = match serving_filesystem {
202 FsType::SingleVolume(serving_filesystem) => {
203 serving_filesystem.shutdown().await.expect("Failed to stop the filesystem");
204 let mut serving_filesystem =
205 self.fs().serve().await.expect("Failed to start the filesystem");
206 serving_filesystem.bind_to_path(MOUNT_PATH).expect("Failed to bind the filesystem");
207 FsType::SingleVolume(serving_filesystem)
208 }
209 FsType::MultiVolume(serving_filesystem, volume) => {
210 volume.shutdown().await.expect("Failed to stop the volume");
211 serving_filesystem.shutdown().await.expect("Failed to stop the filesystem");
212 let serving_filesystem =
213 self.fs().serve_multi_volume().await.expect("Failed to start the filesystem");
214 let mut vol = serving_filesystem
215 .open_volume(
216 "default",
217 MountOptions {
218 crypt: self.crypt_client_fn.as_ref().map(|f| f()),
219 as_blob: Some(self.as_blob),
220 ..MountOptions::default()
221 },
222 )
223 .await
224 .expect("Failed to create volume");
225 vol.bind_to_path(MOUNT_PATH).expect("Failed to bind the volume");
226 FsType::MultiVolume(serving_filesystem, vol)
227 }
228 };
229 self.serving_filesystem = Some(serving_filesystem);
230 }
231}