1use crate::errors::FxfsError;
6use crate::filesystem::{FlushReason, FxFilesystem};
7use crate::object_store::directory::Directory;
8use crate::object_store::transaction::{LockKeys, Mutation, Options, Transaction, lock_keys};
9use crate::object_store::tree_cache::TreeCache;
10use crate::object_store::{
11 ChildValue, DirType, INVALID_OBJECT_ID, LockKey, NewChildStoreOptions, ObjectDescriptor,
12 ObjectKey, ObjectStore, ObjectValue, StoreOptions, load_store_info,
13};
14use crate::serialized_types::LATEST_VERSION;
15use anyhow::{Context, Error, anyhow, bail, ensure};
16use log::error;
17use std::sync::Arc;
18
19pub const VOLUMES_DIRECTORY: &str = "volumes";
27
28pub struct RootVolume {
30 _root_directory: Directory<ObjectStore>,
31 filesystem: Arc<FxFilesystem>,
32}
33
34impl RootVolume {
35 pub fn volume_directory(&self) -> &Directory<ObjectStore> {
36 self.filesystem.object_manager().volume_directory()
37 }
38
39 pub async fn new_volume(
41 &self,
42 volume_name: &str,
43 options: NewChildStoreOptions,
44 ) -> Result<Arc<ObjectStore>, Error> {
45 let root_store = self.filesystem.root_store();
46 let store;
47 let mut transaction = root_store
48 .new_transaction(
49 lock_keys![LockKey::object(
50 root_store.store_object_id(),
51 self.volume_directory().object_id(),
52 )],
53 Options::default(),
54 )
55 .await?;
56
57 ensure!(
58 matches!(self.volume_directory().lookup(volume_name).await?, None),
59 FxfsError::AlreadyExists
60 );
61 store = root_store
62 .new_child_store(&mut transaction, options, Some(Box::new(TreeCache::new())))
63 .await?;
64 store.set_trace(self.filesystem.trace());
65
66 self.filesystem.object_manager().add_store(store.clone());
68
69 struct CleanUp<'a>(&'a ObjectStore);
71 impl Drop for CleanUp<'_> {
72 fn drop(&mut self) {
73 self.0.filesystem().object_manager().forget_store(self.0.store_object_id());
74 }
75 }
76 let clean_up = CleanUp(&store);
77
78 store.create(&mut transaction).await?;
80
81 self.volume_directory()
82 .add_child_volume(&mut transaction, volume_name, store.store_object_id())
83 .await?;
84 transaction.commit().await?;
85
86 std::mem::forget(clean_up);
87
88 Ok(store)
89 }
90
91 pub async fn volume(
93 &self,
94 volume_name: &str,
95 options: StoreOptions,
96 ) -> Result<Arc<ObjectStore>, Error> {
97 let (store_object_id, descriptor, _) = self
99 .volume_directory()
100 .lookup(volume_name)
101 .await
102 .context("Volume lookup failed")?
103 .ok_or(FxfsError::NotFound)
104 .context("Volume missing in volume directory")?;
105 match descriptor {
106 ObjectDescriptor::Volume => (),
107 _ => bail!(anyhow!(FxfsError::Inconsistent).context("Expected volume")),
108 }
109 let store = self
111 .filesystem
112 .object_manager()
113 .store(store_object_id)
114 .ok_or(FxfsError::NotFound)
115 .context("Missing volume store")?;
116 store.set_trace(self.filesystem.trace());
117 if let Some(crypt) = options.crypt {
119 let read_only = self.filesystem.options().read_only;
120 store.unlock_inner(crypt, read_only).await.context("Failed to unlock volume")?;
121 } else if store.is_locked() {
122 bail!(FxfsError::AccessDenied);
123 }
124 if let Some(scope_guard) = self.filesystem.scope().active_guard()
126 && !self.filesystem.options().read_only
127 && store.tree().get_earliest_version() != LATEST_VERSION
128 {
129 let keys = lock_keys![LockKey::flush(store_object_id)];
130 let guard = self
131 .filesystem
132 .lock_manager()
133 .write_lock(keys)
134 .await
135 .into_owned(self.filesystem.clone());
136 let store = store.clone();
137 self.filesystem.scope().spawn(async move {
138 let _guard = guard;
142 let _scope_guard = scope_guard;
148 if let Err(error) =
149 store.flush_guarded_with_reason(FlushReason::UpgradeVersion).await
150 {
151 error!(error:?; "Failed background flush");
152 }
153 });
154 }
155 Ok(store)
156 }
157
158 pub async fn delete_volume(
161 &self,
162 volume_name: &str,
163 mut transaction: Transaction<'_>,
164 callback: impl FnOnce() + Send,
165 ) -> Result<(), Error> {
166 let objects_to_delete = self.delete_volume_impl(volume_name, &mut transaction).await?;
167 transaction.commit_with_callback(|_| callback()).await.context("commit")?;
168 let root_store_id = self.filesystem.root_store().store_object_id();
170 for object_id in &objects_to_delete {
171 self.filesystem.tombstone_object(root_store_id, *object_id, None).await?;
172 }
173 Ok(())
174 }
175
176 async fn delete_volume_impl(
177 &self,
178 volume_name: &str,
179 transaction: &mut Transaction<'_>,
180 ) -> Result<Vec<u64>, Error> {
181 let object_id =
182 match self.volume_directory().lookup(volume_name).await?.ok_or(FxfsError::NotFound)? {
183 (object_id, ObjectDescriptor::Volume, _) => object_id,
184 _ => bail!(anyhow!(FxfsError::Inconsistent).context("Expected volume")),
185 };
186 let root_store = self.filesystem.root_store();
187
188 let mut objects_to_delete = load_store_info(&root_store, object_id).await?.parent_objects();
191 objects_to_delete.push(object_id);
192
193 for object_id in &objects_to_delete {
194 root_store.adjust_refs(transaction, *object_id, -1).await?;
195 }
196 self.filesystem.allocator().mark_for_deletion(transaction, object_id);
198 self.volume_directory().delete_child_volume(transaction, volume_name, object_id)?;
200 Ok(objects_to_delete)
201 }
202
203 pub(crate) async fn replace_volume(
207 &self,
208 transaction: &mut Transaction<'_>,
209 src: &str,
210 dst: &str,
211 ) -> Result<Option<Vec<u64>>, Error> {
212 let src_object_id = match self.volume_directory().lookup(src).await? {
213 Some((object_id, ObjectDescriptor::Volume, _)) => Ok(object_id),
214 Some(_) => Err(FxfsError::Inconsistent),
215 None => Err(FxfsError::NotFound),
216 }?;
217
218 let replaced_objects = if let Some((_, ObjectDescriptor::Volume, _)) =
219 self.volume_directory().lookup(dst).await?
220 {
221 Some(self.delete_volume_impl(dst, transaction).await?)
222 } else {
223 None
224 };
225
226 transaction.add(
227 self.volume_directory().store().store_object_id(),
228 Mutation::replace_or_insert_object(
229 ObjectKey::child(self.volume_directory().object_id(), src, DirType::Normal),
230 ObjectValue::None,
231 ),
232 );
233
234 transaction.add(
235 self.volume_directory().store().store_object_id(),
236 Mutation::replace_or_insert_object(
237 ObjectKey::child(self.volume_directory().object_id(), dst, DirType::Normal),
238 ObjectValue::Child(ChildValue {
239 object_id: src_object_id,
240 object_descriptor: ObjectDescriptor::Volume,
241 }),
242 ),
243 );
244
245 Ok(replaced_objects)
246 }
247
248 pub async fn install_volume(
256 &self,
257 src: &str,
258 image_file: &str,
259 dst: &str,
260 ) -> Result<(), Error> {
261 ObjectStore::install_volume(self, src, image_file, dst).await
262 }
263
264 pub async fn acquire_transaction_for_remove_volume<'a>(
267 &self,
268 name: &str,
269 extra_keys: impl IntoIterator<Item = LockKey>,
270 allow_not_found: bool,
271 options: Options<'a>,
272 ) -> Result<(u64, Transaction<'a>), Error> {
273 let volume_dir = self.volume_directory();
277 let store = volume_dir.store();
278 let extra_keys = extra_keys.into_iter();
279 let mut lock_keys = Vec::with_capacity(extra_keys.size_hint().1.unwrap_or(2) + 2);
280 lock_keys.extend(extra_keys);
281 lock_keys.push(LockKey::object(store.store_object_id(), volume_dir.object_id()));
282 let orig_len = lock_keys.len();
283 let mut transaction = None;
284 loop {
285 lock_keys.truncate(orig_len);
286 let object_id = match volume_dir.lookup(name).await? {
287 Some((object_id, ObjectDescriptor::Volume, _)) => {
288 lock_keys.push(LockKey::flush(object_id));
292 object_id
293 }
294 None => {
295 if allow_not_found {
296 INVALID_OBJECT_ID
297 } else {
298 bail!(FxfsError::NotFound);
299 }
300 }
301 _ => bail!(anyhow!(FxfsError::Inconsistent).context("Expected volume")),
302 };
303
304 match transaction {
306 Some(result @ (id, _)) if id == object_id => return Ok(result),
307 _ => {}
308 }
309
310 transaction = Some((
311 object_id,
312 store.new_transaction(LockKeys::Vec(lock_keys.clone()), options).await?,
313 ));
314 }
315 }
316}
317
318pub async fn root_volume(filesystem: Arc<FxFilesystem>) -> Result<RootVolume, Error> {
320 let root_store = filesystem.root_store();
321 let root_directory = Directory::open(&root_store, root_store.root_directory_object_id())
322 .await
323 .context("Unable to open root volume directory")?;
324 Ok(RootVolume { _root_directory: root_directory, filesystem })
325}
326
327pub async fn list_volumes(volume_directory: &Directory<ObjectStore>) -> Result<Vec<u64>, Error> {
329 let layer_set = volume_directory.store().tree().layer_set();
330 let mut merger = layer_set.merger();
331 let mut iter = volume_directory.iter(&mut merger).await?;
332 let mut object_ids = vec![];
333 while let Some((_, id, _)) = iter.get() {
334 object_ids.push(id);
335 iter.advance().await?;
336 }
337 Ok(object_ids)
338}
339
340#[cfg(test)]
341mod tests {
342 use super::root_volume;
343 use crate::filesystem::{FxFilesystem, SyncOptions};
344 use crate::fsck::{FsckOptions, fsck_volume_with_options, fsck_with_options};
345 use crate::lsm_tree::persistent_layer::PersistentLayerWriter;
346 use crate::lsm_tree::types::LayerWriter as _;
347 use crate::object_handle::{ObjectHandle, WriteObjectHandle};
348 use crate::object_store::directory::Directory;
349 use crate::object_store::transaction::{Options, ReservationOptions, lock_keys};
350 use crate::object_store::{
351 DirectWriter, HandleOptions, LockKey, NewChildStoreOptions, ObjectKey, ObjectStore,
352 ObjectValue, StoreOptions,
353 };
354 use crate::serialized_types::{EARLIEST_SUPPORTED_VERSION, LATEST_VERSION};
355 use fxfs_crypto::{Crypt, EncryptionKey, KeyPurpose};
356 use fxfs_insecure_crypto::new_insecure_crypt;
357 use std::sync::Arc;
358 use storage_device::DeviceHolder;
359 use storage_device::fake_device::FakeDevice;
360 use test_case::test_case;
361
362 async fn do_fsck(
363 fs: &Arc<FxFilesystem>,
364 volume_name: Option<&str>,
365 crypt: Option<Arc<dyn Crypt>>,
366 ) {
367 let fsck_options = FsckOptions {
368 fail_on_warning: true,
369 on_error: Box::new(|err| eprintln!("fsck error: {:?}", err)),
370 ..Default::default()
371 };
372 fsck_with_options(fs.clone(), &fsck_options).await.expect("fsck filesystem");
373 if let Some(volume_name) = volume_name {
374 let root = root_volume(fs.clone()).await.unwrap();
375 let vol = root
376 .volume(
377 volume_name,
378 StoreOptions { crypt: crypt.clone(), ..StoreOptions::default() },
379 )
380 .await
381 .expect("could not open volume");
382 fsck_volume_with_options(&fs, &fsck_options, vol.store_object_id(), crypt)
383 .await
384 .expect("fsck volume");
385 }
386 }
387
388 #[fuchsia::test]
389 async fn test_lookup_nonexistent_volume() {
390 let device = DeviceHolder::new(FakeDevice::new(8192, 512));
391 let filesystem = FxFilesystem::new_empty(device).await.expect("new_empty failed");
392 let root_volume = root_volume(filesystem.clone()).await.expect("root_volume failed");
393 root_volume
394 .volume(
395 "vol",
396 StoreOptions {
397 crypt: Some(Arc::new(new_insecure_crypt())),
398 ..StoreOptions::default()
399 },
400 )
401 .await
402 .err()
403 .expect("Volume shouldn't exist");
404 filesystem.close().await.expect("Close failed");
405 }
406
407 #[fuchsia::test]
408 async fn test_add_volume() {
409 let device = DeviceHolder::new(FakeDevice::new(16384, 512));
410 let filesystem = FxFilesystem::new_empty(device).await.expect("new_empty failed");
411 let crypt = Arc::new(new_insecure_crypt());
412 {
413 let root_volume = root_volume(filesystem.clone()).await.expect("root_volume failed");
414 let store = root_volume
415 .new_volume(
416 "vol",
417 NewChildStoreOptions {
418 options: StoreOptions {
419 crypt: Some(crypt.clone()),
420 ..StoreOptions::default()
421 },
422 ..Default::default()
423 },
424 )
425 .await
426 .expect("new_volume failed");
427 let mut transaction = filesystem
428 .root_store()
429 .new_transaction(
430 lock_keys![LockKey::object(
431 store.store_object_id(),
432 store.root_directory_object_id()
433 )],
434 Options::default(),
435 )
436 .await
437 .expect("new transaction failed");
438 let root_directory = Directory::open(&store, store.root_directory_object_id())
439 .await
440 .expect("open failed");
441 root_directory
442 .create_child_file(&mut transaction, "foo")
443 .await
444 .expect("create_child_file failed");
445 transaction.commit().await.expect("commit failed");
446 filesystem.sync(SyncOptions::default()).await.expect("sync failed");
447 };
448 {
449 filesystem.close().await.expect("Close failed");
450 let device = filesystem.take_device().await;
451 device.reopen(false);
452 let filesystem = FxFilesystem::open(device).await.expect("open failed");
453 do_fsck(&filesystem, Some("vol"), Some(crypt)).await;
454 let root_volume = root_volume(filesystem.clone()).await.expect("root_volume failed");
455 let volume = root_volume
457 .volume("vol", StoreOptions { crypt: None, ..StoreOptions::default() })
458 .await
459 .expect("volume failed");
460 let root_directory = Directory::open(&volume, volume.root_directory_object_id())
461 .await
462 .expect("open failed");
463 root_directory.lookup("foo").await.expect("lookup failed").expect("not found");
464 filesystem.close().await.expect("Close failed");
465 };
466 }
467
468 #[fuchsia::test]
469 async fn test_delete_volume() {
470 let device = DeviceHolder::new(FakeDevice::new(16384, 512));
471 let filesystem = FxFilesystem::new_empty(device).await.expect("new_empty failed");
472 let crypt = Arc::new(new_insecure_crypt());
473 let store_object_id;
474 let parent_objects;
475 let store_id = {
477 let root_volume = root_volume(filesystem.clone()).await.expect("root_volume failed");
478 let store = root_volume
479 .new_volume(
480 "vol",
481 NewChildStoreOptions {
482 options: StoreOptions {
483 crypt: Some(crypt.clone()),
484 ..StoreOptions::default()
485 },
486 ..Default::default()
487 },
488 )
489 .await
490 .expect("new_volume failed");
491 store_object_id = store.store_object_id();
492 let mut transaction = filesystem
493 .root_store()
494 .new_transaction(
495 lock_keys![LockKey::object(store_object_id, store.root_directory_object_id())],
496 Options::default(),
497 )
498 .await
499 .expect("new transaction failed");
500 let root_directory = Directory::open(&store, store.root_directory_object_id())
501 .await
502 .expect("open failed");
503 let handle = root_directory
504 .create_child_file(&mut transaction, "foo")
505 .await
506 .expect("create_child_file failed");
507 transaction.commit().await.expect("commit failed");
508
509 let mut buf = handle.allocate_buffer(8192).await;
510 buf.fill(0xaa);
511 handle.write_or_append(Some(0), buf.as_ref()).await.expect("write failed");
512 store.flush().await.expect("flush failed");
513 filesystem.sync(SyncOptions::default()).await.expect("sync failed");
514 parent_objects = store.parent_objects();
515 for object_id in &parent_objects {
517 let _ = filesystem
518 .root_store()
519 .get_file_size(*object_id)
520 .await
521 .expect("Layer file missing? Bug in test.");
522 }
523 store.store_object_id()
524 };
525 filesystem.close().await.expect("Close failed");
526 let device = filesystem.take_device().await;
527 device.reopen(false);
528 let filesystem = FxFilesystem::open(device).await.expect("open failed");
529 do_fsck(&filesystem, Some("vol"), Some(crypt.clone())).await;
530 {
531 assert_eq!(
533 filesystem.allocator().get_owner_allocated_bytes().get(&store_object_id),
534 Some(&8192)
535 );
536 let root = root_volume(filesystem.clone()).await.expect("root_volume failed");
537 let transaction = filesystem
538 .root_store()
539 .new_transaction(
540 lock_keys![
541 LockKey::object(
542 root.volume_directory().store().store_object_id(),
543 root.volume_directory().object_id(),
544 ),
545 LockKey::flush(store_id)
546 ],
547 Options {
548 reservation: ReservationOptions::BorrowedMetadata,
549 ..Default::default()
550 },
551 )
552 .await
553 .expect("new_transaction failed");
554 root.delete_volume("vol", transaction, || {}).await.expect("delete_volume");
555 assert_eq!(
557 filesystem
558 .allocator()
559 .get_owner_allocated_bytes()
560 .get(&store_object_id)
561 .unwrap_or(&0),
562 &0,
563 );
564 root.volume(
566 "vol",
567 StoreOptions { crypt: Some(crypt.clone()), ..StoreOptions::default() },
568 )
569 .await
570 .err()
571 .expect("volume shouldn't exist anymore.");
572 }
573 filesystem.close().await.expect("Close failed");
574 let device = filesystem.take_device().await;
575 device.reopen(false);
576 let filesystem = FxFilesystem::open(device).await.expect("open failed");
578 do_fsck(&filesystem, None, None).await;
579 for object_id in &parent_objects {
580 let _ = filesystem
581 .root_store()
582 .get_file_size(*object_id)
583 .await
584 .err()
585 .expect("File wasn't deleted.");
586 }
587 filesystem.close().await.expect("Close failed");
588 }
589
590 #[fuchsia::test]
591 async fn test_replace_volume() {
592 let device = DeviceHolder::new(FakeDevice::new(16384, 512));
593 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
594 {
596 let root = root_volume(fs.clone()).await.expect("root_volume failed");
597 let store = root.new_volume("vol", NewChildStoreOptions::default()).await.unwrap();
598 let mut transaction = fs
599 .root_store()
600 .new_transaction(
601 lock_keys![LockKey::object(
602 store.store_object_id(),
603 store.root_directory_object_id()
604 )],
605 Options::default(),
606 )
607 .await
608 .unwrap();
609 let root_directory =
610 Directory::open(&store, store.root_directory_object_id()).await.unwrap();
611 let _ = root_directory.create_child_file(&mut transaction, "foo").await.unwrap();
612 transaction.commit().await.expect("commit failed");
613 }
614 {
616 let root = root_volume(fs.clone()).await.expect("root_volume failed");
617 let store = root
618 .new_volume("vol2", NewChildStoreOptions::default())
619 .await
620 .expect("new_volume failed");
621 let mut transaction = fs
622 .root_store()
623 .new_transaction(
624 lock_keys![LockKey::object(
625 store.store_object_id(),
626 store.root_directory_object_id()
627 )],
628 Options::default(),
629 )
630 .await
631 .expect("new transaction failed");
632 let root_directory = Directory::open(&store, store.root_directory_object_id())
633 .await
634 .expect("open failed");
635 let _ = root_directory
636 .create_child_file(&mut transaction, "foo2")
637 .await
638 .expect("create_child_file failed");
639 transaction.commit().await.expect("commit failed");
640 }
641 {
643 let root = root_volume(fs.clone()).await.expect("root_volume failed");
644 let mut transaction = root
645 .acquire_transaction_for_remove_volume(
646 "vol",
647 [],
648 false,
649 Options {
650 reservation: ReservationOptions::BorrowedMetadata,
651 ..Default::default()
652 },
653 )
654 .await
655 .unwrap()
656 .1;
657 root.replace_volume(&mut transaction, "vol2", "vol").await.unwrap();
658 transaction.commit().await.unwrap();
659 do_fsck(&fs, Some("vol"), None).await;
660 }
661 fs.close().await.expect("Close failed");
662 let device = fs.take_device().await;
663 device.reopen(false);
664 let fs = FxFilesystem::open(device).await.unwrap();
665 do_fsck(&fs, Some("vol"), None).await;
666 {
667 let root = root_volume(fs.clone()).await.unwrap();
668 root.volume("vol2", StoreOptions::default())
670 .await
671 .err()
672 .expect("vol2 shouldn't exist anymore.");
673 let vol = root.volume("vol", StoreOptions::default()).await.unwrap();
674 let dir = Directory::open(&vol, vol.root_directory_object_id()).await.unwrap();
675 assert!(dir.lookup("foo").await.unwrap().is_none(), "foo should not be present");
677 assert!(dir.lookup("foo2").await.unwrap().is_some(), "foo2 should be present");
678 }
679 fs.close().await.unwrap();
680 }
681
682 #[fuchsia::test]
683 async fn test_create_volume_with_guid() {
684 let device = DeviceHolder::new(FakeDevice::new(16384, 512));
685 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
686 let guid = [1u8; 16];
687 {
688 let root = root_volume(fs.clone()).await.expect("root_volume failed");
689 let store = root
690 .new_volume("vol", NewChildStoreOptions { guid: Some(guid), ..Default::default() })
691 .await
692 .unwrap();
693 assert_eq!(store.store_info().unwrap().guid, guid);
694 }
695 fs.close().await.expect("Close failed");
696 let device = fs.take_device().await;
697 device.reopen(false);
698 let fs = FxFilesystem::open(device).await.unwrap();
699 {
700 let root = root_volume(fs.clone()).await.unwrap();
701 let vol = root.volume("vol", StoreOptions::default()).await.unwrap();
702 assert_eq!(vol.guid(), guid);
703 }
704 fs.close().await.unwrap();
705 }
706
707 #[test_case(false; "unencrypted")]
708 #[test_case(true; "encrypted")]
709 #[fuchsia::test]
710 async fn test_flush_on_open_to_update_version(encrypted: bool) {
711 if LATEST_VERSION == EARLIEST_SUPPORTED_VERSION {
713 return;
714 }
715
716 let device = DeviceHolder::new(FakeDevice::new(8192, 1024));
717 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
718 let crypt: Option<Arc<dyn Crypt>> =
719 if encrypted { Some(Arc::new(new_insecure_crypt())) } else { None };
720 {
721 let root_vol = root_volume(fs.clone()).await.expect("root_volume failed");
722 let store = root_vol
723 .new_volume(
724 "test",
725 NewChildStoreOptions {
726 options: StoreOptions { crypt: crypt.clone(), ..StoreOptions::default() },
727 ..Default::default()
728 },
729 )
730 .await
731 .expect("new_volume failed");
732
733 let parent_store = store.parent_store().unwrap();
734 let txn_options = Options {
735 skip_journal_checks: true,
736 reservation: ReservationOptions::BorrowedMetadataAndData,
737 ..Default::default()
738 };
739 let mut transaction = parent_store
740 .new_transaction(lock_keys![], txn_options)
741 .await
742 .expect("new_transaction failed");
743 let new_layer_object = if let Some(crypt) = &crypt {
744 let raw_id = parent_store.get_next_object_id(&transaction).await.unwrap();
745 let (fxfs_key, unwrapped_key) =
746 crypt.create_key(raw_id.get(), KeyPurpose::Data).await.unwrap();
747 ObjectStore::create_object_with_key(
748 &parent_store,
749 &mut transaction,
750 raw_id,
751 HandleOptions { skip_journal_checks: true, ..Default::default() },
752 EncryptionKey::Fxfs(fxfs_key),
753 unwrapped_key,
754 )
755 .await
756 .expect("create_object_with_key failed")
757 } else {
758 ObjectStore::create_object(
759 &parent_store,
760 &mut transaction,
761 HandleOptions { skip_journal_checks: true, ..Default::default() },
762 None,
763 )
764 .await
765 .expect("create_object failed")
766 };
767 transaction.commit().await.expect("commit failed");
768
769 {
771 let layer_writer = DirectWriter::new(&new_layer_object, txn_options).await;
772 let writer = PersistentLayerWriter::<_, ObjectKey, ObjectValue>::new_with_version(
773 layer_writer,
774 0,
775 fs.block_size(),
776 EARLIEST_SUPPORTED_VERSION,
777 )
778 .await
779 .expect("writer failed");
780 writer.complete().await.expect("writer complete failed");
781 }
782
783 let mut store_info = store.load_store_info().await.unwrap();
784 store_info.layers = vec![new_layer_object.object_id()];
785 let mut end_transaction = parent_store
786 .new_transaction(
787 lock_keys![LockKey::object(
788 parent_store.store_object_id(),
789 store.store_info_handle_object_id().unwrap()
790 )],
791 txn_options,
792 )
793 .await
794 .expect("new_transaction failed");
795 store
796 .write_store_info(&mut end_transaction, &store_info)
797 .await
798 .expect("write_store_info failed");
799 end_transaction.commit().await.expect("commit failed");
800 }
801 fs.close().await.expect("close failed");
802
803 let device = fs.take_device().await;
805 device.reopen(false);
806 let fs = FxFilesystem::open(device).await.expect("open failed");
807 {
808 let root_vol = root_volume(fs.clone()).await.expect("root_volume failed");
809 let _store = root_vol
810 .volume("test", StoreOptions { crypt: crypt.clone(), ..StoreOptions::default() })
811 .await
812 .expect("volume failed");
813 }
814
815 fs.close().await.expect("close failed");
817
818 let device = fs.take_device().await;
820 device.reopen(false);
821 let fs = FxFilesystem::open(device).await.expect("open failed");
822 {
823 let root_vol = root_volume(fs.clone()).await.expect("root_volume failed");
824 let store = root_vol
825 .volume("test", StoreOptions { crypt: crypt.clone(), ..StoreOptions::default() })
826 .await
827 .expect("volume failed");
828
829 assert_eq!(store.tree.get_earliest_version(), LATEST_VERSION);
830 }
831
832 fs.close().await.expect("close failed");
833 }
834
835 #[fuchsia::test]
836 async fn test_delete_volume_borrows_and_returns_metadata_space() {
837 let device = DeviceHolder::new(FakeDevice::new(8192, 4096));
838 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
839 let root = root_volume(fs.clone()).await.expect("root_volume failed");
840 let store = root
841 .new_volume("vol", NewChildStoreOptions::default())
842 .await
843 .expect("new_volume failed");
844
845 let dir = Directory::open(&store, store.root_directory_object_id()).await.expect("open");
846 for i in 0..200 {
847 let mut transaction = store
848 .new_transaction(
849 lock_keys![LockKey::object(store.store_object_id(), dir.object_id())],
850 Options::default(),
851 )
852 .await
853 .expect("new_transaction failed");
854 dir.create_child_file(&mut transaction, &format!("f_{i}"))
855 .await
856 .expect("create_child_file failed");
857 transaction.commit().await.expect("commit failed");
858 }
859
860 fs.journal().force_compact().await.expect("force_compact failed");
861 fs.journal().pause_compactions().await;
862
863 {
867 let mut transaction = store
868 .new_transaction(
869 lock_keys![LockKey::object(store.store_object_id(), dir.object_id())],
870 Options::default(),
871 )
872 .await
873 .expect("new_transaction failed");
874 dir.create_child_file(&mut transaction, "extra")
875 .await
876 .expect("create_child_file failed");
877 transaction.commit().await.expect("commit failed");
878 }
879 store.flush().await.expect("flush failed");
880 std::mem::drop(dir);
881 std::mem::drop(store);
882
883 let metadata_before = fs.object_manager().metadata_reservation().amount();
884
885 let mut reservations = Vec::new();
888 let mut chunk = 16 * 1024 * 1024;
889 while chunk >= 4096 {
890 if let Some(r) = fs.allocator().reserve(None, chunk) {
891 reservations.push(r);
892 } else {
893 chunk /= 2;
894 }
895 }
896
897 let (_, transaction) = root
898 .acquire_transaction_for_remove_volume(
899 "vol",
900 [],
901 false,
902 Options { reservation: ReservationOptions::BorrowedMetadata, ..Default::default() },
903 )
904 .await
905 .expect("acquire_transaction_for_remove_volume failed");
906 root.delete_volume("vol", transaction, || {}).await.expect("delete_volume failed");
907
908 let metadata_after = fs.object_manager().metadata_reservation().amount();
909 assert!(
910 metadata_after > metadata_before,
911 "delete_volume should return tombstoned root_store layer blocks to \
912 metadata_reservation (before: {metadata_before}, after: {metadata_after})"
913 );
914
915 std::mem::drop(reservations);
916 fs.journal().resume_compactions();
917 fs.close().await.expect("close failed");
918 }
919}