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