1use crate::errors::FxfsError;
6use crate::filesystem::FxFilesystem;
7use crate::object_store::directory::Directory;
8use crate::object_store::flush::Reason;
9use crate::object_store::transaction::{LockKeys, Mutation, Options, Transaction, lock_keys};
10use crate::object_store::tree_cache::TreeCache;
11use crate::object_store::{
12 ChildValue, DirType, INVALID_OBJECT_ID, LockKey, NewChildStoreOptions, ObjectDescriptor,
13 ObjectKey, ObjectStore, ObjectValue, StoreOptions, load_store_info,
14};
15use crate::serialized_types::LATEST_VERSION;
16use anyhow::{Context, Error, anyhow, bail, ensure};
17use log::error;
18use std::sync::Arc;
19
20pub const VOLUMES_DIRECTORY: &str = "volumes";
28
29pub struct RootVolume {
31 _root_directory: Directory<ObjectStore>,
32 filesystem: Arc<FxFilesystem>,
33}
34
35impl RootVolume {
36 pub fn volume_directory(&self) -> &Directory<ObjectStore> {
37 self.filesystem.object_manager().volume_directory()
38 }
39
40 pub async fn new_volume(
42 &self,
43 volume_name: &str,
44 options: NewChildStoreOptions,
45 ) -> Result<Arc<ObjectStore>, Error> {
46 let root_store = self.filesystem.root_store();
47 let store;
48 let mut transaction = root_store
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(&mut transaction, options, Box::new(TreeCache::new()))
64 .await?;
65 store.set_trace(self.filesystem.trace());
66
67 self.filesystem.object_manager().add_store(store.clone());
69
70 struct CleanUp<'a>(&'a ObjectStore);
72 impl Drop for CleanUp<'_> {
73 fn drop(&mut self) {
74 self.0.filesystem().object_manager().forget_store(self.0.store_object_id());
75 }
76 }
77 let clean_up = CleanUp(&store);
78
79 store.create(&mut transaction).await?;
81
82 self.volume_directory()
83 .add_child_volume(&mut transaction, volume_name, store.store_object_id())
84 .await?;
85 transaction.commit().await?;
86
87 std::mem::forget(clean_up);
88
89 Ok(store)
90 }
91
92 pub async fn volume(
94 &self,
95 volume_name: &str,
96 options: StoreOptions,
97 ) -> Result<Arc<ObjectStore>, Error> {
98 let (store_object_id, descriptor, _) = self
100 .volume_directory()
101 .lookup(volume_name)
102 .await
103 .context("Volume lookup failed")?
104 .ok_or(FxfsError::NotFound)
105 .context("Volume missing in volume directory")?;
106 match descriptor {
107 ObjectDescriptor::Volume => (),
108 _ => bail!(anyhow!(FxfsError::Inconsistent).context("Expected volume")),
109 }
110 let store = self
112 .filesystem
113 .object_manager()
114 .store(store_object_id)
115 .ok_or(FxfsError::NotFound)
116 .context("Missing volume store")?;
117 store.set_trace(self.filesystem.trace());
118 if let Some(crypt) = options.crypt {
120 let read_only = self.filesystem.options().read_only;
121 store.unlock_inner(crypt, read_only).await.context("Failed to unlock volume")?;
122 } else if store.is_locked() {
123 bail!(FxfsError::AccessDenied);
124 }
125 if let Some(scope_guard) = self.filesystem.scope().active_guard()
127 && !self.filesystem.options().read_only
128 && store.tree().get_earliest_version() != LATEST_VERSION
129 {
130 let keys = lock_keys![LockKey::flush(store_object_id)];
131 let guard = self
132 .filesystem
133 .lock_manager()
134 .write_lock(keys)
135 .await
136 .into_owned(self.filesystem.clone());
137 let store = store.clone();
138 self.filesystem.scope().spawn(async move {
139 let _guard = guard;
143 let _scope_guard = scope_guard;
149 if let Err(error) = store.flush_guarded_with_reason(Reason::UpgradeVersion).await {
150 error!(error:?; "Failed background flush");
151 }
152 });
153 }
154 Ok(store)
155 }
156
157 pub async fn delete_volume(
160 &self,
161 volume_name: &str,
162 mut transaction: Transaction<'_>,
163 callback: impl FnOnce() + Send,
164 ) -> Result<(), Error> {
165 let objects_to_delete = self.delete_volume_impl(volume_name, &mut transaction).await?;
166 transaction.commit_with_callback(|_| callback()).await.context("commit")?;
167 let root_store = self.filesystem.root_store();
169 for object_id in &objects_to_delete {
170 root_store.tombstone_object(*object_id, Options::default()).await?;
171 }
172 Ok(())
173 }
174
175 async fn delete_volume_impl(
176 &self,
177 volume_name: &str,
178 transaction: &mut Transaction<'_>,
179 ) -> Result<Vec<u64>, Error> {
180 let object_id =
181 match self.volume_directory().lookup(volume_name).await?.ok_or(FxfsError::NotFound)? {
182 (object_id, ObjectDescriptor::Volume, _) => object_id,
183 _ => bail!(anyhow!(FxfsError::Inconsistent).context("Expected volume")),
184 };
185 let root_store = self.filesystem.root_store();
186
187 let mut objects_to_delete = load_store_info(&root_store, object_id).await?.parent_objects();
190 objects_to_delete.push(object_id);
191
192 for object_id in &objects_to_delete {
193 root_store.adjust_refs(transaction, *object_id, -1).await?;
194 }
195 self.filesystem.allocator().mark_for_deletion(transaction, object_id);
197 self.volume_directory().delete_child_volume(transaction, volume_name, object_id)?;
199 Ok(objects_to_delete)
200 }
201
202 pub(crate) async fn replace_volume(
206 &self,
207 transaction: &mut Transaction<'_>,
208 src: &str,
209 dst: &str,
210 ) -> Result<Option<Vec<u64>>, Error> {
211 let src_object_id = match self.volume_directory().lookup(src).await? {
212 Some((object_id, ObjectDescriptor::Volume, _)) => Ok(object_id),
213 Some(_) => Err(FxfsError::Inconsistent),
214 None => Err(FxfsError::NotFound),
215 }?;
216
217 let replaced_objects = if let Some((_, ObjectDescriptor::Volume, _)) =
218 self.volume_directory().lookup(dst).await?
219 {
220 Some(self.delete_volume_impl(dst, transaction).await?)
221 } else {
222 None
223 };
224
225 transaction.add(
226 self.volume_directory().store().store_object_id(),
227 Mutation::replace_or_insert_object(
228 ObjectKey::child(self.volume_directory().object_id(), src, DirType::Normal),
229 ObjectValue::None,
230 ),
231 );
232
233 transaction.add(
234 self.volume_directory().store().store_object_id(),
235 Mutation::replace_or_insert_object(
236 ObjectKey::child(self.volume_directory().object_id(), dst, DirType::Normal),
237 ObjectValue::Child(ChildValue {
238 object_id: src_object_id,
239 object_descriptor: ObjectDescriptor::Volume,
240 }),
241 ),
242 );
243
244 Ok(replaced_objects)
245 }
246
247 pub async fn install_volume(
255 &self,
256 src: &str,
257 image_file: &str,
258 dst: &str,
259 ) -> Result<(), Error> {
260 ObjectStore::install_volume(self, src, image_file, dst).await
261 }
262
263 pub async fn acquire_transaction_for_remove_volume(
266 &self,
267 name: &str,
268 extra_keys: impl IntoIterator<Item = LockKey>,
269 allow_not_found: bool,
270 ) -> Result<(u64, Transaction<'_>), Error> {
271 let volume_dir = self.volume_directory();
275 let store = volume_dir.store();
276 let extra_keys = extra_keys.into_iter();
277 let mut lock_keys = Vec::with_capacity(extra_keys.size_hint().1.unwrap_or(2) + 2);
278 lock_keys.extend(extra_keys);
279 lock_keys.push(LockKey::object(store.store_object_id(), volume_dir.object_id()));
280 let orig_len = lock_keys.len();
281 let mut transaction = None;
282 loop {
283 lock_keys.truncate(orig_len);
284 let object_id = match volume_dir.lookup(name).await? {
285 Some((object_id, ObjectDescriptor::Volume, _)) => {
286 lock_keys.push(LockKey::flush(object_id));
290 object_id
291 }
292 None => {
293 if allow_not_found {
294 INVALID_OBJECT_ID
295 } else {
296 bail!(FxfsError::NotFound);
297 }
298 }
299 _ => bail!(anyhow!(FxfsError::Inconsistent).context("Expected volume")),
300 };
301
302 match transaction {
304 Some(result @ (id, _)) if id == object_id => return Ok(result),
305 _ => {}
306 }
307
308 transaction = Some((
309 object_id,
310 store
311 .new_transaction(
312 LockKeys::Vec(lock_keys.clone()),
313 Options { borrow_metadata_space: true, ..Default::default() },
314 )
315 .await?,
316 ));
317 }
318 }
319}
320
321pub async fn root_volume(filesystem: Arc<FxFilesystem>) -> Result<RootVolume, Error> {
323 let root_store = filesystem.root_store();
324 let root_directory = Directory::open(&root_store, root_store.root_directory_object_id())
325 .await
326 .context("Unable to open root volume directory")?;
327 Ok(RootVolume { _root_directory: root_directory, filesystem })
328}
329
330pub async fn list_volumes(volume_directory: &Directory<ObjectStore>) -> Result<Vec<u64>, Error> {
332 let layer_set = volume_directory.store().tree().layer_set();
333 let mut merger = layer_set.merger();
334 let mut iter = volume_directory.iter(&mut merger).await?;
335 let mut object_ids = vec![];
336 while let Some((_, id, _)) = iter.get() {
337 object_ids.push(id);
338 iter.advance().await?;
339 }
340 Ok(object_ids)
341}
342
343#[cfg(test)]
344mod tests {
345 use super::root_volume;
346 use crate::filesystem::{FxFilesystem, JournalingObject, SyncOptions};
347 use crate::fsck::{FsckOptions, fsck_volume_with_options, fsck_with_options};
348 use crate::lsm_tree::persistent_layer::PersistentLayerWriter;
349 use crate::lsm_tree::types::LayerWriter as _;
350 use crate::object_handle::{ObjectHandle, WriteObjectHandle};
351 use crate::object_store::directory::Directory;
352 use crate::object_store::transaction::{Options, lock_keys};
353 use crate::object_store::{
354 DirectWriter, HandleOptions, LockKey, NewChildStoreOptions, ObjectKey, ObjectStore,
355 ObjectValue, StoreOptions,
356 };
357 use crate::serialized_types::{EARLIEST_SUPPORTED_VERSION, LATEST_VERSION};
358 use fxfs_crypto::{Crypt, EncryptionKey, KeyPurpose};
359 use fxfs_insecure_crypto::new_insecure_crypt;
360 use std::sync::Arc;
361 use storage_device::DeviceHolder;
362 use storage_device::fake_device::FakeDevice;
363 use test_case::test_case;
364
365 async fn do_fsck(
366 fs: &Arc<FxFilesystem>,
367 volume_name: Option<&str>,
368 crypt: Option<Arc<dyn Crypt>>,
369 ) {
370 let fsck_options = FsckOptions {
371 fail_on_warning: true,
372 on_error: Box::new(|err| eprintln!("fsck error: {:?}", err)),
373 ..Default::default()
374 };
375 fsck_with_options(fs.clone(), &fsck_options).await.expect("fsck filesystem");
376 if let Some(volume_name) = volume_name {
377 let root = root_volume(fs.clone()).await.unwrap();
378 let vol = root
379 .volume(
380 volume_name,
381 StoreOptions { crypt: crypt.clone(), ..StoreOptions::default() },
382 )
383 .await
384 .expect("could not open volume");
385 fsck_volume_with_options(&fs, &fsck_options, vol.store_object_id(), crypt)
386 .await
387 .expect("fsck volume");
388 }
389 }
390
391 #[fuchsia::test]
392 async fn test_lookup_nonexistent_volume() {
393 let device = DeviceHolder::new(FakeDevice::new(8192, 512));
394 let filesystem = FxFilesystem::new_empty(device).await.expect("new_empty failed");
395 let root_volume = root_volume(filesystem.clone()).await.expect("root_volume failed");
396 root_volume
397 .volume(
398 "vol",
399 StoreOptions {
400 crypt: Some(Arc::new(new_insecure_crypt())),
401 ..StoreOptions::default()
402 },
403 )
404 .await
405 .err()
406 .expect("Volume shouldn't exist");
407 filesystem.close().await.expect("Close failed");
408 }
409
410 #[fuchsia::test]
411 async fn test_add_volume() {
412 let device = DeviceHolder::new(FakeDevice::new(16384, 512));
413 let filesystem = FxFilesystem::new_empty(device).await.expect("new_empty failed");
414 let crypt = Arc::new(new_insecure_crypt());
415 {
416 let root_volume = root_volume(filesystem.clone()).await.expect("root_volume failed");
417 let store = root_volume
418 .new_volume(
419 "vol",
420 NewChildStoreOptions {
421 options: StoreOptions {
422 crypt: Some(crypt.clone()),
423 ..StoreOptions::default()
424 },
425 ..Default::default()
426 },
427 )
428 .await
429 .expect("new_volume failed");
430 let mut transaction = filesystem
431 .root_store()
432 .new_transaction(
433 lock_keys![LockKey::object(
434 store.store_object_id(),
435 store.root_directory_object_id()
436 )],
437 Options::default(),
438 )
439 .await
440 .expect("new transaction failed");
441 let root_directory = Directory::open(&store, store.root_directory_object_id())
442 .await
443 .expect("open failed");
444 root_directory
445 .create_child_file(&mut transaction, "foo")
446 .await
447 .expect("create_child_file failed");
448 transaction.commit().await.expect("commit failed");
449 filesystem.sync(SyncOptions::default()).await.expect("sync failed");
450 };
451 {
452 filesystem.close().await.expect("Close failed");
453 let device = filesystem.take_device().await;
454 device.reopen(false);
455 let filesystem = FxFilesystem::open(device).await.expect("open failed");
456 do_fsck(&filesystem, Some("vol"), Some(crypt)).await;
457 let root_volume = root_volume(filesystem.clone()).await.expect("root_volume failed");
458 let volume = root_volume
460 .volume("vol", StoreOptions { crypt: None, ..StoreOptions::default() })
461 .await
462 .expect("volume failed");
463 let root_directory = Directory::open(&volume, volume.root_directory_object_id())
464 .await
465 .expect("open failed");
466 root_directory.lookup("foo").await.expect("lookup failed").expect("not found");
467 filesystem.close().await.expect("Close failed");
468 };
469 }
470
471 #[fuchsia::test]
472 async fn test_delete_volume() {
473 let device = DeviceHolder::new(FakeDevice::new(16384, 512));
474 let filesystem = FxFilesystem::new_empty(device).await.expect("new_empty failed");
475 let crypt = Arc::new(new_insecure_crypt());
476 let store_object_id;
477 let parent_objects;
478 let store_id = {
480 let root_volume = root_volume(filesystem.clone()).await.expect("root_volume failed");
481 let store = root_volume
482 .new_volume(
483 "vol",
484 NewChildStoreOptions {
485 options: StoreOptions {
486 crypt: Some(crypt.clone()),
487 ..StoreOptions::default()
488 },
489 ..Default::default()
490 },
491 )
492 .await
493 .expect("new_volume failed");
494 store_object_id = store.store_object_id();
495 let mut transaction = filesystem
496 .root_store()
497 .new_transaction(
498 lock_keys![LockKey::object(store_object_id, store.root_directory_object_id())],
499 Options::default(),
500 )
501 .await
502 .expect("new transaction failed");
503 let root_directory = Directory::open(&store, store.root_directory_object_id())
504 .await
505 .expect("open failed");
506 let handle = root_directory
507 .create_child_file(&mut transaction, "foo")
508 .await
509 .expect("create_child_file failed");
510 transaction.commit().await.expect("commit failed");
511
512 let mut buf = handle.allocate_buffer(8192).await;
513 buf.fill(0xaa);
514 handle.write_or_append(Some(0), buf.as_ref()).await.expect("write failed");
515 store.flush().await.expect("flush failed");
516 filesystem.sync(SyncOptions::default()).await.expect("sync failed");
517 parent_objects = store.parent_objects();
518 for object_id in &parent_objects {
520 let _ = filesystem
521 .root_store()
522 .get_file_size(*object_id)
523 .await
524 .expect("Layer file missing? Bug in test.");
525 }
526 store.store_object_id()
527 };
528 filesystem.close().await.expect("Close failed");
529 let device = filesystem.take_device().await;
530 device.reopen(false);
531 let filesystem = FxFilesystem::open(device).await.expect("open failed");
532 do_fsck(&filesystem, Some("vol"), Some(crypt.clone())).await;
533 {
534 assert_eq!(
536 filesystem.allocator().get_owner_allocated_bytes().get(&store_object_id),
537 Some(&8192)
538 );
539 let root = root_volume(filesystem.clone()).await.expect("root_volume failed");
540 let transaction = filesystem
541 .root_store()
542 .new_transaction(
543 lock_keys![
544 LockKey::object(
545 root.volume_directory().store().store_object_id(),
546 root.volume_directory().object_id(),
547 ),
548 LockKey::flush(store_id)
549 ],
550 Options { borrow_metadata_space: true, ..Default::default() },
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 =
645 root.acquire_transaction_for_remove_volume("vol", [], false).await.unwrap().1;
646 root.replace_volume(&mut transaction, "vol2", "vol").await.unwrap();
647 transaction.commit().await.unwrap();
648 do_fsck(&fs, Some("vol"), None).await;
649 }
650 fs.close().await.expect("Close failed");
651 let device = fs.take_device().await;
652 device.reopen(false);
653 let fs = FxFilesystem::open(device).await.unwrap();
654 do_fsck(&fs, Some("vol"), None).await;
655 {
656 let root = root_volume(fs.clone()).await.unwrap();
657 root.volume("vol2", StoreOptions::default())
659 .await
660 .err()
661 .expect("vol2 shouldn't exist anymore.");
662 let vol = root.volume("vol", StoreOptions::default()).await.unwrap();
663 let dir = Directory::open(&vol, vol.root_directory_object_id()).await.unwrap();
664 assert!(dir.lookup("foo").await.unwrap().is_none(), "foo should not be present");
666 assert!(dir.lookup("foo2").await.unwrap().is_some(), "foo2 should be present");
667 }
668 fs.close().await.unwrap();
669 }
670
671 #[fuchsia::test]
672 async fn test_create_volume_with_guid() {
673 let device = DeviceHolder::new(FakeDevice::new(16384, 512));
674 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
675 let guid = [1u8; 16];
676 {
677 let root = root_volume(fs.clone()).await.expect("root_volume failed");
678 let store = root
679 .new_volume("vol", NewChildStoreOptions { guid: Some(guid), ..Default::default() })
680 .await
681 .unwrap();
682 assert_eq!(store.store_info().unwrap().guid, guid);
683 }
684 fs.close().await.expect("Close failed");
685 let device = fs.take_device().await;
686 device.reopen(false);
687 let fs = FxFilesystem::open(device).await.unwrap();
688 {
689 let root = root_volume(fs.clone()).await.unwrap();
690 let vol = root.volume("vol", StoreOptions::default()).await.unwrap();
691 assert_eq!(vol.guid(), guid);
692 }
693 fs.close().await.unwrap();
694 }
695
696 #[test_case(false; "unencrypted")]
697 #[test_case(true; "encrypted")]
698 #[fuchsia::test]
699 async fn test_flush_on_open_to_update_version(encrypted: bool) {
700 if LATEST_VERSION == EARLIEST_SUPPORTED_VERSION {
702 return;
703 }
704
705 let device = DeviceHolder::new(FakeDevice::new(8192, 1024));
706 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
707 let crypt: Option<Arc<dyn Crypt>> =
708 if encrypted { Some(Arc::new(new_insecure_crypt())) } else { None };
709 {
710 let root_vol = root_volume(fs.clone()).await.expect("root_volume failed");
711 let store = root_vol
712 .new_volume(
713 "test",
714 NewChildStoreOptions {
715 options: StoreOptions { crypt: crypt.clone(), ..StoreOptions::default() },
716 ..Default::default()
717 },
718 )
719 .await
720 .expect("new_volume failed");
721
722 let parent_store = store.parent_store().unwrap();
723 let txn_options = Options {
724 skip_journal_checks: true,
725 skip_key_roll: true,
726 borrow_metadata_space: true,
727 allocator_reservation: Some(fs.object_manager().metadata_reservation()),
728 ..Default::default()
729 };
730 let mut transaction = parent_store
731 .new_transaction(lock_keys![], txn_options)
732 .await
733 .expect("new_transaction failed");
734 let new_layer_object = if let Some(crypt) = &crypt {
735 let raw_id = parent_store.get_next_object_id().await.unwrap();
736 let (fxfs_key, unwrapped_key) =
737 crypt.create_key(raw_id.get(), KeyPurpose::Data).await.unwrap();
738 ObjectStore::create_object_with_key(
739 &parent_store,
740 &mut transaction,
741 raw_id,
742 HandleOptions { skip_journal_checks: true, ..Default::default() },
743 EncryptionKey::Fxfs(fxfs_key),
744 unwrapped_key,
745 )
746 .await
747 .expect("create_object_with_key failed")
748 } else {
749 ObjectStore::create_object(
750 &parent_store,
751 &mut transaction,
752 HandleOptions { skip_journal_checks: true, ..Default::default() },
753 None,
754 )
755 .await
756 .expect("create_object failed")
757 };
758 transaction.commit().await.expect("commit failed");
759
760 {
762 let layer_writer = DirectWriter::new(&new_layer_object, txn_options).await;
763 let writer = PersistentLayerWriter::<_, ObjectKey, ObjectValue>::new_with_version(
764 layer_writer,
765 0,
766 fs.block_size(),
767 EARLIEST_SUPPORTED_VERSION,
768 )
769 .await
770 .expect("writer failed");
771 writer.complete().await.expect("writer complete failed");
772 }
773
774 let mut store_info = store.load_store_info().await.unwrap();
775 store_info.layers = vec![new_layer_object.object_id()];
776 let mut end_transaction = parent_store
777 .new_transaction(
778 lock_keys![LockKey::object(
779 parent_store.store_object_id(),
780 store.store_info_handle_object_id().unwrap()
781 )],
782 txn_options,
783 )
784 .await
785 .expect("new_transaction failed");
786 store
787 .write_store_info(&mut end_transaction, &store_info)
788 .await
789 .expect("write_store_info failed");
790 end_transaction.commit().await.expect("commit failed");
791 }
792 fs.close().await.expect("close failed");
793
794 let device = fs.take_device().await;
796 device.reopen(false);
797 let fs = FxFilesystem::open(device).await.expect("open failed");
798 {
799 let root_vol = root_volume(fs.clone()).await.expect("root_volume failed");
800 let _store = root_vol
801 .volume("test", StoreOptions { crypt: crypt.clone(), ..StoreOptions::default() })
802 .await
803 .expect("volume failed");
804 }
805
806 fs.close().await.expect("close failed");
808
809 let device = fs.take_device().await;
811 device.reopen(false);
812 let fs = FxFilesystem::open(device).await.expect("open failed");
813 {
814 let root_vol = root_volume(fs.clone()).await.expect("root_volume failed");
815 let store = root_vol
816 .volume("test", StoreOptions { crypt: crypt.clone(), ..StoreOptions::default() })
817 .await
818 .expect("volume failed");
819
820 assert_eq!(store.tree.get_earliest_version(), LATEST_VERSION);
821 }
822
823 fs.close().await.expect("close failed");
824 }
825}