1pub mod allocator;
6pub mod caching_object_handle;
7pub mod data_object_handle;
8pub mod directory;
9pub mod extent;
10mod extent_mapping_iterator;
11mod extent_record;
12pub mod flush;
13use crate::filesystem::FlushReason;
14pub mod graveyard;
15mod install;
16pub mod journal;
17mod key_manager;
18pub mod merge;
19pub mod object_manager;
20pub mod object_record;
21pub mod project_id;
22mod store_object_handle;
23pub mod transaction;
24mod tree;
25mod tree_cache;
26pub mod volume;
27
28pub use data_object_handle::{
29 DataObjectHandle, DataObjectState, DirectWriter, FileExtent, FsverityStateInner, RangeType,
30};
31pub use directory::{Directory, MAX_INLINE_SYMLINK_SIZE};
32pub use object_record::{
33 ChildValue, DirType, FscryptDirInfo, FscryptPolicyFlags, LEGACY_FSCRYPT_FLAGS,
34 ObjectDescriptor, PosixAttributes, Timestamp,
35};
36pub use store_object_handle::{
37 MAX_INLINE_XATTR_SIZE, SetExtendedAttributeMode, StoreObjectHandle, enable_watchdog_backtrace,
38};
39
40use crate::errors::FxfsError;
41use crate::filesystem::{
42 ApplyContext, ApplyMode, Filesystem, FxFilesystem, JournalingObject, MAX_FILE_SIZE,
43 SyncOptions, TruncateGuard,
44};
45use crate::log::*;
46use crate::lsm_tree::cache::ObjectCache;
47use crate::lsm_tree::types::{Existence, Item, ItemRef, LayerIterator};
48use crate::lsm_tree::{LSMTree, Query, open_layers};
49use crate::object_handle::{INVALID_OBJECT_ID, ObjectHandle, ObjectProperties, ReadObjectHandle};
50use crate::object_store::allocator::Allocator;
51use crate::object_store::graveyard::Graveyard;
52use crate::object_store::journal::{JournalCheckpoint, JournalCheckpointV32, JournaledTransaction};
53use crate::object_store::key_manager::KeyManager;
54use crate::object_store::transaction::{
55 AssocObj, AssociatedObject, LockKey, LockKeys, MutationV59, MutationV61, MutationV62,
56 ObjectMutationIterator, ObjectStoreMutation, Operation, Options, ReservationOptions,
57 Transaction, WriteGuard, lock_keys,
58};
59use crate::serialized_types::{
60 AES_JOURNAL_ENCRYPTION_VERSION, DEFAULT_MAX_SERIALIZED_RECORD_SIZE, Version, Versioned,
61 VersionedLatest,
62};
63use anyhow::{Context, Error, anyhow, bail, ensure};
64use async_trait::async_trait;
65use fidl_fuchsia_io as fio;
66use fprint::TypeFingerprint;
67use fscrypt::proxy_filename::ProxyFilename;
68use fuchsia_sync::Mutex;
69use fxfs_crypto::ff1::Ff1;
70use fxfs_crypto::{
71 CipherHolder, Crypt, JournalCipher, JournalXtsCipher, KeyPurpose, ObjectType, StreamCipher,
72 UnwrappedKey, key_to_cipher,
73};
74use rand::Rng as _;
75use scopeguard::ScopeGuard;
76use serde::{Deserialize, Serialize};
77use std::collections::HashSet;
78use std::fmt;
79use std::num::NonZero;
80use std::sync::atomic::{AtomicBool, AtomicU64, Ordering};
81use std::sync::{Arc, OnceLock, Weak};
82use storage_device::Device;
83use storage_units::BlockSize;
84use uuid::Uuid;
85
86pub use extent::Extent;
87pub use extent_record::{ExtentMode, ExtentValue};
88pub use object_record::{
89 AttributeId, AttributeKey, BytesAndNodes, EncryptionKey, EncryptionKeys,
90 ExtendedAttributeValue, FsverityMetadata, FxfsKey, FxfsKeyV49, ObjectAttributes, ObjectKey,
91 ObjectKeyData, ObjectKind, ObjectValue, ProjectProperty, RootDigest,
92};
93pub use project_id::{ProjectId, ProjectIdExt};
94pub use transaction::Mutation;
95
96const OBJECT_ID_HI_MASK: u64 = 0xffffffff00000000;
99
100const TRANSACTION_MUTATION_THRESHOLD: usize = 200;
102
103const CACHED_KEYS_LIMIT: usize = 4;
112
113pub const VOLUME_DATA_KEY_ID: u64 = 0;
119pub const FSCRYPT_KEY_ID: u64 = 1;
120
121pub trait HandleOwner: AsRef<ObjectStore> + Send + Sync + 'static {}
124
125pub type StoreInfo = StoreInfoV52;
128
129#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize, TypeFingerprint, Versioned)]
130pub struct StoreInfoV52 {
131 guid: [u8; 16],
133
134 last_object_id: LastObjectIdInfo,
140
141 pub layers: Vec<u64>,
144
145 root_directory_object_id: u64,
147
148 graveyard_directory_object_id: u64,
150
151 object_count: u64,
154
155 mutations_key: Option<FxfsKeyV49>,
157
158 mutations_cipher_offset: u64,
161
162 pub encrypted_mutations_object_id: u64,
165
166 internal_directory_object_id: u64,
169}
170
171#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, TypeFingerprint)]
172enum LastObjectIdInfo {
173 Unencrypted {
174 id: u64,
175 },
176 Encrypted {
177 id: u64,
179
180 key: FxfsKeyV49,
185 },
186 Low32Bit,
187}
188
189impl Default for LastObjectIdInfo {
190 fn default() -> Self {
191 LastObjectIdInfo::Unencrypted { id: 0 }
192 }
193}
194
195impl StoreInfo {
196 pub fn parent_objects(&self) -> Vec<u64> {
198 let mut objects = self.layers.to_vec();
201 if self.encrypted_mutations_object_id != INVALID_OBJECT_ID {
202 objects.push(self.encrypted_mutations_object_id);
203 }
204 objects
205 }
206}
207
208pub const MAX_STORE_INFO_SERIALIZED_SIZE: usize = 131072;
211
212pub const MAX_ENCRYPTED_MUTATIONS_SIZE: usize = 8 * journal::DEFAULT_RECLAIM_SIZE as usize;
216
217#[derive(Default)]
218pub struct HandleOptions {
219 pub skip_journal_checks: bool,
221 pub skip_checksums: bool,
224 pub skip_fsverity: bool,
227}
228
229pub struct ObjectEncryptionOptions {
231 pub permanent: bool,
236 pub key_id: u64,
237 pub key: EncryptionKey,
238 pub unwrapped_key: UnwrappedKey,
239}
240
241pub struct StoreOptions {
242 pub crypt: Option<Arc<dyn Crypt>>,
244}
245
246impl Default for StoreOptions {
247 fn default() -> Self {
248 Self { crypt: None }
249 }
250}
251
252#[derive(Default)]
253pub struct NewChildStoreOptions {
254 pub options: StoreOptions,
255
256 pub object_id: u64,
259
260 pub reserve_32bit_object_ids: bool,
263
264 pub low_32_bit_object_ids: bool,
267
268 pub guid: Option<[u8; 16]>,
270}
271
272pub type EncryptedMutations = EncryptedMutationsV49;
273
274#[derive(Clone, Default, Deserialize, Serialize, TypeFingerprint)]
275pub struct EncryptedMutationsV49 {
276 transactions: Vec<(JournalCheckpointV32, u64)>,
282
283 #[serde(with = "crate::zerocopy_serialization")]
285 data: Vec<u8>,
286
287 mutations_key_roll: Vec<(usize, FxfsKeyV49)>,
290}
291
292impl std::fmt::Debug for EncryptedMutations {
293 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
294 f.debug_struct("EncryptedMutations")
295 .field("transactions", &self.transactions)
296 .field("len", &self.data.len())
297 .field(
298 "mutations_key_roll",
299 &self.mutations_key_roll.iter().map(|k| k.0).collect::<Vec<usize>>(),
300 )
301 .finish()
302 }
303}
304
305impl Versioned for EncryptedMutations {
306 fn max_serialized_size() -> Option<u64> {
307 Some(MAX_ENCRYPTED_MUTATIONS_SIZE as u64)
308 }
309}
310
311impl EncryptedMutations {
312 fn from_replayed_mutations(
313 store_object_id: u64,
314 transactions: Vec<JournaledTransaction>,
315 ) -> Self {
316 let mut this = Self::default();
317 for JournaledTransaction { checkpoint, non_root_mutations, .. } in transactions {
318 for (object_id, mutation) in non_root_mutations {
319 if store_object_id == object_id {
320 if let Mutation::EncryptedObjectStore(data) = mutation {
321 this.push(&checkpoint, data);
322 } else if let Mutation::UpdateMutationsKey(key) = mutation {
323 this.mutations_key_roll.push((this.data.len(), key.into()));
324 }
325 }
326 }
327 }
328 this
329 }
330
331 fn extend(&mut self, other: &EncryptedMutations) {
332 self.transactions.extend_from_slice(&other.transactions[..]);
333 self.mutations_key_roll.extend(
334 other
335 .mutations_key_roll
336 .iter()
337 .map(|(offset, key)| (offset + self.data.len(), key.clone())),
338 );
339 self.data.extend_from_slice(&other.data[..]);
340 }
341
342 fn push(&mut self, checkpoint: &JournalCheckpoint, data: Box<[u8]>) {
343 let len = data.len();
344 self.data.append(&mut data.into());
345 if checkpoint.version >= AES_JOURNAL_ENCRYPTION_VERSION {
346 if let Some((last_checkpoint, total_len)) = self.transactions.last_mut() {
348 if last_checkpoint.file_offset == checkpoint.file_offset {
349 *total_len += len as u64;
350 return;
351 }
352 }
353 self.transactions.push((checkpoint.clone(), len as u64));
354 } else {
355 if let Some((last_checkpoint, count)) = self.transactions.last_mut() {
357 if last_checkpoint.file_offset == checkpoint.file_offset {
358 *count += 1;
359 return;
360 }
361 }
362 self.transactions.push((checkpoint.clone(), 1));
363 }
364 }
365}
366
367pub enum LockState {
368 Locked,
369 Unencrypted,
370 Unlocked {
371 crypt: Arc<dyn Crypt>,
372 cached_keys: Vec<(NonZero<u64>, EncryptionKey, UnwrappedKey)>,
373 mutations_cipher: JournalCipher,
374 },
375
376 UnlockedReadOnly(Arc<dyn Crypt>),
379
380 Invalid,
383
384 Unknown,
387
388 Locking,
391
392 Unlocking,
395
396 Deleted,
398}
399
400impl fmt::Debug for LockState {
401 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
402 formatter.write_str(match self {
403 LockState::Locked => "Locked",
404 LockState::Unencrypted => "Unencrypted",
405 LockState::Unlocked { .. } => "Unlocked",
406 LockState::UnlockedReadOnly(..) => "UnlockedReadOnly",
407 LockState::Invalid => "Invalid",
408 LockState::Unknown => "Unknown",
409 LockState::Locking => "Locking",
410 LockState::Unlocking => "Unlocking",
411 LockState::Deleted => "Deleted",
412 })
413 }
414}
415
416enum LastObjectId {
417 Pending,
419
420 Unencrypted {
421 id: u64,
422 },
423
424 Encrypted {
425 id: u64,
427
428 cipher: Box<Ff1>,
430 },
431
432 Low32Bit {
433 reserved: HashSet<u32>,
434 unreserved: Vec<u32>,
435 },
436}
437
438impl LastObjectId {
439 fn uses_reserved_ids(&self) -> bool {
441 matches!(self, LastObjectId::Low32Bit { .. })
442 }
443
444 fn try_get_next(&mut self) -> Option<NonZero<u64>> {
448 match self {
449 LastObjectId::Unencrypted { id } => {
450 NonZero::new(id.wrapping_add(1)).inspect(|next| *id = next.get())
451 }
452 LastObjectId::Encrypted { id, cipher } => {
453 let mut next = *id;
454 let hi = next & OBJECT_ID_HI_MASK;
455 loop {
456 if next as u32 == u32::MAX {
457 return None;
458 }
459 next += 1;
460 let candidate = hi | cipher.encrypt(next as u32) as u64;
461 if let Some(candidate) = NonZero::new(candidate) {
462 *id = next;
463 return Some(candidate);
464 }
465 }
466 }
467 _ => None,
468 }
469 }
470
471 fn peek_next(&self) -> u64 {
473 match self {
474 LastObjectId::Unencrypted { id } => id.wrapping_add(1),
475 LastObjectId::Encrypted { id, cipher } => {
476 let mut next = *id;
477 let hi = next & OBJECT_ID_HI_MASK;
478 loop {
479 if next as u32 == u32::MAX {
480 return INVALID_OBJECT_ID;
481 }
482 next += 1;
483 let candidate = hi | cipher.encrypt(next as u32) as u64;
484 if candidate != INVALID_OBJECT_ID {
485 return candidate;
486 }
487 }
488 }
489 _ => INVALID_OBJECT_ID,
490 }
491 }
492
493 fn id(&self) -> u64 {
495 match self {
496 LastObjectId::Unencrypted { id } | LastObjectId::Encrypted { id, .. } => *id,
497 _ => INVALID_OBJECT_ID,
498 }
499 }
500
501 fn is_reserved(&self, id: u64) -> bool {
503 match self {
504 LastObjectId::Low32Bit { reserved, .. } => {
505 if let Ok(id) = id.try_into() {
506 reserved.contains(&id)
507 } else {
508 false
509 }
510 }
511 _ => false,
512 }
513 }
514
515 fn reserve(&mut self, id: u64) {
517 match self {
518 LastObjectId::Low32Bit { reserved, .. } => {
519 assert!(reserved.insert(id.try_into().unwrap()))
520 }
521 _ => unreachable!(),
522 }
523 }
524
525 fn unreserve(&mut self, id: u64) {
527 match self {
528 LastObjectId::Low32Bit { unreserved, .. } => {
529 unreserved.push(id.try_into().unwrap())
548 }
549 _ => {}
550 }
551 }
552
553 fn drain_unreserved(&mut self) {
555 match self {
556 LastObjectId::Low32Bit { reserved, unreserved } => {
557 for u in unreserved.drain(..) {
558 assert!(reserved.remove(&u));
559 }
560 }
561 _ => {}
562 }
563 }
564}
565
566pub struct ReservedId<'a>(&'a ObjectStore, NonZero<u64>);
567
568impl<'a> ReservedId<'a> {
569 pub fn new(store: &'a ObjectStore, id: NonZero<u64>) -> Self {
570 Self(store, id)
571 }
572
573 pub fn get(&self) -> u64 {
574 self.1.get()
575 }
576
577 #[must_use]
579 pub fn release(self) -> NonZero<u64> {
580 let id = self.1;
581 std::mem::forget(self);
582 id
583 }
584}
585
586impl Drop for ReservedId<'_> {
587 fn drop(&mut self) {
588 self.0.last_object_id.lock().unreserve(self.1.get());
589 }
590}
591
592#[async_trait]
593pub trait ObjectStoreTrait: Send + Sync + 'static {
594 async fn purge(
596 &self,
597 object_id: u64,
598 truncate_guard: Option<&TruncateGuard<'_>>,
599 ) -> Result<(), Error>;
600
601 fn purge_async(&self, object_id: u64);
603
604 fn tree(&self) -> &LSMTree<ObjectKey, ObjectValue>;
606
607 fn filesystem(&self) -> Arc<dyn Filesystem>;
609}
610
611pub struct ObjectStore {
616 parent_store: Option<Arc<ObjectStore>>,
617 store_object_id: u64,
618 device: Arc<dyn Device>,
619 block_size: BlockSize,
620 filesystem: Weak<dyn Filesystem>,
621 store_info: Mutex<Option<StoreInfo>>,
623 tree: LSMTree<ObjectKey, ObjectValue>,
624
625 store_info_handle: OnceLock<DataObjectHandle<ObjectStore>>,
630
631 lock_state: Mutex<LockState>,
634 pub key_manager: KeyManager,
635
636 trace: AtomicBool,
638
639 counters: Mutex<ObjectStoreCounters>,
641
642 device_read_ops: AtomicU64,
644 device_write_ops: AtomicU64,
645 logical_read_ops: AtomicU64,
646 logical_write_ops: AtomicU64,
647 graveyard_entries: AtomicU64,
648
649 last_object_id: Mutex<LastObjectId>,
652
653 flush_callback: Mutex<Option<Box<dyn Fn(&ObjectStore) + Send + Sync + 'static>>>,
656}
657
658#[derive(Clone, Default)]
659struct ObjectStoreCounters {
660 mutations_applied: u64,
661 mutations_dropped: u64,
662 num_flushes: u64,
663 last_flush_time: Option<std::time::SystemTime>,
664}
665
666impl ObjectStore {
667 fn new(
668 parent_store: Option<Arc<ObjectStore>>,
669 store_object_id: u64,
670 filesystem: Arc<dyn Filesystem>,
671 store_info: Option<StoreInfo>,
672 object_cache: Option<Box<dyn ObjectCache<ObjectKey, ObjectValue>>>,
673 lock_state: LockState,
674 last_object_id: LastObjectId,
675 ) -> Arc<ObjectStore> {
676 let device = filesystem.ensure_local().device();
677 let block_size = filesystem.block_size();
678 Arc::new(ObjectStore {
679 parent_store,
680 store_object_id,
681 device,
682 block_size,
683 filesystem: Arc::downgrade(&filesystem),
684 store_info: Mutex::new(store_info),
685 tree: LSMTree::new(merge::merge, object_cache),
686 store_info_handle: OnceLock::new(),
687 lock_state: Mutex::new(lock_state),
688 key_manager: KeyManager::new(),
689 trace: AtomicBool::new(false),
690 counters: Mutex::new(ObjectStoreCounters::default()),
691 device_read_ops: AtomicU64::new(0),
692 device_write_ops: AtomicU64::new(0),
693 logical_read_ops: AtomicU64::new(0),
694 logical_write_ops: AtomicU64::new(0),
695 graveyard_entries: AtomicU64::new(0),
696 last_object_id: Mutex::new(last_object_id),
697 flush_callback: Mutex::new(None),
698 })
699 }
700
701 fn new_empty(
702 parent_store: Option<Arc<ObjectStore>>,
703 store_object_id: u64,
704 filesystem: Arc<FxFilesystem>,
705 object_cache: Option<Box<dyn ObjectCache<ObjectKey, ObjectValue>>>,
706 ) -> Arc<Self> {
707 Self::new(
708 parent_store,
709 store_object_id,
710 filesystem,
711 Some(StoreInfo::default()),
712 object_cache,
713 LockState::Unencrypted,
714 LastObjectId::Unencrypted { id: 0 },
715 )
716 }
717
718 pub fn new_root_parent(
721 device: Arc<dyn Device>,
722 block_size: BlockSize,
723 store_object_id: u64,
724 ) -> Self {
725 ObjectStore {
726 parent_store: None,
727 store_object_id,
728 device,
729 block_size,
730 filesystem: Weak::<FxFilesystem>::new(),
731 store_info: Mutex::new(Some(StoreInfo::default())),
732 tree: LSMTree::new(merge::merge, None),
733 store_info_handle: OnceLock::new(),
734 lock_state: Mutex::new(LockState::Unencrypted),
735 key_manager: KeyManager::new(),
736 trace: AtomicBool::new(false),
737 counters: Mutex::new(ObjectStoreCounters::default()),
738 device_read_ops: AtomicU64::new(0),
739 device_write_ops: AtomicU64::new(0),
740 logical_read_ops: AtomicU64::new(0),
741 logical_write_ops: AtomicU64::new(0),
742 graveyard_entries: AtomicU64::new(0),
743 last_object_id: Mutex::new(LastObjectId::Unencrypted { id: 0 }),
744 flush_callback: Mutex::new(None),
745 }
746 }
747
748 pub fn attach_filesystem(mut this: ObjectStore, filesystem: Arc<FxFilesystem>) -> ObjectStore {
751 this.filesystem = Arc::downgrade(&filesystem) as Weak<dyn Filesystem>;
752 this
753 }
754
755 pub async fn new_transaction<'a>(
758 &self,
759 locks: LockKeys,
760 options: Options<'a>,
761 ) -> Result<Transaction<'a>, Error> {
762 self.filesystem().new_transaction(locks, options).await
763 }
764
765 async fn pre_cache_keys(&self) -> Result<(), Error> {
767 let crypt = match &*self.lock_state.lock() {
768 LockState::Unlocked { cached_keys, crypt, .. }
769 if cached_keys.len() < CACHED_KEYS_LIMIT =>
770 {
771 crypt.clone()
772 }
773 _ => return Ok(()),
774 };
775 loop {
776 let parent_store = self.parent_store.as_ref().unwrap();
777
778 assert!(!parent_store.last_object_id.lock().uses_reserved_ids());
781
782 let raw_id = {
785 let reserved_id = parent_store
786 .maybe_get_next_object_id()
787 .expect("maybe_get_next_object_id failed on parent store");
788 reserved_id.release()
789 };
790
791 let (wrapped, unwrapped) = match crypt.create_key(raw_id.get(), KeyPurpose::Data).await
792 {
793 Ok(v) => v,
794 Err(error) => {
795 log::warn!(
796 error:?,
797 store_id = self.store_object_id();
798 "Failed to pre-cache key"
799 );
800 return Err(error.into());
801 }
802 };
803
804 let mut lock_state = self.lock_state.lock();
805 if let LockState::Unlocked { cached_keys, .. } = &mut *lock_state {
806 cached_keys.push((raw_id, EncryptionKey::Fxfs(wrapped), unwrapped));
807 if cached_keys.len() >= CACHED_KEYS_LIMIT {
808 break;
809 }
810 } else {
811 break;
813 }
814 }
815 Ok(())
816 }
817
818 async fn new_child_store(
828 self: &Arc<Self>,
829 transaction: &mut Transaction<'_>,
830 options: NewChildStoreOptions,
831 object_cache: Option<Box<dyn ObjectCache<ObjectKey, ObjectValue>>>,
832 ) -> Result<Arc<Self>, Error> {
833 ensure!(
834 !options.reserve_32bit_object_ids || !options.low_32_bit_object_ids,
835 FxfsError::InvalidArgs
836 );
837 let handle = if let Some(object_id) = NonZero::new(options.object_id) {
838 self.update_last_object_id(object_id.get());
839 let handle = ObjectStore::create_object_with_id(
840 self,
841 transaction,
842 ReservedId::new(self, object_id),
843 HandleOptions::default(),
844 None,
845 )?;
846 handle
847 } else {
848 ObjectStore::create_object(self, transaction, HandleOptions::default(), None).await?
849 };
850 let filesystem = self.filesystem();
851 let id = if options.reserve_32bit_object_ids { 0x1_0000_0000 } else { 0 };
852 let (last_object_id, last_object_id_in_memory) = if options.low_32_bit_object_ids {
853 (
854 LastObjectIdInfo::Low32Bit,
855 LastObjectId::Low32Bit { reserved: HashSet::new(), unreserved: Vec::new() },
856 )
857 } else if let Some(crypt) = &options.options.crypt {
858 let (object_id_wrapped, object_id_unwrapped) =
859 crypt.create_key(handle.object_id(), KeyPurpose::Metadata).await?;
860 (
861 LastObjectIdInfo::Encrypted { id, key: object_id_wrapped },
862 LastObjectId::Encrypted { id, cipher: Box::new(Ff1::new(&object_id_unwrapped)) },
863 )
864 } else {
865 (LastObjectIdInfo::Unencrypted { id }, LastObjectId::Unencrypted { id })
866 };
867 let store = if let Some(crypt) = options.options.crypt {
868 let (wrapped_key, unwrapped_key) =
869 crypt.create_key(handle.object_id(), KeyPurpose::Metadata).await?;
870 Self::new(
871 Some(self.clone()),
872 handle.object_id(),
873 filesystem.clone(),
874 Some(StoreInfo {
875 mutations_key: Some(wrapped_key),
876 last_object_id,
877 guid: options.guid.unwrap_or_else(|| *Uuid::new_v4().as_bytes()),
878 ..Default::default()
879 }),
880 object_cache,
881 LockState::Unlocked {
882 crypt,
883 cached_keys: Vec::new(),
884 mutations_cipher: JournalCipher::new_aes256_xts(&unwrapped_key, 0),
885 },
886 last_object_id_in_memory,
887 )
888 } else {
889 Self::new(
890 Some(self.clone()),
891 handle.object_id(),
892 filesystem.clone(),
893 Some(StoreInfo {
894 last_object_id,
895 guid: options.guid.unwrap_or_else(|| *Uuid::new_v4().as_bytes()),
896 ..Default::default()
897 }),
898 object_cache,
899 LockState::Unencrypted,
900 last_object_id_in_memory,
901 )
902 };
903 assert!(store.store_info_handle.set(handle).is_ok());
904 Ok(store)
905 }
906
907 async fn create<'a>(
910 self: &'a Arc<Self>,
911 transaction: &mut Transaction<'a>,
912 ) -> Result<(), Error> {
913 let buf = {
914 let graveyard_directory_object_id = Graveyard::create(transaction, &self).await?;
916 let root_directory = Directory::create(transaction, &self, None).await?;
917
918 let serialized_info = {
919 let mut store_info = self.store_info.lock();
920 let store_info = store_info.as_mut().unwrap();
921
922 store_info.graveyard_directory_object_id = graveyard_directory_object_id;
923 store_info.root_directory_object_id = root_directory.object_id();
924
925 let mut serialized_info = Vec::new();
926 store_info.serialize_with_version(&mut serialized_info)?;
927 serialized_info
928 };
929 let mut buf = self.device.allocate_buffer(serialized_info.len()).await;
930 buf.copy_from_slice(&serialized_info[..]);
931 buf
932 };
933
934 if self.filesystem().options().image_builder_mode.is_some() {
935 Ok(())
939 } else {
940 self.store_info_handle.get().unwrap().txn_write(transaction, 0u64, buf.as_ref()).await
941 }
942 }
943
944 pub fn set_trace(&self, trace: bool) {
945 let old_value = self.trace.swap(trace, Ordering::Relaxed);
946 if trace != old_value {
947 info!(store_id = self.store_object_id(), trace; "OS: trace",);
948 }
949 }
950
951 pub fn set_flush_callback<F: Fn(&ObjectStore) + Send + Sync + 'static>(&self, callback: F) {
954 let mut flush_callback = self.flush_callback.lock();
955 *flush_callback = Some(Box::new(callback));
956 }
957
958 pub fn is_root(&self) -> bool {
959 if let Some(parent) = &self.parent_store {
960 parent.parent_store.is_none()
961 } else {
962 false
964 }
965 }
966
967 pub fn record_data(self: &Arc<Self>, root: &fuchsia_inspect::Node) {
969 let counters = self.counters.lock();
971 if let Some(store_info) = self.store_info() {
972 root.record_string("guid", Uuid::from_bytes(store_info.guid).to_string());
973 };
974 root.record_uint("store_object_id", self.store_object_id);
975 root.record_uint("mutations_applied", counters.mutations_applied);
976 root.record_uint("mutations_dropped", counters.mutations_dropped);
977 root.record_uint("num_flushes", counters.num_flushes);
978 if let Some(last_flush_time) = counters.last_flush_time.as_ref() {
979 root.record_uint(
980 "last_flush_time_ms",
981 last_flush_time
982 .duration_since(std::time::UNIX_EPOCH)
983 .unwrap_or(std::time::Duration::ZERO)
984 .as_millis()
985 .try_into()
986 .unwrap_or(0u64),
987 );
988 }
989 root.record_uint("device_read_ops", self.device_read_ops.load(Ordering::Relaxed));
990 root.record_uint("device_write_ops", self.device_write_ops.load(Ordering::Relaxed));
991 root.record_uint("logical_read_ops", self.logical_read_ops.load(Ordering::Relaxed));
992 root.record_uint("logical_write_ops", self.logical_write_ops.load(Ordering::Relaxed));
993 root.record_uint("graveyard_entries", self.graveyard_entries.load(Ordering::Relaxed));
994 {
995 let last_object_id = self.last_object_id.lock();
996 root.record_uint("object_id_hi", last_object_id.id() >> 32);
997 root.record_bool(
998 "low_32_bit_object_ids",
999 matches!(&*last_object_id, LastObjectId::Low32Bit { .. }),
1000 );
1001 }
1002
1003 let this = self.clone();
1004 root.record_child("lsm_tree", move |node| this.tree().record_inspect_data(node));
1005 }
1006
1007 pub fn device(&self) -> &Arc<dyn Device> {
1008 &self.device
1009 }
1010
1011 pub fn block_size(&self) -> BlockSize {
1012 self.block_size
1013 }
1014
1015 pub fn filesystem(&self) -> Arc<dyn Filesystem> {
1016 self.filesystem.upgrade().unwrap()
1017 }
1018
1019 pub fn store_object_id(&self) -> u64 {
1020 self.store_object_id
1021 }
1022
1023 pub fn tree(&self) -> &LSMTree<ObjectKey, ObjectValue> {
1024 &self.tree
1025 }
1026
1027 pub fn root_directory_object_id(&self) -> u64 {
1028 self.store_info.lock().as_ref().unwrap().root_directory_object_id
1029 }
1030
1031 pub fn guid(&self) -> [u8; 16] {
1032 self.store_info.lock().as_ref().unwrap().guid
1033 }
1034
1035 pub fn graveyard_directory_object_id(&self) -> u64 {
1036 self.store_info.lock().as_ref().unwrap().graveyard_directory_object_id
1037 }
1038
1039 fn set_graveyard_directory_object_id(&self, oid: u64) {
1040 assert_eq!(
1041 std::mem::replace(
1042 &mut self.store_info.lock().as_mut().unwrap().graveyard_directory_object_id,
1043 oid
1044 ),
1045 INVALID_OBJECT_ID
1046 );
1047 }
1048
1049 pub fn object_count(&self) -> u64 {
1050 self.store_info.lock().as_ref().unwrap().object_count
1051 }
1052
1053 pub(crate) fn unencrypted_last_object_id(&self) -> u64 {
1055 self.last_object_id.lock().id()
1056 }
1057
1058 pub fn key_manager(&self) -> &KeyManager {
1059 &self.key_manager
1060 }
1061
1062 pub fn clear_caches(&self) {
1065 self.tree.clear_cache();
1066 self.key_manager.clear_cached_keys();
1067 }
1068
1069 pub fn parent_store(&self) -> Option<&Arc<ObjectStore>> {
1070 self.parent_store.as_ref()
1071 }
1072
1073 pub fn crypt(&self) -> Option<Arc<dyn Crypt>> {
1075 match &*self.lock_state.lock() {
1076 LockState::Locked => panic!("Store is locked"),
1077 LockState::Invalid
1078 | LockState::Unencrypted
1079 | LockState::Locking
1080 | LockState::Unlocking
1081 | LockState::Deleted => None,
1082 LockState::Unlocked { crypt, .. } => Some(crypt.clone()),
1083 LockState::UnlockedReadOnly(crypt) => Some(crypt.clone()),
1084 LockState::Unknown => {
1085 panic!("Store is of unknown lock state; has the journal been replayed yet?")
1086 }
1087 }
1088 }
1089
1090 pub fn get_internal_directory_id(self: &Arc<Self>) -> Result<u64, Error> {
1093 if let Some(store_info) = self.store_info.lock().as_ref() {
1094 if store_info.internal_directory_object_id == INVALID_OBJECT_ID {
1095 Err(FxfsError::NotFound.into())
1096 } else {
1097 Ok(store_info.internal_directory_object_id)
1098 }
1099 } else {
1100 Err(FxfsError::Unavailable.into())
1101 }
1102 }
1103
1104 pub async fn get_or_create_internal_directory_id(self: &Arc<Self>) -> Result<u64, Error> {
1105 let mut transaction = self
1107 .new_transaction(
1108 lock_keys![LockKey::InternalDirectory { store_object_id: self.store_object_id }],
1109 Options::default(),
1110 )
1111 .await?;
1112 let obj_id = self.store_info.lock().as_ref().unwrap().internal_directory_object_id;
1113 if obj_id != INVALID_OBJECT_ID {
1114 return Ok(obj_id);
1115 }
1116
1117 let directory = Directory::create(&mut transaction, self, None).await?;
1119
1120 transaction.add(self.store_object_id, Mutation::CreateInternalDir(directory.object_id()));
1121 transaction.commit().await?;
1122 Ok(directory.object_id())
1123 }
1124
1125 async fn get_file_size(&self, object_id: u64) -> Result<u64, Error> {
1127 self.tree
1128 .find_map(
1129 &ObjectKey::attribute(object_id, AttributeId::DATA, AttributeKey::Attribute),
1130 |item| match item.value {
1131 ObjectValue::Attribute { size, .. } => Ok(*size),
1132 _ => Err(anyhow!(FxfsError::NotFile)),
1133 },
1134 )
1135 .await?
1136 .ok_or(FxfsError::NotFound)?
1137 }
1138
1139 #[cfg(feature = "migration")]
1140 pub fn last_object_id(&self) -> u64 {
1141 self.last_object_id.lock().id()
1142 }
1143
1144 #[cfg(feature = "migration")]
1146 pub fn mark_allocated(
1147 &self,
1148 transaction: &mut Transaction<'_>,
1149 store_object_id: u64,
1150 device_range: std::ops::Range<u64>,
1151 ) -> Result<(), Error> {
1152 self.allocator().mark_allocated(transaction, store_object_id, device_range)
1153 }
1154
1155 pub async fn open_object<S: HandleOwner>(
1162 owner: &Arc<S>,
1163 obj_id: u64,
1164 options: HandleOptions,
1165 crypt: Option<Arc<dyn Crypt>>,
1166 ) -> Result<DataObjectHandle<S>, Error> {
1167 let store = owner.as_ref().as_ref();
1168 let mut fsverity_descriptor = None;
1169 let mut overwrite_ranges = Vec::new();
1170 let value = store
1171 .tree
1172 .find_value(&ObjectKey::attribute(obj_id, AttributeId::DATA, AttributeKey::Attribute))
1173 .await?
1174 .ok_or(FxfsError::NotFound)?;
1175
1176 let (size, track_overwrite_extents) = match value {
1177 ObjectValue::Attribute { size, has_overwrite_extents } => (size, has_overwrite_extents),
1178 ObjectValue::VerifiedAttribute { size, fsverity_metadata } => {
1179 if !options.skip_fsverity {
1180 fsverity_descriptor = Some(fsverity_metadata);
1181 }
1182 (size, false)
1186 }
1187 _ => bail!(anyhow!(FxfsError::Inconsistent).context("open_object: Expected attibute")),
1188 };
1189
1190 ensure!(size <= MAX_FILE_SIZE, FxfsError::Inconsistent);
1191
1192 if track_overwrite_extents {
1193 let layer_set = store.tree.layer_set();
1194 let mut merger = layer_set.merger();
1195 let mut iter = merger
1196 .query(Query::FullRange(&ObjectKey::attribute(
1197 obj_id,
1198 AttributeId::DATA,
1199 AttributeKey::Extent(Extent::search_key_from_offset(0)),
1200 )))
1201 .await?;
1202 loop {
1203 match iter.get() {
1204 Some(ItemRef {
1205 key:
1206 ObjectKey {
1207 object_id,
1208 data:
1209 ObjectKeyData::Attribute(
1210 AttributeId::DATA,
1211 AttributeKey::Extent(extent),
1212 ),
1213 },
1214 value,
1215 ..
1216 }) if *object_id == obj_id => {
1217 match value {
1218 ObjectValue::Extent(ExtentValue::None)
1219 | ObjectValue::Extent(ExtentValue::Some {
1220 mode: ExtentMode::Raw,
1221 ..
1222 })
1223 | ObjectValue::Extent(ExtentValue::Some {
1224 mode: ExtentMode::Cow(_),
1225 ..
1226 }) => (),
1227 ObjectValue::Extent(ExtentValue::Some {
1228 mode: ExtentMode::OverwritePartial(_),
1229 ..
1230 })
1231 | ObjectValue::Extent(ExtentValue::Some {
1232 mode: ExtentMode::Overwrite,
1233 ..
1234 }) => overwrite_ranges.push(extent.clone().into()),
1235 _ => bail!(
1236 anyhow!(FxfsError::Inconsistent)
1237 .context("open_object: Expected extent")
1238 ),
1239 }
1240 iter.advance().await?;
1241 }
1242 _ => break,
1243 }
1244 }
1245 }
1246
1247 let permanent = if let Some(crypt) = crypt {
1250 store
1251 .key_manager
1252 .get_keys(
1253 obj_id,
1254 crypt.as_ref(),
1255 &mut Some(async || store.get_keys(obj_id).await),
1256 true,
1257 false,
1258 )
1259 .await?;
1260 true
1261 } else {
1262 false
1263 };
1264 let data_object_handle = DataObjectHandle::new(
1265 owner.clone(),
1266 obj_id,
1267 permanent,
1268 AttributeId::DATA,
1269 size,
1270 options,
1271 false,
1272 &overwrite_ranges,
1273 );
1274 if let Some(descriptor) = fsverity_descriptor {
1275 data_object_handle
1276 .set_fsverity_state_some(descriptor)
1277 .await
1278 .context("Invalid or mismatched merkle tree")?;
1279 }
1280 Ok(data_object_handle)
1281 }
1282
1283 pub fn create_object_with_id<S: HandleOwner>(
1284 owner: &Arc<S>,
1285 transaction: &mut Transaction<'_>,
1286 reserved_object_id: ReservedId<'_>,
1287 options: HandleOptions,
1288 encryption_options: Option<ObjectEncryptionOptions>,
1289 ) -> Result<DataObjectHandle<S>, Error> {
1290 let store = owner.as_ref().as_ref();
1291 debug_assert!(store.crypt().is_none() || encryption_options.is_some());
1293 let now = Timestamp::now();
1294 let object_id = reserved_object_id.get();
1295 assert!(
1296 transaction
1297 .add(
1298 store.store_object_id(),
1299 Mutation::insert_object(
1300 ObjectKey::object(reserved_object_id.release().get()),
1301 ObjectValue::file(
1302 1,
1303 0,
1304 now.clone(),
1305 now.clone(),
1306 now.clone(),
1307 now,
1308 None,
1309 None
1310 ),
1311 ),
1312 )
1313 .is_none()
1314 );
1315 let mut permanent_keys = false;
1316 if let Some(ObjectEncryptionOptions { permanent, key_id, key, unwrapped_key }) =
1317 encryption_options
1318 {
1319 permanent_keys = permanent;
1320 let cipher = key_to_cipher(&key, &unwrapped_key)?;
1321 store.key_manager.insert_fscrypt_file_cipher(&key, cipher.clone());
1322 transaction.add(
1323 store.store_object_id(),
1324 Mutation::insert_object(
1325 ObjectKey::keys(object_id),
1326 ObjectValue::keys(vec![(key_id, key)].into()),
1327 ),
1328 );
1329 store.key_manager.insert(
1330 object_id,
1331 Arc::new(vec![(key_id, CipherHolder::Cipher(cipher))].into()),
1332 permanent,
1333 );
1334 }
1335 transaction.add(
1336 store.store_object_id(),
1337 Mutation::insert_object(
1338 ObjectKey::attribute(object_id, AttributeId::DATA, AttributeKey::Attribute),
1339 ObjectValue::attribute(0, false),
1341 ),
1342 );
1343 Ok(DataObjectHandle::new(
1344 owner.clone(),
1345 object_id,
1346 permanent_keys,
1347 AttributeId::DATA,
1348 0,
1349 options,
1350 false,
1351 &[],
1352 ))
1353 }
1354
1355 pub async fn create_object<S: HandleOwner>(
1361 owner: &Arc<S>,
1362 mut transaction: &mut Transaction<'_>,
1363 options: HandleOptions,
1364 fscrypt_info: Option<FscryptDirInfo>,
1365 ) -> Result<DataObjectHandle<S>, Error> {
1366 let store = owner.as_ref().as_ref();
1367 let object_id = store.get_next_object_id(transaction).await?;
1368 let crypt = store.crypt();
1369 let encryption_options = if let Some(crypt) = crypt {
1370 let key_id = if fscrypt_info.is_some() { FSCRYPT_KEY_ID } else { VOLUME_DATA_KEY_ID };
1371 let (key, unwrapped_key) = if let Some(info) = fscrypt_info {
1372 crypt
1373 .create_key_with_id(
1374 object_id.get(),
1375 info.wrapping_key_id,
1376 ObjectType::File,
1377 info.flags.into(),
1378 )
1379 .await?
1380 } else {
1381 let (fxfs_key, unwrapped_key) =
1382 crypt.create_key(object_id.get(), KeyPurpose::Data).await?;
1383 (EncryptionKey::Fxfs(fxfs_key), unwrapped_key)
1384 };
1385 Some(ObjectEncryptionOptions { permanent: false, key_id, key, unwrapped_key })
1386 } else {
1387 None
1388 };
1389 ObjectStore::create_object_with_id(
1390 owner,
1391 &mut transaction,
1392 object_id,
1393 options,
1394 encryption_options,
1395 )
1396 }
1397
1398 pub(crate) async fn create_object_with_key<S: HandleOwner>(
1404 owner: &Arc<S>,
1405 mut transaction: &mut Transaction<'_>,
1406 object_id: ReservedId<'_>,
1407 options: HandleOptions,
1408 key: EncryptionKey,
1409 unwrapped_key: UnwrappedKey,
1410 ) -> Result<DataObjectHandle<S>, Error> {
1411 ObjectStore::create_object_with_id(
1412 owner,
1413 &mut transaction,
1414 object_id,
1415 options,
1416 Some(ObjectEncryptionOptions {
1417 permanent: true,
1418 key_id: VOLUME_DATA_KEY_ID,
1419 key,
1420 unwrapped_key,
1421 }),
1422 )
1423 }
1424
1425 pub async fn adjust_refs(
1428 &self,
1429 transaction: &mut Transaction<'_>,
1430 object_id: u64,
1431 delta: i64,
1432 ) -> Result<bool, Error> {
1433 self.adjust_refs_impl(transaction, object_id, delta, true).await
1434 }
1435
1436 pub async fn adjust_refs_impl(
1440 &self,
1441 transaction: &mut Transaction<'_>,
1442 object_id: u64,
1443 delta: i64,
1444 add_to_graveyard: bool,
1445 ) -> Result<bool, Error> {
1446 let mut mutation = self.txn_get_object_mutation(transaction, object_id).await?;
1447 let refs = if let ObjectValue::Object {
1448 kind:
1449 ObjectKind::File { refs, .. }
1450 | ObjectKind::Symlink { refs, .. }
1451 | ObjectKind::EncryptedSymlink { refs, .. }
1452 | ObjectKind::NonInlineSymlink { refs, .. },
1453 ..
1454 } = &mut mutation.item.value
1455 {
1456 *refs =
1457 refs.checked_add_signed(delta).ok_or_else(|| anyhow!("refs underflow/overflow"))?;
1458 refs
1459 } else {
1460 bail!(FxfsError::NotFile);
1461 };
1462 if *refs == 0 {
1463 if add_to_graveyard {
1464 self.add_to_graveyard(transaction, object_id);
1465
1466 if delta != -1 {
1469 *refs = 1;
1470 transaction.add(self.store_object_id, Mutation::ObjectStore(mutation));
1471 }
1472
1473 }
1476 Ok(true)
1477 } else {
1478 transaction.add(self.store_object_id, Mutation::ObjectStore(mutation));
1479 Ok(false)
1480 }
1481 }
1482
1483 pub async fn tombstone_object(
1491 &self,
1492 object_id: u64,
1493 txn_options: Options<'_>,
1494 truncate_guard: Option<&TruncateGuard<'_>>,
1495 ) -> Result<(), Error> {
1496 debug_assert!(
1497 self.tree.exists(&ObjectKey::object(object_id)).await?,
1498 "Tombstoning missing object"
1499 );
1500 debug_assert!(
1501 self.tree
1502 .exists(&ObjectKey::graveyard_entry(
1503 self.graveyard_directory_object_id(),
1504 object_id
1505 ))
1506 .await?,
1507 "Tombstoning object not in graveyard"
1508 );
1509 self.key_manager.remove(object_id).await;
1510 let _fs;
1511 let _guard;
1512 let truncate_guard = match truncate_guard {
1513 Some(guard) => guard,
1514 None => {
1515 _fs = self.filesystem();
1516 _guard = _fs.truncate_guard(self.store_object_id, object_id).await;
1517 &_guard
1518 }
1519 };
1520 self.trim_or_tombstone(object_id, true, txn_options, truncate_guard).await
1521 }
1522
1523 pub async fn trim(
1526 &self,
1527 object_id: u64,
1528 truncate_guard: &TruncateGuard<'_>,
1529 ) -> Result<(), Error> {
1530 assert!(self.parent_store.as_ref().unwrap().parent_store.is_some());
1532
1533 self.trim_or_tombstone(
1534 object_id,
1535 false,
1536 Options { reservation: ReservationOptions::Borrowed, ..Default::default() },
1537 truncate_guard,
1538 )
1539 .await
1540 }
1541
1542 async fn trim_or_tombstone(
1544 &self,
1545 object_id: u64,
1546 for_tombstone: bool,
1547 txn_options: Options<'_>,
1548 _truncate_guard: &TruncateGuard<'_>,
1549 ) -> Result<(), Error> {
1550 let mut next_attribute = Some(AttributeId::SORTED_START);
1551 while let Some(attribute_id) = next_attribute.take() {
1552 let mut transaction = self
1553 .new_transaction(
1554 lock_keys![
1555 LockKey::object_attribute(self.store_object_id, object_id, attribute_id),
1556 LockKey::object(self.store_object_id, object_id),
1557 ],
1558 txn_options,
1559 )
1560 .await?;
1561
1562 match self
1563 .trim_some(
1564 &mut transaction,
1565 object_id,
1566 attribute_id,
1567 if for_tombstone {
1568 TrimMode::Tombstone(TombstoneMode::Object)
1569 } else {
1570 TrimMode::UseSize
1571 },
1572 )
1573 .await?
1574 {
1575 TrimResult::Incomplete => next_attribute = Some(attribute_id),
1576 TrimResult::Done(None) => {
1577 if for_tombstone
1578 || matches!(
1579 self.tree
1580 .find_value(&ObjectKey::graveyard_entry(
1581 self.graveyard_directory_object_id(),
1582 object_id,
1583 ))
1584 .await?,
1585 Some(ObjectValue::Trim)
1586 )
1587 {
1588 self.remove_from_graveyard(&mut transaction, object_id);
1589 }
1590 if for_tombstone && attribute_id != AttributeId::DATA {
1593 self.remove_attribute_from_graveyard(
1594 &mut transaction,
1595 object_id,
1596 attribute_id,
1597 );
1598 }
1599 }
1600 TrimResult::Done(id) => {
1601 if for_tombstone && attribute_id != AttributeId::DATA {
1604 self.remove_attribute_from_graveyard(
1605 &mut transaction,
1606 object_id,
1607 attribute_id,
1608 );
1609 }
1610 next_attribute = id;
1611 }
1612 }
1613
1614 if !transaction.mutations().is_empty() {
1615 transaction.commit().await?;
1616 }
1617 }
1618 Ok(())
1619 }
1620
1621 pub async fn tombstone_attribute(
1629 &self,
1630 object_id: u64,
1631 attribute_id: AttributeId,
1632 txn_options: Options<'_>,
1633 ) -> Result<(), Error> {
1634 debug_assert!(
1636 self.tree
1637 .exists(&ObjectKey::attribute(object_id, attribute_id, AttributeKey::Attribute))
1638 .await?,
1639 "Tombstoning missing attribute"
1640 );
1641 debug_assert!(
1642 self.tree
1643 .exists(&ObjectKey::graveyard_attribute_entry(
1644 self.graveyard_directory_object_id(),
1645 object_id,
1646 attribute_id
1647 ))
1648 .await?,
1649 "Tombstoning attribute not in graveyard"
1650 );
1651 let mut trim_result = TrimResult::Incomplete;
1652 while matches!(trim_result, TrimResult::Incomplete) {
1653 let mut transaction = self
1654 .new_transaction(
1655 lock_keys![
1656 LockKey::object_attribute(self.store_object_id, object_id, attribute_id),
1657 LockKey::object(self.store_object_id, object_id),
1658 ],
1659 txn_options,
1660 )
1661 .await?;
1662 trim_result = self
1663 .trim_some(
1664 &mut transaction,
1665 object_id,
1666 attribute_id,
1667 TrimMode::Tombstone(TombstoneMode::Attribute),
1668 )
1669 .await?;
1670 if let TrimResult::Done(..) = trim_result {
1671 self.remove_attribute_from_graveyard(&mut transaction, object_id, attribute_id)
1672 }
1673 if !transaction.mutations().is_empty() {
1674 transaction.commit().await?;
1675 }
1676 }
1677 Ok(())
1678 }
1679
1680 pub async fn trim_some(
1684 &self,
1685 transaction: &mut Transaction<'_>,
1686 object_id: u64,
1687 attribute_id: AttributeId,
1688 mode: TrimMode,
1689 ) -> Result<TrimResult, Error> {
1690 let layer_set = self.tree.layer_set();
1691 let mut merger = layer_set.merger();
1692
1693 let aligned_offset = match mode {
1694 TrimMode::FromOffset(offset) => {
1695 self.block_size.align_up(offset).ok_or(FxfsError::Inconsistent)?
1696 }
1697 TrimMode::Tombstone(..) => 0,
1698 TrimMode::UseSize => {
1699 let iter = merger
1700 .query(Query::FullRange(&ObjectKey::attribute(
1701 object_id,
1702 attribute_id,
1703 AttributeKey::Attribute,
1704 )))
1705 .await?;
1706 if let Some(item_ref) = iter.get() {
1707 if item_ref.key.object_id != object_id {
1708 return Ok(TrimResult::Done(None));
1709 }
1710
1711 if let ItemRef {
1712 key:
1713 ObjectKey {
1714 data:
1715 ObjectKeyData::Attribute(size_attribute_id, AttributeKey::Attribute),
1716 ..
1717 },
1718 value: ObjectValue::Attribute { size, .. },
1719 ..
1720 } = item_ref
1721 {
1722 if *size_attribute_id != attribute_id {
1725 return Ok(TrimResult::Done(Some(*size_attribute_id)));
1726 }
1727 self.block_size.align_up(*size).ok_or(FxfsError::Inconsistent)?
1728 } else {
1729 return Ok(TrimResult::Done(Some(attribute_id.next())));
1733 }
1734 } else {
1735 return Ok(TrimResult::Done(None));
1737 }
1738 }
1739 };
1740
1741 let mut iter = merger
1743 .query(Query::FullRange(&ObjectKey::from_extent(
1744 object_id,
1745 attribute_id,
1746 Extent::search_key_from_offset(aligned_offset),
1747 )))
1748 .await?;
1749 let mut end = 0;
1750 let allocator = self.allocator();
1751 let mut result = TrimResult::Done(None);
1752 let mut deallocated = 0;
1753 let block_size = self.block_size;
1754
1755 while let Some(item_ref) = iter.get() {
1756 if item_ref.key.object_id != object_id {
1757 break;
1758 }
1759 if let ObjectKey {
1760 data: ObjectKeyData::Attribute(extent_attribute_id, attribute_key),
1761 ..
1762 } = item_ref.key
1763 {
1764 if *extent_attribute_id != attribute_id {
1765 result = TrimResult::Done(Some(*extent_attribute_id));
1766 break;
1767 }
1768 if let (
1769 AttributeKey::Extent(extent),
1770 ObjectValue::Extent(ExtentValue::Some { device_offset, .. }),
1771 ) = (attribute_key, item_ref.value)
1772 {
1773 let start = std::cmp::max(extent.start, aligned_offset);
1774 ensure!(start < extent.end, FxfsError::Inconsistent);
1775 let device_offset = device_offset
1776 .checked_add(start - extent.start)
1777 .ok_or(FxfsError::Inconsistent)?;
1778 end = extent.end;
1779 let len = end - start;
1780 let device_range = device_offset..device_offset + len;
1781 ensure!(block_size.is_aligned(&device_range), FxfsError::Inconsistent);
1782 allocator.deallocate(transaction, self.store_object_id, device_range).await?;
1783 deallocated += len;
1784 if transaction.mutations().len() >= TRANSACTION_MUTATION_THRESHOLD {
1786 result = TrimResult::Incomplete;
1787 break;
1788 }
1789 }
1790 }
1791 iter.advance().await?;
1792 }
1793
1794 let finished_tombstone_object = matches!(mode, TrimMode::Tombstone(TombstoneMode::Object))
1795 && matches!(result, TrimResult::Done(None));
1796 let finished_tombstone_attribute =
1797 matches!(mode, TrimMode::Tombstone(TombstoneMode::Attribute))
1798 && !matches!(result, TrimResult::Incomplete);
1799 let mut object_mutation = None;
1800 let nodes = if finished_tombstone_object { -1 } else { 0 };
1801 if nodes != 0 || deallocated != 0 {
1802 let mutation = self.txn_get_object_mutation(transaction, object_id).await?;
1803 if let ObjectValue::Object { attributes: ObjectAttributes { project_id, .. }, .. } =
1804 mutation.item.value
1805 {
1806 if let Some(project_id) = project_id {
1807 transaction.merge_bytes_and_nodes(
1808 self.store_object_id,
1809 ObjectKey::project_usage(self.root_directory_object_id(), project_id),
1810 BytesAndNodes { bytes: -i64::try_from(deallocated).unwrap(), nodes },
1811 );
1812 }
1813 object_mutation = Some(mutation);
1814 } else {
1815 panic!("Inconsistent object type.");
1816 }
1817 }
1818
1819 if finished_tombstone_object {
1822 transaction.add(
1823 self.store_object_id,
1824 Mutation::merge_object(ObjectKey::object(object_id), ObjectValue::None),
1825 );
1826 } else {
1827 if finished_tombstone_attribute {
1828 transaction.add(
1829 self.store_object_id,
1830 Mutation::merge_object(
1831 ObjectKey::attribute(object_id, attribute_id, AttributeKey::Attribute),
1832 ObjectValue::None,
1833 ),
1834 );
1835 }
1836 if deallocated > 0 {
1837 let mut mutation = match object_mutation {
1838 Some(mutation) => mutation,
1839 None => self.txn_get_object_mutation(transaction, object_id).await?,
1840 };
1841 transaction.add(
1842 self.store_object_id,
1843 Mutation::merge_object(
1844 ObjectKey::extent(object_id, attribute_id, aligned_offset..end),
1845 ObjectValue::deleted_extent(),
1846 ),
1847 );
1848 if let ObjectValue::Object {
1850 attributes: ObjectAttributes { allocated_size, .. },
1851 ..
1852 } = &mut mutation.item.value
1853 {
1854 *allocated_size = allocated_size.checked_sub(deallocated).ok_or_else(|| {
1856 anyhow!(FxfsError::Inconsistent).context("Allocated size overflow")
1857 })?;
1858 } else {
1859 panic!("Unexpected object value");
1860 }
1861 transaction.add(self.store_object_id, Mutation::ObjectStore(mutation));
1862 }
1863 }
1864 Ok(result)
1865 }
1866
1867 pub fn parent_objects(&self) -> Vec<u64> {
1871 assert!(self.store_info_handle.get().is_some());
1872 self.store_info.lock().as_ref().unwrap().parent_objects()
1873 }
1874
1875 pub fn root_objects(&self) -> Vec<u64> {
1877 let mut objects = Vec::new();
1878 let store_info = self.store_info.lock();
1879 let info = store_info.as_ref().unwrap();
1880 if info.root_directory_object_id != INVALID_OBJECT_ID {
1881 objects.push(info.root_directory_object_id);
1882 }
1883 if info.graveyard_directory_object_id != INVALID_OBJECT_ID {
1884 objects.push(info.graveyard_directory_object_id);
1885 }
1886 if info.internal_directory_object_id != INVALID_OBJECT_ID {
1887 objects.push(info.internal_directory_object_id);
1888 }
1889 objects
1890 }
1891
1892 pub fn store_info(&self) -> Option<StoreInfo> {
1893 self.store_info.lock().as_ref().cloned()
1894 }
1895
1896 pub fn store_info_handle_object_id(&self) -> Option<u64> {
1898 self.store_info_handle.get().map(|h| h.object_id())
1899 }
1900
1901 pub fn graveyard_count(&self) -> u64 {
1902 self.graveyard_entries.load(Ordering::Relaxed)
1903 }
1904
1905 async fn open(
1907 parent_store: &Arc<ObjectStore>,
1908 store_object_id: u64,
1909 object_cache: Option<Box<dyn ObjectCache<ObjectKey, ObjectValue>>>,
1910 ) -> Result<Arc<ObjectStore>, Error> {
1911 let handle =
1912 ObjectStore::open_object(parent_store, store_object_id, HandleOptions::default(), None)
1913 .await?;
1914
1915 let info = load_store_info(parent_store, store_object_id).await?;
1916 let is_encrypted = info.mutations_key.is_some();
1917
1918 let mut total_layer_size = 0;
1919 let last_object_id;
1920
1921 if is_encrypted {
1926 for &oid in &info.layers {
1927 total_layer_size += parent_store.get_file_size(oid).await?;
1928 }
1929 if info.encrypted_mutations_object_id != INVALID_OBJECT_ID {
1930 total_layer_size += layer_size_from_encrypted_mutations_size(
1931 parent_store.get_file_size(info.encrypted_mutations_object_id).await?,
1932 );
1933 }
1934 last_object_id = LastObjectId::Pending;
1935 ensure!(
1936 matches!(
1937 info.last_object_id,
1938 LastObjectIdInfo::Encrypted { .. } | LastObjectIdInfo::Low32Bit { .. }
1939 ),
1940 FxfsError::Inconsistent
1941 );
1942 } else {
1943 last_object_id = match info.last_object_id {
1944 LastObjectIdInfo::Unencrypted { id } => LastObjectId::Unencrypted { id },
1945 LastObjectIdInfo::Low32Bit => {
1946 LastObjectId::Low32Bit { reserved: HashSet::new(), unreserved: Vec::new() }
1947 }
1948 _ => bail!(FxfsError::Inconsistent),
1949 };
1950 }
1951
1952 let fs = parent_store.filesystem();
1953
1954 let store = ObjectStore::new(
1955 Some(parent_store.clone()),
1956 store_object_id,
1957 fs.clone(),
1958 if is_encrypted { None } else { Some(info) },
1959 object_cache,
1960 if is_encrypted { LockState::Locked } else { LockState::Unencrypted },
1961 last_object_id,
1962 );
1963
1964 assert!(store.store_info_handle.set(handle).is_ok(), "Failed to set store_info_handle!");
1965
1966 if !is_encrypted {
1967 let object_tree_layer_object_ids =
1968 store.store_info.lock().as_ref().unwrap().layers.clone();
1969 total_layer_size = store
1970 .tree
1971 .append_layers(&parent_store, object_tree_layer_object_ids, None)
1972 .await
1973 .context("Failed to read object store layers")?;
1974 }
1975
1976 fs.ensure_local().object_manager().update_layer_size(store_object_id, total_layer_size);
1977
1978 Ok(store)
1979 }
1980
1981 async fn load_store_info(&self) -> Result<StoreInfo, Error> {
1982 load_store_info_from_handle(self.store_info_handle.get().unwrap()).await
1983 }
1984
1985 pub async fn unlock(self: &Arc<Self>, crypt: Arc<dyn Crypt>) -> Result<(), Error> {
1988 self.unlock_inner(crypt, false).await
1989 }
1990
1991 pub async fn unlock_read_only(self: &Arc<Self>, crypt: Arc<dyn Crypt>) -> Result<(), Error> {
1999 self.unlock_inner(crypt, true).await
2000 }
2001
2002 async fn unlock_inner(
2004 self: &Arc<Self>,
2005 crypt: Arc<dyn Crypt>,
2006 read_only: bool,
2007 ) -> Result<(), Error> {
2008 #[derive(Debug, PartialEq)]
2013 struct CryptFields {
2014 mutations_key: Option<FxfsKey>,
2015 mutations_cipher_offset: u64,
2016 last_object_id: LastObjectIdInfo,
2017 layers: Vec<u64>,
2018 }
2019 impl From<&StoreInfo> for CryptFields {
2020 fn from(info: &StoreInfo) -> Self {
2021 Self {
2022 mutations_key: info.mutations_key.clone(),
2023 mutations_cipher_offset: info.mutations_cipher_offset,
2024 last_object_id: info.last_object_id.clone(),
2025 layers: info.layers.clone(),
2026 }
2027 }
2028 }
2029
2030 assert!(read_only || !self.filesystem().options().read_only);
2032 match &*self.lock_state.lock() {
2033 LockState::Locked => {}
2034 LockState::Unencrypted => bail!(FxfsError::InvalidArgs),
2035 LockState::Invalid | LockState::Deleted => bail!(FxfsError::Internal),
2036 LockState::Unlocked { .. } | LockState::UnlockedReadOnly(..) => {
2037 bail!(FxfsError::AlreadyBound)
2038 }
2039 LockState::Unknown => panic!("Store was unlocked before replay"),
2040 LockState::Locking => panic!("Store is being locked"),
2041 LockState::Unlocking => panic!("Store is being unlocked"),
2042 }
2043
2044 let fs = self.filesystem();
2047 let guard =
2048 fs.lock_manager().write_lock(lock_keys![LockKey::flush(self.store_object_id())]).await;
2049
2050 let last_num_flushes = self.counters.lock().num_flushes;
2051 let mut store_info = self.load_store_info().await?;
2052
2053 let mut mutations = {
2055 if store_info.encrypted_mutations_object_id == INVALID_OBJECT_ID {
2056 EncryptedMutations::default()
2057 } else {
2058 let parent_store = self.parent_store.as_ref().unwrap();
2059 let handle = ObjectStore::open_object(
2060 &parent_store,
2061 store_info.encrypted_mutations_object_id,
2062 HandleOptions::default(),
2063 None,
2064 )
2065 .await?;
2066 let mut cursor = std::io::Cursor::new(
2067 handle
2068 .contents(MAX_ENCRYPTED_MUTATIONS_SIZE)
2069 .await
2070 .context(FxfsError::Inconsistent)?,
2071 );
2072 let mut mutations = EncryptedMutations::deserialize_with_version(&mut cursor)
2073 .context("Failed to deserialize EncryptedMutations")?
2074 .0;
2075 let len = cursor.get_ref().len() as u64;
2076 while cursor.position() < len {
2077 mutations.extend(
2078 &EncryptedMutations::deserialize_with_version(&mut cursor)
2079 .context("Failed to deserialize EncryptedMutations")?
2080 .0,
2081 );
2082 }
2083 mutations
2084 }
2085 };
2086
2087 let journaled = EncryptedMutations::from_replayed_mutations(
2089 self.store_object_id,
2090 fs.ensure_local()
2091 .journal()
2092 .read_transactions_for_object(self.store_object_id)
2093 .await
2094 .context("Failed to read encrypted mutations from journal")?,
2095 );
2096 mutations.extend(&journaled);
2097
2098 std::mem::drop(guard);
2101
2102 let (layers, _) = open_layers(
2106 self.parent_store.as_ref().unwrap(),
2107 store_info.layers.iter().cloned(),
2108 Some(crypt.clone()),
2109 )
2110 .await
2111 .context("Failed to read object tree layer file contents")?;
2112
2113 let wrapped_key =
2115 fxfs_crypto::WrappedKey::Fxfs(store_info.mutations_key.clone().unwrap().into());
2116 let unwrapped_key = crypt
2117 .unwrap_key(&wrapped_key, self.store_object_id)
2118 .await
2119 .context("Failed to unwrap mutations keys")?;
2120
2121 let last_object_id_cipher = match &store_info.last_object_id {
2123 LastObjectIdInfo::Encrypted { id: _, key } => {
2124 let wrapped_key = fxfs_crypto::WrappedKey::Fxfs(key.clone().into());
2125 let unwrapped = crypt
2126 .unwrap_key(&wrapped_key, self.store_object_id)
2127 .await
2128 .context("Failed to unwrap last object ID key")?;
2129 Some(Box::new(Ff1::new(&unwrapped)))
2130 }
2131 _ => None,
2132 };
2133
2134 let (new_wrapped_mutations_key, new_unwrapped_mutations_key) =
2136 crypt.create_key(self.store_object_id, KeyPurpose::Metadata).await?;
2137
2138 let mut keys_to_cache = Vec::new();
2140 if !read_only && !self.filesystem().options().read_only {
2141 let parent_store = self.parent_store.as_ref().unwrap();
2142 for _ in 0..CACHED_KEYS_LIMIT {
2143 let raw_id = {
2144 let reserved_id = parent_store
2145 .maybe_get_next_object_id()
2146 .expect("maybe_get_next_object_id failed on parent store");
2147 reserved_id.release()
2148 };
2149 let (wrapped, unwrapped) = crypt
2150 .create_key(raw_id.get(), KeyPurpose::Data)
2151 .await
2152 .context("Failed to pre-cache key during unlock")?;
2153 keys_to_cache.push((raw_id, EncryptionKey::Fxfs(wrapped), unwrapped));
2154 }
2155 }
2156
2157 let EncryptedMutations { transactions, mut data, mutations_key_roll } = mutations;
2158
2159 let mut unwrapped_key_rolls = Vec::with_capacity(mutations_key_roll.len());
2160 for (offset, key) in mutations_key_roll {
2161 let unwrapped = crypt
2162 .unwrap_key(&fxfs_crypto::WrappedKey::Fxfs(key.into()), self.store_object_id)
2163 .await
2164 .context("Failed to unwrap mutations keys")?;
2165 unwrapped_key_rolls.push((offset, unwrapped));
2166 }
2167
2168 self.filesystem().hooks().on_unlock_resources_acquired();
2169
2170 let mut mutations_to_apply = Vec::new();
2171
2172 let split_idx = transactions
2176 .partition_point(|(checkpoint, _)| checkpoint.version < AES_JOURNAL_ENCRYPTION_VERSION);
2177 let (chacha_transactions, aes_transactions) = transactions.split_at(split_idx);
2178 let data_offset = if chacha_transactions.is_empty() {
2179 0
2180 } else {
2181 let aes_len = aes_transactions
2182 .iter()
2183 .try_fold(0usize, |total, (_, next)| total.checked_add(*next as usize))
2184 .ok_or(FxfsError::Inconsistent)?;
2185 ensure!(aes_len <= data.len(), FxfsError::Inconsistent);
2186 data.len() - aes_len
2187 };
2188 let (chacha_data, aes_data) = data.split_at_mut(data_offset);
2189
2190 let split_key_idx =
2193 unwrapped_key_rolls.partition_point(|(offset, _)| *offset < data_offset);
2194 let aes_key_rolls: Vec<(usize, UnwrappedKey)> = unwrapped_key_rolls
2195 .split_off(split_key_idx)
2196 .into_iter()
2197 .map(|(offset, key)| (offset - data_offset, key))
2198 .collect();
2199 let chacha_key_rolls = unwrapped_key_rolls;
2200 let mut cipher_sequence_number = store_info.mutations_cipher_offset;
2201
2202 if !chacha_transactions.is_empty() {
2203 ensure!(store_info.mutations_cipher_offset <= u32::MAX as u64, FxfsError::Inconsistent);
2204 let mut cipher = StreamCipher::new(&unwrapped_key, cipher_sequence_number);
2205 mutations_to_apply.append(&mut Self::decrypt_mutations_chacha20(
2206 &mut cipher,
2207 chacha_transactions,
2208 chacha_data,
2209 &chacha_key_rolls,
2210 )?);
2211 cipher_sequence_number = cipher.offset();
2212 }
2213
2214 if !aes_transactions.is_empty() {
2215 let mut cipher = JournalXtsCipher::new(&unwrapped_key, cipher_sequence_number);
2216 mutations_to_apply.append(&mut Self::decrypt_mutations_aes256_xts(
2217 &mut cipher,
2218 aes_transactions,
2219 aes_data,
2220 &aes_key_rolls,
2221 )?);
2222 cipher_sequence_number = cipher.current_tweak();
2223 }
2224
2225 let do_not_use_crypt = crypt;
2228
2229 let guard =
2230 fs.lock_manager().write_lock(lock_keys![LockKey::flush(self.store_object_id())]).await;
2231
2232 if self.counters.lock().num_flushes != last_num_flushes {
2240 let new_store_info = self.load_store_info().await?;
2241 if CryptFields::from(&store_info) != CryptFields::from(&new_store_info) {
2242 return Err(
2243 anyhow!(FxfsError::Inconsistent).context("Crypt fields changed during unlock")
2244 );
2245 }
2246 store_info = new_store_info;
2247 }
2248
2249 let _ = std::mem::replace(&mut *self.lock_state.lock(), LockState::Unlocking);
2250
2251 store_info.mutations_key = Some(new_wrapped_mutations_key);
2252 *self.store_info.lock() = Some(store_info.clone());
2253
2254 let clean_up = scopeguard::guard((), |_| {
2255 *self.lock_state.lock() = LockState::Locked;
2256 *self.store_info.lock() = None;
2257 *self.last_object_id.lock() = LastObjectId::Pending;
2258 self.tree.reset();
2260 });
2261
2262 self.tree.append_open_layers(layers);
2264
2265 match &store_info.last_object_id {
2267 LastObjectIdInfo::Encrypted { id, .. } => {
2268 *self.last_object_id.lock() =
2269 LastObjectId::Encrypted { id: *id, cipher: last_object_id_cipher.unwrap() };
2270 }
2271 LastObjectIdInfo::Low32Bit => {
2272 *self.last_object_id.lock() = LastObjectId::Low32Bit {
2273 reserved: Default::default(),
2274 unreserved: Default::default(),
2275 }
2276 }
2277 _ => unreachable!(),
2278 }
2279
2280 for (checkpoint, mutation) in mutations_to_apply {
2282 let context = ApplyContext { mode: ApplyMode::Replay, checkpoint };
2283 self.apply_mutation(mutation, &context, AssocObj::None)
2284 .context("failed to apply encrypted mutation")?;
2285 }
2286
2287 *self.lock_state.lock() = if read_only {
2289 LockState::UnlockedReadOnly(do_not_use_crypt)
2290 } else {
2291 LockState::Unlocked {
2292 crypt: do_not_use_crypt,
2293 cached_keys: keys_to_cache,
2294 mutations_cipher: JournalCipher::new_aes256_xts(
2295 &new_unwrapped_mutations_key,
2296 cipher_sequence_number,
2297 ),
2298 }
2299 };
2300
2301 std::mem::drop(guard);
2305
2306 if !read_only && !self.filesystem().options().read_only {
2307 self.flush_with_reason(FlushReason::EncryptedMutations).await?;
2308
2309 let _ = self.filesystem().ensure_local().graveyard().initial_reap(&self).await?;
2311 }
2312
2313 Ok(ScopeGuard::into_inner(clean_up))
2315 }
2316
2317 fn decrypt_mutations_aes256_xts(
2318 cipher: &mut JournalXtsCipher,
2319 transactions: &[(JournalCheckpoint, u64)],
2320 data: &mut [u8],
2321 key_rolls: &[(usize, UnwrappedKey)],
2322 ) -> Result<Vec<(JournalCheckpoint, Mutation)>, Error> {
2323 let mut mutations_to_apply = Vec::new();
2324 let mut key_roll_iter = key_rolls.iter().peekable();
2325 let mut offset = 0;
2326
2327 for (checkpoint, chunk_len) in transactions {
2328 ensure!(checkpoint.version >= AES_JOURNAL_ENCRYPTION_VERSION, FxfsError::Inconsistent);
2329 while let Some((roll_offset, unwrapped_key)) = key_roll_iter.peek() {
2330 if offset >= *roll_offset {
2331 key_roll_iter.next();
2332 *cipher = JournalXtsCipher::new(unwrapped_key, cipher.current_tweak());
2333 } else {
2334 break;
2335 }
2336 }
2337 let chunk_len = *chunk_len as usize;
2338 ensure!(offset + chunk_len <= data.len(), FxfsError::Inconsistent);
2339 let chunk = &mut data[offset..offset + chunk_len];
2340 let transaction =
2341 EncryptedTransaction::decrypt_and_deserialize(cipher, chunk, checkpoint.version)?;
2342 for mutation in transaction.0 {
2343 mutations_to_apply.push((checkpoint.clone(), mutation));
2344 }
2345 offset += chunk_len;
2346 }
2347 Ok(mutations_to_apply)
2348 }
2349
2350 fn decrypt_mutations_chacha20(
2351 cipher: &mut StreamCipher,
2352 transactions: &[(JournalCheckpoint, u64)],
2353 data: &mut [u8],
2354 key_rolls: &[(usize, UnwrappedKey)],
2355 ) -> Result<Vec<(JournalCheckpoint, Mutation)>, Error> {
2356 let mut mutations_to_apply = Vec::new();
2357 let mut slice = &mut data[..];
2358 let mut last_offset = 0;
2359 for (offset, unwrapped_key) in key_rolls {
2360 let split_offset = offset.checked_sub(last_offset).ok_or(FxfsError::Inconsistent)?;
2361 ensure!(split_offset <= slice.len(), FxfsError::Inconsistent);
2362 last_offset = *offset;
2363 let (old, new) = slice.split_at_mut(split_offset);
2364 cipher.decrypt(old);
2365 *cipher = StreamCipher::new(unwrapped_key, 0);
2366 slice = new;
2367 }
2368 cipher.decrypt(slice);
2369
2370 let mut cursor = std::io::Cursor::new(&*data);
2371 for (checkpoint, count) in transactions {
2372 for _ in 0..*count {
2373 let mutation = Mutation::deserialize_from_version(&mut cursor, checkpoint.version)
2374 .context("failed to deserialize encrypted mutation")?;
2375 mutations_to_apply.push((checkpoint.clone(), mutation));
2376 }
2377 }
2378 Ok(mutations_to_apply)
2379 }
2380
2381 pub fn is_locked(&self) -> bool {
2382 matches!(
2383 *self.lock_state.lock(),
2384 LockState::Locked | LockState::Locking | LockState::Unknown
2385 )
2386 }
2387
2388 pub fn is_unlocked(&self) -> bool {
2391 matches!(
2392 *self.lock_state.lock(),
2393 LockState::Unlocked { .. } | LockState::UnlockedReadOnly(..) | LockState::Unlocking
2394 )
2395 }
2396
2397 pub fn is_unknown(&self) -> bool {
2398 matches!(*self.lock_state.lock(), LockState::Unknown)
2399 }
2400
2401 pub fn is_encrypted(&self) -> bool {
2402 self.store_info.lock().as_ref().unwrap().mutations_key.is_some()
2403 }
2404
2405 pub(crate) fn can_flush_unlocked(&self) -> bool {
2408 matches!(&*self.lock_state.lock(), LockState::Unencrypted | LockState::Unlocked { .. })
2409 }
2410
2411 pub async fn lock(&self) -> Result<(), Error> {
2417 let keys = lock_keys![LockKey::flush(self.store_object_id())];
2420 let fs = self.filesystem();
2421 let _guard = fs.lock_manager().write_lock(keys).await;
2422
2423 {
2424 let mut lock_state = self.lock_state.lock();
2425 if let LockState::Unlocked { .. } = &*lock_state {
2426 *lock_state = LockState::Locking;
2427 } else {
2428 panic!("Unexpected lock state: {:?}", *lock_state);
2429 }
2430 }
2431
2432 let sync_result =
2437 self.filesystem().sync(SyncOptions { flush_device: true, ..Default::default() }).await;
2438
2439 *self.lock_state.lock() = if let Err(error) = &sync_result {
2440 error!(error:?; "Failed to sync journal; store will no longer be usable");
2441 LockState::Invalid
2442 } else {
2443 LockState::Locked
2444 };
2445 self.key_manager.clear();
2446 *self.store_info.lock() = None;
2447 *self.last_object_id.lock() = LastObjectId::Pending;
2448 self.tree.reset();
2449
2450 sync_result
2451 }
2452
2453 pub fn lock_read_only(&self) {
2457 *self.lock_state.lock() = LockState::Locked;
2458 *self.store_info.lock() = None;
2459 *self.last_object_id.lock() = LastObjectId::Pending;
2460 self.tree.reset();
2461 }
2462
2463 fn maybe_get_next_object_id(&self) -> Option<ReservedId<'_>> {
2466 self.last_object_id.lock().try_get_next().map(|id| ReservedId::new(self, id))
2467 }
2468
2469 pub(super) async fn get_next_object_id(
2473 &self,
2474 parent_transaction: &Transaction<'_>,
2475 ) -> Result<ReservedId<'_>, Error> {
2476 let low_32_bit = {
2477 let mut last_object_id = self.last_object_id.lock();
2478 if let Some(id) = last_object_id.try_get_next() {
2479 return Ok(ReservedId::new(self, id));
2480 }
2481 ensure!(
2482 !matches!(&*last_object_id, LastObjectId::Unencrypted { .. }),
2483 FxfsError::Inconsistent
2484 );
2485 matches!(&*last_object_id, LastObjectId::Low32Bit { .. })
2486 };
2487
2488 let parent_store = self.parent_store().unwrap();
2489 let lock_keys =
2490 lock_keys![LockKey::object(parent_store.store_object_id, self.store_object_id)];
2491 if low_32_bit {
2492 let fs = self.filesystem();
2495 let _guard = fs.lock_manager().txn_lock(lock_keys).await;
2496
2497 self.last_object_id.lock().drain_unreserved();
2501
2502 let layer_set = self.tree.layer_set();
2503 let mut key = ObjectKey::object(0);
2504 loop {
2505 let next_id = rand::rng().next_u32() as u64;
2506 let Some(next_id) = NonZero::new(next_id) else { continue };
2507 if self.last_object_id.lock().is_reserved(next_id.get()) {
2508 continue;
2509 }
2510 key.object_id = next_id.get();
2511 if layer_set.key_exists(&key).await? == Existence::Missing {
2512 self.last_object_id.lock().reserve(next_id.get());
2513 return Ok(ReservedId::new(self, next_id));
2514 }
2515 }
2516 } else {
2517 let mut transaction = parent_store
2522 .new_transaction(
2523 lock_keys,
2524 Options { parent_transaction: Some(parent_transaction), ..Default::default() },
2525 )
2526 .await?;
2527
2528 let next_id_hi = {
2529 let mut last_object_id = self.last_object_id.lock();
2530 if let Some(id) = last_object_id.try_get_next() {
2531 return Ok(ReservedId::new(self, id));
2533 }
2534
2535 match &*last_object_id {
2536 LastObjectId::Encrypted { id, .. } => {
2537 info!(store_id = self.store_object_id; "Rolling object ID key");
2540
2541 id.checked_add(1 << 32).ok_or(FxfsError::Inconsistent)? & OBJECT_ID_HI_MASK
2542 }
2543 _ => unreachable!(),
2544 }
2545 };
2546
2547 let (object_id_wrapped, object_id_unwrapped) = self
2549 .crypt()
2550 .unwrap()
2551 .create_key(self.store_object_id, KeyPurpose::Metadata)
2552 .await?;
2553
2554 let new_store_info = StoreInfo {
2571 last_object_id: LastObjectIdInfo::Encrypted {
2572 id: next_id_hi,
2573 key: object_id_wrapped.clone(),
2574 },
2575 ..self.load_store_info().await?
2576 };
2577
2578 self.write_store_info(&mut transaction, &new_store_info).await?;
2579
2580 transaction
2581 .commit_with_callback(move |_| {
2582 self.store_info.lock().as_mut().unwrap().last_object_id =
2583 new_store_info.last_object_id;
2584 match &mut *self.last_object_id.lock() {
2585 LastObjectId::Encrypted { id, cipher } => {
2586 **cipher = Ff1::new(&object_id_unwrapped);
2587 *id = next_id_hi;
2588 ReservedId::new(
2589 self,
2590 NonZero::new(next_id_hi | cipher.encrypt(0) as u64).unwrap(),
2591 )
2592 }
2593 _ => unreachable!(),
2594 }
2595 })
2596 .await
2597 }
2598 }
2599
2600 pub(crate) fn query_next_object_id(&self) -> u64 {
2603 self.last_object_id.lock().peek_next()
2604 }
2605
2606 fn allocator(&self) -> Arc<Allocator> {
2607 self.filesystem().ensure_local().allocator()
2608 }
2609
2610 async fn txn_get_object_mutation(
2616 &self,
2617 transaction: &Transaction<'_>,
2618 object_id: u64,
2619 ) -> Result<ObjectStoreMutation, Error> {
2620 if let Some(mutation) =
2621 transaction.get_object_mutation(self.store_object_id, ObjectKey::object(object_id))
2622 {
2623 Ok(mutation.clone())
2624 } else {
2625 Ok(ObjectStoreMutation {
2626 item: self
2627 .tree
2628 .find(&ObjectKey::object(object_id))
2629 .await?
2630 .ok_or(FxfsError::Inconsistent)
2631 .context("Object id missing")?,
2632 op: Operation::ReplaceOrInsert,
2633 })
2634 }
2635 }
2636
2637 #[cfg(feature = "migration")]
2640 pub async fn get_object_mutation(
2641 &self,
2642 transaction: &Transaction<'_>,
2643 object_id: u64,
2644 ) -> Result<ObjectStoreMutation, Error> {
2645 self.txn_get_object_mutation(transaction, object_id).await
2646 }
2647
2648 fn update_last_object_id(&self, object_id: u64) {
2649 let mut last_object_id = self.last_object_id.lock();
2650 match &mut *last_object_id {
2651 LastObjectId::Pending => unreachable!(),
2652 LastObjectId::Unencrypted { id } => {
2653 if object_id > *id {
2654 *id = object_id
2655 }
2656 }
2657 LastObjectId::Encrypted { id, cipher } => {
2658 let object_id =
2665 object_id & OBJECT_ID_HI_MASK | cipher.decrypt(object_id as u32) as u64;
2666 if object_id > *id {
2667 *id = object_id;
2668 }
2669 }
2670 LastObjectId::Low32Bit { .. } => {}
2671 }
2672 }
2673
2674 pub fn to_unencrypted_object_id(&self, object_id: u64) -> Option<u64> {
2677 let last_object_id = self.last_object_id.lock();
2678 match &*last_object_id {
2679 LastObjectId::Pending => None,
2680 LastObjectId::Unencrypted { .. } | LastObjectId::Low32Bit { .. } => Some(object_id),
2681 LastObjectId::Encrypted { id, cipher } => {
2682 if id & OBJECT_ID_HI_MASK != object_id & OBJECT_ID_HI_MASK {
2683 None
2684 } else {
2685 Some(object_id & OBJECT_ID_HI_MASK | cipher.decrypt(object_id as u32) as u64)
2686 }
2687 }
2688 }
2689 }
2690
2691 pub fn add_to_graveyard(&self, transaction: &mut Transaction<'_>, object_id: u64) {
2693 let graveyard_id = self.graveyard_directory_object_id();
2694 assert_ne!(graveyard_id, INVALID_OBJECT_ID);
2695 transaction.add(
2696 self.store_object_id,
2697 Mutation::replace_or_insert_object(
2698 ObjectKey::graveyard_entry(graveyard_id, object_id),
2699 ObjectValue::Some,
2700 ),
2701 );
2702 }
2703
2704 pub fn remove_from_graveyard(&self, transaction: &mut Transaction<'_>, object_id: u64) {
2717 transaction.add(
2718 self.store_object_id,
2719 Mutation::replace_or_insert_object(
2720 ObjectKey::graveyard_entry(self.graveyard_directory_object_id(), object_id),
2721 ObjectValue::None,
2722 ),
2723 );
2724 }
2725
2726 pub fn remove_attribute_from_graveyard(
2731 &self,
2732 transaction: &mut Transaction<'_>,
2733 object_id: u64,
2734 attribute_id: AttributeId,
2735 ) {
2736 transaction.add(
2737 self.store_object_id,
2738 Mutation::replace_or_insert_object(
2739 ObjectKey::graveyard_attribute_entry(
2740 self.graveyard_directory_object_id(),
2741 object_id,
2742 attribute_id,
2743 ),
2744 ObjectValue::None,
2745 ),
2746 );
2747 }
2748
2749 pub async fn read_encrypted_symlink(
2754 &self,
2755 object_id: u64,
2756 mut link: Vec<u8>,
2757 ) -> Result<Vec<u8>, Error> {
2758 let key = self
2759 .key_manager
2760 .get_fscrypt_key(object_id, self.crypt().unwrap().as_ref(), async || {
2761 self.get_keys(object_id).await
2762 })
2763 .await?;
2764 if let Some(key) = key.into_cipher() {
2765 key.decrypt_symlink(object_id, &mut link)?;
2766 Ok(link)
2767 } else {
2768 let proxy_filename = ProxyFilename::new_with_hash_code(0, &link);
2770 let proxy_filename_str: String = proxy_filename.into();
2771 Ok(proxy_filename_str.into_bytes())
2772 }
2773 }
2774
2775 pub async fn read_symlink(&self, object_id: u64) -> Result<Vec<u8>, Error> {
2777 match self.tree.find(&ObjectKey::object(object_id)).await? {
2778 None | Some(Item { value: ObjectValue::None, .. }) => bail!(FxfsError::NotFound),
2779 Some(Item {
2780 value: ObjectValue::Object { kind: ObjectKind::EncryptedSymlink { link, .. }, .. },
2781 ..
2782 }) => self.read_encrypted_symlink(object_id, link.into_vec()).await,
2783 Some(Item {
2784 value: ObjectValue::Object { kind: ObjectKind::Symlink { link, .. }, .. },
2785 ..
2786 }) => Ok(link.into_vec()),
2787 Some(Item {
2788 value: ObjectValue::Object { kind: ObjectKind::NonInlineSymlink { .. }, .. },
2789 ..
2790 }) => {
2791 let store = self
2792 .filesystem()
2793 .ensure_local()
2794 .object_manager()
2795 .store(self.store_object_id)
2796 .unwrap();
2797 let handle = StoreObjectHandle::new(
2798 store,
2799 object_id,
2800 false,
2801 HandleOptions::default(),
2802 false,
2803 );
2804 handle.read_non_inline_symlink().await
2805 }
2806 Some(item) => Err(anyhow!(FxfsError::Inconsistent)
2807 .context(format!("Unexpected item in symlink lookup: {item:?}"))),
2808 }
2809 }
2810
2811 fn fail_on_illegal_keys(&self, keys: &EncryptionKeys) -> Result<(), Error> {
2815 if !self.is_root() {
2816 return Ok(());
2817 }
2818
2819 for key in keys.iter() {
2820 if !matches!(key.1, EncryptionKey::Fxfs(_)) {
2821 return Err(
2822 anyhow!(FxfsError::IntegrityError).context("Illegal key type in root store")
2823 );
2824 }
2825 }
2826 Ok(())
2827 }
2828
2829 pub async fn get_keys(&self, object_id: u64) -> Result<EncryptionKeys, Error> {
2832 self.tree
2833 .find_map(&ObjectKey::keys(object_id), |item| match item.value {
2834 ObjectValue::Keys(keys) => {
2835 self.fail_on_illegal_keys(keys)?;
2836 Ok(keys.clone())
2837 }
2838 _ => Err(anyhow!(FxfsError::Inconsistent).context("open_object: Expected keys")),
2839 })
2840 .await?
2841 .ok_or(FxfsError::Inconsistent)?
2842 }
2843
2844 pub async fn update_attributes<'a>(
2845 &self,
2846 transaction: &mut Transaction<'a>,
2847 object_id: u64,
2848 node_attributes: Option<&fio::MutableNodeAttributes>,
2849 change_time: Option<Timestamp>,
2850 ) -> Result<(), Error> {
2851 if change_time.is_none() {
2852 if let Some(attributes) = node_attributes {
2853 let empty_attributes = fio::MutableNodeAttributes { ..Default::default() };
2854 if *attributes == empty_attributes {
2855 return Ok(());
2856 }
2857 } else {
2858 return Ok(());
2859 }
2860 }
2861 let mut mutation = self.txn_get_object_mutation(transaction, object_id).await?;
2862 if let ObjectValue::Object { ref mut attributes, .. } = mutation.item.value {
2863 if let Some(time) = change_time {
2864 attributes.change_time = time;
2865 }
2866 if let Some(node_attributes) = node_attributes {
2867 if let Some(time) = node_attributes.creation_time {
2868 attributes.creation_time = Timestamp::from_nanos(time);
2869 }
2870 if let Some(time) = node_attributes.modification_time {
2871 attributes.modification_time = Timestamp::from_nanos(time);
2872 }
2873 if let Some(time) = node_attributes.access_time {
2874 attributes.access_time = Timestamp::from_nanos(time);
2875 }
2876 if node_attributes.mode.is_some()
2877 || node_attributes.uid.is_some()
2878 || node_attributes.gid.is_some()
2879 || node_attributes.rdev.is_some()
2880 {
2881 if let Some(a) = &mut attributes.posix_attributes {
2882 if let Some(mode) = node_attributes.mode {
2883 a.mode = mode;
2884 }
2885 if let Some(uid) = node_attributes.uid {
2886 a.uid = uid;
2887 }
2888 if let Some(gid) = node_attributes.gid {
2889 a.gid = gid;
2890 }
2891 if let Some(rdev) = node_attributes.rdev {
2892 a.rdev = rdev;
2893 }
2894 } else {
2895 attributes.posix_attributes = Some(PosixAttributes {
2896 mode: node_attributes.mode.unwrap_or_default(),
2897 uid: node_attributes.uid.unwrap_or_default(),
2898 gid: node_attributes.gid.unwrap_or_default(),
2899 rdev: node_attributes.rdev.unwrap_or_default(),
2900 });
2901 }
2902 }
2903 }
2904 } else {
2905 bail!(
2906 anyhow!(FxfsError::Inconsistent)
2907 .context("ObjectStore.update_attributes: Expected object value")
2908 );
2909 };
2910 transaction.add(self.store_object_id(), Mutation::ObjectStore(mutation));
2911 Ok(())
2912 }
2913
2914 pub async fn update_access_time(
2920 &self,
2921 object_id: u64,
2922 props: &mut ObjectProperties,
2923 precondition: impl FnOnce() -> bool,
2924 ) -> Result<(), Error> {
2925 let access_time = props.access_time.as_nanos();
2926 let modification_time = props.modification_time.as_nanos();
2927 let change_time = props.change_time.as_nanos();
2928 let now = Timestamp::now();
2929 if access_time <= modification_time
2930 || access_time <= change_time
2931 || access_time
2932 < now.as_nanos()
2933 - Timestamp::from(std::time::Duration::from_secs(24 * 60 * 60)).as_nanos()
2934 {
2935 let mut transaction = self
2936 .new_transaction(
2937 lock_keys![LockKey::object(self.store_object_id, object_id,)],
2938 Options { reservation: ReservationOptions::Borrowed, ..Default::default() },
2939 )
2940 .await?;
2941 if precondition() {
2942 self.update_attributes(
2943 &mut transaction,
2944 object_id,
2945 Some(&fio::MutableNodeAttributes {
2946 access_time: Some(now.as_nanos()),
2947 ..Default::default()
2948 }),
2949 None,
2950 )
2951 .await?;
2952 transaction.commit().await?;
2953 props.access_time = now;
2954 }
2955 }
2956 Ok(())
2957 }
2958
2959 async fn write_store_info<'a>(
2960 &'a self,
2961 transaction: &mut Transaction<'a>,
2962 info: &StoreInfo,
2963 ) -> Result<(), Error> {
2964 let mut serialized_info = Vec::new();
2965 info.serialize_with_version(&mut serialized_info)?;
2966 let mut buf = self.device.allocate_buffer(serialized_info.len()).await;
2967 buf.copy_from_slice(&serialized_info);
2968 self.store_info_handle.get().unwrap().txn_write(transaction, 0u64, buf.as_ref()).await
2969 }
2970
2971 pub fn mark_deleted(&self) {
2972 *self.lock_state.lock() = LockState::Deleted;
2973 }
2974
2975 #[cfg(test)]
2976 pub(crate) fn test_set_last_object_id(&self, object_id: u64) {
2977 match &mut *self.last_object_id.lock() {
2978 LastObjectId::Encrypted { id, .. } => *id = object_id,
2979 _ => unreachable!(),
2980 }
2981 }
2982
2983 pub async fn get_attribute_size(
2986 &self,
2987 object_id: u64,
2988 attribute_id: AttributeId,
2989 ) -> Result<u64, Error> {
2990 let size = self
2991 .tree
2992 .find_map(
2993 &ObjectKey::attribute(object_id, attribute_id, AttributeKey::Attribute),
2994 |item| match item.value {
2995 ObjectValue::Attribute { size, .. }
2996 | ObjectValue::VerifiedAttribute { size, .. } => Ok(*size),
2997 _ => Err(anyhow!(FxfsError::Inconsistent)),
2998 },
2999 )
3000 .await?
3001 .ok_or(FxfsError::NotFound)??;
3002 Ok(size)
3003 }
3004
3005 pub async fn purge(
3007 &self,
3008 object_id: u64,
3009 truncate_guard: Option<&TruncateGuard<'_>>,
3010 ) -> Result<(), Error> {
3011 self.filesystem().tombstone_object(self.store_object_id, object_id, truncate_guard).await
3012 }
3013
3014 pub fn purge_async(&self, object_id: u64) {
3016 self.filesystem().queue_tombstone_object(self.store_object_id, object_id);
3017 }
3018}
3019
3020#[async_trait]
3021impl ObjectStoreTrait for ObjectStore {
3022 async fn purge(
3023 &self,
3024 object_id: u64,
3025 truncate_guard: Option<&TruncateGuard<'_>>,
3026 ) -> Result<(), Error> {
3027 self.purge(object_id, truncate_guard).await
3028 }
3029
3030 fn purge_async(&self, object_id: u64) {
3031 self.purge_async(object_id);
3032 }
3033
3034 fn tree(&self) -> &LSMTree<ObjectKey, ObjectValue> {
3035 self.tree()
3036 }
3037
3038 fn filesystem(&self) -> Arc<dyn Filesystem> {
3039 self.filesystem()
3040 }
3041}
3042
3043impl AsRef<dyn ObjectStoreTrait> for ObjectStore {
3044 fn as_ref(&self) -> &dyn ObjectStoreTrait {
3045 self
3046 }
3047}
3048
3049#[async_trait]
3050impl JournalingObject for ObjectStore {
3051 fn apply_mutation(
3052 &self,
3053 mutation: Mutation,
3054 context: &ApplyContext<'_, '_>,
3055 _assoc_obj: AssocObj<'_>,
3056 ) -> Result<(), Error> {
3057 match &*self.lock_state.lock() {
3058 LockState::Locked | LockState::Locking => {
3059 ensure!(
3060 matches!(mutation, Mutation::BeginFlush | Mutation::EndFlush(_))
3061 || matches!(
3062 mutation,
3063 Mutation::EncryptedObjectStore(_) | Mutation::UpdateMutationsKey(_)
3064 if context.mode.is_replay()
3065 ),
3066 anyhow!(FxfsError::Inconsistent)
3067 .context(format!("Unexpected mutation for encrypted store: {mutation:?}"))
3068 );
3069 }
3070 LockState::Invalid
3071 | LockState::Unlocking
3072 | LockState::Unencrypted
3073 | LockState::Unlocked { .. }
3074 | LockState::UnlockedReadOnly(..)
3075 | LockState::Deleted => {}
3076 lock_state @ _ => panic!("Unexpected lock state: {lock_state:?}"),
3077 }
3078 match mutation {
3079 Mutation::ObjectStore(ObjectStoreMutation { item, op }) => {
3080 match op {
3081 Operation::Insert => {
3082 let mut unreserve_id = INVALID_OBJECT_ID;
3083 if matches!(item.value, ObjectValue::Object { .. }) {
3086 {
3087 let info = &mut self.store_info.lock();
3088 let object_count = &mut info.as_mut().unwrap().object_count;
3089 *object_count = object_count.saturating_add(1);
3090 }
3091 if context.mode.is_replay() {
3092 self.update_last_object_id(item.key.object_id);
3093 } else {
3094 unreserve_id = item.key.object_id;
3095 }
3096 } else if !context.mode.is_replay()
3097 && matches!(
3098 item.key.data,
3099 ObjectKeyData::GraveyardEntry { .. }
3100 | ObjectKeyData::GraveyardAttributeEntry { .. }
3101 )
3102 {
3103 if matches!(item.value, ObjectValue::Some | ObjectValue::Trim) {
3104 self.graveyard_entries.fetch_add(1, Ordering::Relaxed);
3105 } else if matches!(item.value, ObjectValue::None) {
3106 self.graveyard_entries.fetch_sub(1, Ordering::Relaxed);
3107 }
3108 }
3109 self.tree.insert(item)?;
3110 if unreserve_id != INVALID_OBJECT_ID {
3111 self.last_object_id.lock().unreserve(unreserve_id);
3113 }
3114 }
3115 Operation::ReplaceOrInsert => {
3116 if !context.mode.is_replay()
3117 && matches!(
3118 item.key.data,
3119 ObjectKeyData::GraveyardEntry { .. }
3120 | ObjectKeyData::GraveyardAttributeEntry { .. }
3121 )
3122 {
3123 if matches!(item.value, ObjectValue::Some | ObjectValue::Trim) {
3124 self.graveyard_entries.fetch_add(1, Ordering::Relaxed);
3125 } else if matches!(item.value, ObjectValue::None) {
3126 self.graveyard_entries.fetch_sub(1, Ordering::Relaxed);
3127 }
3128 }
3129 self.tree.replace_or_insert(item);
3130 }
3131 Operation::Merge => {
3132 if item.is_tombstone() {
3133 let info = &mut self.store_info.lock();
3134 let object_count = &mut info.as_mut().unwrap().object_count;
3135 *object_count = object_count.saturating_sub(1);
3136 if !context.mode.is_replay() {
3137 let _ = self.key_manager.remove(item.key.object_id);
3144 }
3145 }
3146 if !context.mode.is_replay()
3147 && matches!(
3148 item.key.data,
3149 ObjectKeyData::GraveyardEntry { .. }
3150 | ObjectKeyData::GraveyardAttributeEntry { .. }
3151 )
3152 {
3153 if matches!(item.value, ObjectValue::Some | ObjectValue::Trim) {
3154 self.graveyard_entries.fetch_add(1, Ordering::Relaxed);
3155 } else if matches!(item.value, ObjectValue::None) {
3156 self.graveyard_entries.fetch_sub(1, Ordering::Relaxed);
3157 }
3158 }
3159 let lower_bound = item.key.key_for_merge_into();
3160 self.tree.merge_into(item, &lower_bound);
3161 }
3162 }
3163 }
3164 Mutation::BeginFlush => {
3165 ensure!(self.parent_store.is_some(), FxfsError::Inconsistent);
3166 self.tree.seal();
3167 }
3168 Mutation::EndFlush(_) => ensure!(self.parent_store.is_some(), FxfsError::Inconsistent),
3169 Mutation::EncryptedObjectStore(_) | Mutation::UpdateMutationsKey(_) => {
3170 ensure!(
3172 !matches!(&*self.lock_state.lock(), LockState::Unencrypted),
3173 FxfsError::Inconsistent
3174 );
3175 }
3176 Mutation::CreateInternalDir(object_id) => {
3177 ensure!(object_id != INVALID_OBJECT_ID, FxfsError::Inconsistent);
3178 self.store_info.lock().as_mut().unwrap().internal_directory_object_id = object_id;
3179 }
3180 _ => bail!("unexpected mutation: {:?}", mutation),
3181 }
3182 self.counters.lock().mutations_applied += 1;
3183 Ok(())
3184 }
3185
3186 fn drop_mutation(&self, mutation: Mutation, _transaction: &Transaction<'_>) {
3187 self.counters.lock().mutations_dropped += 1;
3188 if let Mutation::ObjectStore(ObjectStoreMutation {
3189 item: Item { key: ObjectKey { object_id, .. }, value: ObjectValue::Object { .. }, .. },
3190 op: Operation::Insert,
3191 }) = mutation
3192 {
3193 self.last_object_id.lock().unreserve(object_id);
3194 }
3195 }
3196
3197 async fn prepare_commit<'a>(
3198 &self,
3199 filesystem: &'a FxFilesystem,
3200 _transaction: &Transaction<'_>,
3201 ) -> Result<Option<WriteGuard<'a>>, Error> {
3202 if !matches!(&*self.lock_state.lock(), LockState::Unlocked { .. }) {
3204 return Ok(None);
3205 }
3206
3207 let keys = lock_keys![LockKey::pre_cache_keys(self.store_object_id())];
3211 let guard = filesystem.lock_manager().write_lock(keys).await;
3212
3213 self.pre_cache_keys().await?;
3214
3215 Ok(Some(guard))
3216 }
3217
3218 async fn flush(&self, reason: FlushReason) -> Result<Version, Error> {
3225 self.flush_with_reason(reason).await
3226 }
3227
3228 fn write_mutations(
3229 &self,
3230 mutations: ObjectMutationIterator<'_, '_>,
3231 mut writer: journal::Writer<'_>,
3232 ) {
3233 let mut lock_state = self.lock_state.lock();
3234 if let LockState::Unlocked { mutations_cipher, .. } = &mut *lock_state {
3235 let mut encrypted_transaction = EncryptedTransaction::new();
3236 for mutation in mutations.cloned() {
3237 match mutation {
3242 Mutation::ObjectStore(_) | Mutation::CreateInternalDir(_) => {
3253 encrypted_transaction.0.push(mutation)
3254 }
3255
3256 Mutation::EncryptedObjectStore(_) | Mutation::UpdateMutationsKey(_) => {
3261 debug_assert!(
3262 false,
3263 "Only this method should generate encrypted mutations"
3264 );
3265 }
3266 Mutation::UpdateBorrowed(_) => {
3267 unreachable!(
3268 "UpdateBorrowed is only produced when replaying legacy journals"
3269 );
3270 }
3271
3272 Mutation::Allocator(_)
3278 | Mutation::BeginFlush
3279 | Mutation::EndFlush(_)
3280 | Mutation::DeleteVolume => {
3281 writer.write(mutation);
3282 }
3283 }
3284 }
3285 if !encrypted_transaction.0.is_empty() {
3286 if mutations_cipher.key_is_new() {
3288 writer.write(Mutation::update_mutations_key(
3289 self.store_info
3290 .lock()
3291 .as_ref()
3292 .unwrap()
3293 .mutations_key
3294 .as_ref()
3295 .unwrap()
3296 .clone(),
3297 ));
3298 }
3299 for encrypted in encrypted_transaction.serialize_and_encrypt(mutations_cipher) {
3300 writer.write(Mutation::EncryptedObjectStore(encrypted));
3301 }
3302 }
3303 } else {
3304 for mutation in mutations {
3305 writer.write(mutation.clone());
3306 }
3307 }
3308 }
3309}
3310
3311pub type EncryptedTransaction = EncryptedTransactionV62;
3314
3315static_assertions::const_assert!(EncryptedTransaction::MAX_CHUNK_SIZE % 16 == 0);
3316impl EncryptedTransaction {
3317 const MAX_CHUNK_SIZE: usize = DEFAULT_MAX_SERIALIZED_RECORD_SIZE as usize - 48;
3322
3323 fn new() -> Self {
3324 Self(Vec::new())
3325 }
3326
3327 fn serialize_and_encrypt<'a>(
3328 &self,
3329 cipher: &'a mut JournalCipher,
3330 ) -> impl Iterator<Item = Box<[u8]>> + 'a {
3331 let mut buffer = Vec::new();
3332 self.serialize_into(&mut buffer).unwrap();
3333 (0..buffer.len()).step_by(Self::MAX_CHUNK_SIZE).map(move |offset| {
3335 let end = std::cmp::min(offset + Self::MAX_CHUNK_SIZE, buffer.len());
3336 Box::from(cipher.encrypt(&buffer[offset..end]))
3337 })
3338 }
3339
3340 fn decrypt_and_deserialize(
3341 cipher: &mut JournalXtsCipher,
3342 data: &mut [u8],
3343 version: Version,
3344 ) -> Result<Self, Error> {
3345 let (sub_chunks, remainder) = data.as_chunks_mut::<{ Self::MAX_CHUNK_SIZE }>();
3347 for chunk in sub_chunks {
3348 cipher.decrypt(chunk.as_mut_slice());
3349 }
3350 if remainder.len() > 0 {
3351 cipher.decrypt(remainder);
3352 }
3353 let mut chunk_cursor = std::io::Cursor::new(&*data);
3354 Self::deserialize_from_version(&mut chunk_cursor, version)
3355 .context("failed to deserialize encrypted transaction")
3356 }
3357}
3358
3359#[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd, Serialize, Deserialize)]
3363pub struct EncryptedTransactionV62(pub Vec<MutationV62>);
3364
3365impl TypeFingerprint for EncryptedTransactionV62 {
3366 fn fingerprint() -> String {
3367 format!(
3368 "struct{{MAX_CHUNK_SIZE: {}, {}}}",
3369 Self::MAX_CHUNK_SIZE,
3371 Vec::<MutationV62>::fingerprint()
3372 )
3373 }
3374}
3375
3376impl Versioned for EncryptedTransactionV62 {
3377 fn max_serialized_size() -> Option<u64> {
3380 None
3381 }
3382}
3383
3384#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
3385pub struct EncryptedTransactionV61(pub Vec<MutationV61>);
3386
3387impl TypeFingerprint for EncryptedTransactionV61 {
3388 fn fingerprint() -> String {
3389 format!(
3390 "struct{{MAX_CHUNK_SIZE: {}, {}}}",
3391 EncryptedTransaction::MAX_CHUNK_SIZE,
3392 Vec::<MutationV61>::fingerprint()
3393 )
3394 }
3395}
3396
3397impl Versioned for EncryptedTransactionV61 {
3398 fn max_serialized_size() -> Option<u64> {
3399 None
3400 }
3401}
3402
3403impl From<EncryptedTransactionV61> for EncryptedTransactionV62 {
3404 fn from(old: EncryptedTransactionV61) -> Self {
3405 Self(old.0.into_iter().map(Into::into).collect())
3406 }
3407}
3408
3409#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
3410pub struct EncryptedTransactionV59(pub Vec<MutationV59>);
3411
3412impl TypeFingerprint for EncryptedTransactionV59 {
3413 fn fingerprint() -> String {
3414 format!(
3415 "struct{{MAX_CHUNK_SIZE: {}, {}}}",
3416 EncryptedTransaction::MAX_CHUNK_SIZE,
3417 Vec::<MutationV59>::fingerprint()
3418 )
3419 }
3420}
3421
3422impl Versioned for EncryptedTransactionV59 {
3423 fn max_serialized_size() -> Option<u64> {
3424 None
3425 }
3426}
3427
3428impl From<EncryptedTransactionV59> for EncryptedTransactionV61 {
3429 fn from(old: EncryptedTransactionV59) -> Self {
3430 Self(old.0.into_iter().map(Into::into).collect())
3431 }
3432}
3433
3434#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
3435pub struct EncryptedTransactionV57(pub Vec<crate::object_store::transaction::MutationV57>);
3436
3437impl TypeFingerprint for EncryptedTransactionV57 {
3438 fn fingerprint() -> String {
3439 format!(
3440 "struct{{MAX_CHUNK_SIZE: {}, {}}}",
3441 EncryptedTransaction::MAX_CHUNK_SIZE,
3442 Vec::<crate::object_store::transaction::MutationV57>::fingerprint()
3443 )
3444 }
3445}
3446
3447impl Versioned for EncryptedTransactionV57 {
3448 fn max_serialized_size() -> Option<u64> {
3449 None
3450 }
3451}
3452
3453impl From<EncryptedTransactionV57> for EncryptedTransactionV59 {
3454 fn from(old: EncryptedTransactionV57) -> Self {
3455 Self(old.0.into_iter().map(Into::into).collect())
3456 }
3457}
3458
3459impl Drop for ObjectStore {
3460 fn drop(&mut self) {
3461 let mut last_object_id = self.last_object_id.lock();
3462 last_object_id.drain_unreserved();
3463 match &*last_object_id {
3464 LastObjectId::Low32Bit { reserved, .. } => debug_assert!(reserved.is_empty()),
3465 _ => {}
3466 }
3467 }
3468}
3469
3470impl HandleOwner for ObjectStore {}
3471
3472impl AsRef<ObjectStore> for ObjectStore {
3473 fn as_ref(&self) -> &ObjectStore {
3474 self
3475 }
3476}
3477
3478fn layer_size_from_encrypted_mutations_size(size: u64) -> u64 {
3479 size * 3
3486}
3487
3488impl AssociatedObject for ObjectStore {}
3489
3490#[derive(Debug)]
3492pub enum TrimMode {
3493 UseSize,
3495
3496 FromOffset(u64),
3498
3499 Tombstone(TombstoneMode),
3501}
3502
3503#[derive(Debug)]
3505pub enum TombstoneMode {
3506 Object,
3507 Attribute,
3508}
3509
3510#[derive(Debug)]
3512pub enum TrimResult {
3513 Incomplete,
3515
3516 Done(Option<AttributeId>),
3519}
3520
3521pub async fn load_store_info(
3523 parent: &Arc<ObjectStore>,
3524 store_object_id: u64,
3525) -> Result<StoreInfo, Error> {
3526 load_store_info_from_handle(
3527 &ObjectStore::open_object(parent, store_object_id, HandleOptions::default(), None).await?,
3528 )
3529 .await
3530}
3531
3532async fn load_store_info_from_handle(
3533 handle: &DataObjectHandle<impl HandleOwner>,
3534) -> Result<StoreInfo, Error> {
3535 Ok(if handle.get_size() > 0 {
3536 let serialized_info = handle.contents(MAX_STORE_INFO_SERIALIZED_SIZE).await?;
3537 let mut cursor = std::io::Cursor::new(serialized_info);
3538 let (store_info, _) = StoreInfo::deserialize_with_version(&mut cursor)
3539 .context("Failed to deserialize StoreInfo")?;
3540 store_info
3541 } else {
3542 StoreInfo::default()
3544 })
3545}
3546
3547#[cfg(test)]
3548mod tests {
3549 use super::{
3550 AttributeId, DirectWriter, EncryptedMutations, FsverityMetadata, HandleOptions,
3551 LastObjectId, LastObjectIdInfo, LockKey, LockState, MAX_STORE_INFO_SERIALIZED_SIZE,
3552 Mutation, NewChildStoreOptions, OBJECT_ID_HI_MASK, ObjectEncryptionOptions, ObjectStore,
3553 RootDigest, StoreInfo, StoreOptions,
3554 };
3555 use crate::errors::FxfsError;
3556 use crate::filesystem::{
3557 FlushReason, ForceMajor, FxFilesystem, FxFilesystemBuilder, MAX_IN_FLIGHT_TRANSACTIONS,
3558 OpenFxFilesystem,
3559 };
3560 use crate::fsck::{fsck, fsck_volume};
3561 use crate::hooks::{Hooks, HooksHandle};
3562 use crate::lsm_tree::Query;
3563 use crate::lsm_tree::types::{ItemRef, LayerIterator};
3564 use crate::object_handle::{INVALID_OBJECT_ID, ObjectHandle, WriteBytes, WriteObjectHandle};
3565 use crate::object_store::directory::{Directory, replace_child};
3566 use crate::object_store::journal::{JournalCheckpoint, JournalOptions};
3567 use crate::object_store::object_record::{
3568 AttributeKey, ObjectDescriptor, ObjectKey, ObjectKind, ObjectValue,
3569 };
3570 use crate::object_store::store_object_handle::MAX_INLINE_XATTR_SIZE;
3571 use crate::object_store::transaction::{Options, lock_keys};
3572 use crate::object_store::volume::root_volume;
3573 use crate::serialized_types::{
3574 DEFAULT_MAX_SERIALIZED_RECORD_SIZE, Version, Versioned, VersionedLatest,
3575 };
3576 use crate::testing;
3577 use assert_matches::assert_matches;
3578 use async_trait::async_trait;
3579 use fuchsia_async as fasync;
3580 use fuchsia_sync::Mutex;
3581 use futures::channel::oneshot;
3582 use futures::{FutureExt, join};
3583 use fxfs_crypto::ff1::Ff1;
3584 use fxfs_crypto::{
3585 Crypt, EncryptionKey, FXFS_KEY_SIZE, FXFS_WRAPPED_KEY_SIZE, FxfsKey, JournalCipher,
3586 KeyPurpose, ObjectType, StreamCipher, UnwrappedKey, WrappedKey, WrappedKeyBytes,
3587 WrappingKeyId,
3588 };
3589 use fxfs_insecure_crypto::new_insecure_crypt;
3590 use std::sync::Arc;
3591 use std::sync::atomic::{AtomicBool, AtomicIsize, AtomicU64, Ordering};
3592 use std::time::Duration;
3593 use storage_device::DeviceHolder;
3594 use storage_device::fake_device::FakeDevice;
3595 use test_case::test_case;
3596 use zx_status as zx;
3597
3598 const TEST_DEVICE_BLOCK_SIZE: u32 = 512;
3599
3600 async fn test_filesystem_with_hooks(hooks: Arc<HooksHandle>) -> OpenFxFilesystem {
3601 let device = DeviceHolder::new(FakeDevice::new(8192, TEST_DEVICE_BLOCK_SIZE));
3602 FxFilesystemBuilder::new()
3603 .hooks(hooks)
3604 .format(true)
3605 .open(device)
3606 .await
3607 .expect("open failed")
3608 }
3609
3610 async fn test_filesystem() -> OpenFxFilesystem {
3611 test_filesystem_with_hooks(Default::default()).await
3612 }
3613
3614 #[fuchsia::test]
3615 async fn test_verified_file_with_verified_attribute() {
3616 let fs: OpenFxFilesystem = test_filesystem().await;
3617 let mut transaction = fs
3618 .root_store()
3619 .new_transaction(lock_keys![], Options::default())
3620 .await
3621 .expect("new_transaction failed");
3622 let store = fs.root_store();
3623 let object = Arc::new(
3624 ObjectStore::create_object(&store, &mut transaction, HandleOptions::default(), None)
3625 .await
3626 .expect("create_object failed"),
3627 );
3628
3629 transaction.add(
3630 store.store_object_id(),
3631 Mutation::replace_or_insert_object(
3632 ObjectKey::attribute(
3633 object.object_id(),
3634 AttributeId::DATA,
3635 AttributeKey::Attribute,
3636 ),
3637 ObjectValue::verified_attribute(
3638 0,
3639 FsverityMetadata::Internal(RootDigest::Sha256([0; 32]), vec![]),
3640 ),
3641 ),
3642 );
3643
3644 transaction.add(
3645 store.store_object_id(),
3646 Mutation::replace_or_insert_object(
3647 ObjectKey::attribute(
3648 object.object_id(),
3649 AttributeId::FSVERITY_MERKLE,
3650 AttributeKey::Attribute,
3651 ),
3652 ObjectValue::attribute(0, false),
3653 ),
3654 );
3655
3656 transaction.commit().await.unwrap();
3657
3658 let handle =
3659 ObjectStore::open_object(&store, object.object_id(), HandleOptions::default(), None)
3660 .await
3661 .expect("open_object failed");
3662
3663 assert!(handle.is_verified_file());
3664
3665 fs.close().await.expect("Close failed");
3666 }
3667
3668 #[fuchsia::test]
3669 async fn test_verified_file_without_verified_attribute() {
3670 let fs: OpenFxFilesystem = test_filesystem().await;
3671 let mut transaction = fs
3672 .root_store()
3673 .new_transaction(lock_keys![], Options::default())
3674 .await
3675 .expect("new_transaction failed");
3676 let store = fs.root_store();
3677 let object = Arc::new(
3678 ObjectStore::create_object(&store, &mut transaction, HandleOptions::default(), None)
3679 .await
3680 .expect("create_object failed"),
3681 );
3682
3683 transaction.commit().await.unwrap();
3684
3685 let handle =
3686 ObjectStore::open_object(&store, object.object_id(), HandleOptions::default(), None)
3687 .await
3688 .expect("open_object failed");
3689
3690 assert!(!handle.is_verified_file());
3691
3692 fs.close().await.expect("Close failed");
3693 }
3694
3695 #[fuchsia::test]
3696 async fn test_create_and_open_store() {
3697 let fs = test_filesystem().await;
3698 let store_id = {
3699 let root_volume = root_volume(fs.clone()).await.expect("root_volume failed");
3700 root_volume
3701 .new_volume(
3702 "test",
3703 NewChildStoreOptions {
3704 options: StoreOptions { crypt: Some(Arc::new(new_insecure_crypt())) },
3705 ..Default::default()
3706 },
3707 )
3708 .await
3709 .expect("new_volume failed")
3710 .store_object_id()
3711 };
3712
3713 fs.close().await.expect("close failed");
3714 let device = fs.take_device().await;
3715 device.reopen(false);
3716 let fs = FxFilesystem::open(device).await.expect("open failed");
3717
3718 {
3719 let store = fs.object_manager().store(store_id).expect("store not found");
3720 store.unlock(Arc::new(new_insecure_crypt())).await.expect("unlock failed");
3721 }
3722 fs.close().await.expect("Close failed");
3723 }
3724
3725 #[fuchsia::test]
3726 async fn test_create_and_open_internal_dir() {
3727 let fs = test_filesystem().await;
3728 let dir_id;
3729 let store_id;
3730 {
3731 let root_volume = root_volume(fs.clone()).await.expect("root_volume failed");
3732 let store = root_volume
3733 .new_volume(
3734 "test",
3735 NewChildStoreOptions {
3736 options: StoreOptions { crypt: Some(Arc::new(new_insecure_crypt())) },
3737 ..Default::default()
3738 },
3739 )
3740 .await
3741 .expect("new_volume failed");
3742 dir_id =
3743 store.get_or_create_internal_directory_id().await.expect("Create internal dir");
3744 store_id = store.store_object_id();
3745 }
3746
3747 fs.close().await.expect("close failed");
3748 let device = fs.take_device().await;
3749 device.reopen(false);
3750 let fs = FxFilesystem::open(device).await.expect("open failed");
3751
3752 {
3753 let store = fs.object_manager().store(store_id).expect("store not found");
3754 store.unlock(Arc::new(new_insecure_crypt())).await.expect("unlock failed");
3755 assert_eq!(
3756 dir_id,
3757 store.get_or_create_internal_directory_id().await.expect("Retrieving dir")
3758 );
3759 let obj = store
3760 .tree()
3761 .find_value(&ObjectKey::object(dir_id))
3762 .await
3763 .expect("Searching tree for dir")
3764 .unwrap();
3765 assert_matches!(obj, ObjectValue::Object { kind: ObjectKind::Directory { .. }, .. });
3766 }
3767 fs.close().await.expect("Close failed");
3768 }
3769
3770 #[fuchsia::test]
3771 async fn test_create_and_open_internal_dir_unencrypted() {
3772 let fs = test_filesystem().await;
3773 let dir_id;
3774 let store_id;
3775 {
3776 let root_volume = root_volume(fs.clone()).await.expect("root_volume failed");
3777 let store = root_volume
3778 .new_volume("test", NewChildStoreOptions::default())
3779 .await
3780 .expect("new_volume failed");
3781 dir_id =
3782 store.get_or_create_internal_directory_id().await.expect("Create internal dir");
3783 store_id = store.store_object_id();
3784 }
3785
3786 fs.close().await.expect("close failed");
3787 let device = fs.take_device().await;
3788 device.reopen(false);
3789 let fs = FxFilesystem::open(device).await.expect("open failed");
3790
3791 {
3792 let store = fs.object_manager().store(store_id).expect("store not found");
3793 assert_eq!(
3794 dir_id,
3795 store.get_or_create_internal_directory_id().await.expect("Retrieving dir")
3796 );
3797 let obj = store
3798 .tree()
3799 .find_value(&ObjectKey::object(dir_id))
3800 .await
3801 .expect("Searching tree for dir")
3802 .unwrap();
3803 assert_matches!(obj, ObjectValue::Object { kind: ObjectKind::Directory { .. }, .. });
3804 }
3805 fs.close().await.expect("Close failed");
3806 }
3807
3808 #[fuchsia::test(threads = 10)]
3809 async fn test_old_layers_are_purged() {
3810 let fs = test_filesystem().await;
3811
3812 let store = fs.root_store();
3813 let mut transaction = fs
3814 .root_store()
3815 .new_transaction(lock_keys![], Options::default())
3816 .await
3817 .expect("new_transaction failed");
3818 let object = Arc::new(
3819 ObjectStore::create_object(&store, &mut transaction, HandleOptions::default(), None)
3820 .await
3821 .expect("create_object failed"),
3822 );
3823 transaction.commit().await.expect("commit failed");
3824
3825 store.flush().await.expect("flush failed");
3826
3827 let mut buf = object.allocate_buffer(5).await;
3828 buf.copy_from_slice(b"hello");
3829 object.write_or_append(Some(0), buf.as_ref()).await.expect("write failed");
3830
3831 let layer_set = store.tree().layer_set();
3833
3834 let done = Mutex::new(false);
3835 let mut object_id = 0;
3836
3837 join!(
3838 async {
3839 store.flush().await.expect("flush failed");
3840 assert!(*done.lock());
3841 },
3842 async {
3843 fasync::Timer::new(Duration::from_secs(1)).await;
3845 *done.lock() = true;
3846 object_id = layer_set.layers.last().unwrap().handle().unwrap().object_id();
3847 std::mem::drop(layer_set);
3848 }
3849 );
3850
3851 if let Err(e) = ObjectStore::open_object(
3852 &store.parent_store.as_ref().unwrap(),
3853 object_id,
3854 HandleOptions::default(),
3855 store.crypt(),
3856 )
3857 .await
3858 {
3859 assert!(FxfsError::NotFound.matches(&e));
3860 } else {
3861 panic!("open_object succeeded");
3862 }
3863 }
3864
3865 #[fuchsia::test]
3866 async fn test_tombstone_deletes_data() {
3867 let fs = test_filesystem().await;
3868 let root_store = fs.root_store();
3869 let child_id = {
3870 let mut transaction = fs
3871 .root_store()
3872 .new_transaction(lock_keys![], Options::default())
3873 .await
3874 .expect("new_transaction failed");
3875 let child = ObjectStore::create_object(
3876 &root_store,
3877 &mut transaction,
3878 HandleOptions::default(),
3879 None,
3880 )
3881 .await
3882 .expect("create_object failed");
3883 root_store.add_to_graveyard(&mut transaction, child.object_id());
3884 transaction.commit().await.expect("commit failed");
3885
3886 let mut buffer = child.allocate_buffer(8192).await;
3888 buffer.fill(0xaa);
3889 child.write_or_append(Some(0), buffer.as_ref()).await.expect("write failed");
3890
3891 child.object_id()
3892 };
3893
3894 root_store
3895 .tombstone_object(child_id, Options::default(), None)
3896 .await
3897 .expect("tombstone failed");
3898
3899 fsck(fs.clone()).await.expect("fsck failed");
3901 }
3902
3903 #[fuchsia::test]
3904 async fn test_tombstone_purges_keys() {
3905 let fs = test_filesystem().await;
3906 let root_volume = root_volume(fs.clone()).await.expect("root_volume failed");
3907 let store = root_volume
3908 .new_volume(
3909 "test",
3910 NewChildStoreOptions {
3911 options: StoreOptions {
3912 crypt: Some(Arc::new(new_insecure_crypt())),
3913 ..StoreOptions::default()
3914 },
3915 ..NewChildStoreOptions::default()
3916 },
3917 )
3918 .await
3919 .expect("new_volume failed");
3920 let mut transaction = fs
3921 .root_store()
3922 .new_transaction(lock_keys![], Options::default())
3923 .await
3924 .expect("new_transaction failed");
3925 let child =
3926 ObjectStore::create_object(&store, &mut transaction, HandleOptions::default(), None)
3927 .await
3928 .expect("create_object failed");
3929 store.add_to_graveyard(&mut transaction, child.object_id());
3930 transaction.commit().await.expect("commit failed");
3931 assert!(store.key_manager.get(child.object_id()).await.unwrap().is_some());
3932 store
3933 .tombstone_object(child.object_id(), Options::default(), None)
3934 .await
3935 .expect("tombstone_object failed");
3936 assert!(store.key_manager.get(child.object_id()).await.unwrap().is_none());
3937 fs.close().await.expect("close failed");
3938 }
3939
3940 #[fuchsia::test]
3941 async fn test_major_compaction_discards_unnecessary_records() {
3942 let fs = test_filesystem().await;
3943 let root_store = fs.root_store();
3944 let child_id = {
3945 let mut transaction = fs
3946 .root_store()
3947 .new_transaction(lock_keys![], Options::default())
3948 .await
3949 .expect("new_transaction failed");
3950 let child = ObjectStore::create_object(
3951 &root_store,
3952 &mut transaction,
3953 HandleOptions::default(),
3954 None,
3955 )
3956 .await
3957 .expect("create_object failed");
3958 root_store.add_to_graveyard(&mut transaction, child.object_id());
3959 transaction.commit().await.expect("commit failed");
3960
3961 let mut buffer = child.allocate_buffer(8192).await;
3963 buffer.fill(0xaa);
3964 child.write_or_append(Some(0), buffer.as_ref()).await.expect("write failed");
3965
3966 child.object_id()
3967 };
3968
3969 root_store
3970 .tombstone_object(child_id, Options::default(), None)
3971 .await
3972 .expect("tombstone failed");
3973 {
3974 let layers = root_store.tree.layer_set();
3975 let mut merger = layers.merger();
3976 let iter = merger
3977 .query(Query::FullRange(&ObjectKey::object(child_id)))
3978 .await
3979 .expect("seek failed");
3980 match iter.get() {
3982 Some(ItemRef { key: ObjectKey { object_id, .. }, .. })
3983 if *object_id == child_id => {}
3984 _ => panic!("Objects should still be in the tree."),
3985 }
3986 }
3987 root_store.flush().await.expect("flush failed");
3988
3989 let layers = root_store.tree.layer_set();
3991 let mut merger = layers.merger();
3992 let iter = merger
3993 .query(Query::FullRange(&ObjectKey::object(child_id)))
3994 .await
3995 .expect("seek failed");
3996 match iter.get() {
3997 None => {}
3998 Some(ItemRef { key: ObjectKey { object_id, .. }, .. }) => {
3999 assert_ne!(*object_id, child_id)
4000 }
4001 }
4002 }
4003
4004 #[fuchsia::test]
4005 async fn test_overlapping_extents_in_different_layers() {
4006 let fs = test_filesystem().await;
4007 let store = fs.root_store();
4008
4009 let mut transaction = store
4010 .new_transaction(
4011 lock_keys![LockKey::object(
4012 store.store_object_id(),
4013 store.root_directory_object_id()
4014 )],
4015 Options::default(),
4016 )
4017 .await
4018 .expect("new_transaction failed");
4019 let root_directory =
4020 Directory::open(&store, store.root_directory_object_id()).await.expect("open failed");
4021 let object = root_directory
4022 .create_child_file(&mut transaction, "test")
4023 .await
4024 .expect("create_child_file failed");
4025 transaction.commit().await.expect("commit failed");
4026
4027 let buf = object.allocate_buffer(16384).await;
4028 object.write_or_append(Some(0), buf.as_ref()).await.expect("write failed");
4029
4030 store.flush().await.expect("flush failed");
4031
4032 object.write_or_append(Some(0), buf.subslice(0..4096)).await.expect("write failed");
4033
4034 object.write_or_append(Some(0), buf.as_ref()).await.expect("write failed");
4038
4039 fsck(fs.clone()).await.expect("fsck failed");
4040 }
4041
4042 #[fuchsia::test(threads = 10)]
4043 async fn test_encrypted_mutations() {
4044 async fn one_iteration(
4045 fs: OpenFxFilesystem,
4046 crypt: Arc<dyn Crypt>,
4047 iteration: u64,
4048 ) -> OpenFxFilesystem {
4049 async fn reopen(fs: OpenFxFilesystem) -> OpenFxFilesystem {
4050 fs.close().await.expect("Close failed");
4051 let device = fs.take_device().await;
4052 device.reopen(false);
4053 FxFilesystem::open(device).await.expect("FS open failed")
4054 }
4055
4056 let fs = reopen(fs).await;
4057
4058 let (store_object_id, object_id) = {
4059 let root_volume = root_volume(fs.clone()).await.expect("root_volume failed");
4060 let store = root_volume
4061 .volume(
4062 "test",
4063 StoreOptions { crypt: Some(crypt.clone()), ..StoreOptions::default() },
4064 )
4065 .await
4066 .expect("volume failed");
4067
4068 let mut transaction = fs
4069 .root_store()
4070 .new_transaction(
4071 lock_keys![LockKey::object(
4072 store.store_object_id(),
4073 store.root_directory_object_id(),
4074 )],
4075 Options::default(),
4076 )
4077 .await
4078 .expect("new_transaction failed");
4079 let root_directory = Directory::open(&store, store.root_directory_object_id())
4080 .await
4081 .expect("open failed");
4082 let object = root_directory
4083 .create_child_file(&mut transaction, &format!("test {}", iteration))
4084 .await
4085 .expect("create_child_file failed");
4086 transaction.commit().await.expect("commit failed");
4087
4088 let mut buf = object.allocate_buffer(1000).await;
4089 for (i, byte) in buf.as_mut_ptr_slice().iter_as_mut::<u8>().enumerate() {
4090 byte.write(i as u8);
4091 }
4092 object.write_or_append(Some(0), buf.as_ref()).await.expect("write failed");
4093
4094 (store.store_object_id(), object.object_id())
4095 };
4096
4097 let fs = reopen(fs).await;
4098
4099 let check_object = |fs: Arc<FxFilesystem>| {
4100 let crypt = crypt.clone();
4101 async move {
4102 let root_volume = root_volume(fs).await.expect("root_volume failed");
4103 let volume = root_volume
4104 .volume(
4105 "test",
4106 StoreOptions { crypt: Some(crypt), ..StoreOptions::default() },
4107 )
4108 .await
4109 .expect("volume failed");
4110
4111 let object = ObjectStore::open_object(
4112 &volume,
4113 object_id,
4114 HandleOptions::default(),
4115 None,
4116 )
4117 .await
4118 .expect("open_object failed");
4119 let buf = object.read_bytes(0..1000).await.expect("read failed");
4120 assert_eq!(buf.len(), 1000);
4121 for (i, &byte) in buf.iter().enumerate() {
4122 assert_eq!(byte, i as u8);
4123 }
4124 }
4125 };
4126
4127 check_object(fs.clone()).await;
4128
4129 let fs = reopen(fs).await;
4130
4131 fs.object_manager()
4134 .flush(FlushReason::Journal(ForceMajor::False))
4135 .await
4136 .expect("flush failed");
4137
4138 assert_ne!(
4139 fs.object_manager()
4140 .store(store_object_id)
4141 .unwrap()
4142 .load_store_info()
4143 .await
4144 .expect("load_store_info failed")
4145 .encrypted_mutations_object_id,
4146 INVALID_OBJECT_ID
4147 );
4148
4149 check_object(fs.clone()).await;
4150
4151 assert_eq!(
4154 fs.object_manager()
4155 .store(store_object_id)
4156 .unwrap()
4157 .load_store_info()
4158 .await
4159 .expect("load_store_info failed")
4160 .encrypted_mutations_object_id,
4161 INVALID_OBJECT_ID
4162 );
4163
4164 let fs = reopen(fs).await;
4165
4166 fsck(fs.clone()).await.expect("fsck failed");
4167
4168 let fs = reopen(fs).await;
4169
4170 check_object(fs.clone()).await;
4171
4172 fs
4173 }
4174
4175 let mut fs = test_filesystem().await;
4176 let crypt = Arc::new(new_insecure_crypt());
4177
4178 {
4179 let root_volume = root_volume(fs.clone()).await.expect("root_volume failed");
4180 let _store = root_volume
4181 .new_volume(
4182 "test",
4183 NewChildStoreOptions {
4184 options: StoreOptions {
4185 crypt: Some(crypt.clone()),
4186 ..StoreOptions::default()
4187 },
4188 ..Default::default()
4189 },
4190 )
4191 .await
4192 .expect("new_volume failed");
4193 }
4194
4195 for i in 0..5 {
4197 fs = one_iteration(fs, crypt.clone(), i).await;
4198 }
4199 }
4200
4201 #[test_case(true; "with a flush")]
4202 #[test_case(false; "without a flush")]
4203 #[fuchsia::test(threads = 10)]
4204 async fn test_object_id_cipher_roll(with_flush: bool) {
4205 let fs = test_filesystem().await;
4206 let crypt = Arc::new(new_insecure_crypt());
4207
4208 let expected_key = {
4209 let root_volume = root_volume(fs.clone()).await.expect("root_volume failed");
4210 let store = root_volume
4211 .new_volume(
4212 "test",
4213 NewChildStoreOptions {
4214 options: StoreOptions {
4215 crypt: Some(crypt.clone()),
4216 ..StoreOptions::default()
4217 },
4218 ..Default::default()
4219 },
4220 )
4221 .await
4222 .expect("new_volume failed");
4223
4224 let root_dir_id = store.root_directory_object_id();
4227 let root_dir =
4228 Arc::new(Directory::open(&store, root_dir_id).await.expect("open failed"));
4229 let mut transaction = store
4230 .new_transaction(
4231 lock_keys![LockKey::object(store.store_object_id(), root_dir_id)],
4232 Options::default(),
4233 )
4234 .await
4235 .expect("new_transaction failed");
4236 for i in 0..10 {
4237 root_dir.create_child_file(&mut transaction, &format!("file {i}")).await.unwrap();
4238 }
4239 transaction.commit().await.expect("commit failed");
4240
4241 let orig_store_info = store.store_info().unwrap();
4242
4243 {
4245 let mut last_object_id = store.last_object_id.lock();
4246 match &mut *last_object_id {
4247 LastObjectId::Encrypted { id, .. } => {
4248 assert_eq!(*id & OBJECT_ID_HI_MASK, 0);
4249 *id |= 0xffffffff;
4250 }
4251 _ => unreachable!(),
4252 }
4253 }
4254
4255 let mut transaction = store
4256 .new_transaction(
4257 lock_keys![LockKey::object(
4258 store.store_object_id(),
4259 store.root_directory_object_id()
4260 )],
4261 Options::default(),
4262 )
4263 .await
4264 .expect("new_transaction failed");
4265 let root_directory = Directory::open(&store, store.root_directory_object_id())
4266 .await
4267 .expect("open failed");
4268 let object = root_directory
4269 .create_child_file(&mut transaction, "test")
4270 .await
4271 .expect("create_child_file failed");
4272 transaction.commit().await.expect("commit failed");
4273
4274 assert_eq!(object.object_id() & OBJECT_ID_HI_MASK, 1u64 << 32);
4275
4276 let key = match (
4278 store.store_info().unwrap().last_object_id,
4279 orig_store_info.last_object_id,
4280 ) {
4281 (
4282 LastObjectIdInfo::Encrypted { key, id },
4283 LastObjectIdInfo::Encrypted { key: orig_key, .. },
4284 ) => {
4285 assert_ne!(key, orig_key);
4286 assert_eq!(id, 1u64 << 32);
4287 key
4288 }
4289 _ => unreachable!(),
4290 };
4291
4292 if with_flush {
4293 fs.journal().force_compact().await.unwrap();
4294 }
4295
4296 let last_object_id = store.last_object_id.lock();
4297 assert_eq!(last_object_id.id(), 1u64 << 32);
4298 key
4299 };
4300
4301 fs.close().await.expect("Close failed");
4302 let device = fs.take_device().await;
4303 device.reopen(false);
4304 let fs = FxFilesystem::open(device).await.expect("open failed");
4305 let root_volume = root_volume(fs.clone()).await.expect("root_volume failed");
4306 let store = root_volume
4307 .volume("test", StoreOptions { crypt: Some(crypt.clone()), ..StoreOptions::default() })
4308 .await
4309 .expect("volume failed");
4310
4311 assert_matches!(store.store_info().unwrap().last_object_id, LastObjectIdInfo::Encrypted { key, .. } if key == expected_key);
4312 assert_eq!(store.last_object_id.lock().id(), 1u64 << 32);
4313
4314 fsck(fs.clone()).await.expect("fsck failed");
4315 fsck_volume(&fs, store.store_object_id(), None).await.expect("fsck_volume failed");
4316 }
4317
4318 #[fuchsia::test]
4319 async fn test_object_id_cipher_roll_no_space() {
4320 let fs = test_filesystem().await;
4321 let crypt = Arc::new(new_insecure_crypt());
4322
4323 {
4324 let root_volume = root_volume(fs.clone()).await.expect("root_volume failed");
4325 let store = root_volume
4326 .new_volume(
4327 "test",
4328 NewChildStoreOptions {
4329 options: StoreOptions {
4330 crypt: Some(crypt.clone()),
4331 ..StoreOptions::default()
4332 },
4333 ..Default::default()
4334 },
4335 )
4336 .await
4337 .expect("new_volume failed");
4338
4339 let root_directory = Directory::open(&store, store.root_directory_object_id())
4340 .await
4341 .expect("open failed");
4342
4343 match &mut *store.last_object_id.lock() {
4345 LastObjectId::Encrypted { id, .. } => {
4346 *id |= 0xffffffff;
4347 }
4348 _ => unreachable!(),
4349 }
4350
4351 let mut transaction = store
4352 .new_transaction(
4353 lock_keys![LockKey::object(
4354 store.store_object_id(),
4355 store.root_directory_object_id()
4356 )],
4357 Options::default(),
4358 )
4359 .await
4360 .expect("new_transaction failed");
4361
4362 let reservation = fs.allocator().reserve_with(None, |limit| limit);
4365 let err = root_directory
4366 .create_child_file(&mut transaction, "test")
4367 .await
4368 .err()
4369 .expect("create_child_file should fail with NoSpace");
4370 assert!(FxfsError::NoSpace.matches(&err), "unexpected error: {err:?}");
4371
4372 std::mem::drop(reservation);
4373
4374 let object = root_directory
4375 .create_child_file(&mut transaction, "test")
4376 .await
4377 .expect("create_child_file failed");
4378 transaction.commit().await.expect("commit failed");
4379
4380 assert_eq!(object.object_id() & OBJECT_ID_HI_MASK, 1u64 << 32);
4381 }
4382
4383 fsck(fs.clone()).await.expect("fsck failed");
4384 fs.close().await.expect("Close failed");
4385 }
4386
4387 #[fuchsia::test]
4388 async fn test_object_id_cipher_roll_checks_journal_space() {
4389 let reclaim_size = 65536;
4390 let device = DeviceHolder::new(FakeDevice::new(8192, TEST_DEVICE_BLOCK_SIZE));
4391 let (mut hooks, fs_hooks) = Hooks::new();
4392 let fs = FxFilesystemBuilder::new()
4393 .hooks(fs_hooks)
4394 .journal_options(JournalOptions { reclaim_size, ..Default::default() })
4395 .format(true)
4396 .open(device)
4397 .await
4398 .expect("open failed");
4399
4400 {
4401 let crypt = Arc::new(new_insecure_crypt());
4402 let root_volume = root_volume(fs.clone()).await.expect("root_volume failed");
4403 let store = root_volume
4404 .new_volume(
4405 "test",
4406 NewChildStoreOptions {
4407 options: StoreOptions { crypt: Some(crypt), ..StoreOptions::default() },
4408 ..Default::default()
4409 },
4410 )
4411 .await
4412 .expect("new_volume failed");
4413 let root_directory = Directory::open(&store, store.root_directory_object_id())
4414 .await
4415 .expect("open failed");
4416
4417 let write_xattrs = || async {
4418 for _ in 0..4 {
4419 let mut t = store
4420 .new_transaction(
4421 lock_keys![LockKey::object(store.store_object_id(), 1000)],
4422 Options::default(),
4423 )
4424 .await
4425 .expect("new_transaction failed");
4426 for i in 0..18 {
4427 t.add(
4428 store.store_object_id(),
4429 Mutation::replace_or_insert_object(
4430 ObjectKey::extended_attribute(
4431 1000,
4432 format!("attr_{i}").into_bytes(),
4433 ),
4434 ObjectValue::inline_extended_attribute(vec![0u8; 1024]),
4435 ),
4436 );
4437 }
4438 t.commit().await.expect("commit failed");
4439 }
4440 };
4441
4442 write_xattrs().await;
4444 fs.journal().force_compact().await.expect("force_compact failed");
4445 fs.journal().force_compact().await.expect("force_compact failed");
4446 fs.journal().pause_compactions().await;
4447
4448 let mut transaction = store
4450 .new_transaction(
4451 lock_keys![LockKey::object(
4452 store.store_object_id(),
4453 store.root_directory_object_id()
4454 )],
4455 Options::default(),
4456 )
4457 .await
4458 .expect("new_transaction failed");
4459
4460 write_xattrs().await;
4463
4464 let journal_clone = fs.journal().clone();
4465 hooks.set_waiting_for_journal_space(move || {
4466 journal_clone.resume_compactions();
4467 });
4468
4469 let _reservation = fs.allocator().reserve_with(None, |limit| limit);
4473
4474 match &mut *store.last_object_id.lock() {
4476 LastObjectId::Encrypted { id, .. } => *id |= 0xffffffff,
4477 _ => unreachable!(),
4478 }
4479
4480 let object = root_directory
4481 .create_child_file(&mut transaction, "test")
4482 .await
4483 .expect("create_child_file failed");
4484 transaction.commit().await.expect("commit failed");
4485
4486 assert_eq!(object.object_id() & OBJECT_ID_HI_MASK, 1u64 << 32);
4487 }
4488
4489 fsck(fs.clone()).await.expect("fsck failed");
4490 fs.close().await.expect("Close failed");
4491 }
4492
4493 #[test_case(false; "cipher_roll")]
4494 #[test_case(true; "low_32_bit")]
4495 #[fuchsia::test]
4496 async fn test_get_next_object_id_with_max_in_flight_transactions(low_32_bit_object_ids: bool) {
4497 let fs = test_filesystem().await;
4498 let crypt = Arc::new(new_insecure_crypt());
4499
4500 let root_volume = root_volume(fs.clone()).await.expect("root_volume failed");
4501 let store = root_volume
4502 .new_volume(
4503 "test",
4504 NewChildStoreOptions {
4505 options: StoreOptions { crypt: Some(crypt), ..StoreOptions::default() },
4506 low_32_bit_object_ids,
4507 ..Default::default()
4508 },
4509 )
4510 .await
4511 .expect("new_volume failed");
4512
4513 if !low_32_bit_object_ids {
4514 match &mut *store.last_object_id.lock() {
4516 LastObjectId::Encrypted { id, .. } => *id |= 0xffffffff,
4517 _ => unreachable!(),
4518 }
4519 }
4520
4521 let mut transactions = Vec::new();
4522 for _ in 0..MAX_IN_FLIGHT_TRANSACTIONS {
4523 transactions.push(
4524 store
4525 .new_transaction(lock_keys![], Options::default())
4526 .await
4527 .expect("new_transaction failed"),
4528 );
4529 }
4530
4531 ObjectStore::create_object(
4532 &store,
4533 transactions.last_mut().unwrap(),
4534 HandleOptions::default(),
4535 None,
4536 )
4537 .await
4538 .expect("create_object failed");
4539
4540 for transaction in transactions {
4541 transaction.commit().await.expect("commit failed");
4542 }
4543
4544 fs.close().await.expect("Close failed");
4545 }
4546
4547 #[fuchsia::test(threads = 2)]
4548 async fn test_race_object_id_cipher_roll_and_flush() {
4549 let fs = test_filesystem().await;
4550 let crypt = Arc::new(new_insecure_crypt());
4551
4552 let root_volume = root_volume(fs.clone()).await.expect("root_volume failed");
4553 let store = root_volume
4554 .new_volume(
4555 "test",
4556 NewChildStoreOptions {
4557 options: StoreOptions { crypt: Some(crypt.clone()), ..StoreOptions::default() },
4558 ..Default::default()
4559 },
4560 )
4561 .await
4562 .expect("new_volume failed");
4563
4564 assert!(matches!(&*store.last_object_id.lock(), LastObjectId::Encrypted { .. }));
4565
4566 let root_dir_id = store.root_directory_object_id();
4569 let root_dir = Arc::new(Directory::open(&store, root_dir_id).await.expect("open failed"));
4570
4571 let _executor_tasks = testing::force_executor_threads_to_run(2).await;
4572
4573 for j in 0..100 {
4574 let mut transaction = store
4575 .new_transaction(
4576 lock_keys![LockKey::object(store.store_object_id(), root_dir_id)],
4577 Options::default(),
4578 )
4579 .await
4580 .expect("new_transaction failed");
4581 root_dir.create_child_file(&mut transaction, &format!("file {j}")).await.unwrap();
4582 transaction.commit().await.expect("commit failed");
4583
4584 let task = {
4585 let fs = fs.clone();
4586 fasync::Task::spawn(async move {
4587 fs.journal().force_compact().await.unwrap();
4588 })
4589 };
4590
4591 {
4593 let mut last_object_id = store.last_object_id.lock();
4594 let LastObjectId::Encrypted { id, .. } = &mut *last_object_id else {
4595 unreachable!()
4596 };
4597 assert_eq!(*id >> 32, j);
4598 *id |= 0xffffffff;
4599 }
4600
4601 let mut transaction = store
4602 .new_transaction(
4603 lock_keys![LockKey::object(
4604 store.store_object_id(),
4605 store.root_directory_object_id()
4606 )],
4607 Options::default(),
4608 )
4609 .await
4610 .expect("new_transaction failed");
4611 let root_directory = Directory::open(&store, store.root_directory_object_id())
4612 .await
4613 .expect("open failed");
4614 root_directory
4615 .create_child_file(&mut transaction, "test {j}")
4616 .await
4617 .expect("create_child_file failed");
4618 transaction.commit().await.expect("commit failed");
4619
4620 task.await;
4621
4622 let new_store_info = store.load_store_info().await.unwrap();
4624
4625 let LastObjectIdInfo::Encrypted { id, key } = new_store_info.last_object_id else {
4626 unreachable!()
4627 };
4628 assert_eq!(id >> 32, j + 1);
4629 let LastObjectIdInfo::Encrypted { key: in_memory_key, .. } =
4630 store.store_info().unwrap().last_object_id
4631 else {
4632 unreachable!()
4633 };
4634 assert_eq!(key, in_memory_key);
4635 }
4636
4637 fs.close().await.expect("Close failed");
4638 }
4639
4640 #[fuchsia::test]
4641 async fn test_object_id_no_roll_for_unencrypted_store() {
4642 let fs = test_filesystem().await;
4643
4644 {
4645 let root_volume = root_volume(fs.clone()).await.expect("root_volume failed");
4646 let store = root_volume
4647 .new_volume("test", NewChildStoreOptions::default())
4648 .await
4649 .expect("new_volume failed");
4650
4651 {
4653 let mut last_object_id = store.last_object_id.lock();
4654 match &mut *last_object_id {
4655 LastObjectId::Unencrypted { id } => {
4656 assert_eq!(*id & OBJECT_ID_HI_MASK, 0);
4657 *id |= 0xffffffff;
4658 }
4659 _ => unreachable!(),
4660 }
4661 }
4662
4663 let mut transaction = store
4664 .new_transaction(
4665 lock_keys![LockKey::object(
4666 store.store_object_id(),
4667 store.root_directory_object_id()
4668 )],
4669 Options::default(),
4670 )
4671 .await
4672 .expect("new_transaction failed");
4673 let root_directory = Directory::open(&store, store.root_directory_object_id())
4674 .await
4675 .expect("open failed");
4676 let object = root_directory
4677 .create_child_file(&mut transaction, "test")
4678 .await
4679 .expect("create_child_file failed");
4680 transaction.commit().await.expect("commit failed");
4681
4682 assert_eq!(object.object_id(), 0x1_0000_0000);
4683
4684 assert_matches!(
4686 store.store_info().unwrap().last_object_id,
4687 LastObjectIdInfo::Unencrypted { .. }
4688 );
4689
4690 assert_eq!(store.last_object_id.lock().id(), 0x1_0000_0000);
4691 };
4692
4693 fs.close().await.expect("Close failed");
4694 let device = fs.take_device().await;
4695 device.reopen(false);
4696 let fs = FxFilesystem::open(device).await.expect("open failed");
4697 let root_volume = root_volume(fs.clone()).await.expect("root_volume failed");
4698 let store =
4699 root_volume.volume("test", StoreOptions::default()).await.expect("volume failed");
4700
4701 assert_eq!(store.last_object_id.lock().id(), 0x1_0000_0000);
4702 }
4703
4704 #[fuchsia::test]
4705 fn test_object_id_is_not_invalid_object_id() {
4706 let key = UnwrappedKey::new(vec![0; FXFS_KEY_SIZE]);
4707 let mut last_object_id =
4709 LastObjectId::Encrypted { id: 1106634047, cipher: Box::new(Ff1::new(&key)) };
4710 assert!(last_object_id.try_get_next().is_some());
4711 assert!(last_object_id.try_get_next().is_some());
4712 }
4713
4714 #[fuchsia::test]
4715 async fn test_last_object_id_is_correct_after_unlock() {
4716 let fs = test_filesystem().await;
4717 let crypt = Arc::new(new_insecure_crypt());
4718
4719 let root_volume = root_volume(fs.clone()).await.expect("root_volume failed");
4720 let store = root_volume
4721 .new_volume(
4722 "test",
4723 NewChildStoreOptions {
4724 options: StoreOptions { crypt: Some(crypt.clone()), ..StoreOptions::default() },
4725 ..Default::default()
4726 },
4727 )
4728 .await
4729 .expect("new_volume failed");
4730
4731 let mut transaction = store
4732 .new_transaction(
4733 lock_keys![LockKey::object(
4734 store.store_object_id(),
4735 store.root_directory_object_id()
4736 )],
4737 Options::default(),
4738 )
4739 .await
4740 .expect("new_transaction failed");
4741 let root_directory =
4742 Directory::open(&store, store.root_directory_object_id()).await.expect("open failed");
4743 root_directory
4744 .create_child_file(&mut transaction, "test")
4745 .await
4746 .expect("create_child_file failed");
4747 transaction.commit().await.expect("commit failed");
4748
4749 fs.journal().force_compact().await.unwrap();
4751
4752 let last_object_id = store.last_object_id.lock().id();
4753
4754 store.lock().await.unwrap();
4755 store.unlock(crypt.clone()).await.unwrap();
4756
4757 assert_eq!(store.last_object_id.lock().id(), last_object_id);
4758 }
4759
4760 #[fuchsia::test(threads = 20)]
4761 async fn test_race_when_rolling_last_object_id_cipher() {
4762 const NUM_THREADS: usize = 20;
4765
4766 let fs = test_filesystem().await;
4767 let crypt = Arc::new(new_insecure_crypt());
4768
4769 let root_volume = root_volume(fs.clone()).await.expect("root_volume failed");
4770 let store = root_volume
4771 .new_volume(
4772 "test",
4773 NewChildStoreOptions {
4774 options: StoreOptions { crypt: Some(crypt.clone()), ..StoreOptions::default() },
4775 ..Default::default()
4776 },
4777 )
4778 .await
4779 .expect("new_volume failed");
4780
4781 let store_id = store.store_object_id();
4782 let root_dir_id = store.root_directory_object_id();
4783
4784 let root_directory =
4785 Arc::new(Directory::open(&store, root_dir_id).await.expect("open failed"));
4786
4787 let mut directories = Vec::new();
4789 for _ in 0..NUM_THREADS {
4790 let mut transaction = fs
4791 .root_store()
4792 .new_transaction(
4793 lock_keys![LockKey::object(store_id, root_dir_id,)],
4794 Options::default(),
4795 )
4796 .await
4797 .expect("new_transaction failed");
4798 directories.push(
4799 root_directory
4800 .create_child_dir(&mut transaction, "test")
4801 .await
4802 .expect("create_child_file failed"),
4803 );
4804 transaction.commit().await.expect("commit failed");
4805 }
4806
4807 match &mut *store.last_object_id.lock() {
4809 LastObjectId::Encrypted { id, .. } => *id |= 0xffff_ffff,
4810 _ => unreachable!(),
4811 }
4812
4813 let scope = fasync::Scope::new();
4814
4815 let _executor_tasks = testing::force_executor_threads_to_run(NUM_THREADS).await;
4816
4817 for dir in directories {
4818 let fs = fs.clone();
4819 scope.spawn(async move {
4820 let mut transaction = fs
4821 .root_store()
4822 .new_transaction(
4823 lock_keys![LockKey::object(store_id, dir.object_id(),)],
4824 Options::default(),
4825 )
4826 .await
4827 .expect("new_transaction failed");
4828 dir.create_child_file(&mut transaction, "test")
4829 .await
4830 .expect("create_child_file failed");
4831 transaction.commit().await.expect("commit failed");
4832 });
4833 }
4834
4835 scope.on_no_tasks().await;
4836
4837 assert_eq!(store.last_object_id.lock().id(), 0x1_0000_0000 + NUM_THREADS as u64 - 1);
4838 }
4839
4840 #[fuchsia::test(threads = 10)]
4841 async fn test_lock_store() {
4842 let fs = test_filesystem().await;
4843 let crypt = Arc::new(new_insecure_crypt());
4844
4845 let root_volume = root_volume(fs.clone()).await.expect("root_volume failed");
4846 let store = root_volume
4847 .new_volume(
4848 "test",
4849 NewChildStoreOptions {
4850 options: StoreOptions { crypt: Some(crypt.clone()), ..StoreOptions::default() },
4851 ..NewChildStoreOptions::default()
4852 },
4853 )
4854 .await
4855 .expect("new_volume failed");
4856 let mut transaction = store
4857 .new_transaction(
4858 lock_keys![LockKey::object(
4859 store.store_object_id(),
4860 store.root_directory_object_id()
4861 )],
4862 Options::default(),
4863 )
4864 .await
4865 .expect("new_transaction failed");
4866 let root_directory =
4867 Directory::open(&store, store.root_directory_object_id()).await.expect("open failed");
4868 root_directory
4869 .create_child_file(&mut transaction, "test")
4870 .await
4871 .expect("create_child_file failed");
4872 transaction.commit().await.expect("commit failed");
4873 store.lock().await.expect("lock failed");
4874
4875 store.unlock(crypt).await.expect("unlock failed");
4876 root_directory.lookup("test").await.expect("lookup failed").expect("not found");
4877 }
4878
4879 #[fuchsia::test(threads = 10)]
4880 async fn test_unlock_read_only() {
4881 let fs = test_filesystem().await;
4882 let crypt = Arc::new(new_insecure_crypt());
4883
4884 let root_volume = root_volume(fs.clone()).await.expect("root_volume failed");
4885 let store = root_volume
4886 .new_volume(
4887 "test",
4888 NewChildStoreOptions {
4889 options: StoreOptions { crypt: Some(crypt.clone()), ..StoreOptions::default() },
4890 ..NewChildStoreOptions::default()
4891 },
4892 )
4893 .await
4894 .expect("new_volume failed");
4895 let mut transaction = store
4896 .new_transaction(
4897 lock_keys![LockKey::object(
4898 store.store_object_id(),
4899 store.root_directory_object_id()
4900 )],
4901 Options::default(),
4902 )
4903 .await
4904 .expect("new_transaction failed");
4905 let root_directory =
4906 Directory::open(&store, store.root_directory_object_id()).await.expect("open failed");
4907 root_directory
4908 .create_child_file(&mut transaction, "test")
4909 .await
4910 .expect("create_child_file failed");
4911 transaction.commit().await.expect("commit failed");
4912 store.lock().await.expect("lock failed");
4913
4914 store.unlock_read_only(crypt.clone()).await.expect("unlock failed");
4915 root_directory.lookup("test").await.expect("lookup failed").expect("not found");
4916
4917 assert_eq!(store.store_info().unwrap().encrypted_mutations_object_id, INVALID_OBJECT_ID);
4921 store.flush().await.expect("flush failed");
4922 assert_ne!(store.store_info().unwrap().encrypted_mutations_object_id, INVALID_OBJECT_ID);
4923 store.lock_read_only();
4924 store.unlock_read_only(crypt).await.expect("unlock failed");
4925 root_directory.lookup("test").await.expect("lookup failed").expect("not found");
4926 }
4927
4928 #[fuchsia::test]
4929 async fn test_mutations_cipher_dropped_on_lock() {
4930 let fs = test_filesystem().await;
4931 let crypt = Arc::new(new_insecure_crypt());
4932
4933 let root_volume = root_volume(fs.clone()).await.expect("root_volume failed");
4934 let store = root_volume
4935 .new_volume(
4936 "test",
4937 NewChildStoreOptions {
4938 options: StoreOptions { crypt: Some(crypt.clone()), ..StoreOptions::default() },
4939 ..NewChildStoreOptions::default()
4940 },
4941 )
4942 .await
4943 .expect("new_volume failed");
4944
4945 assert_matches!(*store.lock_state.lock(), LockState::Unlocked { .. });
4948 assert!(matches!(&*store.last_object_id.lock(), LastObjectId::Encrypted { .. }));
4949
4950 store.lock().await.expect("lock failed");
4953 assert_matches!(*store.lock_state.lock(), LockState::Locked);
4954 assert!(matches!(&*store.last_object_id.lock(), LastObjectId::Pending));
4955
4956 store.unlock(crypt).await.expect("unlock failed");
4959 assert_matches!(*store.lock_state.lock(), LockState::Unlocked { .. });
4960 assert!(matches!(&*store.last_object_id.lock(), LastObjectId::Encrypted { .. }));
4961 }
4962
4963 #[fuchsia::test(threads = 10)]
4964 async fn test_key_rolled_when_unlocked() {
4965 let fs = test_filesystem().await;
4966 let crypt = Arc::new(new_insecure_crypt());
4967
4968 let object_id;
4969 {
4970 let root_volume = root_volume(fs.clone()).await.expect("root_volume failed");
4971 let store = root_volume
4972 .new_volume(
4973 "test",
4974 NewChildStoreOptions {
4975 options: StoreOptions {
4976 crypt: Some(crypt.clone()),
4977 ..StoreOptions::default()
4978 },
4979 ..Default::default()
4980 },
4981 )
4982 .await
4983 .expect("new_volume failed");
4984 let mut transaction = store
4985 .new_transaction(
4986 lock_keys![LockKey::object(
4987 store.store_object_id(),
4988 store.root_directory_object_id()
4989 )],
4990 Options::default(),
4991 )
4992 .await
4993 .expect("new_transaction failed");
4994 let root_directory = Directory::open(&store, store.root_directory_object_id())
4995 .await
4996 .expect("open failed");
4997 object_id = root_directory
4998 .create_child_file(&mut transaction, "test")
4999 .await
5000 .expect("create_child_file failed")
5001 .object_id();
5002 transaction.commit().await.expect("commit failed");
5003 }
5004
5005 fs.close().await.expect("Close failed");
5006 let mut device = fs.take_device().await;
5007
5008 for _ in 0..100 {
5011 device.reopen(false);
5012 let fs = FxFilesystem::open(device).await.expect("open failed");
5013 {
5014 let root_volume = root_volume(fs.clone()).await.expect("root_volume failed");
5015 let store = root_volume
5016 .volume(
5017 "test",
5018 StoreOptions { crypt: Some(crypt.clone()), ..StoreOptions::default() },
5019 )
5020 .await
5021 .expect("open_volume failed");
5022
5023 {
5025 let lock_state = store.lock_state.lock();
5026 let LockState::Unlocked { mutations_cipher, .. } = &*lock_state else {
5027 panic!("Unexpected lock state: {lock_state:?}");
5028 };
5029 assert!(mutations_cipher.key_is_new());
5030 }
5031
5032 let handle =
5034 ObjectStore::open_object(&store, object_id, HandleOptions::default(), None)
5035 .await
5036 .expect("open_object failed");
5037 let buffer = handle.allocate_buffer(100).await;
5038 handle
5039 .write_or_append(Some(0), buffer.as_ref())
5040 .await
5041 .expect("write_or_append failed");
5042 }
5043 fs.close().await.expect("Close failed");
5044 device = fs.take_device().await;
5045 }
5046 }
5047
5048 #[test]
5049 fn test_store_info_max_serialized_size() {
5050 let info = StoreInfo {
5051 guid: [0xff; 16],
5052 last_object_id: LastObjectIdInfo::Encrypted {
5053 id: 0x1234567812345678,
5054 key: FxfsKey {
5055 wrapping_key_id: 0x1234567812345678u128.to_le_bytes(),
5056 key: WrappedKeyBytes::from([0xff; FXFS_WRAPPED_KEY_SIZE]),
5057 },
5058 },
5059 layers: vec![0x1234567812345678; 120],
5064 root_directory_object_id: 0x1234567812345678,
5065 graveyard_directory_object_id: 0x1234567812345678,
5066 object_count: 0x1234567812345678,
5067 mutations_key: Some(FxfsKey {
5068 wrapping_key_id: 0x1234567812345678u128.to_le_bytes(),
5069 key: WrappedKeyBytes::from([0xff; FXFS_WRAPPED_KEY_SIZE]),
5070 }),
5071 mutations_cipher_offset: 0x1234567812345678,
5072 encrypted_mutations_object_id: 0x1234567812345678,
5073 internal_directory_object_id: INVALID_OBJECT_ID,
5074 };
5075 let mut serialized_info = Vec::new();
5076 info.serialize_with_version(&mut serialized_info).unwrap();
5077 assert!(
5078 serialized_info.len() <= MAX_STORE_INFO_SERIALIZED_SIZE,
5079 "{}",
5080 serialized_info.len()
5081 );
5082 }
5083
5084 async fn reopen_after_crypt_failure_inner(read_only: bool) {
5085 let fs = test_filesystem().await;
5086 let root_volume = root_volume(fs.clone()).await.expect("root_volume failed");
5087
5088 let store = {
5089 let crypt = Arc::new(new_insecure_crypt());
5090 let store = root_volume
5091 .new_volume(
5092 "vol",
5093 NewChildStoreOptions {
5094 options: StoreOptions {
5095 crypt: Some(crypt.clone()),
5096 ..StoreOptions::default()
5097 },
5098 ..Default::default()
5099 },
5100 )
5101 .await
5102 .expect("new_volume failed");
5103 let root_directory = Directory::open(&store, store.root_directory_object_id())
5104 .await
5105 .expect("open failed");
5106 let mut transaction = fs
5107 .root_store()
5108 .new_transaction(
5109 lock_keys![LockKey::object(
5110 store.store_object_id(),
5111 root_directory.object_id()
5112 )],
5113 Options::default(),
5114 )
5115 .await
5116 .expect("new_transaction failed");
5117 root_directory
5118 .create_child_file(&mut transaction, "test")
5119 .await
5120 .expect("create_child_file failed");
5121 transaction.commit().await.expect("commit failed");
5122
5123 crypt.shutdown();
5124 let mut transaction = fs
5125 .root_store()
5126 .new_transaction(
5127 lock_keys![LockKey::object(
5128 store.store_object_id(),
5129 root_directory.object_id()
5130 )],
5131 Options::default(),
5132 )
5133 .await
5134 .expect("new_transaction failed");
5135 root_directory
5136 .create_child_file(&mut transaction, "test2")
5137 .await
5138 .map(|_| ())
5139 .expect_err("create_child_file should fail");
5140 store.lock().await.expect("lock failed");
5141 store
5142 };
5143
5144 let crypt = Arc::new(new_insecure_crypt());
5145 if read_only {
5146 store.unlock_read_only(crypt).await.expect("unlock failed");
5147 } else {
5148 store.unlock(crypt).await.expect("unlock failed");
5149 }
5150 let root_directory =
5151 Directory::open(&store, store.root_directory_object_id()).await.expect("open failed");
5152 root_directory.lookup("test").await.expect("lookup failed").expect("not found");
5153 }
5154
5155 #[fuchsia::test(threads = 10)]
5156 async fn test_reopen_after_crypt_failure() {
5157 reopen_after_crypt_failure_inner(false).await;
5158 }
5159
5160 #[fuchsia::test(threads = 10)]
5161 async fn test_reopen_read_only_after_crypt_failure() {
5162 reopen_after_crypt_failure_inner(true).await;
5163 }
5164
5165 #[fuchsia::test(threads = 10)]
5166 #[should_panic(expected = "Insufficient reservation space")]
5167 #[cfg(debug_assertions)]
5168 async fn large_transaction_causes_panic_in_debug_builds() {
5169 let fs = test_filesystem().await;
5170 let root_volume = root_volume(fs.clone()).await.expect("root_volume failed");
5171 let store = root_volume
5172 .new_volume("vol", NewChildStoreOptions::default())
5173 .await
5174 .expect("new_volume failed");
5175 let root_directory =
5176 Directory::open(&store, store.root_directory_object_id()).await.expect("open failed");
5177 let mut transaction = fs
5178 .root_store()
5179 .new_transaction(
5180 lock_keys![LockKey::object(store.store_object_id(), root_directory.object_id())],
5181 Options::default(),
5182 )
5183 .await
5184 .expect("transaction");
5185 for i in 0..500 {
5186 root_directory
5187 .create_symlink(&mut transaction, b"link", &format!("{}", i))
5188 .await
5189 .expect("symlink");
5190 }
5191 assert_eq!(transaction.commit().await.expect("commit"), 0);
5192 }
5193
5194 #[fuchsia::test]
5195 async fn test_crypt_failure_does_not_fuse_journal() {
5196 let fs = test_filesystem().await;
5197
5198 {
5199 let root_volume = root_volume(fs.clone()).await.expect("root_volume failed");
5202 let store1 = root_volume
5203 .new_volume(
5204 "vol1",
5205 NewChildStoreOptions {
5206 options: StoreOptions {
5207 crypt: Some(Arc::new(new_insecure_crypt())),
5208 ..StoreOptions::default()
5209 },
5210 ..Default::default()
5211 },
5212 )
5213 .await
5214 .expect("new_volume failed");
5215 let crypt = Arc::new(new_insecure_crypt());
5216 let store2 = root_volume
5217 .new_volume(
5218 "vol2",
5219 NewChildStoreOptions {
5220 options: StoreOptions { crypt: Some(crypt.clone()) },
5221 ..Default::default()
5222 },
5223 )
5224 .await
5225 .expect("new_volume failed");
5226 for store in [&store1, &store2] {
5227 let root_directory = Directory::open(store, store.root_directory_object_id())
5228 .await
5229 .expect("open failed");
5230 let mut transaction = store
5231 .new_transaction(
5232 lock_keys![LockKey::object(
5233 store.store_object_id(),
5234 root_directory.object_id()
5235 )],
5236 Options::default(),
5237 )
5238 .await
5239 .expect("new_transaction failed");
5240 root_directory
5241 .create_child_file(&mut transaction, "test")
5242 .await
5243 .expect("create_child_file failed");
5244 transaction.commit().await.expect("commit failed");
5245 }
5246
5247 crypt.shutdown();
5249
5250 fs.journal().force_compact().await.expect("compact failed");
5253
5254 let root_directory2 = Directory::open(&store2, store2.root_directory_object_id())
5257 .await
5258 .expect("open failed");
5259 let (child_id, _, _) = root_directory2
5260 .lookup("test")
5261 .await
5262 .expect("lookup failed")
5263 .expect("test file not found");
5264 let mut transaction2 = store2
5265 .new_transaction(
5266 lock_keys![
5267 LockKey::object(store2.store_object_id(), root_directory2.object_id()),
5268 LockKey::object(store2.store_object_id(), child_id),
5269 ],
5270 Options::default(),
5271 )
5272 .await
5273 .expect("new_transaction failed");
5274 replace_child(&mut transaction2, None, (&root_directory2, "test"))
5275 .await
5276 .expect("replace_child failed");
5277 assert!(transaction2.commit().await.is_err());
5278
5279 let root_directory1 = Directory::open(&store1, store1.root_directory_object_id())
5281 .await
5282 .expect("open failed");
5283 let mut transaction1 = store1
5284 .new_transaction(
5285 lock_keys![LockKey::object(
5286 store1.store_object_id(),
5287 root_directory1.object_id()
5288 )],
5289 Options::default(),
5290 )
5291 .await
5292 .expect("new_transaction failed");
5293 root_directory1
5294 .create_child_file(&mut transaction1, "test2")
5295 .await
5296 .expect("create_child_file failed");
5297 transaction1.commit().await.expect("commit failed");
5298
5299 fs.journal().force_compact().await.expect("compact failed");
5301 }
5302
5303 fs.close().await.expect("close failed");
5305 let device = fs.take_device().await;
5306 device.reopen(false);
5307 let fs = FxFilesystem::open(device).await.expect("open failed");
5308 let root_volume = root_volume(fs.clone()).await.expect("root_volume failed");
5309
5310 let store1 = root_volume
5312 .volume(
5313 "vol1",
5314 StoreOptions {
5315 crypt: Some(Arc::new(new_insecure_crypt())),
5316 ..StoreOptions::default()
5317 },
5318 )
5319 .await
5320 .expect("volume failed");
5321 let root_directory1 =
5322 Directory::open(&store1, store1.root_directory_object_id()).await.expect("open failed");
5323 assert!(root_directory1.lookup("test").await.expect("lookup failed").is_some());
5324 assert!(root_directory1.lookup("test2").await.expect("lookup failed").is_some());
5325
5326 let store2 = root_volume
5328 .volume(
5329 "vol2",
5330 StoreOptions {
5331 crypt: Some(Arc::new(new_insecure_crypt())),
5332 ..StoreOptions::default()
5333 },
5334 )
5335 .await
5336 .expect("volume failed");
5337 let root_directory2 =
5338 Directory::open(&store2, store2.root_directory_object_id()).await.expect("open failed");
5339 assert!(root_directory2.lookup("test").await.expect("lookup failed").is_some());
5340 assert!(root_directory2.lookup("test2").await.expect("lookup failed").is_none());
5341
5342 fs.close().await.expect("close failed");
5343 }
5344
5345 #[fuchsia::test]
5346 async fn test_crypt_failure_during_unlock_race() {
5347 let fs = test_filesystem().await;
5348
5349 let store_object_id = {
5350 let root_volume = root_volume(fs.clone()).await.expect("root_volume failed");
5351 let store = root_volume
5352 .new_volume(
5353 "vol",
5354 NewChildStoreOptions {
5355 options: StoreOptions { crypt: Some(Arc::new(new_insecure_crypt())) },
5356 ..Default::default()
5357 },
5358 )
5359 .await
5360 .expect("new_volume failed");
5361 let root_directory = Directory::open(&store, store.root_directory_object_id())
5362 .await
5363 .expect("open failed");
5364 let mut transaction = fs
5365 .root_store()
5366 .new_transaction(
5367 lock_keys![LockKey::object(
5368 store.store_object_id(),
5369 root_directory.object_id()
5370 )],
5371 Options::default(),
5372 )
5373 .await
5374 .expect("new_transaction failed");
5375 root_directory
5376 .create_child_file(&mut transaction, "test")
5377 .await
5378 .expect("create_child_file failed");
5379 transaction.commit().await.expect("commit failed");
5380 store.store_object_id()
5381 };
5382
5383 fs.close().await.expect("close failed");
5384 let device = fs.take_device().await;
5385 device.reopen(false);
5386
5387 let fs = FxFilesystem::open(device).await.expect("open failed");
5388 {
5389 let fs_clone = fs.clone();
5390 let root_volume = root_volume(fs.clone()).await.expect("root_volume failed");
5391
5392 let crypt = Arc::new(new_insecure_crypt());
5393 let crypt_clone = crypt.clone();
5394 join!(
5395 async move {
5396 let _ =
5398 root_volume.volume("vol", StoreOptions { crypt: Some(crypt_clone) }).await;
5399 },
5400 async move {
5401 let keys = lock_keys![LockKey::flush(store_object_id)];
5404 let _ = fs_clone.lock_manager().write_lock(keys).await;
5405 crypt.shutdown();
5406 }
5407 );
5408 }
5409
5410 fs.close().await.expect("close failed");
5411 let device = fs.take_device().await;
5412 device.reopen(false);
5413
5414 let fs = FxFilesystem::open(device).await.expect("open failed");
5415 let root_volume = root_volume(fs.clone()).await.expect("root_volume failed");
5416 let store = root_volume
5417 .volume(
5418 "vol",
5419 StoreOptions {
5420 crypt: Some(Arc::new(new_insecure_crypt())),
5421 ..StoreOptions::default()
5422 },
5423 )
5424 .await
5425 .expect("open volume failed");
5426 let root_directory =
5427 Directory::open(&store, store.root_directory_object_id()).await.expect("open failed");
5428 assert!(root_directory.lookup("test").await.expect("lookup failed").is_some());
5429
5430 fs.close().await.expect("close failed");
5431 }
5432
5433 #[fuchsia::test]
5434 async fn test_low_32_bit_object_ids() {
5435 let device = DeviceHolder::new(FakeDevice::new(16384, TEST_DEVICE_BLOCK_SIZE));
5436 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
5437
5438 {
5439 let root_vol = root_volume(fs.clone()).await.expect("root_volume failed");
5440
5441 let store = root_vol
5442 .new_volume(
5443 "test",
5444 NewChildStoreOptions { low_32_bit_object_ids: true, ..Default::default() },
5445 )
5446 .await
5447 .expect("new_volume failed");
5448
5449 let root_dir = Directory::open(&store, store.root_directory_object_id())
5450 .await
5451 .expect("open failed");
5452
5453 let mut ids = std::collections::HashSet::new();
5454
5455 for i in 0..100 {
5456 let mut transaction = fs
5457 .root_store()
5458 .new_transaction(
5459 lock_keys![LockKey::object(store.store_object_id(), root_dir.object_id())],
5460 Options::default(),
5461 )
5462 .await
5463 .expect("new_transaction failed");
5464
5465 for j in 0..100 {
5466 let object = root_dir
5467 .create_child_dir(&mut transaction, &format!("{i}.{j}"))
5468 .await
5469 .expect("create_child_file failed");
5470
5471 assert!(object.object_id() < 1 << 32);
5472 assert_ne!(object.object_id(), INVALID_OBJECT_ID);
5473 assert!(ids.insert(object.object_id()));
5474 }
5475
5476 transaction.commit().await.expect("commit failed");
5477 }
5478
5479 assert_matches!(store.store_info().unwrap().last_object_id, LastObjectIdInfo::Low32Bit);
5480
5481 fsck_volume(&fs, store.store_object_id(), None).await.expect("fsck_volume failed");
5482 }
5483
5484 fs.close().await.expect("Close failed");
5486 let device = fs.take_device().await;
5487 device.reopen(false);
5488 let fs = FxFilesystem::open(device).await.expect("open failed");
5489 let root_vol = root_volume(fs.clone()).await.expect("root_volume failed");
5490 let store = root_vol.volume("test", StoreOptions::default()).await.expect("volume failed");
5491
5492 let root_dir =
5494 Directory::open(&store, store.root_directory_object_id()).await.expect("open failed");
5495 let mut transaction = fs
5496 .root_store()
5497 .new_transaction(
5498 lock_keys![LockKey::object(store.store_object_id(), root_dir.object_id())],
5499 Options::default(),
5500 )
5501 .await
5502 .expect("new_transaction failed");
5503
5504 let object = root_dir
5505 .create_child_file(&mut transaction, "persistence_check")
5506 .await
5507 .expect("create_child_file failed");
5508 assert!(object.object_id() < 1 << 32);
5509
5510 transaction.commit().await.expect("commit failed");
5511
5512 assert_matches!(store.store_info().unwrap().last_object_id, LastObjectIdInfo::Low32Bit);
5513 }
5514
5515 struct StallingCrypt {
5516 delegate: Arc<dyn Crypt>,
5517 unwrap_stall_counter: AtomicIsize,
5518 unwrap_stalled_tx: Mutex<Option<oneshot::Sender<oneshot::Sender<()>>>>,
5519 create_key_stalled_tx: Mutex<Option<oneshot::Sender<oneshot::Sender<()>>>>,
5520 }
5521
5522 impl StallingCrypt {
5523 fn new(delegate: Arc<dyn Crypt>) -> Self {
5524 Self {
5525 delegate,
5526 unwrap_stall_counter: AtomicIsize::new(-1),
5527 unwrap_stalled_tx: Mutex::new(None),
5528 create_key_stalled_tx: Mutex::new(None),
5529 }
5530 }
5531
5532 fn stall_on_unwrap(
5533 self: &Arc<Self>,
5534 index: usize,
5535 ) -> oneshot::Receiver<oneshot::Sender<()>> {
5536 let (tx, rx) = oneshot::channel();
5537 self.unwrap_stall_counter.store(index as isize, Ordering::Relaxed);
5538 *self.unwrap_stalled_tx.lock() = Some(tx);
5539 rx
5540 }
5541
5542 fn stall_on_create_key(self: &Arc<Self>) -> oneshot::Receiver<oneshot::Sender<()>> {
5543 let (tx, rx) = oneshot::channel();
5544 *self.create_key_stalled_tx.lock() = Some(tx);
5545 rx
5546 }
5547 }
5548
5549 #[async_trait]
5550 impl Crypt for StallingCrypt {
5551 async fn create_key(
5552 &self,
5553 owner: u64,
5554 purpose: KeyPurpose,
5555 ) -> Result<(FxfsKey, UnwrappedKey), zx::Status> {
5556 if matches!(purpose, KeyPurpose::Data) {
5557 let stalled_tx = self.create_key_stalled_tx.lock().take();
5558 if let Some(tx) = stalled_tx {
5559 let (continue_tx, continue_rx) = oneshot::channel();
5560 let _ = tx.send(continue_tx);
5561 let _ = continue_rx.await;
5562 }
5563 }
5564 self.delegate.create_key(owner, purpose).await
5565 }
5566
5567 async fn unwrap_key(
5568 &self,
5569 wrapped_key: &WrappedKey,
5570 owner: u64,
5571 ) -> Result<UnwrappedKey, zx::Status> {
5572 let count = self.unwrap_stall_counter.fetch_sub(1, Ordering::Relaxed);
5573 log::info!("unwrap_key called, count was {}, owner {}", count, owner);
5574 if count == 0 {
5575 log::info!("unwrap_key stalling");
5576 let stalled_tx = self.unwrap_stalled_tx.lock().take();
5577 if let Some(tx) = stalled_tx {
5578 let (continue_tx, continue_rx) = oneshot::channel();
5579 let _ = tx.send(continue_tx);
5580 let _ = continue_rx.await;
5581 }
5582 log::info!("unwrap_key resumed");
5583 }
5584 self.delegate.unwrap_key(wrapped_key, owner).await
5585 }
5586
5587 async fn create_key_with_id(
5588 &self,
5589 owner: u64,
5590 wrapping_key_id: WrappingKeyId,
5591 object_type: ObjectType,
5592 flags: fidl_fuchsia_io::FscryptPolicyFlags,
5593 ) -> Result<(EncryptionKey, UnwrappedKey), zx::Status> {
5594 self.delegate.create_key_with_id(owner, wrapping_key_id, object_type, flags).await
5595 }
5596 }
5597
5598 #[fuchsia::test]
5599 async fn test_fsck_during_key_pre_cache_stall() {
5600 let device = DeviceHolder::new(FakeDevice::new(16384, TEST_DEVICE_BLOCK_SIZE));
5601 let fs = FxFilesystemBuilder::new().format(true).open(device).await.expect("open failed");
5602
5603 let crypt = Arc::new(StallingCrypt::new(Arc::new(new_insecure_crypt())));
5605
5606 let root_vol = root_volume(fs.clone()).await.expect("root_volume failed");
5607 let store = root_vol
5608 .new_volume(
5609 "test",
5610 NewChildStoreOptions {
5611 options: StoreOptions { crypt: Some(crypt.clone()), ..StoreOptions::default() },
5612 ..Default::default()
5613 },
5614 )
5615 .await
5616 .expect("new_volume failed");
5617
5618 let stalled_rx = crypt.stall_on_create_key();
5620
5621 {
5624 let mut lock_state = store.lock_state.lock();
5625 if let super::LockState::Unlocked { cached_keys, .. } = &mut *lock_state {
5626 cached_keys.clear();
5627 }
5628 }
5629
5630 let store_clone = store.clone();
5633 let root_dir_id = store.root_directory_object_id();
5634
5635 let tx_join_handle = fasync::Task::spawn(async move {
5636 let root_dir = Directory::open(&store_clone, root_dir_id).await.expect("open failed");
5637 let mut transaction = store_clone
5638 .new_transaction(
5639 lock_keys![LockKey::object(
5640 store_clone.store_object_id(),
5641 root_dir.object_id()
5642 )],
5643 Options::default(),
5644 )
5645 .await
5646 .expect("new_transaction failed");
5647 let name = "foo";
5648 root_dir
5649 .create_child_file(&mut transaction, name)
5650 .await
5651 .expect("create_child_file failed");
5652 transaction.commit().await.expect("commit failed");
5653 });
5654
5655 let continue_tx = stalled_rx.await.expect("stalled_rx failed");
5657
5658 fsck(fs.clone()).await.expect("fsck failed");
5660
5661 let _ = continue_tx.send(());
5663 tx_join_handle.await;
5664
5665 fs.close().await.expect("Close failed");
5666 }
5667
5668 #[fuchsia::test]
5669 async fn test_writes_to_other_store_not_blocked_by_stall() {
5670 let device = DeviceHolder::new(FakeDevice::new(16384, TEST_DEVICE_BLOCK_SIZE));
5671 let fs = FxFilesystemBuilder::new()
5672 .format(true)
5673 .journal_options(JournalOptions { reclaim_size: 32_768, ..Default::default() })
5674 .open(device)
5675 .await
5676 .expect("open failed");
5677
5678 let crypt1 = Arc::new(StallingCrypt::new(Arc::new(new_insecure_crypt())));
5681
5682 let crypt2 = Arc::new(new_insecure_crypt());
5684
5685 let root_vol = root_volume(fs.clone()).await.expect("root_volume failed");
5686
5687 let store1 = root_vol
5688 .new_volume(
5689 "test1",
5690 NewChildStoreOptions {
5691 options: StoreOptions {
5692 crypt: Some(crypt1.clone()),
5693 ..StoreOptions::default()
5694 },
5695 ..Default::default()
5696 },
5697 )
5698 .await
5699 .expect("new_volume failed");
5700
5701 store1.flush().await.expect("flush failed");
5702
5703 let store2 = root_vol
5704 .new_volume(
5705 "test2",
5706 NewChildStoreOptions {
5707 options: StoreOptions {
5708 crypt: Some(crypt2.clone()),
5709 ..StoreOptions::default()
5710 },
5711 ..Default::default()
5712 },
5713 )
5714 .await
5715 .expect("new_volume failed");
5716
5717 let stalled_rx = crypt1.stall_on_create_key();
5719
5720 {
5722 let mut lock_state = store1.lock_state.lock();
5723 if let super::LockState::Unlocked { cached_keys, .. } = &mut *lock_state {
5724 cached_keys.clear();
5725 }
5726 }
5727
5728 let store1_clone = store1.clone();
5731 let root_dir1_id = store1.root_directory_object_id();
5732
5733 let tx_join_handle = fasync::Task::spawn(async move {
5734 let root_dir1 =
5735 Directory::open(&store1_clone, root_dir1_id).await.expect("open failed");
5736 let mut transaction = store1_clone
5737 .new_transaction(
5738 lock_keys![LockKey::object(
5739 store1_clone.store_object_id(),
5740 root_dir1.object_id()
5741 )],
5742 Options::default(),
5743 )
5744 .await
5745 .expect("new_transaction failed");
5746 root_dir1
5747 .create_child_file(&mut transaction, "foo")
5748 .await
5749 .expect("create_child_file failed");
5750 transaction.commit().await.expect("commit failed");
5751 });
5752
5753 let continue_tx = stalled_rx.await.expect("stalled_rx failed");
5755
5756 let root_dir2 =
5758 Directory::open(&store2, store2.root_directory_object_id()).await.expect("open failed");
5759 let long_name = "a".repeat(255);
5760 let mut i = 0;
5761 while store2.counters.lock().num_flushes < 3 {
5762 if i > 200 {
5763 panic!(
5764 "Failed to trigger 3 compactions after 200 transactions. Flushes: {}",
5765 store2.counters.lock().num_flushes
5766 );
5767 }
5768 let mut transaction = store2
5769 .new_transaction(
5770 lock_keys![LockKey::object(store2.store_object_id(), root_dir2.object_id())],
5771 Options::default(),
5772 )
5773 .await
5774 .expect("new_transaction failed");
5775 root_dir2
5776 .create_child_file(&mut transaction, &format!("{}-{:03}", long_name, i))
5777 .await
5778 .expect("create_child_file failed");
5779 transaction.commit().await.expect("commit failed");
5780 i += 1;
5781 fasync::Timer::new(std::time::Duration::from_millis(5)).await;
5782 }
5783
5784 let _ = continue_tx.send(());
5786 tx_join_handle.await;
5787
5788 fs.close().await.expect("Close failed");
5789 }
5790
5791 #[fuchsia::test]
5792 async fn test_concurrent_transactions_exhaust_cached_keys() {
5793 let fs = test_filesystem().await;
5794
5795 let root_volume = root_volume(fs.clone()).await.expect("root_volume failed");
5796 let crypt = Arc::new(new_insecure_crypt());
5797 let store = root_volume
5798 .new_volume(
5799 "vol",
5800 NewChildStoreOptions {
5801 options: StoreOptions { crypt: Some(crypt.clone()), ..Default::default() },
5802 ..Default::default()
5803 },
5804 )
5805 .await
5806 .expect("new_volume failed");
5807
5808 let root_directory =
5809 Directory::open(&store, store.root_directory_object_id()).await.expect("open failed");
5810
5811 let mut transaction = store
5814 .new_transaction(
5815 lock_keys![LockKey::object(store.store_object_id(), root_directory.object_id())],
5816 Options::default(),
5817 )
5818 .await
5819 .expect("new_transaction failed");
5820 let dir1 = root_directory
5821 .create_child_dir(&mut transaction, "dir1")
5822 .await
5823 .expect("create_child_dir failed");
5824 let dir2 = root_directory
5825 .create_child_dir(&mut transaction, "dir2")
5826 .await
5827 .expect("create_child_dir failed");
5828 let dir3 = root_directory
5829 .create_child_dir(&mut transaction, "dir3")
5830 .await
5831 .expect("create_child_dir failed");
5832 transaction.commit().await.expect("commit failed");
5833
5834 let mut transaction1 = store
5840 .new_transaction(
5841 lock_keys![LockKey::object(store.store_object_id(), dir1.object_id())],
5842 Options::default(),
5843 )
5844 .await
5845 .expect("new_transaction 1 failed");
5846 dir1.create_child_file(&mut transaction1, "file1")
5847 .await
5848 .expect("create_child_file 1 failed");
5849
5850 let mut transaction2 = store
5852 .new_transaction(
5853 lock_keys![LockKey::object(store.store_object_id(), dir2.object_id())],
5854 Options::default(),
5855 )
5856 .await
5857 .expect("new_transaction 2 failed");
5858 dir2.create_child_file(&mut transaction2, "file2")
5859 .await
5860 .expect("create_child_file 2 failed");
5861
5862 let mut transaction3 = store
5864 .new_transaction(
5865 lock_keys![LockKey::object(store.store_object_id(), dir3.object_id())],
5866 Options::default(),
5867 )
5868 .await
5869 .expect("new_transaction 3 failed");
5870 dir3.create_child_file(&mut transaction3, "file3")
5871 .await
5872 .expect("create_child_file 3 failed");
5873
5874 crypt.shutdown();
5876
5877 transaction1.commit().await.expect("commit 1 failed");
5879 fs.journal().force_compact().await.expect("compact 1 failed");
5880
5881 assert!(transaction2.commit().await.is_err());
5884
5885 fs.close().await.expect("Close failed");
5886 }
5887
5888 #[fuchsia::test(threads = 10)]
5889 async fn test_key_exhaustion_race() {
5890 let fs;
5891 let in_hook = AtomicBool::new(false);
5892 let (mut hooks, fs_hooks) = Hooks::new();
5893 fs = test_filesystem_with_hooks(fs_hooks).await;
5894
5895 let root_volume = root_volume(fs.clone()).await.expect("root_volume failed");
5896 let crypt = Arc::new(new_insecure_crypt());
5897 let store = root_volume
5898 .new_volume(
5899 "vol",
5900 NewChildStoreOptions {
5901 options: StoreOptions { crypt: Some(crypt.clone()), ..Default::default() },
5902 ..Default::default()
5903 },
5904 )
5905 .await
5906 .expect("new_volume failed");
5907
5908 let root_directory =
5909 Directory::open(&store, store.root_directory_object_id()).await.expect("open failed");
5910
5911 let mut transaction = store
5913 .new_transaction(
5914 lock_keys![LockKey::object(store.store_object_id(), root_directory.object_id())],
5915 Options::default(),
5916 )
5917 .await
5918 .expect("new_transaction failed");
5919 root_directory
5920 .create_child_dir(&mut transaction, "dir")
5921 .await
5922 .expect("create_child_dir failed");
5923 transaction.commit().await.expect("commit failed");
5924
5925 hooks.set_before_commit(|| {
5926 if in_hook.swap(true, Ordering::Relaxed) {
5927 return;
5928 }
5929
5930 futures::executor::block_on(fs.journal().force_compact()).expect("compact failed");
5934 });
5935
5936 let mut transaction = store
5939 .new_transaction(
5940 lock_keys![LockKey::object(store.store_object_id(), root_directory.object_id())],
5941 Options::default(),
5942 )
5943 .await
5944 .expect("new_transaction failed");
5945 root_directory
5946 .create_child_file(&mut transaction, "file1")
5947 .await
5948 .expect("create_child_file failed");
5949
5950 transaction.commit().await.expect("commit failed");
5959
5960 fs.journal().force_compact().await.expect("compaction failed");
5965
5966 fs.close().await.expect("Close failed");
5967 }
5968
5969 #[fuchsia::test(threads = 10)]
5970 async fn test_unlock_pre_cache_stall_does_not_block_other_stores() {
5971 let device = DeviceHolder::new(FakeDevice::new(16384, TEST_DEVICE_BLOCK_SIZE));
5972 let fs = FxFilesystemBuilder::new()
5973 .format(true)
5974 .journal_options(JournalOptions { reclaim_size: 32_768, ..Default::default() })
5975 .open(device)
5976 .await
5977 .expect("open failed");
5978
5979 let crypt1 = Arc::new(StallingCrypt::new(Arc::new(new_insecure_crypt())));
5980 let crypt2 = Arc::new(new_insecure_crypt());
5981
5982 let root_vol = root_volume(fs.clone()).await.expect("root_volume failed");
5983
5984 let store1 = root_vol
5985 .new_volume(
5986 "test1",
5987 NewChildStoreOptions {
5988 options: StoreOptions {
5989 crypt: Some(crypt1.clone()),
5990 ..StoreOptions::default()
5991 },
5992 ..Default::default()
5993 },
5994 )
5995 .await
5996 .expect("new_volume failed");
5997
5998 {
6000 let mut transaction = store1
6001 .new_transaction(
6002 lock_keys![LockKey::object(
6003 store1.store_object_id(),
6004 store1.root_directory_object_id()
6005 )],
6006 Options::default(),
6007 )
6008 .await
6009 .expect("new_transaction failed");
6010 let root_dir1 = Directory::open(&store1, store1.root_directory_object_id())
6011 .await
6012 .expect("open failed");
6013 root_dir1
6014 .create_child_file(&mut transaction, "foo")
6015 .await
6016 .expect("create_child_file failed");
6017 transaction.commit().await.expect("commit failed");
6018 }
6019 store1.lock().await.expect("lock failed");
6020
6021 let store2 = root_vol
6022 .new_volume(
6023 "test2",
6024 NewChildStoreOptions {
6025 options: StoreOptions {
6026 crypt: Some(crypt2.clone()),
6027 ..StoreOptions::default()
6028 },
6029 ..Default::default()
6030 },
6031 )
6032 .await
6033 .expect("new_volume failed");
6034
6035 let stalled_rx = crypt1.stall_on_create_key();
6037
6038 let store1_clone = store1.clone();
6041 let crypt1_clone = crypt1.clone();
6042 let unlock_join_handle = fasync::Task::spawn(async move {
6043 store1_clone.unlock(crypt1_clone).await.expect("unlock failed");
6044 });
6045
6046 let continue_tx = stalled_rx.await.expect("stalled_rx failed");
6048
6049 let root_dir2 =
6052 Directory::open(&store2, store2.root_directory_object_id()).await.expect("open failed");
6053 let long_name = "a".repeat(255);
6054 let mut i = 0;
6055 while store2.counters.lock().num_flushes < 3 {
6056 if i > 200 {
6057 panic!(
6058 "Failed to trigger 3 compactions after 200 transactions. Flushes: {}",
6059 store2.counters.lock().num_flushes
6060 );
6061 }
6062 let mut transaction = store2
6063 .new_transaction(
6064 lock_keys![LockKey::object(store2.store_object_id(), root_dir2.object_id())],
6065 Options::default(),
6066 )
6067 .await
6068 .expect("new_transaction failed");
6069 root_dir2
6070 .create_child_file(&mut transaction, &format!("{}-{:03}", long_name, i))
6071 .await
6072 .expect("create_child_file failed");
6073 transaction.commit().await.expect("commit failed");
6074 i += 1;
6075 fasync::Timer::new(std::time::Duration::from_millis(5)).await;
6076 }
6077
6078 let _ = continue_tx.send(());
6080 unlock_join_handle.await;
6081
6082 fs.close().await.expect("Close failed");
6083 }
6084
6085 async fn run_unlock_stall_test(unwrap_stall_index: usize) -> bool {
6086 log::info!("Starting run_unlock_stall_test for index {}", unwrap_stall_index);
6087 let device = DeviceHolder::new(FakeDevice::new(16384, TEST_DEVICE_BLOCK_SIZE));
6088 let crypt1 = Arc::new(new_insecure_crypt());
6089 let crypt2 = Arc::new(new_insecure_crypt());
6090 let (store1_id, device) = {
6091 let fs = FxFilesystemBuilder::new()
6092 .format(true)
6093 .journal_options(JournalOptions { reclaim_size: 32_768, ..Default::default() })
6094 .open(device)
6095 .await
6096 .expect("open failed");
6097
6098 let store1_id = {
6099 let root_vol = root_volume(fs.clone()).await.expect("root_volume failed");
6100
6101 let store1 = root_vol
6102 .new_volume(
6103 "test1",
6104 NewChildStoreOptions {
6105 options: StoreOptions {
6106 crypt: Some(crypt1.clone()),
6107 ..StoreOptions::default()
6108 },
6109 ..Default::default()
6110 },
6111 )
6112 .await
6113 .expect("new_volume failed");
6114
6115 root_vol
6116 .new_volume(
6117 "test2",
6118 NewChildStoreOptions {
6119 options: StoreOptions {
6120 crypt: Some(crypt2.clone()),
6121 ..StoreOptions::default()
6122 },
6123 ..Default::default()
6124 },
6125 )
6126 .await
6127 .expect("new_volume failed");
6128
6129 let root_dir1 = Directory::open(&store1, store1.root_directory_object_id())
6130 .await
6131 .expect("open failed");
6132
6133 for i in 0..8 {
6134 let mut transaction = store1
6135 .new_transaction(
6136 lock_keys![LockKey::object(
6137 store1.store_object_id(),
6138 root_dir1.object_id()
6139 )],
6140 Options::default(),
6141 )
6142 .await
6143 .expect("new_transaction failed");
6144 let name = format!("file_{i}");
6145 root_dir1
6146 .create_child_file(&mut transaction, &name)
6147 .await
6148 .expect("create_child_file failed");
6149 transaction.commit().await.expect("commit failed");
6150 }
6151
6152 store1.flush().await.expect("flush failed");
6154
6155 {
6158 let mut transaction = store1
6159 .new_transaction(
6160 lock_keys![LockKey::object(
6161 store1.store_object_id(),
6162 root_dir1.object_id()
6163 )],
6164 Options::default(),
6165 )
6166 .await
6167 .expect("new_transaction failed");
6168 root_dir1
6169 .create_child_file(&mut transaction, "file_after_flush")
6170 .await
6171 .expect("create_child_file failed");
6172 transaction.commit().await.expect("commit failed");
6173 }
6174 store1.store_object_id()
6175 };
6176
6177 fs.close().await.expect("Close failed");
6178 let device = fs.take_device().await;
6179 (store1_id, device)
6180 };
6181 device.reopen(false);
6182
6183 log::info!("Opening filesystem");
6184 let fs = FxFilesystemBuilder::new()
6185 .journal_options(JournalOptions { reclaim_size: 32_768, ..Default::default() })
6186 .open(device)
6187 .await
6188 .expect("open failed");
6189 log::info!("Opened filesystem, getting root volume");
6190 let root_vol = root_volume(fs.clone()).await.expect("root_volume failed");
6191 log::info!("Got root volume");
6192
6193 log::info!("Re-opening store2");
6194 let store2 = root_vol
6196 .volume("test2", StoreOptions { crypt: Some(crypt2), ..StoreOptions::default() })
6197 .await
6198 .expect("volume failed");
6199 log::info!("Re-opened store2");
6200
6201 let stalling_crypt1 = Arc::new(StallingCrypt::new(crypt1));
6203 let stalled_rx = stalling_crypt1.stall_on_unwrap(unwrap_stall_index);
6204
6205 let store1 = fs.object_manager().store(store1_id).unwrap();
6207
6208 log::info!("Spawning store1 unlock task");
6209 let store1_clone = store1.clone();
6211 let stalling_crypt1_clone = stalling_crypt1.clone();
6212 let unlock_join_handle = fasync::Task::spawn(async move {
6213 log::info!("store1 unlock task started");
6214 store1_clone.unlock(stalling_crypt1_clone).await.expect("unlock failed");
6215 log::info!("store1 unlock task finished");
6216 });
6217
6218 let continue_tx = futures::select! {
6220 res = stalled_rx.fuse() => {
6221 log::info!("Stalled at index {}", unwrap_stall_index);
6222 Some(res.expect("stalled_rx failed"))
6223 }
6224 _ = unlock_join_handle.fuse() => {
6225 log::info!("Unlock completed without stalling at index {}", unwrap_stall_index);
6226 None
6227 }
6228 };
6229
6230 let stalled = continue_tx.is_some();
6231
6232 if let Some(continue_tx) = continue_tx {
6233 log::info!("Writing to store2 while stalled at index {}", unwrap_stall_index);
6234 let root_dir2 = Directory::open(&store2, store2.root_directory_object_id())
6236 .await
6237 .expect("open failed");
6238 let long_name = "a".repeat(255);
6239 let mut i = 0;
6240 while store2.counters.lock().num_flushes < 3 {
6241 if i > 200 {
6242 panic!(
6243 "Failed to trigger 3 compactions after 200 transactions. Flushes: {}",
6244 store2.counters.lock().num_flushes
6245 );
6246 }
6247 let mut transaction = store2
6248 .new_transaction(
6249 lock_keys![LockKey::object(
6250 store2.store_object_id(),
6251 root_dir2.object_id()
6252 )],
6253 Options::default(),
6254 )
6255 .await
6256 .expect("new_transaction failed");
6257 root_dir2
6258 .create_child_file(&mut transaction, &format!("{}-{:03}", long_name, i))
6259 .await
6260 .expect("create_child_file failed");
6261 transaction.commit().await.expect("commit failed");
6262 i += 1;
6263 fasync::Timer::new(std::time::Duration::from_millis(5)).await;
6264 }
6265
6266 log::info!("Unblocking store1 at index {}", unwrap_stall_index);
6267 let _ = continue_tx.send(());
6269 }
6270
6271 fs.close().await.expect("Close failed");
6272 log::info!(
6273 "Finished run_unlock_stall_test for index {}, stalled: {}",
6274 unwrap_stall_index,
6275 stalled
6276 );
6277 stalled
6278 }
6279
6280 #[fuchsia::test(threads = 10)]
6281 async fn test_unlock_replay_stall_does_not_block_other_stores() {
6282 let mut unwrap_stall_index = 0;
6283 loop {
6284 let stalled = run_unlock_stall_test(unwrap_stall_index).await;
6285 if !stalled {
6286 break;
6287 }
6288 unwrap_stall_index += 1;
6289 }
6290 }
6291
6292 #[fuchsia::test(threads = 10)]
6293 async fn test_unlock_flush_race() {
6294 let device = DeviceHolder::new(FakeDevice::new(16384, TEST_DEVICE_BLOCK_SIZE));
6295 let crypt = Arc::new(new_insecure_crypt());
6296
6297 let (store1_id, device) = {
6299 let (store1_id, fs) = {
6300 let fs = FxFilesystemBuilder::new()
6301 .format(true)
6302 .open(device)
6303 .await
6304 .expect("open failed");
6305 let root_vol = root_volume(fs.clone()).await.expect("root_volume failed");
6306 let store1 = root_vol
6307 .new_volume(
6308 "test1",
6309 NewChildStoreOptions {
6310 options: StoreOptions {
6311 crypt: Some(crypt.clone()),
6312 ..StoreOptions::default()
6313 },
6314 ..Default::default()
6315 },
6316 )
6317 .await
6318 .expect("new_volume failed");
6319
6320 let root_dir = Directory::open(&store1, store1.root_directory_object_id())
6321 .await
6322 .expect("open failed");
6323 let mut transaction = store1
6324 .new_transaction(
6325 lock_keys![LockKey::object(store1.store_object_id(), root_dir.object_id())],
6326 Options::default(),
6327 )
6328 .await
6329 .expect("new_transaction failed");
6330 root_dir
6331 .create_child_file(&mut transaction, "file1")
6332 .await
6333 .expect("create_child_file failed");
6334 transaction.commit().await.expect("commit failed");
6335
6336 (store1.store_object_id(), fs)
6337 };
6338 fs.close().await.expect("Close failed");
6339 let device = fs.take_device().await;
6340 (store1_id, device)
6341 };
6342 device.reopen(false);
6343
6344 let fs;
6346 let store1;
6347 let (mut hooks, fs_hooks) = Hooks::new();
6348 fs = FxFilesystemBuilder::new().hooks(fs_hooks).open(device).await.expect("open failed");
6349
6350 store1 = fs.object_manager().store(store1_id).unwrap();
6351
6352 hooks.set_unlock_resources_acquired(|| {
6355 futures::executor::block_on(store1.flush()).expect("flush failed");
6356 });
6357
6358 store1.unlock(crypt).await.expect("unlock failed");
6359
6360 fs.journal().force_compact().await.expect("compact failed");
6361
6362 fsck(fs.clone()).await.expect("fsck failed");
6363
6364 fs.close().await.expect("Close failed");
6365 }
6366
6367 #[fuchsia::test]
6368 async fn test_open_object_with_illegal_key_in_root_store() {
6369 let fs = test_filesystem().await;
6370 let crypt = Arc::new(new_insecure_crypt());
6371 let object_id = {
6372 let store = fs.root_store();
6373 let mut transaction = store
6374 .new_transaction(lock_keys![], Options::default())
6375 .await
6376 .expect("new_transaction failed");
6377
6378 let reserved_id =
6379 store.get_next_object_id(&transaction).await.expect("get_next_object_id failed");
6380 let object_id = reserved_id.get();
6381
6382 let (fxfs_key, unwrapped_key) =
6383 crypt.create_key(object_id, KeyPurpose::Data).await.expect("create_key failed");
6384
6385 let handle = ObjectStore::create_object_with_id(
6386 &store,
6387 &mut transaction,
6388 reserved_id,
6389 HandleOptions::default(),
6390 Some(ObjectEncryptionOptions {
6391 permanent: false,
6392 key_id: 0,
6393 key: EncryptionKey::Fxfs(fxfs_key),
6394 unwrapped_key,
6395 }),
6396 )
6397 .expect("create_object_with_id failed");
6398 transaction.commit().await.expect("commit failed");
6399
6400 let buf = handle.allocate_buffer(fs.block_size().get() as usize).await;
6401 handle.write_or_append(None, buf.as_ref()).await.expect("Write some data");
6402
6403 let old_keys = store.get_keys(object_id).await.expect("Old keys should work fine");
6407 let mut new_keys =
6408 vec![(1, EncryptionKey::FscryptInoLblk32File { key_identifier: [0; 16] })];
6409 for key in old_keys.iter() {
6410 new_keys.push(key.clone());
6411 }
6412 let mut transaction = store
6413 .new_transaction(
6414 lock_keys![LockKey::Object {
6415 store_object_id: store.store_object_id,
6416 object_id
6417 }],
6418 Options::default(),
6419 )
6420 .await
6421 .expect("new_transaction failed");
6422 transaction.add(
6423 store.store_object_id(),
6424 Mutation::replace_or_insert_object(
6425 ObjectKey::keys(object_id),
6426 ObjectValue::keys(new_keys.into()),
6427 ),
6428 );
6429 transaction.commit().await.expect("commit failed");
6430
6431 object_id
6432 };
6433
6434 fs.close().await.expect("close failed");
6435 let device = fs.take_device().await;
6436 device.reopen(false);
6437 let fs = FxFilesystem::open(device).await.expect("open failed");
6438
6439 let store = fs.root_store();
6440 assert!(
6441 ObjectStore::open_object(&store, object_id, HandleOptions::default(), Some(crypt))
6442 .await
6443 .is_err()
6444 );
6445
6446 let res = store.get_keys(object_id).await;
6447 assert!(matches!(res, Err(e) if FxfsError::IntegrityError.matches(&e)));
6448 }
6449
6450 #[fuchsia::test]
6453 async fn test_encrypted_mutations_mixed_versions() {
6454 let fs = test_filesystem().await;
6455 let crypt = Arc::new(new_insecure_crypt());
6456
6457 let (store_object_id, root_dir_id, unwrapped_key) = {
6459 let root_volume = root_volume(fs.clone()).await.expect("root_volume failed");
6460 let store = root_volume
6461 .new_volume(
6462 "test",
6463 NewChildStoreOptions {
6464 options: StoreOptions {
6465 crypt: Some(crypt.clone()),
6466 ..StoreOptions::default()
6467 },
6468 ..Default::default()
6469 },
6470 )
6471 .await
6472 .expect("new_volume failed");
6473 let store_object_id = store.store_object_id();
6474 let root_dir_id = store.root_directory_object_id();
6475 let store_info = store.store_info().unwrap();
6476 let key = store_info.mutations_key.as_ref().unwrap().clone();
6477 let unwrapped_key = crypt
6478 .unwrap_key(&fxfs_crypto::WrappedKey::Fxfs(key.into()), store_object_id)
6479 .await
6480 .expect("unwrap_key failed");
6481
6482 fs.object_manager()
6484 .flush(FlushReason::Journal(ForceMajor::False))
6485 .await
6486 .expect("flush failed");
6487
6488 (store_object_id, root_dir_id, unwrapped_key)
6489 };
6490
6491 let store = fs.object_manager().store(store_object_id).unwrap();
6494 let (old_file_oid, chacha_offset) = {
6495 let mut transaction = store
6496 .new_transaction(
6497 lock_keys![LockKey::object(store_object_id, root_dir_id)],
6498 Options::default(),
6499 )
6500 .await
6501 .expect("new_transaction failed");
6502 let root_directory =
6503 Directory::open(&store, root_dir_id).await.expect("open root dir failed");
6504 let old_file = root_directory
6505 .create_child_file(&mut transaction, "old_file")
6506 .await
6507 .expect("create_child_file failed");
6508 let oid = old_file.object_id();
6509
6510 let mutations = transaction.take_mutations();
6511 let mut old_data = Vec::new();
6512 for item in &mutations {
6513 item.mutation.serialize_into(&mut old_data).expect("serialize failed");
6514 }
6515
6516 let mut stream_cipher = StreamCipher::new(&unwrapped_key, 0);
6517 stream_cipher.encrypt(&mut old_data);
6518
6519 let old_version = Version { major: 56, minor: 0 };
6520 let encrypted_mutations = EncryptedMutations {
6521 transactions: vec![(
6522 JournalCheckpoint { file_offset: 0, checksum: 0, version: old_version },
6523 mutations.len() as u64,
6524 )],
6525 data: old_data,
6526 mutations_key_roll: Vec::new(),
6527 };
6528
6529 let parent_store = store.parent_store().unwrap();
6531 let mut create_txn = parent_store
6532 .new_transaction(lock_keys![], Options::default())
6533 .await
6534 .expect("new_transaction failed");
6535 let handle = ObjectStore::create_object(
6536 &parent_store,
6537 &mut create_txn,
6538 HandleOptions::default(),
6539 None,
6540 )
6541 .await
6542 .expect("create_object failed");
6543 create_txn.commit().await.expect("commit failed");
6544
6545 let mut writer = DirectWriter::new(&handle, Options::default()).await;
6546 let mut buffer = Vec::new();
6547 encrypted_mutations.serialize_with_version(&mut buffer).expect("serialize failed");
6548 writer.write_bytes(&buffer).await.expect("write_bytes failed");
6549 writer.complete().await.expect("writer complete failed");
6550
6551 let mut store_info = store.load_store_info().await.unwrap();
6552 store_info.encrypted_mutations_object_id = handle.object_id();
6553 store_info.mutations_cipher_offset = 0;
6554
6555 let mut update_txn = parent_store
6556 .new_transaction(
6557 lock_keys![LockKey::object(
6558 parent_store.store_object_id(),
6559 store.store_info_handle_object_id().unwrap(),
6560 )],
6561 Options::default(),
6562 )
6563 .await
6564 .expect("new_transaction failed");
6565 store
6566 .write_store_info(&mut update_txn, &store_info)
6567 .await
6568 .expect("write_store_info failed");
6569 *store.store_info.lock() = Some(store_info);
6570 update_txn.commit().await.expect("commit failed");
6571
6572 (oid, stream_cipher.offset())
6573 };
6574
6575 let (new_wrapped_key, new_unwrapped_key) = crypt
6578 .create_key(store_object_id, KeyPurpose::Metadata)
6579 .await
6580 .expect("create_key failed");
6581 if let LockState::Unlocked { mutations_cipher, .. } = &mut *store.lock_state.lock() {
6582 *mutations_cipher = JournalCipher::new_aes256_xts(&new_unwrapped_key, chacha_offset);
6583 } else {
6584 panic!("Unexpected lock state");
6585 }
6586 store.store_info.lock().as_mut().unwrap().mutations_key = Some(new_wrapped_key);
6587
6588 let new_file_oid = {
6589 let mut transaction = store
6590 .new_transaction(
6591 lock_keys![LockKey::object(store_object_id, root_dir_id)],
6592 Options::default(),
6593 )
6594 .await
6595 .expect("new_transaction failed");
6596 let root_directory =
6597 Directory::open(&store, root_dir_id).await.expect("open root dir failed");
6598 let new_file = root_directory
6599 .create_child_file(&mut transaction, "new_file")
6600 .await
6601 .expect("create_child_file failed");
6602 transaction.commit().await.expect("commit failed");
6603 new_file.object_id()
6604 };
6605
6606 fs.close().await.expect("close failed");
6608 let device = fs.take_device().await;
6609 device.reopen(false);
6610 let fs = FxFilesystem::open(device).await.expect("FS open failed");
6611
6612 let root_volume = root_volume(fs.clone()).await.expect("root_volume failed");
6614 let volume = root_volume
6615 .volume("test", StoreOptions { crypt: Some(crypt.clone()), ..StoreOptions::default() })
6616 .await
6617 .expect("volume failed");
6618
6619 let root_directory =
6620 Directory::open(&volume, root_dir_id).await.expect("open root dir failed");
6621
6622 assert_eq!(
6623 root_directory.lookup("old_file").await.expect("lookup old_file failed"),
6624 Some((old_file_oid, ObjectDescriptor::File, false))
6625 );
6626
6627 assert_eq!(
6628 root_directory.lookup("new_file").await.expect("lookup new_file failed"),
6629 Some((new_file_oid, ObjectDescriptor::File, false))
6630 );
6631
6632 let old_file =
6633 ObjectStore::open_object(&volume, old_file_oid, HandleOptions::default(), None)
6634 .await
6635 .expect("open old_file failed");
6636 assert_eq!(old_file.object_id(), old_file_oid);
6637
6638 let new_file =
6639 ObjectStore::open_object(&volume, new_file_oid, HandleOptions::default(), None)
6640 .await
6641 .expect("open new_file failed");
6642 assert_eq!(new_file.object_id(), new_file_oid);
6643 }
6644
6645 #[test_case(false; "unencrypted")]
6646 #[test_case(true; "encrypted")]
6647 #[fuchsia::test]
6648 async fn test_large_mutations_in_transaction(encrypted: bool) {
6649 let fs = test_filesystem().await;
6650 let crypt = Arc::new(new_insecure_crypt());
6651
6652 let root_volume = root_volume(fs.clone()).await.expect("root_volume failed");
6653 let store = root_volume
6654 .new_volume(
6655 "test",
6656 NewChildStoreOptions {
6657 options: StoreOptions {
6658 crypt: if encrypted { Some(crypt.clone()) } else { None },
6659 ..StoreOptions::default()
6660 },
6661 ..Default::default()
6662 },
6663 )
6664 .await
6665 .expect("new_volume failed");
6666 let store_object_id = store.store_object_id();
6667 let root_dir_id = store.root_directory_object_id();
6668
6669 let root_dir = Directory::open(&store, root_dir_id).await.expect("open root dir failed");
6670 let mut transaction = store
6671 .new_transaction(
6672 lock_keys![LockKey::object(store_object_id, root_dir_id)],
6673 Options::default(),
6674 )
6675 .await
6676 .expect("new_transaction failed");
6677
6678 let file = root_dir
6679 .create_child_file(&mut transaction, "test_file")
6680 .await
6681 .expect("create_child_file failed");
6682
6683 let mut total_size = 0;
6687 let mut i = 0;
6688 while total_size <= DEFAULT_MAX_SERIALIZED_RECORD_SIZE {
6689 let name = format!("attr{i}").into_bytes();
6690 let mutation = Mutation::replace_or_insert_object(
6691 ObjectKey::extended_attribute(file.object_id(), name),
6692 ObjectValue::inline_extended_attribute(vec![0u8; MAX_INLINE_XATTR_SIZE]),
6693 );
6694 let mut buf = Vec::new();
6695 mutation.serialize_into(&mut buf).unwrap();
6696 total_size += buf.len() as u64;
6697 transaction.add(store_object_id, mutation);
6698 i += 1;
6699 }
6700
6701 transaction.commit().await.expect("commit should succeed");
6702
6703 if encrypted {
6704 store.lock().await.expect("lock failed");
6705 store.unlock(crypt).await.expect("unlock failed");
6706 }
6707
6708 for j in 0..i {
6709 let name = format!("attr{j}").into_bytes();
6710 let item = store
6711 .tree
6712 .find(&ObjectKey::extended_attribute(file.object_id(), name))
6713 .await
6714 .expect("find failed")
6715 .expect("attr not found");
6716 assert_eq!(
6717 item.value,
6718 ObjectValue::inline_extended_attribute(vec![0u8; MAX_INLINE_XATTR_SIZE])
6719 );
6720 }
6721 }
6722
6723 #[fuchsia::test(threads = 10)]
6724 async fn test_unlock_concurrent_with_locked_flush() {
6725 let (mut hooks, fs_hooks) = Hooks::new();
6726 let fs = test_filesystem_with_hooks(fs_hooks).await;
6727 let crypt = Arc::new(new_insecure_crypt());
6728 let root_vol = root_volume(fs.clone()).await.expect("root_volume failed");
6729
6730 fs.root_store().update_last_object_id(256);
6734
6735 let root_store_id = fs.root_store().store_object_id();
6736 let target_store_id = Arc::new(AtomicU64::new(0));
6737 let target_store_id_clone = target_store_id.clone();
6738 let is_end_flush = Arc::new(AtomicBool::new(false));
6739 let is_end_flush_clone = is_end_flush.clone();
6740 hooks.set_pre_commit(move |txn| {
6741 let store_id = target_store_id_clone.load(Ordering::SeqCst);
6742 if store_id != 0
6743 && txn
6744 .get_object_mutation(
6745 root_store_id,
6746 ObjectKey::attribute(store_id, AttributeId::DATA, AttributeKey::Attribute),
6747 )
6748 .is_some()
6749 {
6750 is_end_flush_clone.store(true, Ordering::SeqCst);
6751 }
6752 Ok(())
6753 });
6754
6755 let ready = Arc::new(AtomicBool::new(false));
6756 let go = Arc::new(AtomicBool::new(false));
6757 let ready_clone = ready.clone();
6758 let go_clone = go.clone();
6759 let is_end_flush_clone = is_end_flush.clone();
6760 hooks.set_before_commit(move || {
6761 if is_end_flush_clone.swap(false, Ordering::SeqCst) {
6762 ready_clone.store(true, Ordering::SeqCst);
6763 while !go_clone.load(Ordering::SeqCst) {
6764 std::hint::spin_loop();
6765 }
6766 }
6767 });
6768
6769 for i in 0..50 {
6770 let store = root_vol
6771 .new_volume(
6772 &format!("vol_{i}"),
6773 NewChildStoreOptions {
6774 options: StoreOptions {
6775 crypt: Some(crypt.clone()),
6776 ..StoreOptions::default()
6777 },
6778 ..Default::default()
6779 },
6780 )
6781 .await
6782 .expect("new_volume failed");
6783 let root_dir =
6784 Directory::open(&store, store.root_directory_object_id()).await.expect("open");
6785 let mut txn = store
6786 .new_transaction(
6787 lock_keys![LockKey::object(store.store_object_id(), root_dir.object_id())],
6788 Options::default(),
6789 )
6790 .await
6791 .expect("new_transaction failed");
6792 root_dir.create_child_file(&mut txn, "f").await.expect("create_child_file failed");
6793 txn.commit().await.expect("commit failed");
6794
6795 store.lock().await.expect("lock failed");
6796 is_end_flush.store(false, Ordering::SeqCst);
6797 ready.store(false, Ordering::SeqCst);
6798 go.store(false, Ordering::SeqCst);
6799 target_store_id.store(store.store_object_id(), Ordering::SeqCst);
6800
6801 let store_clone = store.clone();
6802 let flush_task = fasync::Task::spawn(async move {
6803 store_clone.flush().await.expect("flush failed");
6804 });
6805
6806 while !ready.load(Ordering::SeqCst) {
6807 fasync::yield_now().await;
6808 }
6809 go.store(true, Ordering::SeqCst);
6810 for _ in 0..(i * 100) {
6811 std::hint::spin_loop();
6812 }
6813 store.unlock_read_only(crypt.clone()).await.expect("unlock_read_only failed");
6814 store.lock_read_only();
6815 flush_task.await;
6816 target_store_id.store(0, Ordering::SeqCst);
6817 }
6818 fs.close().await.expect("close failed");
6819 }
6820
6821 #[fuchsia::test]
6822 async fn test_object_store_trait() {
6823 let fs = test_filesystem().await;
6824 let root_store = fs.root_store();
6825 let store_trait: &dyn super::ObjectStoreTrait = (*root_store).as_ref();
6826
6827 let fs_from_trait = store_trait.filesystem();
6829 assert_eq!(fs_from_trait.block_size(), fs.block_size());
6830
6831 let mut transaction =
6833 root_store.new_transaction(lock_keys![], Options::default()).await.expect("new_txn");
6834 let obj1 = ObjectStore::create_object(
6835 &root_store,
6836 &mut transaction,
6837 HandleOptions::default(),
6838 None,
6839 )
6840 .await
6841 .expect("create_object 1 failed");
6842 let obj2 = ObjectStore::create_object(
6843 &root_store,
6844 &mut transaction,
6845 HandleOptions::default(),
6846 None,
6847 )
6848 .await
6849 .expect("create_object 2 failed");
6850 root_store.add_to_graveyard(&mut transaction, obj1.object_id());
6851 root_store.add_to_graveyard(&mut transaction, obj2.object_id());
6852 transaction.commit().await.expect("commit failed");
6853
6854 let obj1_id = obj1.object_id();
6855 let obj2_id = obj2.object_id();
6856 std::mem::drop(obj1);
6857 std::mem::drop(obj2);
6858
6859 assert!(
6861 store_trait
6862 .tree()
6863 .find(&ObjectKey::object(obj1_id))
6864 .await
6865 .expect("find failed")
6866 .is_some()
6867 );
6868
6869 store_trait.purge(obj1_id, None).await.expect("purge failed");
6871 assert!(
6872 store_trait
6873 .tree()
6874 .find(&ObjectKey::object(obj1_id))
6875 .await
6876 .expect("find failed")
6877 .is_none()
6878 );
6879
6880 store_trait.purge_async(obj2_id);
6882 fs.graveyard().wait_for_reap().await;
6883 assert!(
6884 store_trait
6885 .tree()
6886 .find(&ObjectKey::object(obj2_id))
6887 .await
6888 .expect("find failed")
6889 .is_none()
6890 );
6891
6892 fs.close().await.expect("close failed");
6893 }
6894}