1use crate::errors::FxfsError;
26use crate::filesystem::{ApplyContext, ApplyMode, Filesystem, JournalingObject};
27use crate::log::*;
28use crate::lsm_tree::types::LayerIterator;
29use crate::lsm_tree::{LSMTree, LayerSet, Query};
30use crate::metrics;
31use crate::object_handle::ObjectHandle as _;
32use crate::object_store::data_object_handle::{FileExtent, OverwriteOptions};
33use crate::object_store::journal::bootstrap_handle::BootstrapObjectHandle;
34use crate::object_store::journal::reader::{JournalReader, ReadResult};
35use crate::object_store::journal::writer::JournalWriter;
36use crate::object_store::journal::{BLOCK_SIZE, JournalCheckpoint, JournalCheckpointV32};
37use crate::object_store::object_record::{ObjectItem, ObjectItemV56, ObjectItemV59, ObjectItemV62};
38use crate::object_store::transaction::{AssocObj, Options, ReservationOptions};
39use crate::object_store::tree::MajorCompactable;
40use crate::object_store::{
41 DataObjectHandle, HandleOptions, HandleOwner, Mutation, ObjectKey, ObjectStore, ObjectValue,
42};
43use crate::range::RangeExt;
44use crate::serialized_types::{
45 EARLIEST_SUPPORTED_VERSION, Migrate, Version, Versioned, VersionedLatest, migrate_nodefault,
46 migrate_to_version,
47};
48use anyhow::{Context, Error, bail, ensure};
49use fprint::TypeFingerprint;
50use fuchsia_inspect::{Property as _, UintProperty};
51use fuchsia_sync::Mutex;
52use futures::FutureExt;
53use rustc_hash::FxHashMap as HashMap;
54use serde::{Deserialize, Serialize};
55use std::collections::{HashSet, VecDeque};
56use std::fmt;
57use std::io::{Read, Write};
58use std::ops::Range;
59use std::sync::Arc;
60use std::time::SystemTime;
61use storage_device::Device;
62use storage_units::BlockSize;
63use uuid::Uuid;
64
65const SUPER_BLOCK_A_OBJECT_ID: u64 = 1;
67const SUPER_BLOCK_B_OBJECT_ID: u64 = 2;
68
69pub const SUPER_BLOCK_CHUNK_SIZE: u64 = 65536;
71
72pub(crate) const MIN_SUPER_BLOCK_SIZE: u64 = 4096;
74
75const SUPER_BLOCK_MAGIC: &[u8; 8] = b"FxfsSupr";
77
78#[derive(Copy, Clone, Debug, Eq, PartialEq)]
83pub enum SuperBlockInstance {
84 A,
85 B,
86}
87
88impl SuperBlockInstance {
89 pub fn next(&self) -> SuperBlockInstance {
91 match self {
92 SuperBlockInstance::A => SuperBlockInstance::B,
93 SuperBlockInstance::B => SuperBlockInstance::A,
94 }
95 }
96
97 pub fn object_id(&self) -> u64 {
98 match self {
99 SuperBlockInstance::A => SUPER_BLOCK_A_OBJECT_ID,
100 SuperBlockInstance::B => SUPER_BLOCK_B_OBJECT_ID,
101 }
102 }
103
104 pub fn first_extent(&self) -> Range<u64> {
107 match self {
108 SuperBlockInstance::A => 0..MIN_SUPER_BLOCK_SIZE,
109 SuperBlockInstance::B => 524288..524288 + MIN_SUPER_BLOCK_SIZE,
110 }
111 }
112}
113
114pub type SuperBlockHeader = SuperBlockHeaderV61;
115
116#[derive(
117 Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize, TypeFingerprint, Versioned,
118)]
119pub struct SuperBlockHeaderV61 {
120 pub guid: UuidWrapperV32,
122
123 pub generation: u64,
127
128 pub root_parent_store_object_id: u64,
132
133 pub root_parent_graveyard_directory_object_id: u64,
136
137 pub root_store_object_id: u64,
140
141 pub allocator_object_id: u64,
143
144 pub journal_object_id: u64,
146
147 pub journal_checkpoint: JournalCheckpointV32,
149
150 pub super_block_journal_file_offset: u64,
154
155 pub journal_file_offsets: HashMap<u64, u64>,
157
158 pub reserved_metadata_space: HashMap<u64, u64>,
162
163 pub earliest_version: Version,
167}
168
169#[derive(Serialize, Deserialize, TypeFingerprint, Versioned)]
170pub struct SuperBlockHeaderV32 {
171 guid: UuidWrapperV32,
172 generation: u64,
173 root_parent_store_object_id: u64,
174 root_parent_graveyard_directory_object_id: u64,
175 root_store_object_id: u64,
176 allocator_object_id: u64,
177 journal_object_id: u64,
178 journal_checkpoint: JournalCheckpointV32,
179 super_block_journal_file_offset: u64,
180 journal_file_offsets: HashMap<u64, u64>,
181 borrowed_metadata_space: u64,
182 earliest_version: Version,
183}
184
185impl From<SuperBlockHeaderV32> for SuperBlockHeaderV61 {
186 fn from(header: SuperBlockHeaderV32) -> Self {
187 SuperBlockHeaderV61 {
188 guid: header.guid,
189 generation: header.generation,
190 root_parent_store_object_id: header.root_parent_store_object_id,
191 root_parent_graveyard_directory_object_id: header
192 .root_parent_graveyard_directory_object_id,
193 root_store_object_id: header.root_store_object_id,
194 allocator_object_id: header.allocator_object_id,
195 journal_object_id: header.journal_object_id,
196 journal_checkpoint: header.journal_checkpoint,
197 super_block_journal_file_offset: header.super_block_journal_file_offset,
198 journal_file_offsets: header.journal_file_offsets,
199
200 reserved_metadata_space: HashMap::from_iter([(0, header.borrowed_metadata_space)]),
204 earliest_version: header.earliest_version,
205 }
206 }
207}
208
209type UuidWrapper = UuidWrapperV32;
210#[derive(Clone, Default, Eq, PartialEq)]
211pub struct UuidWrapperV32(pub Uuid);
212
213impl UuidWrapper {
214 fn new() -> Self {
215 Self(Uuid::new_v4())
216 }
217 #[cfg(test)]
218 fn nil() -> Self {
219 Self(Uuid::nil())
220 }
221}
222
223impl fmt::Debug for UuidWrapper {
224 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
225 f.write_str("<redacted>")
228 }
229}
230
231impl TypeFingerprint for UuidWrapper {
232 fn fingerprint() -> String {
233 "<[u8;16]>".to_owned()
234 }
235}
236
237impl Serialize for UuidWrapper {
240 fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
241 self.0.as_bytes().serialize(serializer)
242 }
243}
244
245impl<'de> Deserialize<'de> for UuidWrapper {
246 fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
247 <[u8; 16]>::deserialize(deserializer).map(|bytes| UuidWrapperV32(Uuid::from_bytes(bytes)))
248 }
249}
250
251pub type SuperBlockRecord = SuperBlockRecordV62;
252
253#[allow(clippy::large_enum_variant)]
254#[derive(Debug, Serialize, Deserialize, TypeFingerprint, Versioned)]
255pub enum SuperBlockRecordV62 {
256 Extent(Range<u64>),
259
260 ObjectItem(ObjectItemV62),
263
264 End,
266}
267
268#[allow(clippy::large_enum_variant)]
269#[derive(Migrate, Debug, Serialize, Deserialize, TypeFingerprint, Versioned)]
270#[migrate_to_version(SuperBlockRecordV62)]
271#[migrate_nodefault]
272pub enum SuperBlockRecordV59 {
273 Extent(Range<u64>),
274 ObjectItem(ObjectItemV59),
275 End,
276}
277
278#[allow(clippy::large_enum_variant)]
279#[derive(Migrate, Debug, Serialize, Deserialize, TypeFingerprint, Versioned)]
280#[migrate_to_version(SuperBlockRecordV59)]
281#[migrate_nodefault]
282pub enum SuperBlockRecordV56 {
283 Extent(Range<u64>),
284 ObjectItem(ObjectItemV56),
285 End,
286}
287
288struct SuperBlockMetrics {
289 last_super_block_update_time_ms: UintProperty,
292
293 last_super_block_offset: UintProperty,
295}
296
297impl Default for SuperBlockMetrics {
298 fn default() -> Self {
299 SuperBlockMetrics {
300 last_super_block_update_time_ms: metrics::detail()
301 .create_uint("last_super_block_update_time_ms", 0),
302 last_super_block_offset: metrics::detail().create_uint("last_super_block_offset", 0),
303 }
304 }
305}
306
307async fn read(
310 device: Arc<dyn Device>,
311 block_size: BlockSize,
312 instance: SuperBlockInstance,
313) -> Result<(SuperBlockHeader, SuperBlockInstance, ObjectStore), Error> {
314 let (super_block_header, mut reader) = SuperBlockHeader::read_header(device.clone(), instance)
315 .await
316 .context("failed to read superblock")?;
317 let root_parent = ObjectStore::new_root_parent(
318 device,
319 block_size,
320 super_block_header.root_parent_store_object_id,
321 );
322 root_parent.set_graveyard_directory_object_id(
323 super_block_header.root_parent_graveyard_directory_object_id,
324 );
325
326 loop {
327 let mutation = match reader.next_item().await? {
329 SuperBlockRecord::Extent(_) => bail!("Unexpected extent record"),
331 SuperBlockRecord::ObjectItem(item) => Mutation::insert_object(item.key, item.value),
332 SuperBlockRecord::End => break,
333 };
334 root_parent.apply_mutation(
335 mutation,
336 &ApplyContext {
337 mode: ApplyMode::Replay,
338 checkpoint: JournalCheckpoint { file_offset: 0, ..Default::default() },
342 },
343 AssocObj::None,
344 )?;
345 }
346 Ok((super_block_header, instance, root_parent))
347}
348
349async fn write<S: HandleOwner>(
352 super_block_header: &SuperBlockHeader,
353 items: LayerSet<ObjectKey, ObjectValue>,
354 handle: DataObjectHandle<S>,
355) -> Result<(), Error> {
356 let mut writer = SuperBlockWriter::new(handle, super_block_header).await?;
363 let mut merger = items.merger();
364 let mut iter = LSMTree::major_iter(merger.query(Query::FullScan).await?).await?;
365 while let Some(item) = iter.get() {
366 writer.write_root_parent_item(item.cloned()).await?;
367 iter.advance().await?;
368 }
369 writer.finalize().await
370}
371
372pub fn compact_root_parent(
375 root_parent_store: &ObjectStore,
376) -> Result<LayerSet<ObjectKey, ObjectValue>, Error> {
377 let tree = root_parent_store.tree();
380 let layer_set = tree.layer_set();
381 {
382 let mut merger = layer_set.merger();
383 let mut iter = LSMTree::major_iter(merger.query(Query::FullScan).now_or_never().unwrap()?)
384 .now_or_never()
385 .unwrap()?;
386 let new_layer = LSMTree::new_mutable_layer();
387 while let Some(item_ref) = iter.get() {
388 new_layer.insert(item_ref.cloned())?;
389 iter.advance().now_or_never().unwrap()?;
390 }
391 tree.set_mutable_layer(new_layer);
392 }
393 Ok(layer_set)
394}
395
396pub(super) struct SuperBlockManager {
399 pub next_instance: Mutex<SuperBlockInstance>,
400 metrics: SuperBlockMetrics,
401}
402
403impl SuperBlockManager {
404 pub fn new() -> Self {
405 Self { next_instance: Mutex::new(SuperBlockInstance::A), metrics: Default::default() }
406 }
407
408 pub async fn load(
411 &self,
412 device: Arc<dyn Device>,
413 block_size: BlockSize,
414 ) -> Result<(SuperBlockHeader, ObjectStore), Error> {
415 debug_assert!(MIN_SUPER_BLOCK_SIZE == block_size);
419
420 let (super_block, current_super_block, root_parent) = match futures::join!(
421 read(device.clone(), block_size, SuperBlockInstance::A),
422 read(device.clone(), block_size, SuperBlockInstance::B)
423 ) {
424 (Err(e1), Err(e2)) => {
425 bail!("Failed to load both superblocks due to {:?}\nand\n{:?}", e1, e2)
426 }
427 (Ok(result), Err(_)) => result,
428 (Err(_), Ok(result)) => result,
429 (Ok(result1), Ok(result2)) => {
430 if (result2.0.generation as i64).wrapping_sub(result1.0.generation as i64) > 0 {
432 result2
433 } else {
434 result1
435 }
436 }
437 };
438 info!(super_block:?, current_super_block:?; "loaded super-block");
439 *self.next_instance.lock() = current_super_block.next();
440 Ok((super_block, root_parent))
441 }
442
443 pub async fn save(
446 &self,
447 super_block_header: SuperBlockHeader,
448 filesystem: Arc<dyn Filesystem>,
449 root_parent: LayerSet<ObjectKey, ObjectValue>,
450 ) -> Result<(), Error> {
451 let root_store = filesystem.ensure_local().root_store();
452 let instance = *self.next_instance.lock();
453 let handle = ObjectStore::open_object(
454 &root_store,
455 instance.object_id(),
456 HandleOptions { skip_journal_checks: true, ..Default::default() },
457 None,
458 )
459 .await
460 .context("Failed to open superblock object")?;
461 write(&super_block_header, root_parent, handle).await?;
462 *self.next_instance.lock() = instance.next();
463 self.metrics
464 .last_super_block_offset
465 .set(super_block_header.super_block_journal_file_offset);
466 self.metrics.last_super_block_update_time_ms.set(
467 SystemTime::now()
468 .duration_since(SystemTime::UNIX_EPOCH)
469 .unwrap()
470 .as_millis()
471 .try_into()
472 .unwrap_or(0u64),
473 );
474 Ok(())
475 }
476}
477
478impl SuperBlockHeader {
479 pub fn new(
481 generation: u64,
482 root_parent_store_object_id: u64,
483 root_parent_graveyard_directory_object_id: u64,
484 root_store_object_id: u64,
485 allocator_object_id: u64,
486 journal_object_id: u64,
487 journal_checkpoint: JournalCheckpoint,
488 earliest_version: Version,
489 ) -> Self {
490 SuperBlockHeader {
491 guid: UuidWrapper::new(),
492 generation,
493 root_parent_store_object_id,
494 root_parent_graveyard_directory_object_id,
495 root_store_object_id,
496 allocator_object_id,
497 journal_object_id,
498 journal_checkpoint,
499 earliest_version,
500 ..Default::default()
501 }
502 }
503
504 async fn read_header(
507 device: Arc<dyn Device>,
508 target_super_block: SuperBlockInstance,
509 ) -> Result<(SuperBlockHeader, RecordReader), Error> {
510 let handle = BootstrapObjectHandle::new(
511 target_super_block.object_id(),
512 device,
513 target_super_block.first_extent(),
514 );
515 let mut reader = JournalReader::new(handle, &JournalCheckpoint::default());
516 reader.set_eof_ok();
517
518 reader.fill_buf().await?;
519
520 let mut super_block_header;
521 let super_block_version;
522 reader.consume({
523 let mut cursor = std::io::Cursor::new(reader.buffer());
524 let mut magic_bytes: [u8; 8] = [0; 8];
526 cursor.read_exact(&mut magic_bytes)?;
527 if magic_bytes.as_slice() != SUPER_BLOCK_MAGIC.as_slice() {
528 bail!("Invalid magic: {:?}", magic_bytes);
529 }
530 (super_block_header, super_block_version) =
531 SuperBlockHeader::deserialize_with_version(&mut cursor)?;
532
533 let mut stores = HashSet::new();
535 ensure!(
536 stores.insert(super_block_header.root_parent_store_object_id),
537 FxfsError::Inconsistent
538 );
539 ensure!(
540 stores.insert(super_block_header.root_store_object_id),
541 FxfsError::Inconsistent
542 );
543
544 let mut root_parent_objects = HashSet::new();
546 ensure!(
547 root_parent_objects
548 .insert(super_block_header.root_parent_graveyard_directory_object_id),
549 FxfsError::Inconsistent
550 );
551 ensure!(
552 root_parent_objects.insert(super_block_header.root_store_object_id),
553 FxfsError::Inconsistent
554 );
555 ensure!(
556 root_parent_objects.insert(super_block_header.journal_object_id),
557 FxfsError::Inconsistent
558 );
559
560 ensure!(
562 !stores.contains(&super_block_header.allocator_object_id),
563 FxfsError::Inconsistent
564 );
565
566 if super_block_version < EARLIEST_SUPPORTED_VERSION {
567 bail!("Unsupported SuperBlock version: {:?}", super_block_version);
568 }
569
570 if super_block_header.journal_checkpoint.version < EARLIEST_SUPPORTED_VERSION {
574 bail!(
575 "Unsupported JournalCheckpoint version: {:?}",
576 super_block_header.journal_checkpoint.version
577 );
578 }
579
580 if super_block_header.earliest_version < EARLIEST_SUPPORTED_VERSION {
581 bail!(
582 "Filesystem contains struct with unsupported version: {:?}",
583 super_block_header.earliest_version
584 );
585 }
586
587 cursor.position() as usize
588 });
589
590 if super_block_header.guid.0.is_nil() {
592 super_block_header.guid = UuidWrapper::new();
593 }
594 reader.set_version(super_block_version);
595 Ok((super_block_header, RecordReader { reader }))
596 }
597}
598
599struct SuperBlockWriter<S: HandleOwner> {
600 handle: DataObjectHandle<S>,
601 writer: JournalWriter,
602 existing_extents: VecDeque<FileExtent>,
603 size: u64,
604}
605
606impl<S: HandleOwner> SuperBlockWriter<S> {
607 pub async fn new(
610 handle: DataObjectHandle<S>,
611 super_block_header: &SuperBlockHeader,
612 ) -> Result<Self, Error> {
613 let existing_extents = handle.device_extents().await?;
614 let mut this = Self {
615 handle,
616 writer: JournalWriter::new(BLOCK_SIZE, 0),
617 existing_extents: existing_extents.into_iter().collect(),
618 size: 0,
619 };
620 this.writer.write_all(SUPER_BLOCK_MAGIC)?;
621 super_block_header.serialize_with_version(&mut this.writer)?;
622 Ok(this)
623 }
624
625 fn try_extend_existing(&mut self, target_size: u64) -> Result<(), Error> {
628 while self.size < target_size {
629 if let Some(extent) = self.existing_extents.pop_front() {
630 ensure!(
631 extent.logical_range().start == self.size,
632 "superblock file contains a hole."
633 );
634 self.size += extent.length();
635 SuperBlockRecord::Extent(extent.device_range().clone())
636 .serialize_into(&mut self.writer)?;
637 } else {
638 break;
639 }
640 }
641 Ok(())
642 }
643
644 pub async fn write_root_parent_item(&mut self, record: ObjectItem) -> Result<(), Error> {
645 let min_len = self.writer.journal_file_checkpoint().file_offset + SUPER_BLOCK_CHUNK_SIZE;
646 self.try_extend_existing(min_len)?;
647 if min_len > self.size {
648 let mut transaction = self
650 .handle
651 .new_transaction_with_options(Options {
652 skip_journal_checks: true,
653 reservation: ReservationOptions::Borrowed,
654 ..Default::default()
655 })
656 .await?;
657 let mut file_range = self.size..self.size + SUPER_BLOCK_CHUNK_SIZE;
658 let allocated = self
659 .handle
660 .preallocate_range(&mut transaction, &mut file_range)
661 .await
662 .context("preallocate superblock")?;
663 if file_range.start < file_range.end {
664 bail!("preallocate_range returned too little space");
665 }
666 transaction.commit().await?;
667 for device_range in allocated {
668 self.size += device_range.end - device_range.start;
669 SuperBlockRecord::Extent(device_range).serialize_into(&mut self.writer)?;
670 }
671 }
672 SuperBlockRecord::ObjectItem(record).serialize_into(&mut self.writer)?;
673 Ok(())
674 }
675
676 pub async fn finalize(mut self) -> Result<(), Error> {
677 SuperBlockRecord::End.serialize_into(&mut self.writer)?;
678 self.writer.pad_to_block()?;
679 let mut buf = self.handle.allocate_buffer(self.writer.flushable_bytes()).await;
680 let offset = self.writer.take_flushable(buf.as_mut());
681 self.handle.overwrite(offset, buf.as_mut(), OverwriteOptions::default()).await?;
682 let len =
683 std::cmp::max(MIN_SUPER_BLOCK_SIZE, self.writer.journal_file_checkpoint().file_offset)
684 + SUPER_BLOCK_CHUNK_SIZE;
685
686 self.handle
690 .truncate_with_options(
691 Options {
692 skip_journal_checks: true,
693 reservation: ReservationOptions::Borrowed,
694 ..Default::default()
695 },
696 len,
697 )
698 .await?;
699 Ok(())
700 }
701}
702
703pub struct RecordReader {
704 reader: JournalReader,
705}
706
707impl RecordReader {
708 pub async fn next_item(&mut self) -> Result<SuperBlockRecord, Error> {
709 loop {
710 match self.reader.deserialize().await? {
711 ReadResult::Reset(_) => bail!("Unexpected reset"),
712 ReadResult::ChecksumMismatch => bail!("Checksum mismatch"),
713 ReadResult::Some(SuperBlockRecord::Extent(extent)) => {
714 ensure!(extent.is_valid(), FxfsError::Inconsistent);
715 self.reader.handle().push_extent(0, extent)
716 }
717 ReadResult::Some(x) => return Ok(x),
718 }
719 }
720 }
721}
722
723#[cfg(test)]
724mod tests {
725 use super::{
726 MIN_SUPER_BLOCK_SIZE, SUPER_BLOCK_CHUNK_SIZE, SUPER_BLOCK_MAGIC, SuperBlockHeader,
727 SuperBlockInstance, SuperBlockManager, SuperBlockRecord, UuidWrapper, compact_root_parent,
728 write,
729 };
730 use crate::filesystem::{FxFilesystem, OpenFxFilesystem, SyncOptions};
731 use crate::object_handle::ReadObjectHandle;
732 use crate::object_store::journal::JournalCheckpoint;
733 use crate::object_store::journal::writer::JournalWriter;
734 use crate::object_store::transaction::{Options, lock_keys};
735 use crate::object_store::{
736 DataObjectHandle, HandleOptions, ObjectHandle, ObjectKey, ObjectStore,
737 };
738 use crate::serialized_types::{LATEST_VERSION, Versioned, VersionedLatest};
739 use anyhow::bail;
740 use std::io::Write;
741 use std::sync::Arc;
742 use std::sync::atomic::{AtomicBool, Ordering};
743 use storage_device::DeviceHolder;
744 use storage_device::fake_device::{FakeDevice, Op};
745 use storage_units::BlockSize;
746
747 const TEST_DEVICE_BLOCK_SIZE: BlockSize = BlockSize::SIZE_512B;
750 const TEST_DEVICE_BLOCK_COUNT: u64 = 16384;
751
752 async fn filesystem_and_super_block_handles()
753 -> (OpenFxFilesystem, DataObjectHandle<ObjectStore>, DataObjectHandle<ObjectStore>) {
754 let device = DeviceHolder::new(FakeDevice::new(
755 TEST_DEVICE_BLOCK_COUNT,
756 TEST_DEVICE_BLOCK_SIZE.get() as u32,
757 ));
758 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
759 fs.close().await.expect("Close failed");
760 let device = fs.take_device().await;
761 device.reopen(false);
762 let fs = FxFilesystem::open(device).await.expect("open failed");
763
764 let handle_a = ObjectStore::open_object(
765 &fs.object_manager().root_store(),
766 SuperBlockInstance::A.object_id(),
767 HandleOptions::default(),
768 None,
769 )
770 .await
771 .expect("open superblock failed");
772
773 let handle_b = ObjectStore::open_object(
774 &fs.object_manager().root_store(),
775 SuperBlockInstance::B.object_id(),
776 HandleOptions::default(),
777 None,
778 )
779 .await
780 .expect("open superblock failed");
781 (fs, handle_a, handle_b)
782 }
783
784 #[fuchsia::test]
785 async fn test_read_written_super_block() {
786 let (fs, _handle_a, _handle_b) = filesystem_and_super_block_handles().await;
787 const JOURNAL_OBJECT_ID: u64 = 5;
788
789 assert_eq!(
792 ObjectStore::open_object(
793 &fs.root_store(),
794 SuperBlockInstance::A.object_id(),
795 HandleOptions::default(),
796 None,
797 )
798 .await
799 .expect("open_object failed")
800 .get_size(),
801 MIN_SUPER_BLOCK_SIZE + SUPER_BLOCK_CHUNK_SIZE
802 );
803
804 let mut created_object_ids = vec![];
807 const NUM_ENTRIES: u64 = 16384;
808 for _ in 0..NUM_ENTRIES {
809 let mut transaction = fs
810 .root_store()
811 .new_transaction(lock_keys![], Options::default())
812 .await
813 .expect("new_transaction failed");
814 created_object_ids.push(
815 ObjectStore::create_object(
816 &fs.object_manager().root_parent_store(),
817 &mut transaction,
818 HandleOptions::default(),
819 None,
820 )
821 .await
822 .expect("create_object failed")
823 .object_id(),
824 );
825 transaction.commit().await.expect("commit failed");
826 }
827
828 assert!(
832 ObjectStore::open_object(
833 &fs.root_store(),
834 SuperBlockInstance::A.object_id(),
835 HandleOptions::default(),
836 None,
837 )
838 .await
839 .expect("open_object failed")
840 .get_size()
841 > MIN_SUPER_BLOCK_SIZE + SUPER_BLOCK_CHUNK_SIZE
842 );
843
844 let written_super_block_a =
845 SuperBlockHeader::read_header(fs.device(), SuperBlockInstance::A)
846 .await
847 .expect("read failed");
848 let written_super_block_b =
849 SuperBlockHeader::read_header(fs.device(), SuperBlockInstance::B)
850 .await
851 .expect("read failed");
852
853 assert!(!written_super_block_a.0.guid.0.is_nil());
855
856 assert_eq!(written_super_block_a.0.guid, written_super_block_b.0.guid);
859 assert_eq!(written_super_block_a.0.guid, written_super_block_b.0.guid);
860 assert!(written_super_block_a.0.generation != written_super_block_b.0.generation);
861 assert_eq!(
862 written_super_block_a.0.root_parent_store_object_id,
863 written_super_block_b.0.root_parent_store_object_id
864 );
865 assert_eq!(
866 written_super_block_a.0.root_parent_graveyard_directory_object_id,
867 written_super_block_b.0.root_parent_graveyard_directory_object_id
868 );
869 assert_eq!(written_super_block_a.0.root_store_object_id, fs.root_store().store_object_id());
870 assert_eq!(
871 written_super_block_a.0.root_store_object_id,
872 written_super_block_b.0.root_store_object_id
873 );
874 assert_eq!(written_super_block_a.0.allocator_object_id, fs.allocator().object_id());
875 assert_eq!(
876 written_super_block_a.0.allocator_object_id,
877 written_super_block_b.0.allocator_object_id
878 );
879 assert_eq!(written_super_block_a.0.journal_object_id, JOURNAL_OBJECT_ID);
880 assert_eq!(
881 written_super_block_a.0.journal_object_id,
882 written_super_block_b.0.journal_object_id
883 );
884 assert!(
885 written_super_block_a.0.journal_checkpoint.file_offset
886 != written_super_block_b.0.journal_checkpoint.file_offset
887 );
888 assert!(
889 written_super_block_a.0.super_block_journal_file_offset
890 != written_super_block_b.0.super_block_journal_file_offset
891 );
892 assert_eq!(written_super_block_a.0.earliest_version, LATEST_VERSION);
894 assert_eq!(
895 written_super_block_a.0.earliest_version,
896 written_super_block_b.0.earliest_version
897 );
898
899 for object_id in created_object_ids {
904 let mut transaction = fs
905 .root_store()
906 .new_transaction(lock_keys![], Options::default())
907 .await
908 .expect("new_transaction failed");
909 fs.object_manager()
910 .root_parent_store()
911 .adjust_refs(&mut transaction, object_id, -1)
912 .await
913 .expect("adjust_refs failed");
914 transaction.commit().await.expect("commit failed");
915 fs.object_manager()
916 .root_parent_store()
917 .tombstone_object(object_id, Options::default(), None)
918 .await
919 .expect("tombstone failed");
920 }
921 for _ in 0..NUM_ENTRIES {
924 let mut transaction = fs
925 .root_store()
926 .new_transaction(lock_keys![], Options::default())
927 .await
928 .expect("new_transaction failed");
929 ObjectStore::create_object(
930 &fs.object_manager().root_store(),
931 &mut transaction,
932 HandleOptions::default(),
933 None,
934 )
935 .await
936 .expect("create_object failed");
937 transaction.commit().await.expect("commit failed");
938 }
939
940 assert_eq!(
941 ObjectStore::open_object(
942 &fs.root_store(),
943 SuperBlockInstance::A.object_id(),
944 HandleOptions::default(),
945 None,
946 )
947 .await
948 .expect("open_object failed")
949 .get_size(),
950 MIN_SUPER_BLOCK_SIZE + SUPER_BLOCK_CHUNK_SIZE
951 );
952
953 fs.journal().force_compact().await.expect("force_compact failed");
957 assert_eq!(fs.object_manager().borrowed_metadata_space(), 0);
958 let expected_map = fs.object_manager().reserved_metadata_space();
959 let snapshot = fs.device().snapshot().expect("snapshot failed");
960 fs.close().await.expect("close failed");
961
962 let fs2 = FxFilesystem::open(snapshot).await.expect("open failed");
963 assert_eq!(fs2.object_manager().reserved_metadata_space(), expected_map);
964 assert_eq!(fs2.object_manager().borrowed_metadata_space(), 0);
965 fs2.close().await.expect("close failed");
966 }
967
968 #[fuchsia::test]
969 async fn test_generation_comparison_wrapping() {
970 const BLOCK_SIZE: BlockSize = BlockSize::new(MIN_SUPER_BLOCK_SIZE as u32).unwrap();
971 let device =
972 DeviceHolder::new(FakeDevice::new(TEST_DEVICE_BLOCK_COUNT, BLOCK_SIZE.get() as u32));
973 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
974 fs.close().await.expect("close");
975 let device = fs.take_device().await;
976 device.reopen(false);
977
978 let device_arc = (*device).clone();
981 let write_sb = |instance: SuperBlockInstance, generation: u64| {
982 let device = device_arc.clone();
983 async move {
984 let mut super_block_header = SuperBlockHeader::new(
985 1, 3, 4, 5, 6, 7, JournalCheckpoint::default(),
992 LATEST_VERSION,
993 );
994 super_block_header.generation = generation;
995 super_block_header.journal_checkpoint.version = LATEST_VERSION;
996
997 let mut writer = JournalWriter::new(BLOCK_SIZE, 0);
998 writer.write_all(SUPER_BLOCK_MAGIC).unwrap();
999 super_block_header.serialize_with_version(&mut writer).unwrap();
1000 SuperBlockRecord::End.serialize_into(&mut writer).unwrap();
1001 writer.pad_to_block().unwrap();
1002
1003 let mut buf = device.allocate_buffer(writer.flushable_bytes()).await;
1004 writer.take_flushable(buf.as_mut());
1005 device
1006 .write(instance.first_extent().start, buf.as_ref())
1007 .await
1008 .expect("write failed");
1009 }
1010 };
1011
1012 write_sb(SuperBlockInstance::A, u64::MAX).await;
1014 write_sb(SuperBlockInstance::B, 0).await;
1015 let manager = SuperBlockManager::new();
1016 let (header, _) = manager.load((*device).clone(), BLOCK_SIZE).await.expect("load failed");
1017 assert_eq!(header.generation, 0);
1018
1019 write_sb(SuperBlockInstance::A, 0).await;
1021 write_sb(SuperBlockInstance::B, u64::MAX).await;
1022 let manager = SuperBlockManager::new();
1023 let (header, _) = manager.load((*device).clone(), BLOCK_SIZE).await.expect("load failed");
1024 assert_eq!(header.generation, 0);
1025
1026 write_sb(SuperBlockInstance::A, 100).await;
1028 write_sb(SuperBlockInstance::B, 200).await;
1029 let manager = SuperBlockManager::new();
1030 let (header, _) = manager.load((*device).clone(), BLOCK_SIZE).await.expect("load failed");
1031 assert_eq!(header.generation, 200);
1032 }
1033
1034 #[fuchsia::test]
1035 async fn test_generation_wrapping_on_flush() {
1036 const BLOCK_SIZE: BlockSize = BlockSize::SIZE_4KIB;
1037 let mut device =
1038 DeviceHolder::new(FakeDevice::new(TEST_DEVICE_BLOCK_COUNT, BLOCK_SIZE.get() as u32));
1039 {
1040 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
1041 let root_store = fs.root_store();
1042 let mut transaction = fs
1043 .root_store()
1044 .new_transaction(lock_keys![], Options::default())
1045 .await
1046 .expect("new_transaction failed");
1047 ObjectStore::create_object(
1048 &root_store,
1049 &mut transaction,
1050 HandleOptions::default(),
1051 None,
1052 )
1053 .await
1054 .expect("create_object failed");
1055 transaction.commit().await.expect("commit failed");
1056 fs.sync(SyncOptions::default()).await.expect("sync failed");
1057 fs.close().await.expect("close failed");
1058 device = fs.take_device().await;
1059 }
1060 device.reopen(false);
1061
1062 let manager = SuperBlockManager::new();
1063 let (mut header, _) =
1064 manager.load((*device).clone(), BLOCK_SIZE).await.expect("load failed");
1065
1066 {
1067 let fs = FxFilesystem::open(device).await.expect("open failed");
1068 header.generation = u64::MAX - 1;
1073 manager
1074 .save(header.clone(), (*fs).clone(), fs.root_parent_store().tree().layer_set())
1075 .await
1076 .expect("save 1 failed");
1077 header.generation = u64::MAX;
1078 manager
1079 .save(header, (*fs).clone(), fs.root_parent_store().tree().layer_set())
1080 .await
1081 .expect("save 2 failed");
1082 fs.close().await.expect("close failed");
1083 device = fs.take_device().await;
1084 device.reopen(false);
1085
1086 let fs = FxFilesystem::open(device).await.expect("open failed");
1087
1088 let root_store = fs.root_store();
1089 for _ in 0..6000 {
1090 let mut transaction = fs
1091 .root_store()
1092 .new_transaction(lock_keys![], Options::default())
1093 .await
1094 .expect("new_transaction failed");
1095 ObjectStore::create_object(
1096 &root_store,
1097 &mut transaction,
1098 HandleOptions::default(),
1099 None,
1100 )
1101 .await
1102 .expect("create_object failed");
1103 transaction.commit().await.expect("commit failed");
1104 }
1105 fs.sync(SyncOptions::default()).await.expect("sync failed");
1106 fs.close().await.expect("close failed");
1107 device = fs.take_device().await;
1108 }
1109 device.reopen(false);
1110
1111 let (header, _) = manager.load((*device).clone(), BLOCK_SIZE).await.expect("load failed");
1112 assert!(header.generation < 10);
1113 }
1114
1115 #[fuchsia::test]
1116 async fn test_guid_assign_on_read() {
1117 let (fs, handle_a, _handle_b) = filesystem_and_super_block_handles().await;
1118 const JOURNAL_OBJECT_ID: u64 = 5;
1119 let mut super_block_header_a = SuperBlockHeader::new(
1120 1,
1121 fs.object_manager().root_parent_store().store_object_id(),
1122 1000,
1123 fs.root_store().store_object_id(),
1124 fs.allocator().object_id(),
1125 JOURNAL_OBJECT_ID,
1126 JournalCheckpoint { file_offset: 1234, checksum: 5678, version: LATEST_VERSION },
1127 LATEST_VERSION,
1128 );
1129 super_block_header_a.guid = UuidWrapper::nil();
1131 write(
1132 &super_block_header_a,
1133 compact_root_parent(fs.object_manager().root_parent_store().as_ref())
1134 .expect("scan failed"),
1135 handle_a,
1136 )
1137 .await
1138 .expect("write failed");
1139 let super_block_header = SuperBlockHeader::read_header(fs.device(), SuperBlockInstance::A)
1140 .await
1141 .expect("read failed");
1142 assert!(!super_block_header.0.guid.0.is_nil());
1144 }
1145
1146 #[fuchsia::test]
1147 async fn test_init_wipes_superblocks() {
1148 let device = DeviceHolder::new(FakeDevice::new(8192, TEST_DEVICE_BLOCK_SIZE.get() as u32));
1149
1150 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
1151 let root_store = fs.root_store();
1152 for _ in 0..6000 {
1154 let mut transaction = fs
1155 .root_store()
1156 .new_transaction(lock_keys![], Options::default())
1157 .await
1158 .expect("new_transaction failed");
1159 ObjectStore::create_object(
1160 &root_store,
1161 &mut transaction,
1162 HandleOptions::default(),
1163 None,
1164 )
1165 .await
1166 .expect("create_object failed");
1167 transaction.commit().await.expect("commit failed");
1168 }
1169 fs.close().await.expect("Close failed");
1170 let device = fs.take_device().await;
1171 device.reopen(false);
1172
1173 SuperBlockHeader::read_header(device.clone(), SuperBlockInstance::A)
1174 .await
1175 .expect("read failed");
1176 let header = SuperBlockHeader::read_header(device.clone(), SuperBlockInstance::B)
1177 .await
1178 .expect("read failed");
1179
1180 let old_guid = header.0.guid;
1181
1182 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
1184 fs.close().await.expect("Close failed");
1185 let device = fs.take_device().await;
1186 device.reopen(false);
1187
1188 let a = SuperBlockHeader::read_header(device.clone(), SuperBlockInstance::A)
1189 .await
1190 .expect("read failed");
1191 let b = SuperBlockHeader::read_header(device.clone(), SuperBlockInstance::B)
1192 .await
1193 .expect("read failed");
1194
1195 assert_eq!(a.0.guid, b.0.guid);
1196 assert_ne!(old_guid, a.0.guid);
1197 }
1198
1199 #[fuchsia::test]
1200 async fn test_alternating_super_blocks() {
1201 let device = DeviceHolder::new(FakeDevice::new(8192, TEST_DEVICE_BLOCK_SIZE.get() as u32));
1202
1203 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
1204 fs.close().await.expect("Close failed");
1205 let device = fs.take_device().await;
1206 device.reopen(false);
1207
1208 let (super_block_header_a, _) =
1209 SuperBlockHeader::read_header(device.clone(), SuperBlockInstance::A)
1210 .await
1211 .expect("read failed");
1212
1213 let fs = FxFilesystem::open(device).await.expect("open failed");
1216 let root_store = fs.root_store();
1217 for _ in 0..6000 {
1219 let mut transaction = fs
1220 .root_store()
1221 .new_transaction(lock_keys![], Options::default())
1222 .await
1223 .expect("new_transaction failed");
1224 ObjectStore::create_object(
1225 &root_store,
1226 &mut transaction,
1227 HandleOptions::default(),
1228 None,
1229 )
1230 .await
1231 .expect("create_object failed");
1232 transaction.commit().await.expect("commit failed");
1233 }
1234 fs.close().await.expect("Close failed");
1235 let device = fs.take_device().await;
1236 device.reopen(false);
1237
1238 let (super_block_header_a_after, _) =
1239 SuperBlockHeader::read_header(device.clone(), SuperBlockInstance::A)
1240 .await
1241 .expect("read failed");
1242 let (super_block_header_b_after, _) =
1243 SuperBlockHeader::read_header(device.clone(), SuperBlockInstance::B)
1244 .await
1245 .expect("read failed");
1246
1247 assert_eq!(
1251 (super_block_header_b_after.generation as i64
1252 - super_block_header_a_after.generation as i64)
1253 .abs(),
1254 1
1255 );
1256
1257 assert!(
1259 std::cmp::max(
1260 super_block_header_a_after.generation,
1261 super_block_header_b_after.generation
1262 ) > super_block_header_a.generation
1263 );
1264
1265 assert_eq!(super_block_header_a_after.generation & 1, super_block_header_a.generation & 1);
1267 }
1268
1269 #[fuchsia::test]
1270 async fn test_root_parent_is_compacted() {
1271 let device = DeviceHolder::new(FakeDevice::new(8192, TEST_DEVICE_BLOCK_SIZE.get() as u32));
1272
1273 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
1274
1275 let mut transaction = fs
1276 .root_store()
1277 .new_transaction(lock_keys![], Options::default())
1278 .await
1279 .expect("new_transaction failed");
1280 let store = fs.root_parent_store();
1281 let handle =
1282 ObjectStore::create_object(&store, &mut transaction, HandleOptions::default(), None)
1283 .await
1284 .expect("create_object failed");
1285 store.add_to_graveyard(&mut transaction, handle.object_id());
1286 transaction.commit().await.expect("commit failed");
1287
1288 store
1289 .tombstone_object(handle.object_id(), Options::default(), None)
1290 .await
1291 .expect("tombstone failed");
1292
1293 let root_store = fs.root_store();
1295 for _ in 0..6000 {
1296 let mut transaction = fs
1297 .root_store()
1298 .new_transaction(lock_keys![], Options::default())
1299 .await
1300 .expect("new_transaction failed");
1301 ObjectStore::create_object(
1302 &root_store,
1303 &mut transaction,
1304 HandleOptions::default(),
1305 None,
1306 )
1307 .await
1308 .expect("create_object failed");
1309 transaction.commit().await.expect("commit failed");
1310 }
1311
1312 assert!(
1315 !store
1316 .tree()
1317 .exists(&ObjectKey::object(handle.object_id()))
1318 .await
1319 .expect("exists failed")
1320 );
1321 }
1322
1323 #[fuchsia::test]
1324 async fn test_invalid_object_ids_validation() {
1325 const BLOCK_SIZE: BlockSize = BlockSize::new(MIN_SUPER_BLOCK_SIZE as u32).unwrap();
1326 let device =
1327 DeviceHolder::new(FakeDevice::new(TEST_DEVICE_BLOCK_COUNT, BLOCK_SIZE.get() as u32));
1328 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
1329 fs.close().await.expect("close");
1330 let device = fs.take_device().await;
1331 device.reopen(false);
1332
1333 let device_arc = (*device).clone();
1335 let write_sb = |instance: SuperBlockInstance,
1336 root_parent_store_object_id: u64,
1337 root_parent_graveyard_directory_object_id: u64,
1338 root_store_object_id: u64,
1339 allocator_object_id: u64,
1340 journal_object_id: u64| {
1341 let device = device_arc.clone();
1342 async move {
1343 let mut super_block_header = SuperBlockHeader::new(
1344 1, root_parent_store_object_id,
1346 root_parent_graveyard_directory_object_id,
1347 root_store_object_id,
1348 allocator_object_id,
1349 journal_object_id,
1350 JournalCheckpoint::default(),
1351 LATEST_VERSION,
1352 );
1353 super_block_header.journal_checkpoint.version = LATEST_VERSION;
1354
1355 let mut writer = JournalWriter::new(BLOCK_SIZE, 0);
1356 writer.write_all(SUPER_BLOCK_MAGIC).unwrap();
1357 super_block_header.serialize_with_version(&mut writer).unwrap();
1358 SuperBlockRecord::End.serialize_into(&mut writer).unwrap();
1359 writer.pad_to_block().unwrap();
1360
1361 let mut buf = device.allocate_buffer(writer.flushable_bytes()).await;
1362 writer.take_flushable(buf.as_mut());
1363 device
1364 .write(instance.first_extent().start, buf.as_ref())
1365 .await
1366 .expect("write failed");
1367 }
1368 };
1369
1370 let manager = SuperBlockManager::new();
1371
1372 write_sb(SuperBlockInstance::A, 3, 4, 3, 5, 6).await;
1374 write_sb(SuperBlockInstance::B, 3, 4, 3, 5, 6).await;
1375 assert!(manager.load((*device).clone(), BLOCK_SIZE).await.is_err());
1376
1377 write_sb(SuperBlockInstance::A, 3, 4, 5, 3, 6).await;
1379 write_sb(SuperBlockInstance::B, 3, 4, 5, 3, 6).await;
1380 assert!(manager.load((*device).clone(), BLOCK_SIZE).await.is_err());
1381
1382 write_sb(SuperBlockInstance::A, 3, 4, 5, 5, 6).await;
1384 write_sb(SuperBlockInstance::B, 3, 4, 5, 5, 6).await;
1385 assert!(manager.load((*device).clone(), BLOCK_SIZE).await.is_err());
1386
1387 write_sb(SuperBlockInstance::A, 3, 4, 5, 6, 4).await;
1389 write_sb(SuperBlockInstance::B, 3, 4, 5, 6, 4).await;
1390 assert!(manager.load((*device).clone(), BLOCK_SIZE).await.is_err());
1391
1392 write_sb(SuperBlockInstance::A, 3, 4, 5, 6, 7).await;
1394 write_sb(SuperBlockInstance::B, 3, 4, 5, 6, 7).await;
1395 assert!(manager.load((*device).clone(), BLOCK_SIZE).await.is_ok());
1396 }
1397
1398 #[fuchsia::test]
1399 async fn test_save_failure_does_not_advance_next_instance() {
1400 const BLOCK_SIZE: BlockSize = BlockSize::SIZE_4KIB;
1401 let fail_writes = Arc::new(AtomicBool::new(false));
1402 let fail_writes_clone = fail_writes.clone();
1403 let mut fake_device = FakeDevice::new(TEST_DEVICE_BLOCK_COUNT, BLOCK_SIZE.get() as u32);
1404 fake_device.set_op_callback(move |op| match op {
1405 Op::Write if fail_writes_clone.load(Ordering::Relaxed) => {
1406 bail!("Injected write error");
1407 }
1408 _ => Ok(()),
1409 });
1410
1411 let device = DeviceHolder::new(fake_device);
1412 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
1413 fs.close().await.expect("close failed");
1414 let device = fs.take_device().await;
1415 device.reopen(false);
1416
1417 let manager = SuperBlockManager::new();
1418 let (header, _) = manager.load((*device).clone(), BLOCK_SIZE).await.expect("load failed");
1419 let fs = FxFilesystem::open(device).await.expect("open failed");
1420
1421 assert_eq!(*manager.next_instance.lock(), SuperBlockInstance::A);
1423
1424 fail_writes.store(true, Ordering::Relaxed);
1426
1427 assert!(
1429 manager
1430 .save(header.clone(), (*fs).clone(), fs.root_parent_store().tree().layer_set())
1431 .await
1432 .is_err()
1433 );
1434
1435 assert_eq!(*manager.next_instance.lock(), SuperBlockInstance::A);
1437
1438 fail_writes.store(false, Ordering::Relaxed);
1440
1441 manager
1443 .save(header, (*fs).clone(), fs.root_parent_store().tree().layer_set())
1444 .await
1445 .expect("save failed");
1446 assert_eq!(*manager.next_instance.lock(), SuperBlockInstance::B);
1447 }
1448}