gpt_component/
partitions_directory.rs

1// Copyright 2024 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::gpt::GptManager;
6use block_server::{BlockServer, SessionManager};
7use fuchsia_sync::Mutex;
8use std::collections::BTreeMap;
9use std::sync::{Arc, Weak};
10use vfs::directory::helper::DirectlyMutable as _;
11
12/// A directory of instances of the fuchsia.storage.partitions.PartitionService service.
13pub struct PartitionsDirectory {
14    node: Arc<vfs::directory::immutable::Simple>,
15    entries: Mutex<BTreeMap<String, PartitionsDirectoryEntry>>,
16}
17
18impl std::fmt::Debug for PartitionsDirectory {
19    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
20        f.debug_struct("PartitionDirectory").field("entries", &self.entries).finish()
21    }
22}
23
24impl PartitionsDirectory {
25    pub fn new(node: Arc<vfs::directory::immutable::Simple>) -> Self {
26        Self { node, entries: Default::default() }
27    }
28
29    pub fn clear(&self) {
30        self.node.remove_all_entries();
31        self.entries.lock().clear();
32    }
33
34    /// Adds an entry for a GPT partition.  Serves the "volume" and "partition" protocols.
35    pub fn add_partition<SM: SessionManager + Send + Sync + 'static>(
36        &self,
37        name: &str,
38        block_server: Weak<BlockServer<SM>>,
39        gpt_manager: Weak<GptManager>,
40        gpt_index: usize,
41    ) {
42        let entry = PartitionsDirectoryEntry::new_partition(block_server, gpt_manager, gpt_index);
43        self.node.add_entry(name, entry.node.clone()).expect("Added an entry twice");
44        self.entries.lock().insert(name.to_string(), entry);
45    }
46
47    /// Adds an entry for an overlay partition.  Serves the "volume" and "overlay" protocols.
48    pub fn add_overlay<SM: SessionManager + Send + Sync + 'static>(
49        &self,
50        name: &str,
51        block_server: Weak<BlockServer<SM>>,
52        gpt_manager: Weak<GptManager>,
53        gpt_indexes: Vec<usize>,
54    ) {
55        let entry = PartitionsDirectoryEntry::new_overlay(block_server, gpt_manager, gpt_indexes);
56        self.node.add_entry(name, entry.node.clone()).expect("Added an entry twice");
57        self.entries.lock().insert(name.to_string(), entry);
58    }
59}
60
61/// A node which hosts an instance of fuchsia.storage.partitions.PartitionService.
62pub struct PartitionsDirectoryEntry {
63    node: Arc<vfs::directory::immutable::Simple>,
64}
65
66impl std::fmt::Debug for PartitionsDirectoryEntry {
67    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
68        f.debug_struct("PartitionDirectoryEntry").finish()
69    }
70}
71
72impl PartitionsDirectoryEntry {
73    fn new_partition<SM: SessionManager + Send + Sync + 'static>(
74        block_server: Weak<BlockServer<SM>>,
75        gpt_manager: Weak<GptManager>,
76        gpt_index: usize,
77    ) -> Self {
78        let node = vfs::directory::immutable::simple();
79        node.add_entry(
80            "volume",
81            vfs::service::host(move |requests| {
82                let server = block_server.clone();
83                async move {
84                    if let Some(server) = server.upgrade() {
85                        if let Err(err) = server.handle_requests(requests).await {
86                            log::error!(err:?; "Error handling requests");
87                        }
88                    }
89                }
90            }),
91        )
92        .unwrap();
93        node.add_entry(
94            "partition",
95            vfs::service::host(move |requests| {
96                let manager = gpt_manager.clone();
97                async move {
98                    if let Some(manager) = manager.upgrade() {
99                        if let Err(err) =
100                            manager.handle_partitions_requests(gpt_index, requests).await
101                        {
102                            log::error!(err:?; "Error handling requests");
103                        }
104                    }
105                }
106            }),
107        )
108        .unwrap();
109
110        Self { node }
111    }
112
113    fn new_overlay<SM: SessionManager + Send + Sync + 'static>(
114        block_server: Weak<BlockServer<SM>>,
115        gpt_manager: Weak<GptManager>,
116        gpt_indexes: Vec<usize>,
117    ) -> Self {
118        let node = vfs::directory::immutable::simple();
119        node.add_entry(
120            "volume",
121            vfs::service::host(move |requests| {
122                let server = block_server.clone();
123                async move {
124                    if let Some(server) = server.upgrade() {
125                        if let Err(err) = server.handle_requests(requests).await {
126                            log::error!(err:?; "Error handling requests");
127                        }
128                    }
129                }
130            }),
131        )
132        .unwrap();
133        node.add_entry(
134            "overlay",
135            vfs::service::host(move |requests| {
136                let manager = gpt_manager.clone();
137                let gpt_indexes = gpt_indexes.clone();
138                async move {
139                    if let Some(manager) = manager.upgrade() {
140                        if let Err(err) =
141                            manager.handle_overlay_partitions_requests(gpt_indexes, requests).await
142                        {
143                            log::error!(err:?; "Error handling requests");
144                        }
145                    }
146                }
147            }),
148        )
149        .unwrap();
150
151        Self { node }
152    }
153}