fuchsia_storage_benchmarks/filesystems/
memfs.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::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/// Config object for starting Memfs instances.
16#[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}