fuchsia_storage_benchmarks/filesystems/
memfs.rs1use crate::filesystems::MOUNT_PATH;
6use async_trait::async_trait;
7use fidl_fuchsia_component::{CreateChildArgs, RealmMarker};
8use fs_management::FS_COLLECTION_NAME;
9use fuchsia_component::client::{connect_to_protocol, open_childs_exposed_directory};
10use std::path::Path;
11use std::sync::atomic::{AtomicU64, Ordering};
12use storage_benchmarks::{BlockDeviceFactory, Filesystem, FilesystemConfig};
13use {fidl_fuchsia_component_decl as fdecl, fidl_fuchsia_io as fio};
14
15#[derive(Clone)]
17pub struct Memfs;
18
19#[async_trait]
20impl FilesystemConfig for Memfs {
21 type Filesystem = MemfsInstance;
22
23 async fn start_filesystem(
24 &self,
25 _block_device_factory: &dyn BlockDeviceFactory,
26 ) -> MemfsInstance {
27 MemfsInstance::new().await
28 }
29
30 fn name(&self) -> String {
31 "memfs".to_owned()
32 }
33}
34
35pub struct MemfsInstance {
36 instance_name: String,
37}
38
39impl MemfsInstance {
40 async fn new() -> Self {
41 static INSTANCE_COUNTER: AtomicU64 = AtomicU64::new(0);
42 let instance_name = format!("memfs-{}", INSTANCE_COUNTER.fetch_add(1, Ordering::Relaxed));
43 let collection_ref = fdecl::CollectionRef { name: FS_COLLECTION_NAME.to_string() };
44 let child_decl = fdecl::Child {
45 name: Some(instance_name.to_string()),
46 url: Some("#meta/memfs.cm".to_string()),
47 startup: Some(fdecl::StartupMode::Lazy),
48 ..Default::default()
49 };
50
51 let realm_proxy = connect_to_protocol::<RealmMarker>().unwrap();
52 realm_proxy
53 .create_child(&collection_ref, &child_decl, CreateChildArgs::default())
54 .await
55 .expect("Failed to send FIDL request")
56 .expect("Failed to create memfs instance");
57
58 let exposed_dir =
59 open_childs_exposed_directory(&instance_name, Some(FS_COLLECTION_NAME.to_string()))
60 .await
61 .expect("Failed to connect to memfs's exposed directory");
62
63 let (root_dir, server_end) = fidl::endpoints::create_endpoints();
64 exposed_dir
65 .open(
66 "memfs",
67 fio::PERM_READABLE
68 | fio::Flags::PERM_INHERIT_WRITE
69 | fio::Flags::PERM_INHERIT_EXECUTE,
70 &Default::default(),
71 server_end.into_channel(),
72 )
73 .expect("Failed to open memfs's root");
74 let namespace = fdio::Namespace::installed().expect("Failed to get local namespace");
75 namespace.bind(MOUNT_PATH, root_dir).expect("Failed to bind memfs");
76
77 Self { instance_name }
78 }
79}
80
81#[async_trait]
82impl Filesystem for MemfsInstance {
83 async fn shutdown(self) {
84 let realm_proxy = connect_to_protocol::<RealmMarker>().unwrap();
85 realm_proxy
86 .destroy_child(&fdecl::ChildRef {
87 name: self.instance_name.clone(),
88 collection: Some(FS_COLLECTION_NAME.to_string()),
89 })
90 .await
91 .expect("Failed to send FIDL request")
92 .expect("Failed to destroy memfs instance");
93
94 let namespace = fdio::Namespace::installed().expect("Failed to get local namespace");
95 namespace.unbind(MOUNT_PATH).expect("Failed to unbind memfs");
96 }
97
98 fn benchmark_dir(&self) -> &Path {
99 Path::new(MOUNT_PATH)
100 }
101}
102
103#[cfg(test)]
104mod tests {
105 use super::Memfs;
106 use std::fs::OpenOptions;
107 use std::io::{Read, Write};
108 use storage_benchmarks::block_device::PanickingBlockDeviceFactory;
109 use storage_benchmarks::{Filesystem, FilesystemConfig};
110
111 #[fuchsia::test]
112 async fn start_memfs() {
113 const FILE_CONTENTS: &str = "file-contents";
114 let block_device_factory = PanickingBlockDeviceFactory::new();
115 let fs = Memfs.start_filesystem(&block_device_factory).await;
116
117 let file_path = fs.benchmark_dir().join("filename");
118 {
119 let mut file =
120 OpenOptions::new().create_new(true).write(true).open(&file_path).unwrap();
121 file.write_all(FILE_CONTENTS.as_bytes()).unwrap();
122 }
123 {
124 let mut file = OpenOptions::new().read(true).open(&file_path).unwrap();
125 let mut buf = [0u8; FILE_CONTENTS.len()];
126 file.read_exact(&mut buf).unwrap();
127 assert_eq!(std::str::from_utf8(&buf).unwrap(), FILE_CONTENTS);
128 }
129 fs.shutdown().await;
130 }
131}