1use crate::errors::FxfsError;
6use crate::filesystem::FxFilesystem;
7use crate::object_store::directory::Directory;
8use crate::object_store::transaction::{lock_keys, Options, Transaction};
9use crate::object_store::tree_cache::TreeCache;
10use crate::object_store::{
11 load_store_info, LockKey, NewChildStoreOptions, ObjectDescriptor, ObjectStore, StoreOwner,
12};
13use anyhow::{anyhow, bail, ensure, Context, Error};
14use fxfs_crypto::Crypt;
15use std::sync::{Arc, Weak};
16
17pub const VOLUMES_DIRECTORY: &str = "volumes";
25
26pub struct RootVolume {
28 _root_directory: Directory<ObjectStore>,
29 filesystem: Arc<FxFilesystem>,
30}
31
32impl RootVolume {
33 pub fn volume_directory(&self) -> &Directory<ObjectStore> {
34 self.filesystem.object_manager().volume_directory()
35 }
36
37 pub async fn new_volume(
39 &self,
40 volume_name: &str,
41 owner: Weak<dyn StoreOwner>,
42 crypt: Option<Arc<dyn Crypt>>,
43 ) -> Result<Arc<ObjectStore>, Error> {
44 let root_store = self.filesystem.root_store();
45 let store;
46 let mut transaction = self
47 .filesystem
48 .clone()
49 .new_transaction(
50 lock_keys![LockKey::object(
51 root_store.store_object_id(),
52 self.volume_directory().object_id(),
53 )],
54 Options::default(),
55 )
56 .await?;
57
58 ensure!(
59 matches!(self.volume_directory().lookup(volume_name).await?, None),
60 FxfsError::AlreadyExists
61 );
62 store = root_store
63 .new_child_store(
64 &mut transaction,
65 NewChildStoreOptions { owner, crypt, ..Default::default() },
66 Box::new(TreeCache::new()),
67 )
68 .await?;
69 store.set_trace(self.filesystem.trace());
70
71 self.filesystem.object_manager().add_store(store.clone());
73
74 struct CleanUp<'a>(&'a ObjectStore);
76 impl Drop for CleanUp<'_> {
77 fn drop(&mut self) {
78 self.0.filesystem().object_manager().forget_store(self.0.store_object_id());
79 }
80 }
81 let clean_up = CleanUp(&store);
82
83 store.create(&mut transaction).await?;
85
86 self.volume_directory()
87 .add_child_volume(&mut transaction, volume_name, store.store_object_id())
88 .await?;
89 transaction.commit().await?;
90
91 std::mem::forget(clean_up);
92
93 Ok(store)
94 }
95
96 pub async fn volume(
98 &self,
99 volume_name: &str,
100 owner: Weak<dyn StoreOwner>,
101 crypt: Option<Arc<dyn Crypt>>,
102 ) -> Result<Arc<ObjectStore>, Error> {
103 self.volume_from_id(
104 match self.volume_directory().lookup(volume_name).await?.ok_or(FxfsError::NotFound)? {
105 (object_id, ObjectDescriptor::Volume) => object_id,
106 _ => bail!(anyhow!(FxfsError::Inconsistent).context("Expected volume")),
107 },
108 owner,
109 crypt,
110 )
111 .await
112 }
113
114 pub async fn volume_from_id(
116 &self,
117 store_object_id: u64,
118 owner: Weak<dyn StoreOwner>,
119 crypt: Option<Arc<dyn Crypt>>,
120 ) -> Result<Arc<ObjectStore>, Error> {
121 let store =
122 self.filesystem.object_manager().store(store_object_id).ok_or(FxfsError::NotFound)?;
123 store.set_trace(self.filesystem.trace());
124 if let Some(crypt) = crypt {
125 store.unlock(owner, crypt).await.context("Failed to unlock volume")?;
126 } else if store.is_locked() {
127 bail!(FxfsError::AccessDenied);
128 }
129 Ok(store)
130 }
131
132 pub async fn delete_volume(
134 &self,
135 volume_name: &str,
136 mut transaction: Transaction<'_>,
137 callback: impl FnOnce() + Send,
138 ) -> Result<(), Error> {
139 let object_id =
140 match self.volume_directory().lookup(volume_name).await?.ok_or(FxfsError::NotFound)? {
141 (object_id, ObjectDescriptor::Volume) => object_id,
142 _ => bail!(anyhow!(FxfsError::Inconsistent).context("Expected volume")),
143 };
144 let root_store = self.filesystem.root_store();
145
146 let mut objects_to_delete = load_store_info(&root_store, object_id).await?.parent_objects();
149 objects_to_delete.push(object_id);
150
151 for object_id in &objects_to_delete {
152 root_store.adjust_refs(&mut transaction, *object_id, -1).await?;
153 }
154 self.filesystem.allocator().mark_for_deletion(&mut transaction, object_id).await;
156 self.volume_directory()
158 .delete_child_volume(&mut transaction, volume_name, object_id)
159 .await?;
160 transaction.commit_with_callback(|_| callback()).await.context("commit")?;
161 for object_id in &objects_to_delete {
163 root_store.tombstone_object(*object_id, Options::default()).await?;
164 }
165 Ok(())
166 }
167}
168
169pub async fn root_volume(filesystem: Arc<FxFilesystem>) -> Result<RootVolume, Error> {
171 let root_store = filesystem.root_store();
172 let root_directory = Directory::open(&root_store, root_store.root_directory_object_id())
173 .await
174 .context("Unable to open root volume directory")?;
175 Ok(RootVolume { _root_directory: root_directory, filesystem })
176}
177
178pub async fn list_volumes(volume_directory: &Directory<ObjectStore>) -> Result<Vec<u64>, Error> {
180 let layer_set = volume_directory.store().tree().layer_set();
181 let mut merger = layer_set.merger();
182 let mut iter = volume_directory.iter(&mut merger).await?;
183 let mut object_ids = vec![];
184 while let Some((_, id, _)) = iter.get() {
185 object_ids.push(id);
186 iter.advance().await?;
187 }
188 Ok(object_ids)
189}
190
191#[cfg(test)]
192mod tests {
193 use super::root_volume;
194 use crate::filesystem::{FxFilesystem, JournalingObject, SyncOptions};
195 use crate::object_handle::{ObjectHandle, WriteObjectHandle};
196 use crate::object_store::directory::Directory;
197 use crate::object_store::transaction::{lock_keys, Options};
198 use crate::object_store::{LockKey, NO_OWNER};
199 use fxfs_insecure_crypto::InsecureCrypt;
200 use std::sync::Arc;
201 use storage_device::fake_device::FakeDevice;
202 use storage_device::DeviceHolder;
203
204 #[fuchsia::test]
205 async fn test_lookup_nonexistent_volume() {
206 let device = DeviceHolder::new(FakeDevice::new(8192, 512));
207 let filesystem = FxFilesystem::new_empty(device).await.expect("new_empty failed");
208 let root_volume = root_volume(filesystem.clone()).await.expect("root_volume failed");
209 root_volume
210 .volume("vol", NO_OWNER, Some(Arc::new(InsecureCrypt::new())))
211 .await
212 .err()
213 .expect("Volume shouldn't exist");
214 filesystem.close().await.expect("Close failed");
215 }
216
217 #[fuchsia::test]
218 async fn test_add_volume() {
219 let device = DeviceHolder::new(FakeDevice::new(16384, 512));
220 let filesystem = FxFilesystem::new_empty(device).await.expect("new_empty failed");
221 let crypt = Arc::new(InsecureCrypt::new());
222 {
223 let root_volume = root_volume(filesystem.clone()).await.expect("root_volume failed");
224 let store = root_volume
225 .new_volume("vol", NO_OWNER, Some(crypt.clone()))
226 .await
227 .expect("new_volume failed");
228 let mut transaction = filesystem
229 .clone()
230 .new_transaction(
231 lock_keys![LockKey::object(
232 store.store_object_id(),
233 store.root_directory_object_id()
234 )],
235 Options::default(),
236 )
237 .await
238 .expect("new transaction failed");
239 let root_directory = Directory::open(&store, store.root_directory_object_id())
240 .await
241 .expect("open failed");
242 root_directory
243 .create_child_file(&mut transaction, "foo")
244 .await
245 .expect("create_child_file failed");
246 transaction.commit().await.expect("commit failed");
247 filesystem.sync(SyncOptions::default()).await.expect("sync failed");
248 };
249 {
250 filesystem.close().await.expect("Close failed");
251 let device = filesystem.take_device().await;
252 device.reopen(false);
253 let filesystem = FxFilesystem::open(device).await.expect("open failed");
254 let root_volume = root_volume(filesystem.clone()).await.expect("root_volume failed");
255 let volume =
256 root_volume.volume("vol", NO_OWNER, Some(crypt)).await.expect("volume failed");
257 let root_directory = Directory::open(&volume, volume.root_directory_object_id())
258 .await
259 .expect("open failed");
260 root_directory.lookup("foo").await.expect("lookup failed").expect("not found");
261 filesystem.close().await.expect("Close failed");
262 };
263 }
264
265 #[fuchsia::test]
266 async fn test_delete_volume() {
267 let device = DeviceHolder::new(FakeDevice::new(16384, 512));
268 let filesystem = FxFilesystem::new_empty(device).await.expect("new_empty failed");
269 let crypt = Arc::new(InsecureCrypt::new());
270 let store_object_id;
271 let parent_objects;
272 {
274 let root_volume = root_volume(filesystem.clone()).await.expect("root_volume failed");
275 let store = root_volume
276 .new_volume("vol", NO_OWNER, Some(crypt.clone()))
277 .await
278 .expect("new_volume failed");
279 store_object_id = store.store_object_id();
280 let mut transaction = filesystem
281 .clone()
282 .new_transaction(
283 lock_keys![LockKey::object(store_object_id, store.root_directory_object_id())],
284 Options::default(),
285 )
286 .await
287 .expect("new transaction failed");
288 let root_directory = Directory::open(&store, store.root_directory_object_id())
289 .await
290 .expect("open failed");
291 let handle = root_directory
292 .create_child_file(&mut transaction, "foo")
293 .await
294 .expect("create_child_file failed");
295 transaction.commit().await.expect("commit failed");
296
297 let mut buf = handle.allocate_buffer(8192).await;
298 buf.as_mut_slice().fill(0xaa);
299 handle.write_or_append(Some(0), buf.as_ref()).await.expect("write failed");
300 store.flush().await.expect("flush failed");
301 filesystem.sync(SyncOptions::default()).await.expect("sync failed");
302 parent_objects = store.parent_objects();
303 for object_id in &parent_objects {
305 let _ = filesystem
306 .root_store()
307 .get_file_size(*object_id)
308 .await
309 .expect("Layer file missing? Bug in test.");
310 }
311 }
312 filesystem.close().await.expect("Close failed");
313 let device = filesystem.take_device().await;
314 device.reopen(false);
315 let filesystem = FxFilesystem::open(device).await.expect("open failed");
316 {
317 assert_eq!(
319 filesystem.allocator().get_owner_allocated_bytes().get(&store_object_id),
320 Some(&8192)
321 );
322 let root_volume = root_volume(filesystem.clone()).await.expect("root_volume failed");
323 let transaction = filesystem
324 .clone()
325 .new_transaction(
326 lock_keys![LockKey::object(
327 root_volume.volume_directory().store().store_object_id(),
328 root_volume.volume_directory().object_id(),
329 )],
330 Options { borrow_metadata_space: true, ..Default::default() },
331 )
332 .await
333 .expect("new_transaction failed");
334 root_volume.delete_volume("vol", transaction, || {}).await.expect("delete_volume");
335 assert_eq!(
337 filesystem
338 .allocator()
339 .get_owner_allocated_bytes()
340 .get(&store_object_id)
341 .unwrap_or(&0),
342 &0,
343 );
344 root_volume
346 .volume("vol", NO_OWNER, Some(crypt.clone()))
347 .await
348 .err()
349 .expect("volume shouldn't exist anymore.");
350 }
351 filesystem.close().await.expect("Close failed");
352 let device = filesystem.take_device().await;
353 device.reopen(false);
354 let filesystem = FxFilesystem::open(device).await.expect("open failed");
356 for object_id in &parent_objects {
357 let _ = filesystem
358 .root_store()
359 .get_file_size(*object_id)
360 .await
361 .err()
362 .expect("File wasn't deleted.");
363 }
364 filesystem.close().await.expect("Close failed");
365 }
366}