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;
12mod flush;
13pub mod graveyard;
14mod install;
15pub mod journal;
16mod key_manager;
17pub(crate) mod merge;
18pub mod object_manager;
19pub mod object_record;
20pub mod project_id;
21mod store_object_handle;
22pub mod transaction;
23mod tree;
24mod tree_cache;
25pub mod volume;
26
27pub use data_object_handle::{
28 DataObjectHandle, DirectWriter, FileExtent, FsverityState, FsverityStateInner, RangeType,
29};
30pub use directory::Directory;
31pub use object_record::{ChildValue, DirType, ObjectDescriptor, PosixAttributes, Timestamp};
32pub use store_object_handle::{SetExtendedAttributeMode, StoreObjectHandle};
33
34use crate::errors::FxfsError;
35use crate::filesystem::{
36 ApplyContext, ApplyMode, FxFilesystem, JournalingObject, MAX_FILE_SIZE, SyncOptions,
37 TruncateGuard,
38};
39use crate::log::*;
40use crate::lsm_tree::cache::{NullCache, ObjectCache};
41use crate::lsm_tree::types::{Existence, Item, ItemRef, LayerIterator};
42use crate::lsm_tree::{LSMTree, Query};
43use crate::object_handle::{INVALID_OBJECT_ID, ObjectHandle, ObjectProperties, ReadObjectHandle};
44use crate::object_store::allocator::Allocator;
45use crate::object_store::graveyard::Graveyard;
46use crate::object_store::journal::{JournalCheckpoint, JournalCheckpointV32, JournaledTransaction};
47use crate::object_store::key_manager::KeyManager;
48use crate::object_store::transaction::{
49 AssocObj, AssociatedObject, LockKey, LockKeys, ObjectStoreMutation, Operation, Options,
50 Transaction, WriteGuard, lock_keys,
51};
52use crate::range::RangeExt;
53use crate::round::round_up;
54use crate::serialized_types::{Version, Versioned, VersionedLatest};
55use anyhow::{Context, Error, anyhow, bail, ensure};
56use async_trait::async_trait;
57use fidl_fuchsia_io as fio;
58use fprint::TypeFingerprint;
59use fuchsia_sync::Mutex;
60use fxfs_crypto::ff1::Ff1;
61use fxfs_crypto::{
62 CipherHolder, Crypt, KeyPurpose, ObjectType, StreamCipher, UnwrappedKey, WrappingKeyId,
63 key_to_cipher,
64};
65use fxfs_macros::{Migrate, migrate_to_version};
66use rand::RngCore;
67use scopeguard::ScopeGuard;
68use serde::{Deserialize, Serialize};
69use std::collections::HashSet;
70use std::fmt;
71use std::num::NonZero;
72use std::sync::atomic::{AtomicBool, AtomicU64, Ordering};
73use std::sync::{Arc, OnceLock, Weak};
74use storage_device::Device;
75use uuid::Uuid;
76
77#[cfg(test)]
80pub static CALLBACK_UNLOCK_RESOURCES_ACQUIRED: crate::test_callback::TestCallback =
81 crate::test_callback::TestCallback::new();
82
83pub use extent::Extent;
84pub use extent_record::{ExtentMode, ExtentValue};
85pub use object_record::{
86 AttributeId, AttributeKey, EncryptionKey, EncryptionKeys, ExtendedAttributeValue,
87 FsverityMetadata, FxfsKey, FxfsKeyV40, FxfsKeyV49, ObjectAttributes, ObjectKey, ObjectKeyData,
88 ObjectKind, ObjectValue, ProjectProperty, RootDigest,
89};
90pub use project_id::{ProjectId, ProjectIdExt};
91pub use transaction::Mutation;
92
93const OBJECT_ID_HI_MASK: u64 = 0xffffffff00000000;
96
97const TRANSACTION_MUTATION_THRESHOLD: usize = 200;
99
100const CACHED_KEYS_LIMIT: usize = 2;
108
109pub const VOLUME_DATA_KEY_ID: u64 = 0;
115pub const FSCRYPT_KEY_ID: u64 = 1;
116
117pub trait HandleOwner: AsRef<ObjectStore> + Send + Sync + 'static {}
120
121pub type StoreInfo = StoreInfoV52;
124
125#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize, TypeFingerprint, Versioned)]
126pub struct StoreInfoV52 {
127 guid: [u8; 16],
129
130 last_object_id: LastObjectIdInfo,
136
137 pub layers: Vec<u64>,
140
141 root_directory_object_id: u64,
143
144 graveyard_directory_object_id: u64,
146
147 object_count: u64,
150
151 mutations_key: Option<FxfsKeyV49>,
153
154 mutations_cipher_offset: u64,
157
158 pub encrypted_mutations_object_id: u64,
161
162 internal_directory_object_id: u64,
165}
166
167#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, TypeFingerprint)]
168enum LastObjectIdInfo {
169 Unencrypted {
170 id: u64,
171 },
172 Encrypted {
173 id: u64,
175
176 key: FxfsKeyV49,
181 },
182 Low32Bit,
183}
184
185impl Default for LastObjectIdInfo {
186 fn default() -> Self {
187 LastObjectIdInfo::Unencrypted { id: 0 }
188 }
189}
190
191#[derive(Default, Serialize, Deserialize, TypeFingerprint, Versioned)]
192pub struct StoreInfoV49 {
193 guid: [u8; 16],
194 last_object_id: u64,
195 layers: Vec<u64>,
196 root_directory_object_id: u64,
197 graveyard_directory_object_id: u64,
198 object_count: u64,
199 mutations_key: Option<FxfsKeyV49>,
200 mutations_cipher_offset: u64,
201 encrypted_mutations_object_id: u64,
202 object_id_key: Option<FxfsKeyV49>,
203 internal_directory_object_id: u64,
204}
205
206impl From<StoreInfoV49> for StoreInfoV52 {
207 fn from(value: StoreInfoV49) -> Self {
208 Self {
209 guid: value.guid,
210 last_object_id: if let Some(key) = value.object_id_key {
211 LastObjectIdInfo::Encrypted { id: value.last_object_id, key: key }
212 } else {
213 LastObjectIdInfo::Unencrypted { id: value.last_object_id }
214 },
215 layers: value.layers,
216 root_directory_object_id: value.root_directory_object_id,
217 graveyard_directory_object_id: value.graveyard_directory_object_id,
218 object_count: value.object_count,
219 mutations_key: value.mutations_key,
220 mutations_cipher_offset: value.mutations_cipher_offset,
221 encrypted_mutations_object_id: value.encrypted_mutations_object_id,
222 internal_directory_object_id: value.internal_directory_object_id,
223 }
224 }
225}
226
227#[derive(Migrate, Serialize, Deserialize, TypeFingerprint, Versioned)]
228#[migrate_to_version(StoreInfoV49)]
229pub struct StoreInfoV40 {
230 guid: [u8; 16],
231 last_object_id: u64,
232 layers: Vec<u64>,
233 root_directory_object_id: u64,
234 graveyard_directory_object_id: u64,
235 object_count: u64,
236 mutations_key: Option<FxfsKeyV40>,
237 mutations_cipher_offset: u64,
238 encrypted_mutations_object_id: u64,
239 object_id_key: Option<FxfsKeyV40>,
240 internal_directory_object_id: u64,
241}
242
243impl StoreInfo {
244 pub fn parent_objects(&self) -> Vec<u64> {
246 let mut objects = self.layers.to_vec();
249 if self.encrypted_mutations_object_id != INVALID_OBJECT_ID {
250 objects.push(self.encrypted_mutations_object_id);
251 }
252 objects
253 }
254}
255
256pub const MAX_STORE_INFO_SERIALIZED_SIZE: usize = 131072;
259
260pub const MAX_ENCRYPTED_MUTATIONS_SIZE: usize = 8 * journal::DEFAULT_RECLAIM_SIZE as usize;
264
265#[derive(Default)]
266pub struct HandleOptions {
267 pub skip_journal_checks: bool,
269 pub skip_checksums: bool,
272 pub skip_fsverity: bool,
275}
276
277pub struct ObjectEncryptionOptions {
279 pub permanent: bool,
284 pub key_id: u64,
285 pub key: EncryptionKey,
286 pub unwrapped_key: UnwrappedKey,
287}
288
289pub struct StoreOptions {
290 pub crypt: Option<Arc<dyn Crypt>>,
292}
293
294impl Default for StoreOptions {
295 fn default() -> Self {
296 Self { crypt: None }
297 }
298}
299
300#[derive(Default)]
301pub struct NewChildStoreOptions {
302 pub options: StoreOptions,
303
304 pub object_id: u64,
307
308 pub reserve_32bit_object_ids: bool,
311
312 pub low_32_bit_object_ids: bool,
315
316 pub guid: Option<[u8; 16]>,
318}
319
320pub type EncryptedMutations = EncryptedMutationsV49;
321
322#[derive(Clone, Default, Deserialize, Serialize, TypeFingerprint)]
323pub struct EncryptedMutationsV49 {
324 transactions: Vec<(JournalCheckpointV32, u64)>,
330
331 #[serde(with = "crate::zerocopy_serialization")]
333 data: Vec<u8>,
334
335 mutations_key_roll: Vec<(usize, FxfsKeyV49)>,
338}
339
340impl std::fmt::Debug for EncryptedMutations {
341 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
342 f.debug_struct("EncryptedMutations")
343 .field("transactions", &self.transactions)
344 .field("len", &self.data.len())
345 .field(
346 "mutations_key_roll",
347 &self.mutations_key_roll.iter().map(|k| k.0).collect::<Vec<usize>>(),
348 )
349 .finish()
350 }
351}
352
353impl Versioned for EncryptedMutations {
354 fn max_serialized_size() -> Option<u64> {
355 Some(MAX_ENCRYPTED_MUTATIONS_SIZE as u64)
356 }
357}
358
359impl From<EncryptedMutationsV40> for EncryptedMutationsV49 {
360 fn from(value: EncryptedMutationsV40) -> Self {
361 EncryptedMutationsV49 {
362 transactions: value.transactions,
363 data: value.data,
364 mutations_key_roll: value
365 .mutations_key_roll
366 .into_iter()
367 .map(|(offset, key)| (offset, key.into()))
368 .collect(),
369 }
370 }
371}
372
373#[derive(Deserialize, Serialize, TypeFingerprint)]
374pub struct EncryptedMutationsV40 {
375 transactions: Vec<(JournalCheckpointV32, u64)>,
376 data: Vec<u8>,
377 mutations_key_roll: Vec<(usize, FxfsKeyV40)>,
378}
379
380impl Versioned for EncryptedMutationsV40 {
381 fn max_serialized_size() -> Option<u64> {
382 Some(MAX_ENCRYPTED_MUTATIONS_SIZE as u64)
383 }
384}
385
386impl EncryptedMutations {
387 fn from_replayed_mutations(
388 store_object_id: u64,
389 transactions: Vec<JournaledTransaction>,
390 ) -> Self {
391 let mut this = Self::default();
392 for JournaledTransaction { checkpoint, non_root_mutations, .. } in transactions {
393 for (object_id, mutation) in non_root_mutations {
394 if store_object_id == object_id {
395 if let Mutation::EncryptedObjectStore(data) = mutation {
396 this.push(&checkpoint, data);
397 } else if let Mutation::UpdateMutationsKey(key) = mutation {
398 this.mutations_key_roll.push((this.data.len(), key.into()));
399 }
400 }
401 }
402 }
403 this
404 }
405
406 fn extend(&mut self, other: &EncryptedMutations) {
407 self.transactions.extend_from_slice(&other.transactions[..]);
408 self.mutations_key_roll.extend(
409 other
410 .mutations_key_roll
411 .iter()
412 .map(|(offset, key)| (offset + self.data.len(), key.clone())),
413 );
414 self.data.extend_from_slice(&other.data[..]);
415 }
416
417 fn push(&mut self, checkpoint: &JournalCheckpoint, data: Box<[u8]>) {
418 self.data.append(&mut data.into());
419 if let Some((last_checkpoint, count)) = self.transactions.last_mut() {
421 if last_checkpoint.file_offset == checkpoint.file_offset {
422 *count += 1;
423 return;
424 }
425 }
426 self.transactions.push((checkpoint.clone(), 1));
427 }
428}
429
430pub enum LockState {
431 Locked,
432 Unencrypted,
433 Unlocked {
434 crypt: Arc<dyn Crypt>,
435 cached_keys: Vec<(NonZero<u64>, EncryptionKey, UnwrappedKey)>,
436 },
437
438 UnlockedReadOnly(Arc<dyn Crypt>),
441
442 Invalid,
445
446 Unknown,
449
450 Locking,
453
454 Unlocking,
457
458 Deleted,
460}
461
462impl fmt::Debug for LockState {
463 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
464 formatter.write_str(match self {
465 LockState::Locked => "Locked",
466 LockState::Unencrypted => "Unencrypted",
467 LockState::Unlocked { .. } => "Unlocked",
468 LockState::UnlockedReadOnly(..) => "UnlockedReadOnly",
469 LockState::Invalid => "Invalid",
470 LockState::Unknown => "Unknown",
471 LockState::Locking => "Locking",
472 LockState::Unlocking => "Unlocking",
473 LockState::Deleted => "Deleted",
474 })
475 }
476}
477
478enum LastObjectId {
479 Pending,
481
482 Unencrypted {
483 id: u64,
484 },
485
486 Encrypted {
487 id: u64,
489
490 cipher: Box<Ff1>,
492 },
493
494 Low32Bit {
495 reserved: HashSet<u32>,
496 unreserved: Vec<u32>,
497 },
498}
499
500impl LastObjectId {
501 fn uses_reserved_ids(&self) -> bool {
503 matches!(self, LastObjectId::Low32Bit { .. })
504 }
505
506 fn try_get_next(&mut self) -> Option<NonZero<u64>> {
510 match self {
511 LastObjectId::Unencrypted { id } => {
512 NonZero::new(id.wrapping_add(1)).inspect(|next| *id = next.get())
513 }
514 LastObjectId::Encrypted { id, cipher } => {
515 let mut next = *id;
516 let hi = next & OBJECT_ID_HI_MASK;
517 loop {
518 if next as u32 == u32::MAX {
519 return None;
520 }
521 next += 1;
522 let candidate = hi | cipher.encrypt(next as u32) as u64;
523 if let Some(candidate) = NonZero::new(candidate) {
524 *id = next;
525 return Some(candidate);
526 }
527 }
528 }
529 _ => None,
530 }
531 }
532
533 fn peek_next(&self) -> u64 {
535 match self {
536 LastObjectId::Unencrypted { id } => id.wrapping_add(1),
537 LastObjectId::Encrypted { id, cipher } => {
538 let mut next = *id;
539 let hi = next & OBJECT_ID_HI_MASK;
540 loop {
541 if next as u32 == u32::MAX {
542 return INVALID_OBJECT_ID;
543 }
544 next += 1;
545 let candidate = hi | cipher.encrypt(next as u32) as u64;
546 if candidate != INVALID_OBJECT_ID {
547 return candidate;
548 }
549 }
550 }
551 _ => INVALID_OBJECT_ID,
552 }
553 }
554
555 fn id(&self) -> u64 {
557 match self {
558 LastObjectId::Unencrypted { id } | LastObjectId::Encrypted { id, .. } => *id,
559 _ => INVALID_OBJECT_ID,
560 }
561 }
562
563 fn is_reserved(&self, id: u64) -> bool {
565 match self {
566 LastObjectId::Low32Bit { reserved, .. } => {
567 if let Ok(id) = id.try_into() {
568 reserved.contains(&id)
569 } else {
570 false
571 }
572 }
573 _ => false,
574 }
575 }
576
577 fn reserve(&mut self, id: u64) {
579 match self {
580 LastObjectId::Low32Bit { reserved, .. } => {
581 assert!(reserved.insert(id.try_into().unwrap()))
582 }
583 _ => unreachable!(),
584 }
585 }
586
587 fn unreserve(&mut self, id: u64) {
589 match self {
590 LastObjectId::Low32Bit { unreserved, .. } => {
591 unreserved.push(id.try_into().unwrap())
610 }
611 _ => {}
612 }
613 }
614
615 fn drain_unreserved(&mut self) {
617 match self {
618 LastObjectId::Low32Bit { reserved, unreserved } => {
619 for u in unreserved.drain(..) {
620 assert!(reserved.remove(&u));
621 }
622 }
623 _ => {}
624 }
625 }
626}
627
628pub struct ReservedId<'a>(&'a ObjectStore, NonZero<u64>);
629
630impl<'a> ReservedId<'a> {
631 pub fn new(store: &'a ObjectStore, id: NonZero<u64>) -> Self {
632 Self(store, id)
633 }
634
635 pub fn get(&self) -> u64 {
636 self.1.get()
637 }
638
639 #[must_use]
641 pub fn release(self) -> NonZero<u64> {
642 let id = self.1;
643 std::mem::forget(self);
644 id
645 }
646}
647
648impl Drop for ReservedId<'_> {
649 fn drop(&mut self) {
650 self.0.last_object_id.lock().unreserve(self.1.get());
651 }
652}
653
654pub struct ObjectStore {
659 parent_store: Option<Arc<ObjectStore>>,
660 store_object_id: u64,
661 device: Arc<dyn Device>,
662 block_size: u64,
663 filesystem: Weak<FxFilesystem>,
664 store_info: Mutex<Option<StoreInfo>>,
666 tree: LSMTree<ObjectKey, ObjectValue>,
667
668 store_info_handle: OnceLock<DataObjectHandle<ObjectStore>>,
673
674 mutations_cipher: Mutex<Option<StreamCipher>>,
676
677 lock_state: Mutex<LockState>,
680 pub key_manager: KeyManager,
681
682 trace: AtomicBool,
684
685 counters: Mutex<ObjectStoreCounters>,
687
688 device_read_ops: AtomicU64,
690 device_write_ops: AtomicU64,
691 logical_read_ops: AtomicU64,
692 logical_write_ops: AtomicU64,
693 graveyard_entries: AtomicU64,
694
695 last_object_id: Mutex<LastObjectId>,
698
699 flush_callback: Mutex<Option<Box<dyn Fn(&ObjectStore) + Send + Sync + 'static>>>,
702}
703
704#[derive(Clone, Default)]
705struct ObjectStoreCounters {
706 mutations_applied: u64,
707 mutations_dropped: u64,
708 num_flushes: u64,
709 last_flush_time: Option<std::time::SystemTime>,
710}
711
712impl ObjectStore {
713 fn new(
714 parent_store: Option<Arc<ObjectStore>>,
715 store_object_id: u64,
716 filesystem: Arc<FxFilesystem>,
717 store_info: Option<StoreInfo>,
718 object_cache: Box<dyn ObjectCache<ObjectKey, ObjectValue>>,
719 mutations_cipher: Option<StreamCipher>,
720 lock_state: LockState,
721 last_object_id: LastObjectId,
722 ) -> Arc<ObjectStore> {
723 let device = filesystem.device();
724 let block_size = filesystem.block_size();
725 Arc::new(ObjectStore {
726 parent_store,
727 store_object_id,
728 device,
729 block_size,
730 filesystem: Arc::downgrade(&filesystem),
731 store_info: Mutex::new(store_info),
732 tree: LSMTree::new(merge::merge, object_cache),
733 store_info_handle: OnceLock::new(),
734 mutations_cipher: Mutex::new(mutations_cipher),
735 lock_state: Mutex::new(lock_state),
736 key_manager: KeyManager::new(),
737 trace: AtomicBool::new(false),
738 counters: Mutex::new(ObjectStoreCounters::default()),
739 device_read_ops: AtomicU64::new(0),
740 device_write_ops: AtomicU64::new(0),
741 logical_read_ops: AtomicU64::new(0),
742 logical_write_ops: AtomicU64::new(0),
743 graveyard_entries: AtomicU64::new(0),
744 last_object_id: Mutex::new(last_object_id),
745 flush_callback: Mutex::new(None),
746 })
747 }
748
749 fn new_empty(
750 parent_store: Option<Arc<ObjectStore>>,
751 store_object_id: u64,
752 filesystem: Arc<FxFilesystem>,
753 object_cache: Box<dyn ObjectCache<ObjectKey, ObjectValue>>,
754 ) -> Arc<Self> {
755 Self::new(
756 parent_store,
757 store_object_id,
758 filesystem,
759 Some(StoreInfo::default()),
760 object_cache,
761 None,
762 LockState::Unencrypted,
763 LastObjectId::Unencrypted { id: 0 },
764 )
765 }
766
767 pub fn new_root_parent(device: Arc<dyn Device>, block_size: u64, store_object_id: u64) -> Self {
770 ObjectStore {
771 parent_store: None,
772 store_object_id,
773 device,
774 block_size,
775 filesystem: Weak::<FxFilesystem>::new(),
776 store_info: Mutex::new(Some(StoreInfo::default())),
777 tree: LSMTree::new(merge::merge, Box::new(NullCache {})),
778 store_info_handle: OnceLock::new(),
779 mutations_cipher: Mutex::new(None),
780 lock_state: Mutex::new(LockState::Unencrypted),
781 key_manager: KeyManager::new(),
782 trace: AtomicBool::new(false),
783 counters: Mutex::new(ObjectStoreCounters::default()),
784 device_read_ops: AtomicU64::new(0),
785 device_write_ops: AtomicU64::new(0),
786 logical_read_ops: AtomicU64::new(0),
787 logical_write_ops: AtomicU64::new(0),
788 graveyard_entries: AtomicU64::new(0),
789 last_object_id: Mutex::new(LastObjectId::Unencrypted { id: 0 }),
790 flush_callback: Mutex::new(None),
791 }
792 }
793
794 pub fn attach_filesystem(mut this: ObjectStore, filesystem: Arc<FxFilesystem>) -> ObjectStore {
797 this.filesystem = Arc::downgrade(&filesystem);
798 this
799 }
800
801 pub async fn new_transaction<'a>(
804 &self,
805 locks: LockKeys,
806 options: Options<'a>,
807 ) -> Result<Transaction<'a>, Error> {
808 if !options.skip_key_roll && self.needs_mutations_key_roll() {
809 if let Some(crypt) = self.crypt() {
810 let keys = lock_keys![LockKey::mutations_key_roll(self.store_object_id())];
811 let fs = self.filesystem();
812 let _guard = fs.lock_manager().write_lock(keys).await;
813 if self.needs_mutations_key_roll() {
814 self.roll_mutations_key(crypt.as_ref()).await?;
815 }
816 }
817 }
818 let fs = self.filesystem();
819 Transaction::new(fs, options, locks).await
820 }
821
822 async fn pre_cache_keys(&self) -> Result<(), Error> {
824 let crypt = match &*self.lock_state.lock() {
825 LockState::Unlocked { cached_keys, crypt, .. }
826 if cached_keys.len() < CACHED_KEYS_LIMIT =>
827 {
828 crypt.clone()
829 }
830 _ => return Ok(()),
831 };
832 loop {
833 let parent_store = self.parent_store.as_ref().unwrap();
834
835 assert!(!parent_store.last_object_id.lock().uses_reserved_ids());
838
839 let raw_id = {
842 let reserved_id = parent_store
843 .maybe_get_next_object_id()
844 .expect("maybe_get_next_object_id failed on parent store");
845 reserved_id.release()
846 };
847
848 let (wrapped, unwrapped) = match crypt.create_key(raw_id.get(), KeyPurpose::Data).await
849 {
850 Ok(v) => v,
851 Err(error) => {
852 log::warn!(
853 error:?,
854 store_id = self.store_object_id();
855 "Failed to pre-cache key"
856 );
857 return Err(error.into());
858 }
859 };
860
861 let mut lock_state = self.lock_state.lock();
862 if let LockState::Unlocked { cached_keys, .. } = &mut *lock_state {
863 cached_keys.push((raw_id, EncryptionKey::Fxfs(wrapped), unwrapped));
864 if cached_keys.len() >= CACHED_KEYS_LIMIT {
865 break;
866 }
867 } else {
868 break;
870 }
871 }
872 Ok(())
873 }
874
875 async fn new_child_store(
885 self: &Arc<Self>,
886 transaction: &mut Transaction<'_>,
887 options: NewChildStoreOptions,
888 object_cache: Box<dyn ObjectCache<ObjectKey, ObjectValue>>,
889 ) -> Result<Arc<Self>, Error> {
890 ensure!(
891 !options.reserve_32bit_object_ids || !options.low_32_bit_object_ids,
892 FxfsError::InvalidArgs
893 );
894 let handle = if let Some(object_id) = NonZero::new(options.object_id) {
895 self.update_last_object_id(object_id.get());
896 let handle = ObjectStore::create_object_with_id(
897 self,
898 transaction,
899 ReservedId::new(self, object_id),
900 HandleOptions::default(),
901 None,
902 )?;
903 handle
904 } else {
905 ObjectStore::create_object(self, transaction, HandleOptions::default(), None).await?
906 };
907 let filesystem = self.filesystem();
908 let id = if options.reserve_32bit_object_ids { 0x1_0000_0000 } else { 0 };
909 let (last_object_id, last_object_id_in_memory) = if options.low_32_bit_object_ids {
910 (
911 LastObjectIdInfo::Low32Bit,
912 LastObjectId::Low32Bit { reserved: HashSet::new(), unreserved: Vec::new() },
913 )
914 } else if let Some(crypt) = &options.options.crypt {
915 let (object_id_wrapped, object_id_unwrapped) =
916 crypt.create_key(handle.object_id(), KeyPurpose::Metadata).await?;
917 (
918 LastObjectIdInfo::Encrypted { id, key: object_id_wrapped },
919 LastObjectId::Encrypted { id, cipher: Box::new(Ff1::new(&object_id_unwrapped)) },
920 )
921 } else {
922 (LastObjectIdInfo::Unencrypted { id }, LastObjectId::Unencrypted { id })
923 };
924 let store = if let Some(crypt) = options.options.crypt {
925 let (wrapped_key, unwrapped_key) =
926 crypt.create_key(handle.object_id(), KeyPurpose::Metadata).await?;
927 Self::new(
928 Some(self.clone()),
929 handle.object_id(),
930 filesystem.clone(),
931 Some(StoreInfo {
932 mutations_key: Some(wrapped_key),
933 last_object_id,
934 guid: options.guid.unwrap_or_else(|| *Uuid::new_v4().as_bytes()),
935 ..Default::default()
936 }),
937 object_cache,
938 Some(StreamCipher::new(&unwrapped_key, 0)),
939 LockState::Unlocked { crypt, cached_keys: Vec::new() },
940 last_object_id_in_memory,
941 )
942 } else {
943 Self::new(
944 Some(self.clone()),
945 handle.object_id(),
946 filesystem.clone(),
947 Some(StoreInfo {
948 last_object_id,
949 guid: options.guid.unwrap_or_else(|| *Uuid::new_v4().as_bytes()),
950 ..Default::default()
951 }),
952 object_cache,
953 None,
954 LockState::Unencrypted,
955 last_object_id_in_memory,
956 )
957 };
958 assert!(store.store_info_handle.set(handle).is_ok());
959 Ok(store)
960 }
961
962 async fn create<'a>(
965 self: &'a Arc<Self>,
966 transaction: &mut Transaction<'a>,
967 ) -> Result<(), Error> {
968 let buf = {
969 let graveyard_directory_object_id = Graveyard::create(transaction, &self).await?;
971 let root_directory = Directory::create(transaction, &self, None).await?;
972
973 let serialized_info = {
974 let mut store_info = self.store_info.lock();
975 let store_info = store_info.as_mut().unwrap();
976
977 store_info.graveyard_directory_object_id = graveyard_directory_object_id;
978 store_info.root_directory_object_id = root_directory.object_id();
979
980 let mut serialized_info = Vec::new();
981 store_info.serialize_with_version(&mut serialized_info)?;
982 serialized_info
983 };
984 let mut buf = self.device.allocate_buffer(serialized_info.len()).await;
985 buf.as_mut_slice().copy_from_slice(&serialized_info[..]);
986 buf
987 };
988
989 if self.filesystem().options().image_builder_mode.is_some() {
990 Ok(())
994 } else {
995 self.store_info_handle.get().unwrap().txn_write(transaction, 0u64, buf.as_ref()).await
996 }
997 }
998
999 pub fn set_trace(&self, trace: bool) {
1000 let old_value = self.trace.swap(trace, Ordering::Relaxed);
1001 if trace != old_value {
1002 info!(store_id = self.store_object_id(), trace; "OS: trace",);
1003 }
1004 }
1005
1006 pub fn set_flush_callback<F: Fn(&ObjectStore) + Send + Sync + 'static>(&self, callback: F) {
1009 let mut flush_callback = self.flush_callback.lock();
1010 *flush_callback = Some(Box::new(callback));
1011 }
1012
1013 pub fn is_root(&self) -> bool {
1014 if let Some(parent) = &self.parent_store {
1015 parent.parent_store.is_none()
1016 } else {
1017 false
1019 }
1020 }
1021
1022 pub fn record_data(self: &Arc<Self>, root: &fuchsia_inspect::Node) {
1024 let counters = self.counters.lock();
1026 if let Some(store_info) = self.store_info() {
1027 root.record_string("guid", Uuid::from_bytes(store_info.guid).to_string());
1028 };
1029 root.record_uint("store_object_id", self.store_object_id);
1030 root.record_uint("mutations_applied", counters.mutations_applied);
1031 root.record_uint("mutations_dropped", counters.mutations_dropped);
1032 root.record_uint("num_flushes", counters.num_flushes);
1033 if let Some(last_flush_time) = counters.last_flush_time.as_ref() {
1034 root.record_uint(
1035 "last_flush_time_ms",
1036 last_flush_time
1037 .duration_since(std::time::UNIX_EPOCH)
1038 .unwrap_or(std::time::Duration::ZERO)
1039 .as_millis()
1040 .try_into()
1041 .unwrap_or(0u64),
1042 );
1043 }
1044 root.record_uint("device_read_ops", self.device_read_ops.load(Ordering::Relaxed));
1045 root.record_uint("device_write_ops", self.device_write_ops.load(Ordering::Relaxed));
1046 root.record_uint("logical_read_ops", self.logical_read_ops.load(Ordering::Relaxed));
1047 root.record_uint("logical_write_ops", self.logical_write_ops.load(Ordering::Relaxed));
1048 root.record_uint("graveyard_entries", self.graveyard_entries.load(Ordering::Relaxed));
1049 {
1050 let last_object_id = self.last_object_id.lock();
1051 root.record_uint("object_id_hi", last_object_id.id() >> 32);
1052 root.record_bool(
1053 "low_32_bit_object_ids",
1054 matches!(&*last_object_id, LastObjectId::Low32Bit { .. }),
1055 );
1056 }
1057
1058 let this = self.clone();
1059 root.record_child("lsm_tree", move |node| this.tree().record_inspect_data(node));
1060 }
1061
1062 pub fn device(&self) -> &Arc<dyn Device> {
1063 &self.device
1064 }
1065
1066 pub fn block_size(&self) -> u64 {
1067 self.block_size
1068 }
1069
1070 pub fn filesystem(&self) -> Arc<FxFilesystem> {
1071 self.filesystem.upgrade().unwrap()
1072 }
1073
1074 pub fn store_object_id(&self) -> u64 {
1075 self.store_object_id
1076 }
1077
1078 pub fn tree(&self) -> &LSMTree<ObjectKey, ObjectValue> {
1079 &self.tree
1080 }
1081
1082 pub fn root_directory_object_id(&self) -> u64 {
1083 self.store_info.lock().as_ref().unwrap().root_directory_object_id
1084 }
1085
1086 pub fn guid(&self) -> [u8; 16] {
1087 self.store_info.lock().as_ref().unwrap().guid
1088 }
1089
1090 pub fn graveyard_directory_object_id(&self) -> u64 {
1091 self.store_info.lock().as_ref().unwrap().graveyard_directory_object_id
1092 }
1093
1094 fn set_graveyard_directory_object_id(&self, oid: u64) {
1095 assert_eq!(
1096 std::mem::replace(
1097 &mut self.store_info.lock().as_mut().unwrap().graveyard_directory_object_id,
1098 oid
1099 ),
1100 INVALID_OBJECT_ID
1101 );
1102 }
1103
1104 pub fn object_count(&self) -> u64 {
1105 self.store_info.lock().as_ref().unwrap().object_count
1106 }
1107
1108 pub(crate) fn unencrypted_last_object_id(&self) -> u64 {
1110 self.last_object_id.lock().id()
1111 }
1112
1113 pub fn key_manager(&self) -> &KeyManager {
1114 &self.key_manager
1115 }
1116
1117 pub fn parent_store(&self) -> Option<&Arc<ObjectStore>> {
1118 self.parent_store.as_ref()
1119 }
1120
1121 pub fn crypt(&self) -> Option<Arc<dyn Crypt>> {
1123 match &*self.lock_state.lock() {
1124 LockState::Locked => panic!("Store is locked"),
1125 LockState::Invalid
1126 | LockState::Unencrypted
1127 | LockState::Locking
1128 | LockState::Unlocking
1129 | LockState::Deleted => None,
1130 LockState::Unlocked { crypt, .. } => Some(crypt.clone()),
1131 LockState::UnlockedReadOnly(crypt) => Some(crypt.clone()),
1132 LockState::Unknown => {
1133 panic!("Store is of unknown lock state; has the journal been replayed yet?")
1134 }
1135 }
1136 }
1137
1138 pub fn get_internal_directory_id(self: &Arc<Self>) -> Result<u64, Error> {
1141 if let Some(store_info) = self.store_info.lock().as_ref() {
1142 if store_info.internal_directory_object_id == INVALID_OBJECT_ID {
1143 Err(FxfsError::NotFound.into())
1144 } else {
1145 Ok(store_info.internal_directory_object_id)
1146 }
1147 } else {
1148 Err(FxfsError::Unavailable.into())
1149 }
1150 }
1151
1152 pub async fn get_or_create_internal_directory_id(self: &Arc<Self>) -> Result<u64, Error> {
1153 let mut transaction = self
1155 .new_transaction(
1156 lock_keys![LockKey::InternalDirectory { store_object_id: self.store_object_id }],
1157 Options::default(),
1158 )
1159 .await?;
1160 let obj_id = self.store_info.lock().as_ref().unwrap().internal_directory_object_id;
1161 if obj_id != INVALID_OBJECT_ID {
1162 return Ok(obj_id);
1163 }
1164
1165 let directory = Directory::create(&mut transaction, self, None).await?;
1167
1168 transaction.add(self.store_object_id, Mutation::CreateInternalDir(directory.object_id()));
1169 transaction.commit().await?;
1170 Ok(directory.object_id())
1171 }
1172
1173 async fn get_file_size(&self, object_id: u64) -> Result<u64, Error> {
1175 let item = self
1176 .tree
1177 .find(&ObjectKey::attribute(object_id, AttributeId::DATA, AttributeKey::Attribute))
1178 .await?
1179 .ok_or(FxfsError::NotFound)?;
1180 if let ObjectValue::Attribute { size, .. } = item.value {
1181 Ok(size)
1182 } else {
1183 bail!(FxfsError::NotFile);
1184 }
1185 }
1186
1187 #[cfg(feature = "migration")]
1188 pub fn last_object_id(&self) -> u64 {
1189 self.last_object_id.lock().id()
1190 }
1191
1192 #[cfg(feature = "migration")]
1194 pub fn mark_allocated(
1195 &self,
1196 transaction: &mut Transaction<'_>,
1197 store_object_id: u64,
1198 device_range: std::ops::Range<u64>,
1199 ) -> Result<(), Error> {
1200 self.allocator().mark_allocated(transaction, store_object_id, device_range)
1201 }
1202
1203 pub async fn open_object<S: HandleOwner>(
1210 owner: &Arc<S>,
1211 obj_id: u64,
1212 options: HandleOptions,
1213 crypt: Option<Arc<dyn Crypt>>,
1214 ) -> Result<DataObjectHandle<S>, Error> {
1215 let store = owner.as_ref().as_ref();
1216 let mut fsverity_descriptor = None;
1217 let mut overwrite_ranges = Vec::new();
1218 let item = store
1219 .tree
1220 .find(&ObjectKey::attribute(obj_id, AttributeId::DATA, AttributeKey::Attribute))
1221 .await?
1222 .ok_or(FxfsError::NotFound)?;
1223
1224 let (size, track_overwrite_extents) = match item.value {
1225 ObjectValue::Attribute { size, has_overwrite_extents } => (size, has_overwrite_extents),
1226 ObjectValue::VerifiedAttribute { size, fsverity_metadata } => {
1227 if !options.skip_fsverity {
1228 fsverity_descriptor = Some(fsverity_metadata);
1229 }
1230 (size, false)
1234 }
1235 _ => bail!(anyhow!(FxfsError::Inconsistent).context("open_object: Expected attibute")),
1236 };
1237
1238 ensure!(size <= MAX_FILE_SIZE, FxfsError::Inconsistent);
1239
1240 if track_overwrite_extents {
1241 let layer_set = store.tree.layer_set();
1242 let mut merger = layer_set.merger();
1243 let mut iter = merger
1244 .query(Query::FullRange(&ObjectKey::attribute(
1245 obj_id,
1246 AttributeId::DATA,
1247 AttributeKey::Extent(Extent::search_key_from_offset(0)),
1248 )))
1249 .await?;
1250 loop {
1251 match iter.get() {
1252 Some(ItemRef {
1253 key:
1254 ObjectKey {
1255 object_id,
1256 data:
1257 ObjectKeyData::Attribute(
1258 AttributeId::DATA,
1259 AttributeKey::Extent(extent),
1260 ),
1261 },
1262 value,
1263 ..
1264 }) if *object_id == obj_id => {
1265 match value {
1266 ObjectValue::Extent(ExtentValue::None)
1267 | ObjectValue::Extent(ExtentValue::Some {
1268 mode: ExtentMode::Raw,
1269 ..
1270 })
1271 | ObjectValue::Extent(ExtentValue::Some {
1272 mode: ExtentMode::Cow(_),
1273 ..
1274 }) => (),
1275 ObjectValue::Extent(ExtentValue::Some {
1276 mode: ExtentMode::OverwritePartial(_),
1277 ..
1278 })
1279 | ObjectValue::Extent(ExtentValue::Some {
1280 mode: ExtentMode::Overwrite,
1281 ..
1282 }) => overwrite_ranges.push(extent.clone().into()),
1283 _ => bail!(
1284 anyhow!(FxfsError::Inconsistent)
1285 .context("open_object: Expected extent")
1286 ),
1287 }
1288 iter.advance().await?;
1289 }
1290 _ => break,
1291 }
1292 }
1293 }
1294
1295 let permanent = if let Some(crypt) = crypt {
1298 store
1299 .key_manager
1300 .get_keys(
1301 obj_id,
1302 crypt.as_ref(),
1303 &mut Some(async || store.get_keys(obj_id).await),
1304 true,
1305 false,
1306 )
1307 .await?;
1308 true
1309 } else {
1310 false
1311 };
1312 let data_object_handle = DataObjectHandle::new(
1313 owner.clone(),
1314 obj_id,
1315 permanent,
1316 AttributeId::DATA,
1317 size,
1318 FsverityState::None,
1319 options,
1320 false,
1321 &overwrite_ranges,
1322 );
1323 if let Some(descriptor) = fsverity_descriptor {
1324 data_object_handle
1325 .set_fsverity_state_some(descriptor)
1326 .await
1327 .context("Invalid or mismatched merkle tree")?;
1328 }
1329 Ok(data_object_handle)
1330 }
1331
1332 pub fn create_object_with_id<S: HandleOwner>(
1333 owner: &Arc<S>,
1334 transaction: &mut Transaction<'_>,
1335 reserved_object_id: ReservedId<'_>,
1336 options: HandleOptions,
1337 encryption_options: Option<ObjectEncryptionOptions>,
1338 ) -> Result<DataObjectHandle<S>, Error> {
1339 let store = owner.as_ref().as_ref();
1340 debug_assert!(store.crypt().is_none() || encryption_options.is_some());
1342 let now = Timestamp::now();
1343 let object_id = reserved_object_id.get();
1344 assert!(
1345 transaction
1346 .add(
1347 store.store_object_id(),
1348 Mutation::insert_object(
1349 ObjectKey::object(reserved_object_id.release().get()),
1350 ObjectValue::file(
1351 1,
1352 0,
1353 now.clone(),
1354 now.clone(),
1355 now.clone(),
1356 now,
1357 None,
1358 None
1359 ),
1360 ),
1361 )
1362 .is_none()
1363 );
1364 let mut permanent_keys = false;
1365 if let Some(ObjectEncryptionOptions { permanent, key_id, key, unwrapped_key }) =
1366 encryption_options
1367 {
1368 permanent_keys = permanent;
1369 let cipher = key_to_cipher(&key, &unwrapped_key)?;
1370 transaction.add(
1371 store.store_object_id(),
1372 Mutation::insert_object(
1373 ObjectKey::keys(object_id),
1374 ObjectValue::keys(vec![(key_id, key)].into()),
1375 ),
1376 );
1377 store.key_manager.insert(
1378 object_id,
1379 Arc::new(vec![(key_id, CipherHolder::Cipher(cipher))].into()),
1380 permanent,
1381 );
1382 }
1383 transaction.add(
1384 store.store_object_id(),
1385 Mutation::insert_object(
1386 ObjectKey::attribute(object_id, AttributeId::DATA, AttributeKey::Attribute),
1387 ObjectValue::attribute(0, false),
1389 ),
1390 );
1391 Ok(DataObjectHandle::new(
1392 owner.clone(),
1393 object_id,
1394 permanent_keys,
1395 AttributeId::DATA,
1396 0,
1397 FsverityState::None,
1398 options,
1399 false,
1400 &[],
1401 ))
1402 }
1403
1404 pub async fn create_object<S: HandleOwner>(
1410 owner: &Arc<S>,
1411 mut transaction: &mut Transaction<'_>,
1412 options: HandleOptions,
1413 wrapping_key_id: Option<WrappingKeyId>,
1414 ) -> Result<DataObjectHandle<S>, Error> {
1415 let store = owner.as_ref().as_ref();
1416 let object_id = store.get_next_object_id().await?;
1417 let crypt = store.crypt();
1418 let encryption_options = if let Some(crypt) = crypt {
1419 let key_id =
1420 if wrapping_key_id.is_some() { FSCRYPT_KEY_ID } else { VOLUME_DATA_KEY_ID };
1421 let (key, unwrapped_key) = if let Some(wrapping_key_id) = wrapping_key_id {
1422 crypt.create_key_with_id(object_id.get(), wrapping_key_id, ObjectType::File).await?
1423 } else {
1424 let (fxfs_key, unwrapped_key) =
1425 crypt.create_key(object_id.get(), KeyPurpose::Data).await?;
1426 (EncryptionKey::Fxfs(fxfs_key), unwrapped_key)
1427 };
1428 Some(ObjectEncryptionOptions { permanent: false, key_id, key, unwrapped_key })
1429 } else {
1430 None
1431 };
1432 ObjectStore::create_object_with_id(
1433 owner,
1434 &mut transaction,
1435 object_id,
1436 options,
1437 encryption_options,
1438 )
1439 }
1440
1441 pub(crate) async fn create_object_with_key<S: HandleOwner>(
1447 owner: &Arc<S>,
1448 mut transaction: &mut Transaction<'_>,
1449 object_id: ReservedId<'_>,
1450 options: HandleOptions,
1451 key: EncryptionKey,
1452 unwrapped_key: UnwrappedKey,
1453 ) -> Result<DataObjectHandle<S>, Error> {
1454 ObjectStore::create_object_with_id(
1455 owner,
1456 &mut transaction,
1457 object_id,
1458 options,
1459 Some(ObjectEncryptionOptions {
1460 permanent: true,
1461 key_id: VOLUME_DATA_KEY_ID,
1462 key,
1463 unwrapped_key,
1464 }),
1465 )
1466 }
1467
1468 pub async fn adjust_refs(
1471 &self,
1472 transaction: &mut Transaction<'_>,
1473 object_id: u64,
1474 delta: i64,
1475 ) -> Result<bool, Error> {
1476 let mut mutation = self.txn_get_object_mutation(transaction, object_id).await?;
1477 let refs = if let ObjectValue::Object {
1478 kind: ObjectKind::File { refs, .. } | ObjectKind::Symlink { refs, .. },
1479 ..
1480 } = &mut mutation.item.value
1481 {
1482 *refs =
1483 refs.checked_add_signed(delta).ok_or_else(|| anyhow!("refs underflow/overflow"))?;
1484 refs
1485 } else {
1486 bail!(FxfsError::NotFile);
1487 };
1488 if *refs == 0 {
1489 self.add_to_graveyard(transaction, object_id);
1490
1491 if delta != -1 {
1494 *refs = 1;
1495 transaction.add(self.store_object_id, Mutation::ObjectStore(mutation));
1496 }
1497 Ok(true)
1500 } else {
1501 transaction.add(self.store_object_id, Mutation::ObjectStore(mutation));
1502 Ok(false)
1503 }
1504 }
1505
1506 pub async fn tombstone_object(
1508 &self,
1509 object_id: u64,
1510 txn_options: Options<'_>,
1511 ) -> Result<(), Error> {
1512 debug_assert!(
1513 self.tree.find(&ObjectKey::object(object_id)).await?.is_some(),
1514 "Tombstoning missing object"
1515 );
1516 debug_assert!(
1517 self.tree
1518 .find(&ObjectKey::graveyard_entry(self.graveyard_directory_object_id(), object_id))
1519 .await?
1520 .is_some(),
1521 "Tombstoning object not in graveyard"
1522 );
1523 self.key_manager.remove(object_id).await;
1524 let fs = self.filesystem();
1525 let truncate_guard = fs.truncate_guard(self.store_object_id, object_id).await;
1526 self.trim_or_tombstone(object_id, true, txn_options, &truncate_guard).await
1527 }
1528
1529 pub async fn trim(
1532 &self,
1533 object_id: u64,
1534 truncate_guard: &TruncateGuard<'_>,
1535 ) -> Result<(), Error> {
1536 assert!(self.parent_store.as_ref().unwrap().parent_store.is_some());
1539
1540 self.trim_or_tombstone(
1541 object_id,
1542 false,
1543 Options { borrow_metadata_space: true, ..Default::default() },
1544 truncate_guard,
1545 )
1546 .await
1547 }
1548
1549 async fn trim_or_tombstone(
1551 &self,
1552 object_id: u64,
1553 for_tombstone: bool,
1554 txn_options: Options<'_>,
1555 _truncate_guard: &TruncateGuard<'_>,
1556 ) -> Result<(), Error> {
1557 let mut next_attribute = Some(AttributeId::SORTED_START);
1558 while let Some(attribute_id) = next_attribute.take() {
1559 let mut transaction = self
1560 .new_transaction(
1561 lock_keys![
1562 LockKey::object_attribute(self.store_object_id, object_id, attribute_id),
1563 LockKey::object(self.store_object_id, object_id),
1564 ],
1565 txn_options,
1566 )
1567 .await?;
1568
1569 match self
1570 .trim_some(
1571 &mut transaction,
1572 object_id,
1573 attribute_id,
1574 if for_tombstone {
1575 TrimMode::Tombstone(TombstoneMode::Object)
1576 } else {
1577 TrimMode::UseSize
1578 },
1579 )
1580 .await?
1581 {
1582 TrimResult::Incomplete => next_attribute = Some(attribute_id),
1583 TrimResult::Done(None) => {
1584 if for_tombstone
1585 || matches!(
1586 self.tree
1587 .find(&ObjectKey::graveyard_entry(
1588 self.graveyard_directory_object_id(),
1589 object_id,
1590 ))
1591 .await?,
1592 Some(Item { value: ObjectValue::Trim, .. })
1593 )
1594 {
1595 self.remove_from_graveyard(&mut transaction, object_id);
1596 }
1597 if for_tombstone && attribute_id != AttributeId::DATA {
1600 self.remove_attribute_from_graveyard(
1601 &mut transaction,
1602 object_id,
1603 attribute_id,
1604 );
1605 }
1606 }
1607 TrimResult::Done(id) => {
1608 if for_tombstone && attribute_id != AttributeId::DATA {
1611 self.remove_attribute_from_graveyard(
1612 &mut transaction,
1613 object_id,
1614 attribute_id,
1615 );
1616 }
1617 next_attribute = id;
1618 }
1619 }
1620
1621 if !transaction.mutations().is_empty() {
1622 transaction.commit().await?;
1623 }
1624 }
1625 Ok(())
1626 }
1627
1628 pub async fn tombstone_attribute(
1630 &self,
1631 object_id: u64,
1632 attribute_id: AttributeId,
1633 txn_options: Options<'_>,
1634 ) -> Result<(), Error> {
1635 debug_assert!(
1637 self.tree
1638 .find(&ObjectKey::attribute(object_id, attribute_id, AttributeKey::Attribute))
1639 .await?
1640 .is_some(),
1641 "Tombstoning missing attribute"
1642 );
1643 debug_assert!(
1644 self.tree
1645 .find(&ObjectKey::graveyard_attribute_entry(
1646 self.graveyard_directory_object_id(),
1647 object_id,
1648 attribute_id
1649 ))
1650 .await?
1651 .is_some(),
1652 "Tombstoning attribute not in graveyard"
1653 );
1654 let mut trim_result = TrimResult::Incomplete;
1655 while matches!(trim_result, TrimResult::Incomplete) {
1656 let mut transaction = self
1657 .new_transaction(
1658 lock_keys![
1659 LockKey::object_attribute(self.store_object_id, object_id, attribute_id),
1660 LockKey::object(self.store_object_id, object_id),
1661 ],
1662 txn_options,
1663 )
1664 .await?;
1665 trim_result = self
1666 .trim_some(
1667 &mut transaction,
1668 object_id,
1669 attribute_id,
1670 TrimMode::Tombstone(TombstoneMode::Attribute),
1671 )
1672 .await?;
1673 if let TrimResult::Done(..) = trim_result {
1674 self.remove_attribute_from_graveyard(&mut transaction, object_id, attribute_id)
1675 }
1676 if !transaction.mutations().is_empty() {
1677 transaction.commit().await?;
1678 }
1679 }
1680 Ok(())
1681 }
1682
1683 pub async fn trim_some(
1687 &self,
1688 transaction: &mut Transaction<'_>,
1689 object_id: u64,
1690 attribute_id: AttributeId,
1691 mode: TrimMode,
1692 ) -> Result<TrimResult, Error> {
1693 let layer_set = self.tree.layer_set();
1694 let mut merger = layer_set.merger();
1695
1696 let aligned_offset = match mode {
1697 TrimMode::FromOffset(offset) => {
1698 round_up(offset, self.block_size).ok_or(FxfsError::Inconsistent)?
1699 }
1700 TrimMode::Tombstone(..) => 0,
1701 TrimMode::UseSize => {
1702 let iter = merger
1703 .query(Query::FullRange(&ObjectKey::attribute(
1704 object_id,
1705 attribute_id,
1706 AttributeKey::Attribute,
1707 )))
1708 .await?;
1709 if let Some(item_ref) = iter.get() {
1710 if item_ref.key.object_id != object_id {
1711 return Ok(TrimResult::Done(None));
1712 }
1713
1714 if let ItemRef {
1715 key:
1716 ObjectKey {
1717 data:
1718 ObjectKeyData::Attribute(size_attribute_id, AttributeKey::Attribute),
1719 ..
1720 },
1721 value: ObjectValue::Attribute { size, .. },
1722 ..
1723 } = item_ref
1724 {
1725 if *size_attribute_id != attribute_id {
1728 return Ok(TrimResult::Done(Some(*size_attribute_id)));
1729 }
1730 round_up(*size, self.block_size).ok_or(FxfsError::Inconsistent)?
1731 } else {
1732 return Ok(TrimResult::Done(Some(attribute_id.next())));
1736 }
1737 } else {
1738 return Ok(TrimResult::Done(None));
1740 }
1741 }
1742 };
1743
1744 let mut iter = merger
1746 .query(Query::FullRange(&ObjectKey::from_extent(
1747 object_id,
1748 attribute_id,
1749 Extent::search_key_from_offset(aligned_offset),
1750 )))
1751 .await?;
1752 let mut end = 0;
1753 let allocator = self.allocator();
1754 let mut result = TrimResult::Done(None);
1755 let mut deallocated = 0;
1756 let block_size = self.block_size;
1757
1758 while let Some(item_ref) = iter.get() {
1759 if item_ref.key.object_id != object_id {
1760 break;
1761 }
1762 if let ObjectKey {
1763 data: ObjectKeyData::Attribute(extent_attribute_id, attribute_key),
1764 ..
1765 } = item_ref.key
1766 {
1767 if *extent_attribute_id != attribute_id {
1768 result = TrimResult::Done(Some(*extent_attribute_id));
1769 break;
1770 }
1771 if let (
1772 AttributeKey::Extent(extent),
1773 ObjectValue::Extent(ExtentValue::Some { device_offset, .. }),
1774 ) = (attribute_key, item_ref.value)
1775 {
1776 let start = std::cmp::max(extent.start, aligned_offset);
1777 ensure!(start < extent.end, FxfsError::Inconsistent);
1778 let device_offset = device_offset
1779 .checked_add(start - extent.start)
1780 .ok_or(FxfsError::Inconsistent)?;
1781 end = extent.end;
1782 let len = end - start;
1783 let device_range = device_offset..device_offset + len;
1784 ensure!(device_range.is_aligned(block_size), FxfsError::Inconsistent);
1785 allocator.deallocate(transaction, self.store_object_id, device_range).await?;
1786 deallocated += len;
1787 if transaction.mutations().len() >= TRANSACTION_MUTATION_THRESHOLD {
1789 result = TrimResult::Incomplete;
1790 break;
1791 }
1792 }
1793 }
1794 iter.advance().await?;
1795 }
1796
1797 let finished_tombstone_object = matches!(mode, TrimMode::Tombstone(TombstoneMode::Object))
1798 && matches!(result, TrimResult::Done(None));
1799 let finished_tombstone_attribute =
1800 matches!(mode, TrimMode::Tombstone(TombstoneMode::Attribute))
1801 && !matches!(result, TrimResult::Incomplete);
1802 let mut object_mutation = None;
1803 let nodes = if finished_tombstone_object { -1 } else { 0 };
1804 if nodes != 0 || deallocated != 0 {
1805 let mutation = self.txn_get_object_mutation(transaction, object_id).await?;
1806 if let ObjectValue::Object { attributes: ObjectAttributes { project_id, .. }, .. } =
1807 mutation.item.value
1808 {
1809 if let Some(project_id) = project_id {
1810 transaction.add(
1811 self.store_object_id,
1812 Mutation::merge_object(
1813 ObjectKey::project_usage(self.root_directory_object_id(), project_id),
1814 ObjectValue::BytesAndNodes {
1815 bytes: -i64::try_from(deallocated).unwrap(),
1816 nodes,
1817 },
1818 ),
1819 );
1820 }
1821 object_mutation = Some(mutation);
1822 } else {
1823 panic!("Inconsistent object type.");
1824 }
1825 }
1826
1827 if finished_tombstone_object {
1830 transaction.add(
1831 self.store_object_id,
1832 Mutation::merge_object(ObjectKey::object(object_id), ObjectValue::None),
1833 );
1834 } else {
1835 if finished_tombstone_attribute {
1836 transaction.add(
1837 self.store_object_id,
1838 Mutation::merge_object(
1839 ObjectKey::attribute(object_id, attribute_id, AttributeKey::Attribute),
1840 ObjectValue::None,
1841 ),
1842 );
1843 }
1844 if deallocated > 0 {
1845 let mut mutation = match object_mutation {
1846 Some(mutation) => mutation,
1847 None => self.txn_get_object_mutation(transaction, object_id).await?,
1848 };
1849 transaction.add(
1850 self.store_object_id,
1851 Mutation::merge_object(
1852 ObjectKey::extent(object_id, attribute_id, aligned_offset..end),
1853 ObjectValue::deleted_extent(),
1854 ),
1855 );
1856 if let ObjectValue::Object {
1858 attributes: ObjectAttributes { allocated_size, .. },
1859 ..
1860 } = &mut mutation.item.value
1861 {
1862 *allocated_size = allocated_size.checked_sub(deallocated).ok_or_else(|| {
1864 anyhow!(FxfsError::Inconsistent).context("Allocated size overflow")
1865 })?;
1866 } else {
1867 panic!("Unexpected object value");
1868 }
1869 transaction.add(self.store_object_id, Mutation::ObjectStore(mutation));
1870 }
1871 }
1872 Ok(result)
1873 }
1874
1875 pub fn parent_objects(&self) -> Vec<u64> {
1879 assert!(self.store_info_handle.get().is_some());
1880 self.store_info.lock().as_ref().unwrap().parent_objects()
1881 }
1882
1883 pub fn root_objects(&self) -> Vec<u64> {
1885 let mut objects = Vec::new();
1886 let store_info = self.store_info.lock();
1887 let info = store_info.as_ref().unwrap();
1888 if info.root_directory_object_id != INVALID_OBJECT_ID {
1889 objects.push(info.root_directory_object_id);
1890 }
1891 if info.graveyard_directory_object_id != INVALID_OBJECT_ID {
1892 objects.push(info.graveyard_directory_object_id);
1893 }
1894 if info.internal_directory_object_id != INVALID_OBJECT_ID {
1895 objects.push(info.internal_directory_object_id);
1896 }
1897 objects
1898 }
1899
1900 pub fn store_info(&self) -> Option<StoreInfo> {
1901 self.store_info.lock().as_ref().cloned()
1902 }
1903
1904 pub fn store_info_handle_object_id(&self) -> Option<u64> {
1906 self.store_info_handle.get().map(|h| h.object_id())
1907 }
1908
1909 pub fn graveyard_count(&self) -> u64 {
1910 self.graveyard_entries.load(Ordering::Relaxed)
1911 }
1912
1913 async fn open(
1915 parent_store: &Arc<ObjectStore>,
1916 store_object_id: u64,
1917 object_cache: Box<dyn ObjectCache<ObjectKey, ObjectValue>>,
1918 ) -> Result<Arc<ObjectStore>, Error> {
1919 let handle =
1920 ObjectStore::open_object(parent_store, store_object_id, HandleOptions::default(), None)
1921 .await?;
1922
1923 let info = load_store_info(parent_store, store_object_id).await?;
1924 let is_encrypted = info.mutations_key.is_some();
1925
1926 let mut total_layer_size = 0;
1927 let last_object_id;
1928
1929 if is_encrypted {
1934 for &oid in &info.layers {
1935 total_layer_size += parent_store.get_file_size(oid).await?;
1936 }
1937 if info.encrypted_mutations_object_id != INVALID_OBJECT_ID {
1938 total_layer_size += layer_size_from_encrypted_mutations_size(
1939 parent_store.get_file_size(info.encrypted_mutations_object_id).await?,
1940 );
1941 }
1942 last_object_id = LastObjectId::Pending;
1943 ensure!(
1944 matches!(
1945 info.last_object_id,
1946 LastObjectIdInfo::Encrypted { .. } | LastObjectIdInfo::Low32Bit { .. }
1947 ),
1948 FxfsError::Inconsistent
1949 );
1950 } else {
1951 last_object_id = match info.last_object_id {
1952 LastObjectIdInfo::Unencrypted { id } => LastObjectId::Unencrypted { id },
1953 LastObjectIdInfo::Low32Bit => {
1954 LastObjectId::Low32Bit { reserved: HashSet::new(), unreserved: Vec::new() }
1955 }
1956 _ => bail!(FxfsError::Inconsistent),
1957 };
1958 }
1959
1960 let fs = parent_store.filesystem();
1961
1962 let store = ObjectStore::new(
1963 Some(parent_store.clone()),
1964 store_object_id,
1965 fs.clone(),
1966 if is_encrypted { None } else { Some(info) },
1967 object_cache,
1968 None,
1969 if is_encrypted { LockState::Locked } else { LockState::Unencrypted },
1970 last_object_id,
1971 );
1972
1973 assert!(store.store_info_handle.set(handle).is_ok(), "Failed to set store_info_handle!");
1974
1975 if !is_encrypted {
1976 let object_tree_layer_object_ids =
1977 store.store_info.lock().as_ref().unwrap().layers.clone();
1978 let object_layers = store.open_layers(object_tree_layer_object_ids, None).await?;
1979 total_layer_size = object_layers.iter().map(|h| h.get_size()).sum();
1980 store
1981 .tree
1982 .append_layers(object_layers)
1983 .await
1984 .context("Failed to read object store layers")?;
1985 }
1986
1987 fs.object_manager().update_reservation(
1988 store_object_id,
1989 tree::reservation_amount_from_layer_size(total_layer_size),
1990 );
1991
1992 Ok(store)
1993 }
1994
1995 async fn load_store_info(&self) -> Result<StoreInfo, Error> {
1996 load_store_info_from_handle(self.store_info_handle.get().unwrap()).await
1997 }
1998
1999 async fn open_layers(
2000 &self,
2001 object_ids: impl std::iter::IntoIterator<Item = u64>,
2002 crypt: Option<Arc<dyn Crypt>>,
2003 ) -> Result<Vec<DataObjectHandle<ObjectStore>>, Error> {
2004 let parent_store = self.parent_store.as_ref().unwrap();
2005 let mut handles = Vec::new();
2006 for object_id in object_ids {
2007 let handle = ObjectStore::open_object(
2008 &parent_store,
2009 object_id,
2010 HandleOptions::default(),
2011 crypt.clone(),
2012 )
2013 .await
2014 .with_context(|| format!("Failed to open layer file {}", object_id))?;
2015 handles.push(handle);
2016 }
2017 Ok(handles)
2018 }
2019
2020 pub async fn unlock(self: &Arc<Self>, crypt: Arc<dyn Crypt>) -> Result<(), Error> {
2023 self.unlock_inner(crypt, false).await
2024 }
2025
2026 pub async fn unlock_read_only(self: &Arc<Self>, crypt: Arc<dyn Crypt>) -> Result<(), Error> {
2034 self.unlock_inner(crypt, true).await
2035 }
2036
2037 async fn unlock_inner(
2039 self: &Arc<Self>,
2040 crypt: Arc<dyn Crypt>,
2041 read_only: bool,
2042 ) -> Result<(), Error> {
2043 #[derive(Debug, PartialEq)]
2048 struct CryptFields {
2049 mutations_key: Option<FxfsKey>,
2050 mutations_cipher_offset: u64,
2051 last_object_id: LastObjectIdInfo,
2052 layers: Vec<u64>,
2053 }
2054 impl From<&StoreInfo> for CryptFields {
2055 fn from(info: &StoreInfo) -> Self {
2056 Self {
2057 mutations_key: info.mutations_key.clone(),
2058 mutations_cipher_offset: info.mutations_cipher_offset,
2059 last_object_id: info.last_object_id.clone(),
2060 layers: info.layers.clone(),
2061 }
2062 }
2063 }
2064
2065 assert!(read_only || !self.filesystem().options().read_only);
2067 match &*self.lock_state.lock() {
2068 LockState::Locked => {}
2069 LockState::Unencrypted => bail!(FxfsError::InvalidArgs),
2070 LockState::Invalid | LockState::Deleted => bail!(FxfsError::Internal),
2071 LockState::Unlocked { .. } | LockState::UnlockedReadOnly(..) => {
2072 bail!(FxfsError::AlreadyBound)
2073 }
2074 LockState::Unknown => panic!("Store was unlocked before replay"),
2075 LockState::Locking => panic!("Store is being locked"),
2076 LockState::Unlocking => panic!("Store is being unlocked"),
2077 }
2078
2079 let mut last_num_flushes = self.counters.lock().num_flushes;
2082 let mut store_info = self.load_store_info().await?;
2083 let crypt_fields = CryptFields::from(&store_info);
2084
2085 let mut update_store_info = async |store_info: &mut StoreInfo| -> Result<(), Error> {
2086 let new_num_flushes = self.counters.lock().num_flushes;
2087 if last_num_flushes == new_num_flushes {
2088 return Ok(());
2089 }
2090 last_num_flushes = new_num_flushes;
2091 *store_info = self.load_store_info().await?;
2092 if crypt_fields != CryptFields::from(&*store_info) {
2093 return Err(
2094 anyhow!(FxfsError::Inconsistent).context("Crypt fields changed during unlock")
2095 );
2096 }
2097 Ok(())
2098 };
2099
2100 let layers = self
2102 .open_layers(store_info.layers.iter().cloned(), Some(crypt.clone()))
2103 .await
2104 .context("Failed to read object tree layer file contents")?;
2105
2106 let wrapped_key =
2108 fxfs_crypto::WrappedKey::Fxfs(store_info.mutations_key.clone().unwrap().into());
2109 let unwrapped_key = crypt
2110 .unwrap_key(&wrapped_key, self.store_object_id)
2111 .await
2112 .context("Failed to unwrap mutations keys")?;
2113
2114 let last_object_id_cipher = match &store_info.last_object_id {
2116 LastObjectIdInfo::Encrypted { id: _, key } => {
2117 let wrapped_key = fxfs_crypto::WrappedKey::Fxfs(key.clone().into());
2118 let unwrapped = crypt
2119 .unwrap_key(&wrapped_key, self.store_object_id)
2120 .await
2121 .context("Failed to unwrap last object ID key")?;
2122 Some(Box::new(Ff1::new(&unwrapped)))
2123 }
2124 _ => None,
2125 };
2126
2127 let (new_wrapped_mutations_key, new_unwrapped_mutations_key) =
2129 crypt.create_key(self.store_object_id, KeyPurpose::Metadata).await?;
2130
2131 let mut keys_to_cache = Vec::new();
2133 if !read_only && !self.filesystem().options().read_only {
2134 let parent_store = self.parent_store.as_ref().unwrap();
2135 for _ in 0..CACHED_KEYS_LIMIT {
2136 let raw_id = {
2137 let reserved_id = parent_store
2138 .maybe_get_next_object_id()
2139 .expect("maybe_get_next_object_id failed on parent store");
2140 reserved_id.release()
2141 };
2142 let (wrapped, unwrapped) = crypt
2143 .create_key(raw_id.get(), KeyPurpose::Data)
2144 .await
2145 .context("Failed to pre-cache key during unlock")?;
2146 keys_to_cache.push((raw_id, EncryptionKey::Fxfs(wrapped), unwrapped));
2147 }
2148 }
2149
2150 let do_not_use_crypt = crypt;
2153
2154 let fs = self.filesystem();
2155 let guard =
2156 fs.lock_manager().write_lock(lock_keys![LockKey::flush(self.store_object_id())]).await;
2157
2158 update_store_info(&mut store_info).await?;
2159
2160 let mut mutations = {
2162 if store_info.encrypted_mutations_object_id == INVALID_OBJECT_ID {
2163 EncryptedMutations::default()
2164 } else {
2165 let parent_store = self.parent_store.as_ref().unwrap();
2166 let handle = ObjectStore::open_object(
2167 &parent_store,
2168 store_info.encrypted_mutations_object_id,
2169 HandleOptions::default(),
2170 None,
2171 )
2172 .await?;
2173 let mut cursor = std::io::Cursor::new(
2174 handle
2175 .contents(MAX_ENCRYPTED_MUTATIONS_SIZE)
2176 .await
2177 .context(FxfsError::Inconsistent)?,
2178 );
2179 let mut mutations = EncryptedMutations::deserialize_with_version(&mut cursor)
2180 .context("Failed to deserialize EncryptedMutations")?
2181 .0;
2182 let len = cursor.get_ref().len() as u64;
2183 while cursor.position() < len {
2184 mutations.extend(
2185 &EncryptedMutations::deserialize_with_version(&mut cursor)
2186 .context("Failed to deserialize EncryptedMutations")?
2187 .0,
2188 );
2189 }
2190 mutations
2191 }
2192 };
2193
2194 let journaled = EncryptedMutations::from_replayed_mutations(
2196 self.store_object_id,
2197 fs.journal()
2198 .read_transactions_for_object(self.store_object_id)
2199 .await
2200 .context("Failed to read encrypted mutations from journal")?,
2201 );
2202 mutations.extend(&journaled);
2203
2204 std::mem::drop(guard);
2206
2207 let crypt = do_not_use_crypt;
2209
2210 #[cfg(test)]
2211 CALLBACK_UNLOCK_RESOURCES_ACQUIRED.call();
2212
2213 let EncryptedMutations { transactions, mut data, mutations_key_roll } = mutations;
2216
2217 ensure!(store_info.mutations_cipher_offset <= u32::MAX as u64, FxfsError::Inconsistent);
2218 let mut mutations_cipher =
2219 StreamCipher::new(&unwrapped_key, store_info.mutations_cipher_offset);
2220
2221 let mut slice = &mut data[..];
2222 let mut last_offset = 0;
2223 for (offset, key) in mutations_key_roll {
2224 let split_offset = offset
2225 .checked_sub(last_offset)
2226 .ok_or(FxfsError::Inconsistent)
2227 .context("Invalid mutation key roll offset")?;
2228 last_offset = offset;
2229 ensure!(split_offset <= slice.len(), FxfsError::Inconsistent);
2230 let (old, new) = slice.split_at_mut(split_offset);
2231 mutations_cipher.decrypt(old);
2232 let unwrapped_key = crypt
2233 .unwrap_key(&fxfs_crypto::WrappedKey::Fxfs(key.into()), self.store_object_id)
2234 .await
2235 .context("Failed to unwrap mutations keys")?;
2236 mutations_cipher = StreamCipher::new(&unwrapped_key, 0);
2237 slice = new;
2238 }
2239 mutations_cipher.decrypt(slice);
2240
2241 let mut mutations_to_apply = Vec::new();
2242 let mut cursor = std::io::Cursor::new(data);
2243 for (checkpoint, count) in transactions {
2244 for _ in 0..count {
2245 let mutation = Mutation::deserialize_from_version(&mut cursor, checkpoint.version)
2246 .context("failed to deserialize encrypted mutation")?;
2247 mutations_to_apply.push((checkpoint.clone(), mutation));
2248 }
2249 }
2250
2251 let do_not_use_crypt = crypt;
2254
2255 let guard =
2256 fs.lock_manager().write_lock(lock_keys![LockKey::flush(self.store_object_id())]).await;
2257
2258 update_store_info(&mut store_info).await?;
2259
2260 let _ = std::mem::replace(&mut *self.lock_state.lock(), LockState::Unlocking);
2261
2262 store_info.mutations_key = Some(new_wrapped_mutations_key);
2263 *self.store_info.lock() = Some(store_info.clone());
2264
2265 let clean_up = scopeguard::guard((), |_| {
2266 *self.lock_state.lock() = LockState::Locked;
2267 *self.store_info.lock() = None;
2268 *self.mutations_cipher.lock() = None;
2269 self.tree.reset();
2271 });
2272
2273 self.tree.append_layers(layers).await.context("Failed to append layers to object tree")?;
2275
2276 match &store_info.last_object_id {
2278 LastObjectIdInfo::Encrypted { id, .. } => {
2279 *self.last_object_id.lock() =
2280 LastObjectId::Encrypted { id: *id, cipher: last_object_id_cipher.unwrap() };
2281 }
2282 LastObjectIdInfo::Low32Bit => {
2283 *self.last_object_id.lock() = LastObjectId::Low32Bit {
2284 reserved: Default::default(),
2285 unreserved: Default::default(),
2286 }
2287 }
2288 _ => unreachable!(),
2289 }
2290
2291 *self.mutations_cipher.lock() = Some(StreamCipher::new(&new_unwrapped_mutations_key, 0));
2293
2294 for (checkpoint, mutation) in mutations_to_apply {
2296 let context = ApplyContext { mode: ApplyMode::Replay, checkpoint };
2297 self.apply_mutation(mutation, &context, AssocObj::None)
2298 .context("failed to apply encrypted mutation")?;
2299 }
2300
2301 *self.lock_state.lock() = if read_only {
2303 LockState::UnlockedReadOnly(do_not_use_crypt)
2304 } else {
2305 LockState::Unlocked { crypt: do_not_use_crypt, cached_keys: keys_to_cache }
2306 };
2307
2308 std::mem::drop(guard);
2312
2313 if !read_only && !self.filesystem().options().read_only {
2314 self.flush_with_reason(flush::Reason::PostMount).await?;
2315
2316 let _ = self.filesystem().graveyard().initial_reap(&self).await?;
2318 }
2319
2320 Ok(ScopeGuard::into_inner(clean_up))
2322 }
2323
2324 pub fn is_locked(&self) -> bool {
2325 matches!(
2326 *self.lock_state.lock(),
2327 LockState::Locked | LockState::Locking | LockState::Unknown
2328 )
2329 }
2330
2331 pub fn is_unlocked(&self) -> bool {
2334 matches!(
2335 *self.lock_state.lock(),
2336 LockState::Unlocked { .. } | LockState::UnlockedReadOnly(..) | LockState::Unlocking
2337 )
2338 }
2339
2340 pub fn is_unknown(&self) -> bool {
2341 matches!(*self.lock_state.lock(), LockState::Unknown)
2342 }
2343
2344 pub fn is_encrypted(&self) -> bool {
2345 self.store_info.lock().as_ref().unwrap().mutations_key.is_some()
2346 }
2347
2348 pub async fn lock(&self) -> Result<(), Error> {
2354 let keys = lock_keys![LockKey::flush(self.store_object_id())];
2357 let fs = self.filesystem();
2358 let _guard = fs.lock_manager().write_lock(keys).await;
2359
2360 {
2361 let mut lock_state = self.lock_state.lock();
2362 if let LockState::Unlocked { .. } = &*lock_state {
2363 *lock_state = LockState::Locking;
2364 } else {
2365 panic!("Unexpected lock state: {:?}", *lock_state);
2366 }
2367 }
2368
2369 let sync_result =
2374 self.filesystem().sync(SyncOptions { flush_device: true, ..Default::default() }).await;
2375
2376 *self.lock_state.lock() = if let Err(error) = &sync_result {
2377 error!(error:?; "Failed to sync journal; store will no longer be usable");
2378 LockState::Invalid
2379 } else {
2380 LockState::Locked
2381 };
2382 self.key_manager.clear();
2383 *self.store_info.lock() = None;
2384 self.tree.reset();
2385
2386 sync_result
2387 }
2388
2389 pub fn lock_read_only(&self) {
2393 *self.lock_state.lock() = LockState::Locked;
2394 *self.store_info.lock() = None;
2395 self.tree.reset();
2396 }
2397
2398 fn maybe_get_next_object_id(&self) -> Option<ReservedId<'_>> {
2401 self.last_object_id.lock().try_get_next().map(|id| ReservedId::new(self, id))
2402 }
2403
2404 pub(super) async fn get_next_object_id(&self) -> Result<ReservedId<'_>, Error> {
2408 {
2409 let mut last_object_id = self.last_object_id.lock();
2410 if let Some(id) = last_object_id.try_get_next() {
2411 return Ok(ReservedId::new(self, id));
2412 }
2413 ensure!(
2414 !matches!(&*last_object_id, LastObjectId::Unencrypted { .. }),
2415 FxfsError::Inconsistent
2416 );
2417 }
2418
2419 let parent_store = self.parent_store().unwrap();
2420
2421 let mut transaction = parent_store
2426 .new_transaction(
2427 lock_keys![LockKey::object(parent_store.store_object_id, self.store_object_id)],
2428 Options {
2429 skip_journal_checks: true,
2432 borrow_metadata_space: true,
2433 ..Default::default()
2434 },
2435 )
2436 .await?;
2437
2438 let mut next_id_hi = 0;
2439
2440 let is_low_32_bit = {
2441 let mut last_object_id = self.last_object_id.lock();
2442 if let Some(id) = last_object_id.try_get_next() {
2443 return Ok(ReservedId::new(self, id));
2445 }
2446
2447 match &*last_object_id {
2448 LastObjectId::Encrypted { id, .. } => {
2449 next_id_hi =
2452 id.checked_add(1 << 32).ok_or(FxfsError::Inconsistent)? & OBJECT_ID_HI_MASK;
2453
2454 info!(store_id = self.store_object_id; "Rolling object ID key");
2455
2456 false
2457 }
2458 LastObjectId::Low32Bit { .. } => true,
2459 _ => unreachable!(),
2460 }
2461 };
2462
2463 if is_low_32_bit {
2464 self.last_object_id.lock().drain_unreserved();
2468
2469 let layer_set = self.tree.layer_set();
2470 let mut key = ObjectKey::object(0);
2471 loop {
2472 let next_id = rand::rng().next_u32() as u64;
2473 let Some(next_id) = NonZero::new(next_id) else { continue };
2474 if self.last_object_id.lock().is_reserved(next_id.get()) {
2475 continue;
2476 }
2477 key.object_id = next_id.get();
2478 if layer_set.key_exists(&key).await? == Existence::Missing {
2479 self.last_object_id.lock().reserve(next_id.get());
2480 return Ok(ReservedId::new(self, next_id));
2481 }
2482 }
2483 } else {
2484 let (object_id_wrapped, object_id_unwrapped) = self
2486 .crypt()
2487 .unwrap()
2488 .create_key(self.store_object_id, KeyPurpose::Metadata)
2489 .await?;
2490
2491 let new_store_info = StoreInfo {
2508 last_object_id: LastObjectIdInfo::Encrypted {
2509 id: next_id_hi,
2510 key: object_id_wrapped.clone(),
2511 },
2512 ..self.load_store_info().await?
2513 };
2514
2515 self.write_store_info(&mut transaction, &new_store_info).await?;
2516
2517 transaction
2518 .commit_with_callback(|_| {
2519 self.store_info.lock().as_mut().unwrap().last_object_id =
2520 new_store_info.last_object_id;
2521 match &mut *self.last_object_id.lock() {
2522 LastObjectId::Encrypted { id, cipher } => {
2523 **cipher = Ff1::new(&object_id_unwrapped);
2524 *id = next_id_hi;
2525 ReservedId::new(
2526 self,
2527 NonZero::new(next_id_hi | cipher.encrypt(0) as u64).unwrap(),
2528 )
2529 }
2530 _ => unreachable!(),
2531 }
2532 })
2533 .await
2534 }
2535 }
2536
2537 pub(crate) fn query_next_object_id(&self) -> u64 {
2540 self.last_object_id.lock().peek_next()
2541 }
2542
2543 fn allocator(&self) -> Arc<Allocator> {
2544 self.filesystem().allocator()
2545 }
2546
2547 async fn txn_get_object_mutation(
2553 &self,
2554 transaction: &Transaction<'_>,
2555 object_id: u64,
2556 ) -> Result<ObjectStoreMutation, Error> {
2557 if let Some(mutation) =
2558 transaction.get_object_mutation(self.store_object_id, ObjectKey::object(object_id))
2559 {
2560 Ok(mutation.clone())
2561 } else {
2562 Ok(ObjectStoreMutation {
2563 item: self
2564 .tree
2565 .find(&ObjectKey::object(object_id))
2566 .await?
2567 .ok_or(FxfsError::Inconsistent)
2568 .context("Object id missing")?,
2569 op: Operation::ReplaceOrInsert,
2570 })
2571 }
2572 }
2573
2574 #[cfg(feature = "migration")]
2577 pub async fn get_object_mutation(
2578 &self,
2579 transaction: &Transaction<'_>,
2580 object_id: u64,
2581 ) -> Result<ObjectStoreMutation, Error> {
2582 self.txn_get_object_mutation(transaction, object_id).await
2583 }
2584
2585 fn update_last_object_id(&self, object_id: u64) {
2586 let mut last_object_id = self.last_object_id.lock();
2587 match &mut *last_object_id {
2588 LastObjectId::Pending => unreachable!(),
2589 LastObjectId::Unencrypted { id } => {
2590 if object_id > *id {
2591 *id = object_id
2592 }
2593 }
2594 LastObjectId::Encrypted { id, cipher } => {
2595 let object_id =
2602 object_id & OBJECT_ID_HI_MASK | cipher.decrypt(object_id as u32) as u64;
2603 if object_id > *id {
2604 *id = object_id;
2605 }
2606 }
2607 LastObjectId::Low32Bit { .. } => {}
2608 }
2609 }
2610
2611 pub fn to_unencrypted_object_id(&self, object_id: u64) -> Option<u64> {
2614 let last_object_id = self.last_object_id.lock();
2615 match &*last_object_id {
2616 LastObjectId::Pending => None,
2617 LastObjectId::Unencrypted { .. } | LastObjectId::Low32Bit { .. } => Some(object_id),
2618 LastObjectId::Encrypted { id, cipher } => {
2619 if id & OBJECT_ID_HI_MASK != object_id & OBJECT_ID_HI_MASK {
2620 None
2621 } else {
2622 Some(object_id & OBJECT_ID_HI_MASK | cipher.decrypt(object_id as u32) as u64)
2623 }
2624 }
2625 }
2626 }
2627
2628 pub fn add_to_graveyard(&self, transaction: &mut Transaction<'_>, object_id: u64) {
2630 let graveyard_id = self.graveyard_directory_object_id();
2631 assert_ne!(graveyard_id, INVALID_OBJECT_ID);
2632 transaction.add(
2633 self.store_object_id,
2634 Mutation::replace_or_insert_object(
2635 ObjectKey::graveyard_entry(graveyard_id, object_id),
2636 ObjectValue::Some,
2637 ),
2638 );
2639 }
2640
2641 pub fn remove_from_graveyard(&self, transaction: &mut Transaction<'_>, object_id: u64) {
2654 transaction.add(
2655 self.store_object_id,
2656 Mutation::replace_or_insert_object(
2657 ObjectKey::graveyard_entry(self.graveyard_directory_object_id(), object_id),
2658 ObjectValue::None,
2659 ),
2660 );
2661 }
2662
2663 pub fn remove_attribute_from_graveyard(
2668 &self,
2669 transaction: &mut Transaction<'_>,
2670 object_id: u64,
2671 attribute_id: AttributeId,
2672 ) {
2673 transaction.add(
2674 self.store_object_id,
2675 Mutation::replace_or_insert_object(
2676 ObjectKey::graveyard_attribute_entry(
2677 self.graveyard_directory_object_id(),
2678 object_id,
2679 attribute_id,
2680 ),
2681 ObjectValue::None,
2682 ),
2683 );
2684 }
2685
2686 fn needs_mutations_key_roll(&self) -> bool {
2687 self.mutations_cipher.lock().as_ref().is_some_and(|cipher| {
2688 cipher.offset() >= self.filesystem().options().roll_metadata_key_byte_count
2689 })
2690 }
2691
2692 async fn roll_mutations_key(&self, crypt: &dyn Crypt) -> Result<(), Error> {
2694 let (wrapped_key, unwrapped_key) =
2695 crypt.create_key(self.store_object_id, KeyPurpose::Metadata).await?;
2696
2697 let mut cipher = self.mutations_cipher.lock();
2701 *cipher = Some(StreamCipher::new(&unwrapped_key, 0));
2702 self.store_info.lock().as_mut().unwrap().mutations_key = Some(wrapped_key);
2703 Ok(())
2705 }
2706
2707 pub async fn read_encrypted_symlink(
2712 &self,
2713 object_id: u64,
2714 link: Vec<u8>,
2715 ) -> Result<Vec<u8>, Error> {
2716 let mut link = link;
2717 let key = self
2718 .key_manager()
2719 .get_fscrypt_key(object_id, self.crypt().unwrap().as_ref(), async || {
2720 self.get_keys(object_id).await
2721 })
2722 .await?;
2723 if let Some(key) = key.into_cipher() {
2724 key.decrypt_symlink(object_id, &mut link)?;
2725 Ok(link)
2726 } else {
2727 let proxy_filename =
2729 fscrypt::proxy_filename::ProxyFilename::new_with_hash_code(0, &link);
2730 let proxy_filename_str: String = proxy_filename.into();
2731 Ok(proxy_filename_str.into_bytes())
2732 }
2733 }
2734
2735 pub async fn read_symlink(&self, object_id: u64) -> Result<Vec<u8>, Error> {
2737 match self.tree.find(&ObjectKey::object(object_id)).await? {
2738 None => bail!(FxfsError::NotFound),
2739 Some(Item {
2740 value: ObjectValue::Object { kind: ObjectKind::EncryptedSymlink { link, .. }, .. },
2741 ..
2742 }) => self.read_encrypted_symlink(object_id, link.to_vec()).await,
2743 Some(Item {
2744 value: ObjectValue::Object { kind: ObjectKind::Symlink { link, .. }, .. },
2745 ..
2746 }) => Ok(link.to_vec()),
2747 Some(item) => Err(anyhow!(FxfsError::Inconsistent)
2748 .context(format!("Unexpected item in lookup: {item:?}"))),
2749 }
2750 }
2751
2752 pub async fn get_keys(&self, object_id: u64) -> Result<EncryptionKeys, Error> {
2755 match self.tree.find(&ObjectKey::keys(object_id)).await?.ok_or(FxfsError::Inconsistent)? {
2756 Item { value: ObjectValue::Keys(keys), .. } => Ok(keys),
2757 _ => Err(anyhow!(FxfsError::Inconsistent).context("open_object: Expected keys")),
2758 }
2759 }
2760
2761 pub async fn update_attributes<'a>(
2762 &self,
2763 transaction: &mut Transaction<'a>,
2764 object_id: u64,
2765 node_attributes: Option<&fio::MutableNodeAttributes>,
2766 change_time: Option<Timestamp>,
2767 ) -> Result<(), Error> {
2768 if change_time.is_none() {
2769 if let Some(attributes) = node_attributes {
2770 let empty_attributes = fio::MutableNodeAttributes { ..Default::default() };
2771 if *attributes == empty_attributes {
2772 return Ok(());
2773 }
2774 } else {
2775 return Ok(());
2776 }
2777 }
2778 let mut mutation = self.txn_get_object_mutation(transaction, object_id).await?;
2779 if let ObjectValue::Object { ref mut attributes, .. } = mutation.item.value {
2780 if let Some(time) = change_time {
2781 attributes.change_time = time;
2782 }
2783 if let Some(node_attributes) = node_attributes {
2784 if let Some(time) = node_attributes.creation_time {
2785 attributes.creation_time = Timestamp::from_nanos(time);
2786 }
2787 if let Some(time) = node_attributes.modification_time {
2788 attributes.modification_time = Timestamp::from_nanos(time);
2789 }
2790 if let Some(time) = node_attributes.access_time {
2791 attributes.access_time = Timestamp::from_nanos(time);
2792 }
2793 if node_attributes.mode.is_some()
2794 || node_attributes.uid.is_some()
2795 || node_attributes.gid.is_some()
2796 || node_attributes.rdev.is_some()
2797 {
2798 if let Some(a) = &mut attributes.posix_attributes {
2799 if let Some(mode) = node_attributes.mode {
2800 a.mode = mode;
2801 }
2802 if let Some(uid) = node_attributes.uid {
2803 a.uid = uid;
2804 }
2805 if let Some(gid) = node_attributes.gid {
2806 a.gid = gid;
2807 }
2808 if let Some(rdev) = node_attributes.rdev {
2809 a.rdev = rdev;
2810 }
2811 } else {
2812 attributes.posix_attributes = Some(PosixAttributes {
2813 mode: node_attributes.mode.unwrap_or_default(),
2814 uid: node_attributes.uid.unwrap_or_default(),
2815 gid: node_attributes.gid.unwrap_or_default(),
2816 rdev: node_attributes.rdev.unwrap_or_default(),
2817 });
2818 }
2819 }
2820 }
2821 } else {
2822 bail!(
2823 anyhow!(FxfsError::Inconsistent)
2824 .context("ObjectStore.update_attributes: Expected object value")
2825 );
2826 };
2827 transaction.add(self.store_object_id(), Mutation::ObjectStore(mutation));
2828 Ok(())
2829 }
2830
2831 pub async fn update_access_time(
2837 &self,
2838 object_id: u64,
2839 props: &mut ObjectProperties,
2840 precondition: impl FnOnce() -> bool,
2841 ) -> Result<(), Error> {
2842 let access_time = props.access_time.as_nanos();
2843 let modification_time = props.modification_time.as_nanos();
2844 let change_time = props.change_time.as_nanos();
2845 let now = Timestamp::now();
2846 if access_time <= modification_time
2847 || access_time <= change_time
2848 || access_time
2849 < now.as_nanos()
2850 - Timestamp::from(std::time::Duration::from_secs(24 * 60 * 60)).as_nanos()
2851 {
2852 let mut transaction = self
2853 .new_transaction(
2854 lock_keys![LockKey::object(self.store_object_id, object_id,)],
2855 Options { borrow_metadata_space: true, ..Default::default() },
2856 )
2857 .await?;
2858 if precondition() {
2859 self.update_attributes(
2860 &mut transaction,
2861 object_id,
2862 Some(&fio::MutableNodeAttributes {
2863 access_time: Some(now.as_nanos()),
2864 ..Default::default()
2865 }),
2866 None,
2867 )
2868 .await?;
2869 transaction.commit().await?;
2870 props.access_time = now;
2871 }
2872 }
2873 Ok(())
2874 }
2875
2876 async fn write_store_info<'a>(
2877 &'a self,
2878 transaction: &mut Transaction<'a>,
2879 info: &StoreInfo,
2880 ) -> Result<(), Error> {
2881 let mut serialized_info = Vec::new();
2882 info.serialize_with_version(&mut serialized_info)?;
2883 let mut buf = self.device.allocate_buffer(serialized_info.len()).await;
2884 buf.as_mut_slice().copy_from_slice(&serialized_info[..]);
2885 self.store_info_handle.get().unwrap().txn_write(transaction, 0u64, buf.as_ref()).await
2886 }
2887
2888 pub fn mark_deleted(&self) {
2889 *self.lock_state.lock() = LockState::Deleted;
2890 }
2891
2892 #[cfg(test)]
2893 pub(crate) fn test_set_last_object_id(&self, object_id: u64) {
2894 match &mut *self.last_object_id.lock() {
2895 LastObjectId::Encrypted { id, .. } => *id = object_id,
2896 _ => unreachable!(),
2897 }
2898 }
2899
2900 pub async fn get_attribute_size(
2903 &self,
2904 object_id: u64,
2905 attribute_id: AttributeId,
2906 ) -> Result<u64, Error> {
2907 let item = self
2908 .tree
2909 .find(&ObjectKey::attribute(object_id, attribute_id, AttributeKey::Attribute))
2910 .await?
2911 .ok_or(FxfsError::NotFound)?;
2912 let size = match item.value {
2913 ObjectValue::Attribute { size, .. } => size,
2914 ObjectValue::VerifiedAttribute { size, .. } => size,
2915 _ => bail!(FxfsError::Inconsistent),
2916 };
2917 Ok(size)
2918 }
2919}
2920
2921#[async_trait]
2922impl JournalingObject for ObjectStore {
2923 fn apply_mutation(
2924 &self,
2925 mutation: Mutation,
2926 context: &ApplyContext<'_, '_>,
2927 _assoc_obj: AssocObj<'_>,
2928 ) -> Result<(), Error> {
2929 match &*self.lock_state.lock() {
2930 LockState::Locked | LockState::Locking => {
2931 ensure!(
2932 matches!(mutation, Mutation::BeginFlush | Mutation::EndFlush)
2933 || matches!(
2934 mutation,
2935 Mutation::EncryptedObjectStore(_) | Mutation::UpdateMutationsKey(_)
2936 if context.mode.is_replay()
2937 ),
2938 anyhow!(FxfsError::Inconsistent)
2939 .context(format!("Unexpected mutation for encrypted store: {mutation:?}"))
2940 );
2941 }
2942 LockState::Invalid
2943 | LockState::Unlocking
2944 | LockState::Unencrypted
2945 | LockState::Unlocked { .. }
2946 | LockState::UnlockedReadOnly(..)
2947 | LockState::Deleted => {}
2948 lock_state @ _ => panic!("Unexpected lock state: {lock_state:?}"),
2949 }
2950 match mutation {
2951 Mutation::ObjectStore(ObjectStoreMutation { item, op }) => {
2952 match op {
2953 Operation::Insert => {
2954 let mut unreserve_id = INVALID_OBJECT_ID;
2955 if matches!(item.value, ObjectValue::Object { .. }) {
2958 {
2959 let info = &mut self.store_info.lock();
2960 let object_count = &mut info.as_mut().unwrap().object_count;
2961 *object_count = object_count.saturating_add(1);
2962 }
2963 if context.mode.is_replay() {
2964 self.update_last_object_id(item.key.object_id);
2965 } else {
2966 unreserve_id = item.key.object_id;
2967 }
2968 } else if !context.mode.is_replay()
2969 && matches!(
2970 item.key.data,
2971 ObjectKeyData::GraveyardEntry { .. }
2972 | ObjectKeyData::GraveyardAttributeEntry { .. }
2973 )
2974 {
2975 if matches!(item.value, ObjectValue::Some | ObjectValue::Trim) {
2976 self.graveyard_entries.fetch_add(1, Ordering::Relaxed);
2977 } else if matches!(item.value, ObjectValue::None) {
2978 self.graveyard_entries.fetch_sub(1, Ordering::Relaxed);
2979 }
2980 }
2981 self.tree.insert(item)?;
2982 if unreserve_id != INVALID_OBJECT_ID {
2983 self.last_object_id.lock().unreserve(unreserve_id);
2985 }
2986 }
2987 Operation::ReplaceOrInsert => {
2988 if !context.mode.is_replay()
2989 && matches!(
2990 item.key.data,
2991 ObjectKeyData::GraveyardEntry { .. }
2992 | ObjectKeyData::GraveyardAttributeEntry { .. }
2993 )
2994 {
2995 if matches!(item.value, ObjectValue::Some | ObjectValue::Trim) {
2996 self.graveyard_entries.fetch_add(1, Ordering::Relaxed);
2997 } else if matches!(item.value, ObjectValue::None) {
2998 self.graveyard_entries.fetch_sub(1, Ordering::Relaxed);
2999 }
3000 }
3001 self.tree.replace_or_insert(item);
3002 }
3003 Operation::Merge => {
3004 if item.is_tombstone() {
3005 let info = &mut self.store_info.lock();
3006 let object_count = &mut info.as_mut().unwrap().object_count;
3007 *object_count = object_count.saturating_sub(1);
3008 }
3009 if !context.mode.is_replay()
3010 && matches!(
3011 item.key.data,
3012 ObjectKeyData::GraveyardEntry { .. }
3013 | ObjectKeyData::GraveyardAttributeEntry { .. }
3014 )
3015 {
3016 if matches!(item.value, ObjectValue::Some | ObjectValue::Trim) {
3017 self.graveyard_entries.fetch_add(1, Ordering::Relaxed);
3018 } else if matches!(item.value, ObjectValue::None) {
3019 self.graveyard_entries.fetch_sub(1, Ordering::Relaxed);
3020 }
3021 }
3022 let lower_bound = item.key.key_for_merge_into();
3023 self.tree.merge_into(item, &lower_bound);
3024 }
3025 }
3026 }
3027 Mutation::BeginFlush => {
3028 ensure!(self.parent_store.is_some(), FxfsError::Inconsistent);
3029 self.tree.seal();
3030 }
3031 Mutation::EndFlush => ensure!(self.parent_store.is_some(), FxfsError::Inconsistent),
3032 Mutation::EncryptedObjectStore(_) | Mutation::UpdateMutationsKey(_) => {
3033 ensure!(
3035 !matches!(&*self.lock_state.lock(), LockState::Unencrypted),
3036 FxfsError::Inconsistent
3037 );
3038 }
3039 Mutation::CreateInternalDir(object_id) => {
3040 ensure!(object_id != INVALID_OBJECT_ID, FxfsError::Inconsistent);
3041 self.store_info.lock().as_mut().unwrap().internal_directory_object_id = object_id;
3042 }
3043 _ => bail!("unexpected mutation: {:?}", mutation),
3044 }
3045 self.counters.lock().mutations_applied += 1;
3046 Ok(())
3047 }
3048
3049 fn drop_mutation(&self, mutation: Mutation, _transaction: &Transaction<'_>) {
3050 self.counters.lock().mutations_dropped += 1;
3051 if let Mutation::ObjectStore(ObjectStoreMutation {
3052 item: Item { key: ObjectKey { object_id, .. }, value: ObjectValue::Object { .. }, .. },
3053 op: Operation::Insert,
3054 }) = mutation
3055 {
3056 self.last_object_id.lock().unreserve(object_id);
3057 }
3058 }
3059
3060 async fn prepare_commit<'a>(
3061 &self,
3062 filesystem: &'a FxFilesystem,
3063 _transaction: &Transaction<'_>,
3064 ) -> Result<Option<WriteGuard<'a>>, Error> {
3065 if !matches!(&*self.lock_state.lock(), LockState::Unlocked { .. }) {
3067 return Ok(None);
3068 }
3069
3070 let keys = lock_keys![LockKey::pre_cache_keys(self.store_object_id())];
3074 let guard = filesystem.lock_manager().write_lock(keys).await;
3075
3076 self.pre_cache_keys().await?;
3077
3078 Ok(Some(guard))
3079 }
3080
3081 async fn flush(&self) -> Result<Version, Error> {
3088 self.flush_with_reason(flush::Reason::Journal).await
3089 }
3090
3091 fn write_mutation(&self, mutation: &Mutation, mut writer: journal::Writer<'_>) {
3092 match mutation {
3097 Mutation::ObjectStore(_) | Mutation::CreateInternalDir(_) => {
3106 let mut cipher = self.mutations_cipher.lock();
3107 if let Some(cipher) = cipher.as_mut() {
3108 if cipher.offset() == 0 {
3110 writer.write(Mutation::update_mutations_key(
3111 self.store_info
3112 .lock()
3113 .as_ref()
3114 .unwrap()
3115 .mutations_key
3116 .as_ref()
3117 .unwrap()
3118 .clone(),
3119 ));
3120 }
3121 let mut buffer = Vec::new();
3122 mutation.serialize_into(&mut buffer).unwrap();
3123 cipher.encrypt(&mut buffer);
3124 writer.write(Mutation::EncryptedObjectStore(buffer.into()));
3125 return;
3126 }
3127 }
3128 Mutation::EncryptedObjectStore(_) | Mutation::UpdateMutationsKey(_) => {
3132 debug_assert!(false, "Only this method should generate encrypted mutations");
3133 }
3134 Mutation::Allocator(_)
3139 | Mutation::BeginFlush
3140 | Mutation::EndFlush
3141 | Mutation::DeleteVolume
3142 | Mutation::UpdateBorrowed(_) => {}
3143 }
3144 writer.write(mutation.clone());
3145 }
3146}
3147
3148impl Drop for ObjectStore {
3149 fn drop(&mut self) {
3150 let mut last_object_id = self.last_object_id.lock();
3151 last_object_id.drain_unreserved();
3152 match &*last_object_id {
3153 LastObjectId::Low32Bit { reserved, .. } => debug_assert!(reserved.is_empty()),
3154 _ => {}
3155 }
3156 }
3157}
3158
3159impl HandleOwner for ObjectStore {}
3160
3161impl AsRef<ObjectStore> for ObjectStore {
3162 fn as_ref(&self) -> &ObjectStore {
3163 self
3164 }
3165}
3166
3167fn layer_size_from_encrypted_mutations_size(size: u64) -> u64 {
3168 size * 3
3176}
3177
3178impl AssociatedObject for ObjectStore {}
3179
3180#[derive(Debug)]
3182pub enum TrimMode {
3183 UseSize,
3185
3186 FromOffset(u64),
3188
3189 Tombstone(TombstoneMode),
3191}
3192
3193#[derive(Debug)]
3195pub enum TombstoneMode {
3196 Object,
3197 Attribute,
3198}
3199
3200#[derive(Debug)]
3202pub enum TrimResult {
3203 Incomplete,
3205
3206 Done(Option<AttributeId>),
3209}
3210
3211pub async fn load_store_info(
3213 parent: &Arc<ObjectStore>,
3214 store_object_id: u64,
3215) -> Result<StoreInfo, Error> {
3216 load_store_info_from_handle(
3217 &ObjectStore::open_object(parent, store_object_id, HandleOptions::default(), None).await?,
3218 )
3219 .await
3220}
3221
3222async fn load_store_info_from_handle(
3223 handle: &DataObjectHandle<impl HandleOwner>,
3224) -> Result<StoreInfo, Error> {
3225 Ok(if handle.get_size() > 0 {
3226 let serialized_info = handle.contents(MAX_STORE_INFO_SERIALIZED_SIZE).await?;
3227 let mut cursor = std::io::Cursor::new(serialized_info);
3228 let (store_info, _) = StoreInfo::deserialize_with_version(&mut cursor)
3229 .context("Failed to deserialize StoreInfo")?;
3230 store_info
3231 } else {
3232 StoreInfo::default()
3234 })
3235}
3236
3237#[cfg(test)]
3238mod tests {
3239 use super::{
3240 AttributeId, CALLBACK_UNLOCK_RESOURCES_ACQUIRED, FsverityMetadata, HandleOptions,
3241 LastObjectId, LastObjectIdInfo, LockKey, MAX_STORE_INFO_SERIALIZED_SIZE, Mutation,
3242 NewChildStoreOptions, OBJECT_ID_HI_MASK, ObjectStore, RootDigest, StoreInfo, StoreOptions,
3243 };
3244 use crate::errors::FxfsError;
3245 use crate::filesystem::{
3246 FxFilesystem, FxFilesystemBuilder, JournalingObject, OpenFxFilesystem,
3247 };
3248 use crate::fsck::{fsck, fsck_volume};
3249 use crate::lsm_tree::Query;
3250 use crate::lsm_tree::types::{ItemRef, LayerIterator};
3251 use crate::object_handle::{
3252 INVALID_OBJECT_ID, ObjectHandle, ReadObjectHandle, WriteObjectHandle,
3253 };
3254 use crate::object_store::directory::{Directory, replace_child};
3255 use crate::object_store::journal::JournalOptions;
3256 use crate::object_store::object_record::{AttributeKey, ObjectKey, ObjectKind, ObjectValue};
3257 use crate::object_store::transaction::{Options, lock_keys};
3258 use crate::object_store::volume::root_volume;
3259 use crate::serialized_types::VersionedLatest;
3260 use crate::testing;
3261 use assert_matches::assert_matches;
3262 use async_trait::async_trait;
3263 use fuchsia_async as fasync;
3264 use fuchsia_sync::Mutex;
3265 use futures::channel::oneshot;
3266 use futures::{FutureExt, join};
3267 use fxfs_crypto::ff1::Ff1;
3268 use fxfs_crypto::{
3269 Crypt, EncryptionKey, FXFS_KEY_SIZE, FXFS_WRAPPED_KEY_SIZE, FxfsKey, KeyPurpose,
3270 ObjectType, UnwrappedKey, WrappedKey, WrappedKeyBytes, WrappingKeyId,
3271 };
3272 use fxfs_insecure_crypto::new_insecure_crypt;
3273 use std::sync::Arc;
3274 use std::sync::atomic::{AtomicIsize, Ordering};
3275 use std::time::Duration;
3276 use storage_device::DeviceHolder;
3277 use storage_device::fake_device::FakeDevice;
3278 use test_case::test_case;
3279 use zx_status as zx;
3280
3281 const TEST_DEVICE_BLOCK_SIZE: u32 = 512;
3282
3283 async fn test_filesystem() -> OpenFxFilesystem {
3284 let device = DeviceHolder::new(FakeDevice::new(8192, TEST_DEVICE_BLOCK_SIZE));
3285 FxFilesystem::new_empty(device).await.expect("new_empty failed")
3286 }
3287
3288 #[fuchsia::test]
3289 async fn test_verified_file_with_verified_attribute() {
3290 let fs: OpenFxFilesystem = test_filesystem().await;
3291 let mut transaction = fs
3292 .root_store()
3293 .new_transaction(lock_keys![], Options::default())
3294 .await
3295 .expect("new_transaction failed");
3296 let store = fs.root_store();
3297 let object = Arc::new(
3298 ObjectStore::create_object(&store, &mut transaction, HandleOptions::default(), None)
3299 .await
3300 .expect("create_object failed"),
3301 );
3302
3303 transaction.add(
3304 store.store_object_id(),
3305 Mutation::replace_or_insert_object(
3306 ObjectKey::attribute(
3307 object.object_id(),
3308 AttributeId::DATA,
3309 AttributeKey::Attribute,
3310 ),
3311 ObjectValue::verified_attribute(
3312 0,
3313 FsverityMetadata::Internal(RootDigest::Sha256([0; 32]), vec![]),
3314 ),
3315 ),
3316 );
3317
3318 transaction.add(
3319 store.store_object_id(),
3320 Mutation::replace_or_insert_object(
3321 ObjectKey::attribute(
3322 object.object_id(),
3323 AttributeId::FSVERITY_MERKLE,
3324 AttributeKey::Attribute,
3325 ),
3326 ObjectValue::attribute(0, false),
3327 ),
3328 );
3329
3330 transaction.commit().await.unwrap();
3331
3332 let handle =
3333 ObjectStore::open_object(&store, object.object_id(), HandleOptions::default(), None)
3334 .await
3335 .expect("open_object failed");
3336
3337 assert!(handle.is_verified_file());
3338
3339 fs.close().await.expect("Close failed");
3340 }
3341
3342 #[fuchsia::test]
3343 async fn test_verified_file_without_verified_attribute() {
3344 let fs: OpenFxFilesystem = test_filesystem().await;
3345 let mut transaction = fs
3346 .root_store()
3347 .new_transaction(lock_keys![], Options::default())
3348 .await
3349 .expect("new_transaction failed");
3350 let store = fs.root_store();
3351 let object = Arc::new(
3352 ObjectStore::create_object(&store, &mut transaction, HandleOptions::default(), None)
3353 .await
3354 .expect("create_object failed"),
3355 );
3356
3357 transaction.commit().await.unwrap();
3358
3359 let handle =
3360 ObjectStore::open_object(&store, object.object_id(), HandleOptions::default(), None)
3361 .await
3362 .expect("open_object failed");
3363
3364 assert!(!handle.is_verified_file());
3365
3366 fs.close().await.expect("Close failed");
3367 }
3368
3369 #[fuchsia::test]
3370 async fn test_create_and_open_store() {
3371 let fs = test_filesystem().await;
3372 let store_id = {
3373 let root_volume = root_volume(fs.clone()).await.expect("root_volume failed");
3374 root_volume
3375 .new_volume(
3376 "test",
3377 NewChildStoreOptions {
3378 options: StoreOptions { crypt: Some(Arc::new(new_insecure_crypt())) },
3379 ..Default::default()
3380 },
3381 )
3382 .await
3383 .expect("new_volume failed")
3384 .store_object_id()
3385 };
3386
3387 fs.close().await.expect("close failed");
3388 let device = fs.take_device().await;
3389 device.reopen(false);
3390 let fs = FxFilesystem::open(device).await.expect("open failed");
3391
3392 {
3393 let store = fs.object_manager().store(store_id).expect("store not found");
3394 store.unlock(Arc::new(new_insecure_crypt())).await.expect("unlock failed");
3395 }
3396 fs.close().await.expect("Close failed");
3397 }
3398
3399 #[fuchsia::test]
3400 async fn test_create_and_open_internal_dir() {
3401 let fs = test_filesystem().await;
3402 let dir_id;
3403 let store_id;
3404 {
3405 let root_volume = root_volume(fs.clone()).await.expect("root_volume failed");
3406 let store = root_volume
3407 .new_volume(
3408 "test",
3409 NewChildStoreOptions {
3410 options: StoreOptions { crypt: Some(Arc::new(new_insecure_crypt())) },
3411 ..Default::default()
3412 },
3413 )
3414 .await
3415 .expect("new_volume failed");
3416 dir_id =
3417 store.get_or_create_internal_directory_id().await.expect("Create internal dir");
3418 store_id = store.store_object_id();
3419 }
3420
3421 fs.close().await.expect("close failed");
3422 let device = fs.take_device().await;
3423 device.reopen(false);
3424 let fs = FxFilesystem::open(device).await.expect("open failed");
3425
3426 {
3427 let store = fs.object_manager().store(store_id).expect("store not found");
3428 store.unlock(Arc::new(new_insecure_crypt())).await.expect("unlock failed");
3429 assert_eq!(
3430 dir_id,
3431 store.get_or_create_internal_directory_id().await.expect("Retrieving dir")
3432 );
3433 let obj = store
3434 .tree()
3435 .find(&ObjectKey::object(dir_id))
3436 .await
3437 .expect("Searching tree for dir")
3438 .unwrap();
3439 assert_matches!(
3440 obj.value,
3441 ObjectValue::Object { kind: ObjectKind::Directory { .. }, .. }
3442 );
3443 }
3444 fs.close().await.expect("Close failed");
3445 }
3446
3447 #[fuchsia::test]
3448 async fn test_create_and_open_internal_dir_unencrypted() {
3449 let fs = test_filesystem().await;
3450 let dir_id;
3451 let store_id;
3452 {
3453 let root_volume = root_volume(fs.clone()).await.expect("root_volume failed");
3454 let store = root_volume
3455 .new_volume("test", NewChildStoreOptions::default())
3456 .await
3457 .expect("new_volume failed");
3458 dir_id =
3459 store.get_or_create_internal_directory_id().await.expect("Create internal dir");
3460 store_id = store.store_object_id();
3461 }
3462
3463 fs.close().await.expect("close failed");
3464 let device = fs.take_device().await;
3465 device.reopen(false);
3466 let fs = FxFilesystem::open(device).await.expect("open failed");
3467
3468 {
3469 let store = fs.object_manager().store(store_id).expect("store not found");
3470 assert_eq!(
3471 dir_id,
3472 store.get_or_create_internal_directory_id().await.expect("Retrieving dir")
3473 );
3474 let obj = store
3475 .tree()
3476 .find(&ObjectKey::object(dir_id))
3477 .await
3478 .expect("Searching tree for dir")
3479 .unwrap();
3480 assert_matches!(
3481 obj.value,
3482 ObjectValue::Object { kind: ObjectKind::Directory { .. }, .. }
3483 );
3484 }
3485 fs.close().await.expect("Close failed");
3486 }
3487
3488 #[fuchsia::test(threads = 10)]
3489 async fn test_old_layers_are_purged() {
3490 let fs = test_filesystem().await;
3491
3492 let store = fs.root_store();
3493 let mut transaction = fs
3494 .root_store()
3495 .new_transaction(lock_keys![], Options::default())
3496 .await
3497 .expect("new_transaction failed");
3498 let object = Arc::new(
3499 ObjectStore::create_object(&store, &mut transaction, HandleOptions::default(), None)
3500 .await
3501 .expect("create_object failed"),
3502 );
3503 transaction.commit().await.expect("commit failed");
3504
3505 store.flush().await.expect("flush failed");
3506
3507 let mut buf = object.allocate_buffer(5).await;
3508 buf.as_mut_slice().copy_from_slice(b"hello");
3509 object.write_or_append(Some(0), buf.as_ref()).await.expect("write failed");
3510
3511 let layer_set = store.tree().layer_set();
3513
3514 let done = Mutex::new(false);
3515 let mut object_id = 0;
3516
3517 join!(
3518 async {
3519 store.flush().await.expect("flush failed");
3520 assert!(*done.lock());
3521 },
3522 async {
3523 fasync::Timer::new(Duration::from_secs(1)).await;
3525 *done.lock() = true;
3526 object_id = layer_set.layers.last().unwrap().handle().unwrap().object_id();
3527 std::mem::drop(layer_set);
3528 }
3529 );
3530
3531 if let Err(e) = ObjectStore::open_object(
3532 &store.parent_store.as_ref().unwrap(),
3533 object_id,
3534 HandleOptions::default(),
3535 store.crypt(),
3536 )
3537 .await
3538 {
3539 assert!(FxfsError::NotFound.matches(&e));
3540 } else {
3541 panic!("open_object succeeded");
3542 }
3543 }
3544
3545 #[fuchsia::test]
3546 async fn test_tombstone_deletes_data() {
3547 let fs = test_filesystem().await;
3548 let root_store = fs.root_store();
3549 let child_id = {
3550 let mut transaction = fs
3551 .root_store()
3552 .new_transaction(lock_keys![], Options::default())
3553 .await
3554 .expect("new_transaction failed");
3555 let child = ObjectStore::create_object(
3556 &root_store,
3557 &mut transaction,
3558 HandleOptions::default(),
3559 None,
3560 )
3561 .await
3562 .expect("create_object failed");
3563 root_store.add_to_graveyard(&mut transaction, child.object_id());
3564 transaction.commit().await.expect("commit failed");
3565
3566 let mut buffer = child.allocate_buffer(8192).await;
3568 buffer.as_mut_slice().fill(0xaa);
3569 child.write_or_append(Some(0), buffer.as_ref()).await.expect("write failed");
3570
3571 child.object_id()
3572 };
3573
3574 root_store.tombstone_object(child_id, Options::default()).await.expect("tombstone failed");
3575
3576 fsck(fs.clone()).await.expect("fsck failed");
3578 }
3579
3580 #[fuchsia::test]
3581 async fn test_tombstone_purges_keys() {
3582 let fs = test_filesystem().await;
3583 let root_volume = root_volume(fs.clone()).await.expect("root_volume failed");
3584 let store = root_volume
3585 .new_volume(
3586 "test",
3587 NewChildStoreOptions {
3588 options: StoreOptions {
3589 crypt: Some(Arc::new(new_insecure_crypt())),
3590 ..StoreOptions::default()
3591 },
3592 ..NewChildStoreOptions::default()
3593 },
3594 )
3595 .await
3596 .expect("new_volume failed");
3597 let mut transaction = fs
3598 .root_store()
3599 .new_transaction(lock_keys![], Options::default())
3600 .await
3601 .expect("new_transaction failed");
3602 let child =
3603 ObjectStore::create_object(&store, &mut transaction, HandleOptions::default(), None)
3604 .await
3605 .expect("create_object failed");
3606 store.add_to_graveyard(&mut transaction, child.object_id());
3607 transaction.commit().await.expect("commit failed");
3608 assert!(store.key_manager.get(child.object_id()).await.unwrap().is_some());
3609 store
3610 .tombstone_object(child.object_id(), Options::default())
3611 .await
3612 .expect("tombstone_object failed");
3613 assert!(store.key_manager.get(child.object_id()).await.unwrap().is_none());
3614 fs.close().await.expect("close failed");
3615 }
3616
3617 #[fuchsia::test]
3618 async fn test_major_compaction_discards_unnecessary_records() {
3619 let fs = test_filesystem().await;
3620 let root_store = fs.root_store();
3621 let child_id = {
3622 let mut transaction = fs
3623 .root_store()
3624 .new_transaction(lock_keys![], Options::default())
3625 .await
3626 .expect("new_transaction failed");
3627 let child = ObjectStore::create_object(
3628 &root_store,
3629 &mut transaction,
3630 HandleOptions::default(),
3631 None,
3632 )
3633 .await
3634 .expect("create_object failed");
3635 root_store.add_to_graveyard(&mut transaction, child.object_id());
3636 transaction.commit().await.expect("commit failed");
3637
3638 let mut buffer = child.allocate_buffer(8192).await;
3640 buffer.as_mut_slice().fill(0xaa);
3641 child.write_or_append(Some(0), buffer.as_ref()).await.expect("write failed");
3642
3643 child.object_id()
3644 };
3645
3646 root_store.tombstone_object(child_id, Options::default()).await.expect("tombstone failed");
3647 {
3648 let layers = root_store.tree.layer_set();
3649 let mut merger = layers.merger();
3650 let iter = merger
3651 .query(Query::FullRange(&ObjectKey::object(child_id)))
3652 .await
3653 .expect("seek failed");
3654 match iter.get() {
3656 Some(ItemRef { key: ObjectKey { object_id, .. }, .. })
3657 if *object_id == child_id => {}
3658 _ => panic!("Objects should still be in the tree."),
3659 }
3660 }
3661 root_store.flush().await.expect("flush failed");
3662
3663 let layers = root_store.tree.layer_set();
3665 let mut merger = layers.merger();
3666 let iter = merger
3667 .query(Query::FullRange(&ObjectKey::object(child_id)))
3668 .await
3669 .expect("seek failed");
3670 match iter.get() {
3671 None => {}
3672 Some(ItemRef { key: ObjectKey { object_id, .. }, .. }) => {
3673 assert_ne!(*object_id, child_id)
3674 }
3675 }
3676 }
3677
3678 #[fuchsia::test]
3679 async fn test_overlapping_extents_in_different_layers() {
3680 let fs = test_filesystem().await;
3681 let store = fs.root_store();
3682
3683 let mut transaction = store
3684 .new_transaction(
3685 lock_keys![LockKey::object(
3686 store.store_object_id(),
3687 store.root_directory_object_id()
3688 )],
3689 Options::default(),
3690 )
3691 .await
3692 .expect("new_transaction failed");
3693 let root_directory =
3694 Directory::open(&store, store.root_directory_object_id()).await.expect("open failed");
3695 let object = root_directory
3696 .create_child_file(&mut transaction, "test")
3697 .await
3698 .expect("create_child_file failed");
3699 transaction.commit().await.expect("commit failed");
3700
3701 let buf = object.allocate_buffer(16384).await;
3702 object.write_or_append(Some(0), buf.as_ref()).await.expect("write failed");
3703
3704 store.flush().await.expect("flush failed");
3705
3706 object.write_or_append(Some(0), buf.subslice(0..4096)).await.expect("write failed");
3707
3708 object.write_or_append(Some(0), buf.as_ref()).await.expect("write failed");
3712
3713 fsck(fs.clone()).await.expect("fsck failed");
3714 }
3715
3716 #[fuchsia::test(threads = 10)]
3717 async fn test_encrypted_mutations() {
3718 async fn one_iteration(
3719 fs: OpenFxFilesystem,
3720 crypt: Arc<dyn Crypt>,
3721 iteration: u64,
3722 ) -> OpenFxFilesystem {
3723 async fn reopen(fs: OpenFxFilesystem) -> OpenFxFilesystem {
3724 fs.close().await.expect("Close failed");
3725 let device = fs.take_device().await;
3726 device.reopen(false);
3727 FxFilesystem::open(device).await.expect("FS open failed")
3728 }
3729
3730 let fs = reopen(fs).await;
3731
3732 let (store_object_id, object_id) = {
3733 let root_volume = root_volume(fs.clone()).await.expect("root_volume failed");
3734 let store = root_volume
3735 .volume(
3736 "test",
3737 StoreOptions { crypt: Some(crypt.clone()), ..StoreOptions::default() },
3738 )
3739 .await
3740 .expect("volume failed");
3741
3742 let mut transaction = fs
3743 .root_store()
3744 .new_transaction(
3745 lock_keys![LockKey::object(
3746 store.store_object_id(),
3747 store.root_directory_object_id(),
3748 )],
3749 Options::default(),
3750 )
3751 .await
3752 .expect("new_transaction failed");
3753 let root_directory = Directory::open(&store, store.root_directory_object_id())
3754 .await
3755 .expect("open failed");
3756 let object = root_directory
3757 .create_child_file(&mut transaction, &format!("test {}", iteration))
3758 .await
3759 .expect("create_child_file failed");
3760 transaction.commit().await.expect("commit failed");
3761
3762 let mut buf = object.allocate_buffer(1000).await;
3763 for i in 0..buf.len() {
3764 buf.as_mut_slice()[i] = i as u8;
3765 }
3766 object.write_or_append(Some(0), buf.as_ref()).await.expect("write failed");
3767
3768 (store.store_object_id(), object.object_id())
3769 };
3770
3771 let fs = reopen(fs).await;
3772
3773 let check_object = |fs: Arc<FxFilesystem>| {
3774 let crypt = crypt.clone();
3775 async move {
3776 let root_volume = root_volume(fs).await.expect("root_volume failed");
3777 let volume = root_volume
3778 .volume(
3779 "test",
3780 StoreOptions { crypt: Some(crypt), ..StoreOptions::default() },
3781 )
3782 .await
3783 .expect("volume failed");
3784
3785 let object = ObjectStore::open_object(
3786 &volume,
3787 object_id,
3788 HandleOptions::default(),
3789 None,
3790 )
3791 .await
3792 .expect("open_object failed");
3793 let mut buf = object.allocate_buffer(1000).await;
3794 assert_eq!(object.read(0, buf.as_mut()).await.expect("read failed"), 1000);
3795 for i in 0..buf.len() {
3796 assert_eq!(buf.as_slice()[i], i as u8);
3797 }
3798 }
3799 };
3800
3801 check_object(fs.clone()).await;
3802
3803 let fs = reopen(fs).await;
3804
3805 fs.object_manager().flush().await.expect("flush failed");
3808
3809 assert_ne!(
3810 fs.object_manager()
3811 .store(store_object_id)
3812 .unwrap()
3813 .load_store_info()
3814 .await
3815 .expect("load_store_info failed")
3816 .encrypted_mutations_object_id,
3817 INVALID_OBJECT_ID
3818 );
3819
3820 check_object(fs.clone()).await;
3821
3822 assert_eq!(
3825 fs.object_manager()
3826 .store(store_object_id)
3827 .unwrap()
3828 .load_store_info()
3829 .await
3830 .expect("load_store_info failed")
3831 .encrypted_mutations_object_id,
3832 INVALID_OBJECT_ID
3833 );
3834
3835 let fs = reopen(fs).await;
3836
3837 fsck(fs.clone()).await.expect("fsck failed");
3838
3839 let fs = reopen(fs).await;
3840
3841 check_object(fs.clone()).await;
3842
3843 fs
3844 }
3845
3846 let mut fs = test_filesystem().await;
3847 let crypt = Arc::new(new_insecure_crypt());
3848
3849 {
3850 let root_volume = root_volume(fs.clone()).await.expect("root_volume failed");
3851 let _store = root_volume
3852 .new_volume(
3853 "test",
3854 NewChildStoreOptions {
3855 options: StoreOptions {
3856 crypt: Some(crypt.clone()),
3857 ..StoreOptions::default()
3858 },
3859 ..Default::default()
3860 },
3861 )
3862 .await
3863 .expect("new_volume failed");
3864 }
3865
3866 for i in 0..5 {
3868 fs = one_iteration(fs, crypt.clone(), i).await;
3869 }
3870 }
3871
3872 #[test_case(true; "with a flush")]
3873 #[test_case(false; "without a flush")]
3874 #[fuchsia::test(threads = 10)]
3875 async fn test_object_id_cipher_roll(with_flush: bool) {
3876 let fs = test_filesystem().await;
3877 let crypt = Arc::new(new_insecure_crypt());
3878
3879 let expected_key = {
3880 let root_volume = root_volume(fs.clone()).await.expect("root_volume failed");
3881 let store = root_volume
3882 .new_volume(
3883 "test",
3884 NewChildStoreOptions {
3885 options: StoreOptions {
3886 crypt: Some(crypt.clone()),
3887 ..StoreOptions::default()
3888 },
3889 ..Default::default()
3890 },
3891 )
3892 .await
3893 .expect("new_volume failed");
3894
3895 let root_dir_id = store.root_directory_object_id();
3898 let root_dir =
3899 Arc::new(Directory::open(&store, root_dir_id).await.expect("open failed"));
3900 let mut transaction = store
3901 .new_transaction(
3902 lock_keys![LockKey::object(store.store_object_id(), root_dir_id)],
3903 Options::default(),
3904 )
3905 .await
3906 .expect("new_transaction failed");
3907 for i in 0..10 {
3908 root_dir.create_child_file(&mut transaction, &format!("file {i}")).await.unwrap();
3909 }
3910 transaction.commit().await.expect("commit failed");
3911
3912 let orig_store_info = store.store_info().unwrap();
3913
3914 {
3916 let mut last_object_id = store.last_object_id.lock();
3917 match &mut *last_object_id {
3918 LastObjectId::Encrypted { id, .. } => {
3919 assert_eq!(*id & OBJECT_ID_HI_MASK, 0);
3920 *id |= 0xffffffff;
3921 }
3922 _ => unreachable!(),
3923 }
3924 }
3925
3926 let mut transaction = store
3927 .new_transaction(
3928 lock_keys![LockKey::object(
3929 store.store_object_id(),
3930 store.root_directory_object_id()
3931 )],
3932 Options::default(),
3933 )
3934 .await
3935 .expect("new_transaction failed");
3936 let root_directory = Directory::open(&store, store.root_directory_object_id())
3937 .await
3938 .expect("open failed");
3939 let object = root_directory
3940 .create_child_file(&mut transaction, "test")
3941 .await
3942 .expect("create_child_file failed");
3943 transaction.commit().await.expect("commit failed");
3944
3945 assert_eq!(object.object_id() & OBJECT_ID_HI_MASK, 1u64 << 32);
3946
3947 let key = match (
3949 store.store_info().unwrap().last_object_id,
3950 orig_store_info.last_object_id,
3951 ) {
3952 (
3953 LastObjectIdInfo::Encrypted { key, id },
3954 LastObjectIdInfo::Encrypted { key: orig_key, .. },
3955 ) => {
3956 assert_ne!(key, orig_key);
3957 assert_eq!(id, 1u64 << 32);
3958 key
3959 }
3960 _ => unreachable!(),
3961 };
3962
3963 if with_flush {
3964 fs.journal().force_compact().await.unwrap();
3965 }
3966
3967 let last_object_id = store.last_object_id.lock();
3968 assert_eq!(last_object_id.id(), 1u64 << 32);
3969 key
3970 };
3971
3972 fs.close().await.expect("Close failed");
3973 let device = fs.take_device().await;
3974 device.reopen(false);
3975 let fs = FxFilesystem::open(device).await.expect("open failed");
3976 let root_volume = root_volume(fs.clone()).await.expect("root_volume failed");
3977 let store = root_volume
3978 .volume("test", StoreOptions { crypt: Some(crypt.clone()), ..StoreOptions::default() })
3979 .await
3980 .expect("volume failed");
3981
3982 assert_matches!(store.store_info().unwrap().last_object_id, LastObjectIdInfo::Encrypted { key, .. } if key == expected_key);
3983 assert_eq!(store.last_object_id.lock().id(), 1u64 << 32);
3984
3985 fsck(fs.clone()).await.expect("fsck failed");
3986 fsck_volume(&fs, store.store_object_id(), None).await.expect("fsck_volume failed");
3987 }
3988
3989 #[fuchsia::test(threads = 2)]
3990 async fn test_race_object_id_cipher_roll_and_flush() {
3991 let fs = test_filesystem().await;
3992 let crypt = Arc::new(new_insecure_crypt());
3993
3994 let root_volume = root_volume(fs.clone()).await.expect("root_volume failed");
3995 let store = root_volume
3996 .new_volume(
3997 "test",
3998 NewChildStoreOptions {
3999 options: StoreOptions { crypt: Some(crypt.clone()), ..StoreOptions::default() },
4000 ..Default::default()
4001 },
4002 )
4003 .await
4004 .expect("new_volume failed");
4005
4006 assert!(matches!(&*store.last_object_id.lock(), LastObjectId::Encrypted { .. }));
4007
4008 let root_dir_id = store.root_directory_object_id();
4011 let root_dir = Arc::new(Directory::open(&store, root_dir_id).await.expect("open failed"));
4012
4013 let _executor_tasks = testing::force_executor_threads_to_run(2).await;
4014
4015 for j in 0..100 {
4016 let mut transaction = store
4017 .new_transaction(
4018 lock_keys![LockKey::object(store.store_object_id(), root_dir_id)],
4019 Options::default(),
4020 )
4021 .await
4022 .expect("new_transaction failed");
4023 root_dir.create_child_file(&mut transaction, &format!("file {j}")).await.unwrap();
4024 transaction.commit().await.expect("commit failed");
4025
4026 let task = {
4027 let fs = fs.clone();
4028 fasync::Task::spawn(async move {
4029 fs.journal().force_compact().await.unwrap();
4030 })
4031 };
4032
4033 {
4035 let mut last_object_id = store.last_object_id.lock();
4036 let LastObjectId::Encrypted { id, .. } = &mut *last_object_id else {
4037 unreachable!()
4038 };
4039 assert_eq!(*id >> 32, j);
4040 *id |= 0xffffffff;
4041 }
4042
4043 let mut transaction = store
4044 .new_transaction(
4045 lock_keys![LockKey::object(
4046 store.store_object_id(),
4047 store.root_directory_object_id()
4048 )],
4049 Options::default(),
4050 )
4051 .await
4052 .expect("new_transaction failed");
4053 let root_directory = Directory::open(&store, store.root_directory_object_id())
4054 .await
4055 .expect("open failed");
4056 root_directory
4057 .create_child_file(&mut transaction, "test {j}")
4058 .await
4059 .expect("create_child_file failed");
4060 transaction.commit().await.expect("commit failed");
4061
4062 task.await;
4063
4064 let new_store_info = store.load_store_info().await.unwrap();
4066
4067 let LastObjectIdInfo::Encrypted { id, key } = new_store_info.last_object_id else {
4068 unreachable!()
4069 };
4070 assert_eq!(id >> 32, j + 1);
4071 let LastObjectIdInfo::Encrypted { key: in_memory_key, .. } =
4072 store.store_info().unwrap().last_object_id
4073 else {
4074 unreachable!()
4075 };
4076 assert_eq!(key, in_memory_key);
4077 }
4078
4079 fs.close().await.expect("Close failed");
4080 }
4081
4082 #[fuchsia::test]
4083 async fn test_object_id_no_roll_for_unencrypted_store() {
4084 let fs = test_filesystem().await;
4085
4086 {
4087 let root_volume = root_volume(fs.clone()).await.expect("root_volume failed");
4088 let store = root_volume
4089 .new_volume("test", NewChildStoreOptions::default())
4090 .await
4091 .expect("new_volume failed");
4092
4093 {
4095 let mut last_object_id = store.last_object_id.lock();
4096 match &mut *last_object_id {
4097 LastObjectId::Unencrypted { id } => {
4098 assert_eq!(*id & OBJECT_ID_HI_MASK, 0);
4099 *id |= 0xffffffff;
4100 }
4101 _ => unreachable!(),
4102 }
4103 }
4104
4105 let mut transaction = store
4106 .new_transaction(
4107 lock_keys![LockKey::object(
4108 store.store_object_id(),
4109 store.root_directory_object_id()
4110 )],
4111 Options::default(),
4112 )
4113 .await
4114 .expect("new_transaction failed");
4115 let root_directory = Directory::open(&store, store.root_directory_object_id())
4116 .await
4117 .expect("open failed");
4118 let object = root_directory
4119 .create_child_file(&mut transaction, "test")
4120 .await
4121 .expect("create_child_file failed");
4122 transaction.commit().await.expect("commit failed");
4123
4124 assert_eq!(object.object_id(), 0x1_0000_0000);
4125
4126 assert_matches!(
4128 store.store_info().unwrap().last_object_id,
4129 LastObjectIdInfo::Unencrypted { .. }
4130 );
4131
4132 assert_eq!(store.last_object_id.lock().id(), 0x1_0000_0000);
4133 };
4134
4135 fs.close().await.expect("Close failed");
4136 let device = fs.take_device().await;
4137 device.reopen(false);
4138 let fs = FxFilesystem::open(device).await.expect("open failed");
4139 let root_volume = root_volume(fs.clone()).await.expect("root_volume failed");
4140 let store =
4141 root_volume.volume("test", StoreOptions::default()).await.expect("volume failed");
4142
4143 assert_eq!(store.last_object_id.lock().id(), 0x1_0000_0000);
4144 }
4145
4146 #[fuchsia::test]
4147 fn test_object_id_is_not_invalid_object_id() {
4148 let key = UnwrappedKey::new(vec![0; FXFS_KEY_SIZE]);
4149 let mut last_object_id =
4151 LastObjectId::Encrypted { id: 1106634047, cipher: Box::new(Ff1::new(&key)) };
4152 assert!(last_object_id.try_get_next().is_some());
4153 assert!(last_object_id.try_get_next().is_some());
4154 }
4155
4156 #[fuchsia::test]
4157 async fn test_last_object_id_is_correct_after_unlock() {
4158 let fs = test_filesystem().await;
4159 let crypt = Arc::new(new_insecure_crypt());
4160
4161 let root_volume = root_volume(fs.clone()).await.expect("root_volume failed");
4162 let store = root_volume
4163 .new_volume(
4164 "test",
4165 NewChildStoreOptions {
4166 options: StoreOptions { crypt: Some(crypt.clone()), ..StoreOptions::default() },
4167 ..Default::default()
4168 },
4169 )
4170 .await
4171 .expect("new_volume failed");
4172
4173 let mut transaction = store
4174 .new_transaction(
4175 lock_keys![LockKey::object(
4176 store.store_object_id(),
4177 store.root_directory_object_id()
4178 )],
4179 Options::default(),
4180 )
4181 .await
4182 .expect("new_transaction failed");
4183 let root_directory =
4184 Directory::open(&store, store.root_directory_object_id()).await.expect("open failed");
4185 root_directory
4186 .create_child_file(&mut transaction, "test")
4187 .await
4188 .expect("create_child_file failed");
4189 transaction.commit().await.expect("commit failed");
4190
4191 fs.journal().force_compact().await.unwrap();
4193
4194 let last_object_id = store.last_object_id.lock().id();
4195
4196 store.lock().await.unwrap();
4197 store.unlock(crypt.clone()).await.unwrap();
4198
4199 assert_eq!(store.last_object_id.lock().id(), last_object_id);
4200 }
4201
4202 #[fuchsia::test(threads = 20)]
4203 async fn test_race_when_rolling_last_object_id_cipher() {
4204 const NUM_THREADS: usize = 20;
4207
4208 let fs = test_filesystem().await;
4209 let crypt = Arc::new(new_insecure_crypt());
4210
4211 let root_volume = root_volume(fs.clone()).await.expect("root_volume failed");
4212 let store = root_volume
4213 .new_volume(
4214 "test",
4215 NewChildStoreOptions {
4216 options: StoreOptions { crypt: Some(crypt.clone()), ..StoreOptions::default() },
4217 ..Default::default()
4218 },
4219 )
4220 .await
4221 .expect("new_volume failed");
4222
4223 let store_id = store.store_object_id();
4224 let root_dir_id = store.root_directory_object_id();
4225
4226 let root_directory =
4227 Arc::new(Directory::open(&store, root_dir_id).await.expect("open failed"));
4228
4229 let mut directories = Vec::new();
4231 for _ in 0..NUM_THREADS {
4232 let mut transaction = fs
4233 .root_store()
4234 .new_transaction(
4235 lock_keys![LockKey::object(store_id, root_dir_id,)],
4236 Options::default(),
4237 )
4238 .await
4239 .expect("new_transaction failed");
4240 directories.push(
4241 root_directory
4242 .create_child_dir(&mut transaction, "test")
4243 .await
4244 .expect("create_child_file failed"),
4245 );
4246 transaction.commit().await.expect("commit failed");
4247 }
4248
4249 match &mut *store.last_object_id.lock() {
4251 LastObjectId::Encrypted { id, .. } => *id |= 0xffff_ffff,
4252 _ => unreachable!(),
4253 }
4254
4255 let scope = fasync::Scope::new();
4256
4257 let _executor_tasks = testing::force_executor_threads_to_run(NUM_THREADS).await;
4258
4259 for dir in directories {
4260 let fs = fs.clone();
4261 scope.spawn(async move {
4262 let mut transaction = fs
4263 .root_store()
4264 .new_transaction(
4265 lock_keys![LockKey::object(store_id, dir.object_id(),)],
4266 Options::default(),
4267 )
4268 .await
4269 .expect("new_transaction failed");
4270 dir.create_child_file(&mut transaction, "test")
4271 .await
4272 .expect("create_child_file failed");
4273 transaction.commit().await.expect("commit failed");
4274 });
4275 }
4276
4277 scope.on_no_tasks().await;
4278
4279 assert_eq!(store.last_object_id.lock().id(), 0x1_0000_0000 + NUM_THREADS as u64 - 1);
4280 }
4281
4282 #[fuchsia::test(threads = 10)]
4283 async fn test_lock_store() {
4284 let fs = test_filesystem().await;
4285 let crypt = Arc::new(new_insecure_crypt());
4286
4287 let root_volume = root_volume(fs.clone()).await.expect("root_volume failed");
4288 let store = root_volume
4289 .new_volume(
4290 "test",
4291 NewChildStoreOptions {
4292 options: StoreOptions { crypt: Some(crypt.clone()), ..StoreOptions::default() },
4293 ..NewChildStoreOptions::default()
4294 },
4295 )
4296 .await
4297 .expect("new_volume failed");
4298 let mut transaction = store
4299 .new_transaction(
4300 lock_keys![LockKey::object(
4301 store.store_object_id(),
4302 store.root_directory_object_id()
4303 )],
4304 Options::default(),
4305 )
4306 .await
4307 .expect("new_transaction failed");
4308 let root_directory =
4309 Directory::open(&store, store.root_directory_object_id()).await.expect("open failed");
4310 root_directory
4311 .create_child_file(&mut transaction, "test")
4312 .await
4313 .expect("create_child_file failed");
4314 transaction.commit().await.expect("commit failed");
4315 store.lock().await.expect("lock failed");
4316
4317 store.unlock(crypt).await.expect("unlock failed");
4318 root_directory.lookup("test").await.expect("lookup failed").expect("not found");
4319 }
4320
4321 #[fuchsia::test(threads = 10)]
4322 async fn test_unlock_read_only() {
4323 let fs = test_filesystem().await;
4324 let crypt = Arc::new(new_insecure_crypt());
4325
4326 let root_volume = root_volume(fs.clone()).await.expect("root_volume failed");
4327 let store = root_volume
4328 .new_volume(
4329 "test",
4330 NewChildStoreOptions {
4331 options: StoreOptions { crypt: Some(crypt.clone()), ..StoreOptions::default() },
4332 ..NewChildStoreOptions::default()
4333 },
4334 )
4335 .await
4336 .expect("new_volume failed");
4337 let mut transaction = store
4338 .new_transaction(
4339 lock_keys![LockKey::object(
4340 store.store_object_id(),
4341 store.root_directory_object_id()
4342 )],
4343 Options::default(),
4344 )
4345 .await
4346 .expect("new_transaction failed");
4347 let root_directory =
4348 Directory::open(&store, store.root_directory_object_id()).await.expect("open failed");
4349 root_directory
4350 .create_child_file(&mut transaction, "test")
4351 .await
4352 .expect("create_child_file failed");
4353 transaction.commit().await.expect("commit failed");
4354 store.lock().await.expect("lock failed");
4355
4356 store.unlock_read_only(crypt.clone()).await.expect("unlock failed");
4357 root_directory.lookup("test").await.expect("lookup failed").expect("not found");
4358 store.lock_read_only();
4359 store.unlock_read_only(crypt).await.expect("unlock failed");
4360 root_directory.lookup("test").await.expect("lookup failed").expect("not found");
4361 }
4362
4363 #[fuchsia::test(threads = 10)]
4364 async fn test_key_rolled_when_unlocked() {
4365 let fs = test_filesystem().await;
4366 let crypt = Arc::new(new_insecure_crypt());
4367
4368 let object_id;
4369 {
4370 let root_volume = root_volume(fs.clone()).await.expect("root_volume failed");
4371 let store = root_volume
4372 .new_volume(
4373 "test",
4374 NewChildStoreOptions {
4375 options: StoreOptions {
4376 crypt: Some(crypt.clone()),
4377 ..StoreOptions::default()
4378 },
4379 ..Default::default()
4380 },
4381 )
4382 .await
4383 .expect("new_volume failed");
4384 let mut transaction = store
4385 .new_transaction(
4386 lock_keys![LockKey::object(
4387 store.store_object_id(),
4388 store.root_directory_object_id()
4389 )],
4390 Options::default(),
4391 )
4392 .await
4393 .expect("new_transaction failed");
4394 let root_directory = Directory::open(&store, store.root_directory_object_id())
4395 .await
4396 .expect("open failed");
4397 object_id = root_directory
4398 .create_child_file(&mut transaction, "test")
4399 .await
4400 .expect("create_child_file failed")
4401 .object_id();
4402 transaction.commit().await.expect("commit failed");
4403 }
4404
4405 fs.close().await.expect("Close failed");
4406 let mut device = fs.take_device().await;
4407
4408 for _ in 0..100 {
4411 device.reopen(false);
4412 let fs = FxFilesystem::open(device).await.expect("open failed");
4413 {
4414 let root_volume = root_volume(fs.clone()).await.expect("root_volume failed");
4415 let store = root_volume
4416 .volume(
4417 "test",
4418 StoreOptions { crypt: Some(crypt.clone()), ..StoreOptions::default() },
4419 )
4420 .await
4421 .expect("open_volume failed");
4422
4423 assert_eq!(store.mutations_cipher.lock().as_ref().unwrap().offset(), 0);
4425
4426 let handle =
4428 ObjectStore::open_object(&store, object_id, HandleOptions::default(), None)
4429 .await
4430 .expect("open_object failed");
4431 let buffer = handle.allocate_buffer(100).await;
4432 handle
4433 .write_or_append(Some(0), buffer.as_ref())
4434 .await
4435 .expect("write_or_append failed");
4436 }
4437 fs.close().await.expect("Close failed");
4438 device = fs.take_device().await;
4439 }
4440 }
4441
4442 #[test]
4443 fn test_store_info_max_serialized_size() {
4444 let info = StoreInfo {
4445 guid: [0xff; 16],
4446 last_object_id: LastObjectIdInfo::Encrypted {
4447 id: 0x1234567812345678,
4448 key: FxfsKey {
4449 wrapping_key_id: 0x1234567812345678u128.to_le_bytes(),
4450 key: WrappedKeyBytes::from([0xff; FXFS_WRAPPED_KEY_SIZE]),
4451 },
4452 },
4453 layers: vec![0x1234567812345678; 120],
4458 root_directory_object_id: 0x1234567812345678,
4459 graveyard_directory_object_id: 0x1234567812345678,
4460 object_count: 0x1234567812345678,
4461 mutations_key: Some(FxfsKey {
4462 wrapping_key_id: 0x1234567812345678u128.to_le_bytes(),
4463 key: WrappedKeyBytes::from([0xff; FXFS_WRAPPED_KEY_SIZE]),
4464 }),
4465 mutations_cipher_offset: 0x1234567812345678,
4466 encrypted_mutations_object_id: 0x1234567812345678,
4467 internal_directory_object_id: INVALID_OBJECT_ID,
4468 };
4469 let mut serialized_info = Vec::new();
4470 info.serialize_with_version(&mut serialized_info).unwrap();
4471 assert!(
4472 serialized_info.len() <= MAX_STORE_INFO_SERIALIZED_SIZE,
4473 "{}",
4474 serialized_info.len()
4475 );
4476 }
4477
4478 async fn reopen_after_crypt_failure_inner(read_only: bool) {
4479 let fs = test_filesystem().await;
4480 let root_volume = root_volume(fs.clone()).await.expect("root_volume failed");
4481
4482 let store = {
4483 let crypt = Arc::new(new_insecure_crypt());
4484 let store = root_volume
4485 .new_volume(
4486 "vol",
4487 NewChildStoreOptions {
4488 options: StoreOptions {
4489 crypt: Some(crypt.clone()),
4490 ..StoreOptions::default()
4491 },
4492 ..Default::default()
4493 },
4494 )
4495 .await
4496 .expect("new_volume failed");
4497 let root_directory = Directory::open(&store, store.root_directory_object_id())
4498 .await
4499 .expect("open failed");
4500 let mut transaction = fs
4501 .root_store()
4502 .new_transaction(
4503 lock_keys![LockKey::object(
4504 store.store_object_id(),
4505 root_directory.object_id()
4506 )],
4507 Options::default(),
4508 )
4509 .await
4510 .expect("new_transaction failed");
4511 root_directory
4512 .create_child_file(&mut transaction, "test")
4513 .await
4514 .expect("create_child_file failed");
4515 transaction.commit().await.expect("commit failed");
4516
4517 crypt.shutdown();
4518 let mut transaction = fs
4519 .root_store()
4520 .new_transaction(
4521 lock_keys![LockKey::object(
4522 store.store_object_id(),
4523 root_directory.object_id()
4524 )],
4525 Options::default(),
4526 )
4527 .await
4528 .expect("new_transaction failed");
4529 root_directory
4530 .create_child_file(&mut transaction, "test2")
4531 .await
4532 .map(|_| ())
4533 .expect_err("create_child_file should fail");
4534 store.lock().await.expect("lock failed");
4535 store
4536 };
4537
4538 let crypt = Arc::new(new_insecure_crypt());
4539 if read_only {
4540 store.unlock_read_only(crypt).await.expect("unlock failed");
4541 } else {
4542 store.unlock(crypt).await.expect("unlock failed");
4543 }
4544 let root_directory =
4545 Directory::open(&store, store.root_directory_object_id()).await.expect("open failed");
4546 root_directory.lookup("test").await.expect("lookup failed").expect("not found");
4547 }
4548
4549 #[fuchsia::test(threads = 10)]
4550 async fn test_reopen_after_crypt_failure() {
4551 reopen_after_crypt_failure_inner(false).await;
4552 }
4553
4554 #[fuchsia::test(threads = 10)]
4555 async fn test_reopen_read_only_after_crypt_failure() {
4556 reopen_after_crypt_failure_inner(true).await;
4557 }
4558
4559 #[fuchsia::test(threads = 10)]
4560 #[should_panic(expected = "Insufficient reservation space")]
4561 #[cfg(debug_assertions)]
4562 async fn large_transaction_causes_panic_in_debug_builds() {
4563 let fs = test_filesystem().await;
4564 let root_volume = root_volume(fs.clone()).await.expect("root_volume failed");
4565 let store = root_volume
4566 .new_volume("vol", NewChildStoreOptions::default())
4567 .await
4568 .expect("new_volume failed");
4569 let root_directory =
4570 Directory::open(&store, store.root_directory_object_id()).await.expect("open failed");
4571 let mut transaction = fs
4572 .root_store()
4573 .new_transaction(
4574 lock_keys![LockKey::object(store.store_object_id(), root_directory.object_id())],
4575 Options::default(),
4576 )
4577 .await
4578 .expect("transaction");
4579 for i in 0..500 {
4580 root_directory
4581 .create_symlink(&mut transaction, b"link", &format!("{}", i))
4582 .await
4583 .expect("symlink");
4584 }
4585 assert_eq!(transaction.commit().await.expect("commit"), 0);
4586 }
4587
4588 #[fuchsia::test]
4589 async fn test_crypt_failure_does_not_fuse_journal() {
4590 let fs = test_filesystem().await;
4591
4592 {
4593 let root_volume = root_volume(fs.clone()).await.expect("root_volume failed");
4596 let store1 = root_volume
4597 .new_volume(
4598 "vol1",
4599 NewChildStoreOptions {
4600 options: StoreOptions {
4601 crypt: Some(Arc::new(new_insecure_crypt())),
4602 ..StoreOptions::default()
4603 },
4604 ..Default::default()
4605 },
4606 )
4607 .await
4608 .expect("new_volume failed");
4609 let crypt = Arc::new(new_insecure_crypt());
4610 let store2 = root_volume
4611 .new_volume(
4612 "vol2",
4613 NewChildStoreOptions {
4614 options: StoreOptions { crypt: Some(crypt.clone()) },
4615 ..Default::default()
4616 },
4617 )
4618 .await
4619 .expect("new_volume failed");
4620 for store in [&store1, &store2] {
4621 let root_directory = Directory::open(store, store.root_directory_object_id())
4622 .await
4623 .expect("open failed");
4624 let mut transaction = store
4625 .new_transaction(
4626 lock_keys![LockKey::object(
4627 store.store_object_id(),
4628 root_directory.object_id()
4629 )],
4630 Options::default(),
4631 )
4632 .await
4633 .expect("new_transaction failed");
4634 root_directory
4635 .create_child_file(&mut transaction, "test")
4636 .await
4637 .expect("create_child_file failed");
4638 transaction.commit().await.expect("commit failed");
4639 }
4640
4641 crypt.shutdown();
4643
4644 fs.journal().force_compact().await.expect("compact failed");
4647
4648 let root_directory2 = Directory::open(&store2, store2.root_directory_object_id())
4651 .await
4652 .expect("open failed");
4653 let (child_id, _, _) = root_directory2
4654 .lookup("test")
4655 .await
4656 .expect("lookup failed")
4657 .expect("test file not found");
4658 let mut transaction2 = store2
4659 .new_transaction(
4660 lock_keys![
4661 LockKey::object(store2.store_object_id(), root_directory2.object_id()),
4662 LockKey::object(store2.store_object_id(), child_id),
4663 ],
4664 Options::default(),
4665 )
4666 .await
4667 .expect("new_transaction failed");
4668 replace_child(&mut transaction2, None, (&root_directory2, "test"))
4669 .await
4670 .expect("replace_child failed");
4671 assert!(transaction2.commit().await.is_err());
4672
4673 let root_directory1 = Directory::open(&store1, store1.root_directory_object_id())
4675 .await
4676 .expect("open failed");
4677 let mut transaction1 = store1
4678 .new_transaction(
4679 lock_keys![LockKey::object(
4680 store1.store_object_id(),
4681 root_directory1.object_id()
4682 )],
4683 Options::default(),
4684 )
4685 .await
4686 .expect("new_transaction failed");
4687 root_directory1
4688 .create_child_file(&mut transaction1, "test2")
4689 .await
4690 .expect("create_child_file failed");
4691 transaction1.commit().await.expect("commit failed");
4692
4693 fs.journal().force_compact().await.expect("compact failed");
4695 }
4696
4697 fs.close().await.expect("close failed");
4699 let device = fs.take_device().await;
4700 device.reopen(false);
4701 let fs = FxFilesystem::open(device).await.expect("open failed");
4702 let root_volume = root_volume(fs.clone()).await.expect("root_volume failed");
4703
4704 let store1 = root_volume
4706 .volume(
4707 "vol1",
4708 StoreOptions {
4709 crypt: Some(Arc::new(new_insecure_crypt())),
4710 ..StoreOptions::default()
4711 },
4712 )
4713 .await
4714 .expect("volume failed");
4715 let root_directory1 =
4716 Directory::open(&store1, store1.root_directory_object_id()).await.expect("open failed");
4717 assert!(root_directory1.lookup("test").await.expect("lookup failed").is_some());
4718 assert!(root_directory1.lookup("test2").await.expect("lookup failed").is_some());
4719
4720 let store2 = root_volume
4722 .volume(
4723 "vol2",
4724 StoreOptions {
4725 crypt: Some(Arc::new(new_insecure_crypt())),
4726 ..StoreOptions::default()
4727 },
4728 )
4729 .await
4730 .expect("volume failed");
4731 let root_directory2 =
4732 Directory::open(&store2, store2.root_directory_object_id()).await.expect("open failed");
4733 assert!(root_directory2.lookup("test").await.expect("lookup failed").is_some());
4734 assert!(root_directory2.lookup("test2").await.expect("lookup failed").is_none());
4735
4736 fs.close().await.expect("close failed");
4737 }
4738
4739 #[fuchsia::test]
4740 async fn test_crypt_failure_during_unlock_race() {
4741 let fs = test_filesystem().await;
4742
4743 let store_object_id = {
4744 let root_volume = root_volume(fs.clone()).await.expect("root_volume failed");
4745 let store = root_volume
4746 .new_volume(
4747 "vol",
4748 NewChildStoreOptions {
4749 options: StoreOptions { crypt: Some(Arc::new(new_insecure_crypt())) },
4750 ..Default::default()
4751 },
4752 )
4753 .await
4754 .expect("new_volume failed");
4755 let root_directory = Directory::open(&store, store.root_directory_object_id())
4756 .await
4757 .expect("open failed");
4758 let mut transaction = fs
4759 .root_store()
4760 .new_transaction(
4761 lock_keys![LockKey::object(
4762 store.store_object_id(),
4763 root_directory.object_id()
4764 )],
4765 Options::default(),
4766 )
4767 .await
4768 .expect("new_transaction failed");
4769 root_directory
4770 .create_child_file(&mut transaction, "test")
4771 .await
4772 .expect("create_child_file failed");
4773 transaction.commit().await.expect("commit failed");
4774 store.store_object_id()
4775 };
4776
4777 fs.close().await.expect("close failed");
4778 let device = fs.take_device().await;
4779 device.reopen(false);
4780
4781 let fs = FxFilesystem::open(device).await.expect("open failed");
4782 {
4783 let fs_clone = fs.clone();
4784 let root_volume = root_volume(fs.clone()).await.expect("root_volume failed");
4785
4786 let crypt = Arc::new(new_insecure_crypt());
4787 let crypt_clone = crypt.clone();
4788 join!(
4789 async move {
4790 let _ =
4792 root_volume.volume("vol", StoreOptions { crypt: Some(crypt_clone) }).await;
4793 },
4794 async move {
4795 let keys = lock_keys![LockKey::flush(store_object_id)];
4798 let _ = fs_clone.lock_manager().write_lock(keys).await;
4799 crypt.shutdown();
4800 }
4801 );
4802 }
4803
4804 fs.close().await.expect("close failed");
4805 let device = fs.take_device().await;
4806 device.reopen(false);
4807
4808 let fs = FxFilesystem::open(device).await.expect("open failed");
4809 let root_volume = root_volume(fs.clone()).await.expect("root_volume failed");
4810 let store = root_volume
4811 .volume(
4812 "vol",
4813 StoreOptions {
4814 crypt: Some(Arc::new(new_insecure_crypt())),
4815 ..StoreOptions::default()
4816 },
4817 )
4818 .await
4819 .expect("open volume failed");
4820 let root_directory =
4821 Directory::open(&store, store.root_directory_object_id()).await.expect("open failed");
4822 assert!(root_directory.lookup("test").await.expect("lookup failed").is_some());
4823
4824 fs.close().await.expect("close failed");
4825 }
4826
4827 #[fuchsia::test]
4828 async fn test_low_32_bit_object_ids() {
4829 let device = DeviceHolder::new(FakeDevice::new(16384, TEST_DEVICE_BLOCK_SIZE));
4830 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
4831
4832 {
4833 let root_vol = root_volume(fs.clone()).await.expect("root_volume failed");
4834
4835 let store = root_vol
4836 .new_volume(
4837 "test",
4838 NewChildStoreOptions { low_32_bit_object_ids: true, ..Default::default() },
4839 )
4840 .await
4841 .expect("new_volume failed");
4842
4843 let root_dir = Directory::open(&store, store.root_directory_object_id())
4844 .await
4845 .expect("open failed");
4846
4847 let mut ids = std::collections::HashSet::new();
4848
4849 for i in 0..100 {
4850 let mut transaction = fs
4851 .root_store()
4852 .new_transaction(
4853 lock_keys![LockKey::object(store.store_object_id(), root_dir.object_id())],
4854 Options::default(),
4855 )
4856 .await
4857 .expect("new_transaction failed");
4858
4859 for j in 0..100 {
4860 let object = root_dir
4861 .create_child_dir(&mut transaction, &format!("{i}.{j}"))
4862 .await
4863 .expect("create_child_file failed");
4864
4865 assert!(object.object_id() < 1 << 32);
4866 assert_ne!(object.object_id(), INVALID_OBJECT_ID);
4867 assert!(ids.insert(object.object_id()));
4868 }
4869
4870 transaction.commit().await.expect("commit failed");
4871 }
4872
4873 assert_matches!(store.store_info().unwrap().last_object_id, LastObjectIdInfo::Low32Bit);
4874
4875 fsck_volume(&fs, store.store_object_id(), None).await.expect("fsck_volume failed");
4876 }
4877
4878 fs.close().await.expect("Close failed");
4880 let device = fs.take_device().await;
4881 device.reopen(false);
4882 let fs = FxFilesystem::open(device).await.expect("open failed");
4883 let root_vol = root_volume(fs.clone()).await.expect("root_volume failed");
4884 let store = root_vol.volume("test", StoreOptions::default()).await.expect("volume failed");
4885
4886 let root_dir =
4888 Directory::open(&store, store.root_directory_object_id()).await.expect("open failed");
4889 let mut transaction = fs
4890 .root_store()
4891 .new_transaction(
4892 lock_keys![LockKey::object(store.store_object_id(), root_dir.object_id())],
4893 Options::default(),
4894 )
4895 .await
4896 .expect("new_transaction failed");
4897
4898 let object = root_dir
4899 .create_child_file(&mut transaction, "persistence_check")
4900 .await
4901 .expect("create_child_file failed");
4902 assert!(object.object_id() < 1 << 32);
4903
4904 transaction.commit().await.expect("commit failed");
4905
4906 assert_matches!(store.store_info().unwrap().last_object_id, LastObjectIdInfo::Low32Bit);
4907 }
4908
4909 #[fuchsia::test]
4910 async fn test_mutations_key_roll_during_flush() {
4911 let device = DeviceHolder::new(FakeDevice::new(16384, TEST_DEVICE_BLOCK_SIZE));
4912 let fs = FxFilesystemBuilder::new()
4913 .format(true)
4914 .roll_metadata_key_byte_count(2048)
4915 .open(device)
4916 .await
4917 .expect("open failed");
4918
4919 let crypt = Arc::new(new_insecure_crypt());
4920
4921 {
4922 let root_vol = root_volume(fs.clone()).await.expect("root_volume failed");
4923 let store = root_vol
4924 .new_volume(
4925 "test",
4926 NewChildStoreOptions {
4927 options: StoreOptions {
4928 crypt: Some(crypt.clone()),
4929 ..StoreOptions::default()
4930 },
4931 ..Default::default()
4932 },
4933 )
4934 .await
4935 .expect("new_volume failed");
4936
4937 let root_dir = Directory::open(&store, store.root_directory_object_id())
4938 .await
4939 .expect("open failed");
4940
4941 let mut last_offset = 0;
4942 loop {
4943 let offset = store.mutations_cipher.lock().as_ref().unwrap().offset();
4944 if offset >= 2048 {
4945 break;
4946 }
4947 if offset < last_offset {
4948 panic!("Key rolled during setup loop");
4949 }
4950 last_offset = offset;
4951
4952 let mut transaction = fs
4953 .root_store()
4954 .new_transaction(
4955 lock_keys![LockKey::object(store.store_object_id(), root_dir.object_id())],
4956 Options::default(),
4957 )
4958 .await
4959 .expect("new_transaction failed");
4960 let name = format!("file_{offset}");
4961 root_dir
4962 .create_child_file(&mut transaction, &name)
4963 .await
4964 .expect("create_child_file failed");
4965 transaction.commit().await.expect("commit failed");
4966 }
4967
4968 store.flush().await.expect("flush failed");
4969
4970 fs.journal().force_compact().await.expect("compact failed");
4974
4975 let mut transaction = fs
4977 .root_store()
4978 .new_transaction(
4979 lock_keys![LockKey::object(store.store_object_id(), root_dir.object_id())],
4980 Options::default(),
4981 )
4982 .await
4983 .expect("new_transaction failed");
4984 let name = "file_after_flush";
4985 root_dir
4986 .create_child_file(&mut transaction, &name)
4987 .await
4988 .expect("create_child_file failed");
4989 transaction.commit().await.expect("commit failed");
4990 }
4991
4992 fs.close().await.expect("Close failed");
4993 let device = fs.take_device().await;
4994 device.reopen(false);
4995
4996 let fs = FxFilesystem::open(device).await.expect("open failed");
4997
4998 {
4999 let root_vol = root_volume(fs.clone()).await.expect("root_volume failed");
5000 let store = root_vol
5001 .volume("test", StoreOptions { crypt: Some(crypt), ..StoreOptions::default() })
5002 .await
5003 .expect("volume failed");
5004
5005 let root_dir = Directory::open(&store, store.root_directory_object_id())
5006 .await
5007 .expect("open failed");
5008
5009 let child = root_dir.lookup("file_after_flush").await.expect("lookup failed");
5010 assert!(child.is_some(), "file_after_flush missing!");
5011 }
5012 fs.close().await.expect("Close failed");
5013 }
5014
5015 struct StallingCrypt {
5016 delegate: Arc<dyn Crypt>,
5017 unwrap_stall_counter: AtomicIsize,
5018 unwrap_stalled_tx: Mutex<Option<oneshot::Sender<oneshot::Sender<()>>>>,
5019 create_key_stalled_tx: Mutex<Option<oneshot::Sender<oneshot::Sender<()>>>>,
5020 }
5021
5022 impl StallingCrypt {
5023 fn new(delegate: Arc<dyn Crypt>) -> Self {
5024 Self {
5025 delegate,
5026 unwrap_stall_counter: AtomicIsize::new(-1),
5027 unwrap_stalled_tx: Mutex::new(None),
5028 create_key_stalled_tx: Mutex::new(None),
5029 }
5030 }
5031
5032 fn stall_on_unwrap(
5033 self: &Arc<Self>,
5034 index: usize,
5035 ) -> oneshot::Receiver<oneshot::Sender<()>> {
5036 let (tx, rx) = oneshot::channel();
5037 self.unwrap_stall_counter.store(index as isize, Ordering::Relaxed);
5038 *self.unwrap_stalled_tx.lock() = Some(tx);
5039 rx
5040 }
5041
5042 fn stall_on_create_key(self: &Arc<Self>) -> oneshot::Receiver<oneshot::Sender<()>> {
5043 let (tx, rx) = oneshot::channel();
5044 *self.create_key_stalled_tx.lock() = Some(tx);
5045 rx
5046 }
5047 }
5048
5049 #[async_trait]
5050 impl Crypt for StallingCrypt {
5051 async fn create_key(
5052 &self,
5053 owner: u64,
5054 purpose: KeyPurpose,
5055 ) -> Result<(FxfsKey, UnwrappedKey), zx::Status> {
5056 if matches!(purpose, KeyPurpose::Data) {
5057 let stalled_tx = self.create_key_stalled_tx.lock().take();
5058 if let Some(tx) = stalled_tx {
5059 let (continue_tx, continue_rx) = oneshot::channel();
5060 let _ = tx.send(continue_tx);
5061 let _ = continue_rx.await;
5062 }
5063 }
5064 self.delegate.create_key(owner, purpose).await
5065 }
5066
5067 async fn unwrap_key(
5068 &self,
5069 wrapped_key: &WrappedKey,
5070 owner: u64,
5071 ) -> Result<UnwrappedKey, zx::Status> {
5072 let count = self.unwrap_stall_counter.fetch_sub(1, Ordering::Relaxed);
5073 log::info!("unwrap_key called, count was {}, owner {}", count, owner);
5074 if count == 0 {
5075 log::info!("unwrap_key stalling");
5076 let stalled_tx = self.unwrap_stalled_tx.lock().take();
5077 if let Some(tx) = stalled_tx {
5078 let (continue_tx, continue_rx) = oneshot::channel();
5079 let _ = tx.send(continue_tx);
5080 let _ = continue_rx.await;
5081 }
5082 log::info!("unwrap_key resumed");
5083 }
5084 self.delegate.unwrap_key(wrapped_key, owner).await
5085 }
5086
5087 async fn create_key_with_id(
5088 &self,
5089 owner: u64,
5090 wrapping_key_id: WrappingKeyId,
5091 object_type: ObjectType,
5092 ) -> Result<(EncryptionKey, UnwrappedKey), zx::Status> {
5093 self.delegate.create_key_with_id(owner, wrapping_key_id, object_type).await
5094 }
5095 }
5096
5097 #[fuchsia::test]
5098 async fn test_fsck_during_key_pre_cache_stall() {
5099 let device = DeviceHolder::new(FakeDevice::new(16384, TEST_DEVICE_BLOCK_SIZE));
5100 let fs = FxFilesystemBuilder::new().format(true).open(device).await.expect("open failed");
5101
5102 let crypt = Arc::new(StallingCrypt::new(Arc::new(new_insecure_crypt())));
5104
5105 let root_vol = root_volume(fs.clone()).await.expect("root_volume failed");
5106 let store = root_vol
5107 .new_volume(
5108 "test",
5109 NewChildStoreOptions {
5110 options: StoreOptions { crypt: Some(crypt.clone()), ..StoreOptions::default() },
5111 ..Default::default()
5112 },
5113 )
5114 .await
5115 .expect("new_volume failed");
5116
5117 let stalled_rx = crypt.stall_on_create_key();
5119
5120 {
5123 let mut lock_state = store.lock_state.lock();
5124 if let super::LockState::Unlocked { cached_keys, .. } = &mut *lock_state {
5125 cached_keys.clear();
5126 }
5127 }
5128
5129 let store_clone = store.clone();
5132 let root_dir_id = store.root_directory_object_id();
5133
5134 let tx_join_handle = fasync::Task::spawn(async move {
5135 let root_dir = Directory::open(&store_clone, root_dir_id).await.expect("open failed");
5136 let mut transaction = store_clone
5137 .new_transaction(
5138 lock_keys![LockKey::object(
5139 store_clone.store_object_id(),
5140 root_dir.object_id()
5141 )],
5142 Options::default(),
5143 )
5144 .await
5145 .expect("new_transaction failed");
5146 let name = "foo";
5147 root_dir
5148 .create_child_file(&mut transaction, name)
5149 .await
5150 .expect("create_child_file failed");
5151 transaction.commit().await.expect("commit failed");
5152 });
5153
5154 let continue_tx = stalled_rx.await.expect("stalled_rx failed");
5156
5157 fsck(fs.clone()).await.expect("fsck failed");
5159
5160 let _ = continue_tx.send(());
5162 tx_join_handle.await;
5163
5164 fs.close().await.expect("Close failed");
5165 }
5166
5167 #[fuchsia::test]
5168 async fn test_writes_to_other_store_not_blocked_by_stall() {
5169 let device = DeviceHolder::new(FakeDevice::new(16384, TEST_DEVICE_BLOCK_SIZE));
5170 let fs = FxFilesystemBuilder::new()
5171 .format(true)
5172 .journal_options(JournalOptions { reclaim_size: 32_768, ..Default::default() })
5173 .open(device)
5174 .await
5175 .expect("open failed");
5176
5177 let crypt1 = Arc::new(StallingCrypt::new(Arc::new(new_insecure_crypt())));
5180
5181 let crypt2 = Arc::new(new_insecure_crypt());
5183
5184 let root_vol = root_volume(fs.clone()).await.expect("root_volume failed");
5185
5186 let store1 = root_vol
5187 .new_volume(
5188 "test1",
5189 NewChildStoreOptions {
5190 options: StoreOptions {
5191 crypt: Some(crypt1.clone()),
5192 ..StoreOptions::default()
5193 },
5194 ..Default::default()
5195 },
5196 )
5197 .await
5198 .expect("new_volume failed");
5199
5200 store1.flush().await.expect("flush failed");
5201
5202 let store2 = root_vol
5203 .new_volume(
5204 "test2",
5205 NewChildStoreOptions {
5206 options: StoreOptions {
5207 crypt: Some(crypt2.clone()),
5208 ..StoreOptions::default()
5209 },
5210 ..Default::default()
5211 },
5212 )
5213 .await
5214 .expect("new_volume failed");
5215
5216 let stalled_rx = crypt1.stall_on_create_key();
5218
5219 {
5221 let mut lock_state = store1.lock_state.lock();
5222 if let super::LockState::Unlocked { cached_keys, .. } = &mut *lock_state {
5223 cached_keys.clear();
5224 }
5225 }
5226
5227 let store1_clone = store1.clone();
5230 let root_dir1_id = store1.root_directory_object_id();
5231
5232 let tx_join_handle = fasync::Task::spawn(async move {
5233 let root_dir1 =
5234 Directory::open(&store1_clone, root_dir1_id).await.expect("open failed");
5235 let mut transaction = store1_clone
5236 .new_transaction(
5237 lock_keys![LockKey::object(
5238 store1_clone.store_object_id(),
5239 root_dir1.object_id()
5240 )],
5241 Options::default(),
5242 )
5243 .await
5244 .expect("new_transaction failed");
5245 root_dir1
5246 .create_child_file(&mut transaction, "foo")
5247 .await
5248 .expect("create_child_file failed");
5249 transaction.commit().await.expect("commit failed");
5250 });
5251
5252 let continue_tx = stalled_rx.await.expect("stalled_rx failed");
5254
5255 let root_dir2 =
5257 Directory::open(&store2, store2.root_directory_object_id()).await.expect("open failed");
5258 let long_name = "a".repeat(255);
5259 let mut i = 0;
5260 while store2.counters.lock().num_flushes < 3 {
5261 if i > 200 {
5262 panic!(
5263 "Failed to trigger 3 compactions after 200 transactions. Flushes: {}",
5264 store2.counters.lock().num_flushes
5265 );
5266 }
5267 let mut transaction = store2
5268 .new_transaction(
5269 lock_keys![LockKey::object(store2.store_object_id(), root_dir2.object_id())],
5270 Options::default(),
5271 )
5272 .await
5273 .expect("new_transaction failed");
5274 root_dir2
5275 .create_child_file(&mut transaction, &format!("{}-{:03}", long_name, i))
5276 .await
5277 .expect("create_child_file failed");
5278 transaction.commit().await.expect("commit failed");
5279 i += 1;
5280 fasync::Timer::new(std::time::Duration::from_millis(5)).await;
5281 }
5282
5283 let _ = continue_tx.send(());
5285 tx_join_handle.await;
5286
5287 fs.close().await.expect("Close failed");
5288 }
5289
5290 #[fuchsia::test]
5291 async fn test_concurrent_transactions_exhaust_cached_keys() {
5292 let fs = test_filesystem().await;
5293
5294 let root_volume = root_volume(fs.clone()).await.expect("root_volume failed");
5295 let crypt = Arc::new(new_insecure_crypt());
5296 let store = root_volume
5297 .new_volume(
5298 "vol",
5299 NewChildStoreOptions {
5300 options: StoreOptions { crypt: Some(crypt.clone()), ..Default::default() },
5301 ..Default::default()
5302 },
5303 )
5304 .await
5305 .expect("new_volume failed");
5306
5307 let root_directory =
5308 Directory::open(&store, store.root_directory_object_id()).await.expect("open failed");
5309
5310 let mut transaction = store
5313 .new_transaction(
5314 lock_keys![LockKey::object(store.store_object_id(), root_directory.object_id())],
5315 Options::default(),
5316 )
5317 .await
5318 .expect("new_transaction failed");
5319 let dir1 = root_directory
5320 .create_child_dir(&mut transaction, "dir1")
5321 .await
5322 .expect("create_child_dir failed");
5323 let dir2 = root_directory
5324 .create_child_dir(&mut transaction, "dir2")
5325 .await
5326 .expect("create_child_dir failed");
5327 let dir3 = root_directory
5328 .create_child_dir(&mut transaction, "dir3")
5329 .await
5330 .expect("create_child_dir failed");
5331 transaction.commit().await.expect("commit failed");
5332
5333 let mut transaction1 = store
5339 .new_transaction(
5340 lock_keys![LockKey::object(store.store_object_id(), dir1.object_id())],
5341 Options::default(),
5342 )
5343 .await
5344 .expect("new_transaction 1 failed");
5345 dir1.create_child_file(&mut transaction1, "file1")
5346 .await
5347 .expect("create_child_file 1 failed");
5348
5349 let mut transaction2 = store
5351 .new_transaction(
5352 lock_keys![LockKey::object(store.store_object_id(), dir2.object_id())],
5353 Options::default(),
5354 )
5355 .await
5356 .expect("new_transaction 2 failed");
5357 dir2.create_child_file(&mut transaction2, "file2")
5358 .await
5359 .expect("create_child_file 2 failed");
5360
5361 let mut transaction3 = store
5363 .new_transaction(
5364 lock_keys![LockKey::object(store.store_object_id(), dir3.object_id())],
5365 Options::default(),
5366 )
5367 .await
5368 .expect("new_transaction 3 failed");
5369 dir3.create_child_file(&mut transaction3, "file3")
5370 .await
5371 .expect("create_child_file 3 failed");
5372
5373 crypt.shutdown();
5375
5376 transaction1.commit().await.expect("commit 1 failed");
5378 fs.journal().force_compact().await.expect("compact 1 failed");
5379
5380 assert!(transaction2.commit().await.is_err());
5383
5384 fs.close().await.expect("Close failed");
5385 }
5386
5387 #[fuchsia::test(threads = 10)]
5388 async fn test_key_exhaustion_race() {
5389 let fs = test_filesystem().await;
5390
5391 let root_volume = root_volume(fs.clone()).await.expect("root_volume failed");
5392 let crypt = Arc::new(new_insecure_crypt());
5393 let store = root_volume
5394 .new_volume(
5395 "vol",
5396 NewChildStoreOptions {
5397 options: StoreOptions { crypt: Some(crypt.clone()), ..Default::default() },
5398 ..Default::default()
5399 },
5400 )
5401 .await
5402 .expect("new_volume failed");
5403
5404 let root_directory =
5405 Directory::open(&store, store.root_directory_object_id()).await.expect("open failed");
5406
5407 let mut transaction = store
5409 .new_transaction(
5410 lock_keys![LockKey::object(store.store_object_id(), root_directory.object_id())],
5411 Options::default(),
5412 )
5413 .await
5414 .expect("new_transaction failed");
5415 root_directory
5416 .create_child_dir(&mut transaction, "dir")
5417 .await
5418 .expect("create_child_dir failed");
5419 transaction.commit().await.expect("commit failed");
5420
5421 let fs_clone = fs.clone();
5422 let in_hook = Arc::new(Mutex::new(false));
5423 let _guard = crate::filesystem::CALLBACK_BEFORE_COMMIT.set(move || {
5424 {
5425 let mut in_hook = in_hook.lock();
5426 if *in_hook {
5427 return;
5428 }
5429 *in_hook = true;
5430 }
5431 let fs = fs_clone.clone();
5432
5433 futures::executor::block_on(fs.journal().force_compact()).expect("compact failed");
5437 });
5438
5439 let mut transaction = store
5442 .new_transaction(
5443 lock_keys![LockKey::object(store.store_object_id(), root_directory.object_id())],
5444 Options::default(),
5445 )
5446 .await
5447 .expect("new_transaction failed");
5448 root_directory
5449 .create_child_file(&mut transaction, "file1")
5450 .await
5451 .expect("create_child_file failed");
5452
5453 transaction.commit().await.expect("commit failed");
5462
5463 fs.journal().force_compact().await.expect("compaction failed");
5468
5469 fs.close().await.expect("Close failed");
5470 }
5471
5472 #[fuchsia::test(threads = 10)]
5473 async fn test_unlock_pre_cache_stall_does_not_block_other_stores() {
5474 let device = DeviceHolder::new(FakeDevice::new(16384, TEST_DEVICE_BLOCK_SIZE));
5475 let fs = FxFilesystemBuilder::new()
5476 .format(true)
5477 .journal_options(JournalOptions { reclaim_size: 32_768, ..Default::default() })
5478 .open(device)
5479 .await
5480 .expect("open failed");
5481
5482 let crypt1 = Arc::new(StallingCrypt::new(Arc::new(new_insecure_crypt())));
5483 let crypt2 = Arc::new(new_insecure_crypt());
5484
5485 let root_vol = root_volume(fs.clone()).await.expect("root_volume failed");
5486
5487 let store1 = root_vol
5488 .new_volume(
5489 "test1",
5490 NewChildStoreOptions {
5491 options: StoreOptions {
5492 crypt: Some(crypt1.clone()),
5493 ..StoreOptions::default()
5494 },
5495 ..Default::default()
5496 },
5497 )
5498 .await
5499 .expect("new_volume failed");
5500
5501 {
5503 let mut transaction = store1
5504 .new_transaction(
5505 lock_keys![LockKey::object(
5506 store1.store_object_id(),
5507 store1.root_directory_object_id()
5508 )],
5509 Options::default(),
5510 )
5511 .await
5512 .expect("new_transaction failed");
5513 let root_dir1 = Directory::open(&store1, store1.root_directory_object_id())
5514 .await
5515 .expect("open failed");
5516 root_dir1
5517 .create_child_file(&mut transaction, "foo")
5518 .await
5519 .expect("create_child_file failed");
5520 transaction.commit().await.expect("commit failed");
5521 }
5522 store1.lock().await.expect("lock failed");
5523
5524 let store2 = root_vol
5525 .new_volume(
5526 "test2",
5527 NewChildStoreOptions {
5528 options: StoreOptions {
5529 crypt: Some(crypt2.clone()),
5530 ..StoreOptions::default()
5531 },
5532 ..Default::default()
5533 },
5534 )
5535 .await
5536 .expect("new_volume failed");
5537
5538 let stalled_rx = crypt1.stall_on_create_key();
5540
5541 let store1_clone = store1.clone();
5544 let crypt1_clone = crypt1.clone();
5545 let unlock_join_handle = fasync::Task::spawn(async move {
5546 store1_clone.unlock(crypt1_clone).await.expect("unlock failed");
5547 });
5548
5549 let continue_tx = stalled_rx.await.expect("stalled_rx failed");
5551
5552 let root_dir2 =
5555 Directory::open(&store2, store2.root_directory_object_id()).await.expect("open failed");
5556 let long_name = "a".repeat(255);
5557 let mut i = 0;
5558 while store2.counters.lock().num_flushes < 3 {
5559 if i > 200 {
5560 panic!(
5561 "Failed to trigger 3 compactions after 200 transactions. Flushes: {}",
5562 store2.counters.lock().num_flushes
5563 );
5564 }
5565 let mut transaction = store2
5566 .new_transaction(
5567 lock_keys![LockKey::object(store2.store_object_id(), root_dir2.object_id())],
5568 Options::default(),
5569 )
5570 .await
5571 .expect("new_transaction failed");
5572 root_dir2
5573 .create_child_file(&mut transaction, &format!("{}-{:03}", long_name, i))
5574 .await
5575 .expect("create_child_file failed");
5576 transaction.commit().await.expect("commit failed");
5577 i += 1;
5578 fasync::Timer::new(std::time::Duration::from_millis(5)).await;
5579 }
5580
5581 let _ = continue_tx.send(());
5583 unlock_join_handle.await;
5584
5585 fs.close().await.expect("Close failed");
5586 }
5587
5588 async fn run_unlock_stall_test(unwrap_stall_index: usize) -> bool {
5589 log::info!("Starting run_unlock_stall_test for index {}", unwrap_stall_index);
5590 let device = DeviceHolder::new(FakeDevice::new(16384, TEST_DEVICE_BLOCK_SIZE));
5591 let crypt1 = Arc::new(new_insecure_crypt());
5592 let crypt2 = Arc::new(new_insecure_crypt());
5593 let (store1_id, device) = {
5594 let fs = FxFilesystemBuilder::new()
5595 .format(true)
5596 .roll_metadata_key_byte_count(128)
5597 .journal_options(JournalOptions { reclaim_size: 32_768, ..Default::default() })
5598 .open(device)
5599 .await
5600 .expect("open failed");
5601
5602 let store1_id = {
5603 let root_vol = root_volume(fs.clone()).await.expect("root_volume failed");
5604
5605 let store1 = root_vol
5606 .new_volume(
5607 "test1",
5608 NewChildStoreOptions {
5609 options: StoreOptions {
5610 crypt: Some(crypt1.clone()),
5611 ..StoreOptions::default()
5612 },
5613 ..Default::default()
5614 },
5615 )
5616 .await
5617 .expect("new_volume failed");
5618
5619 root_vol
5620 .new_volume(
5621 "test2",
5622 NewChildStoreOptions {
5623 options: StoreOptions {
5624 crypt: Some(crypt2.clone()),
5625 ..StoreOptions::default()
5626 },
5627 ..Default::default()
5628 },
5629 )
5630 .await
5631 .expect("new_volume failed");
5632
5633 let root_dir1 = Directory::open(&store1, store1.root_directory_object_id())
5635 .await
5636 .expect("open failed");
5637
5638 let mut last_offset = 0;
5639 loop {
5640 let offset = store1.mutations_cipher.lock().as_ref().unwrap().offset();
5641 if offset >= 128 {
5642 break;
5643 }
5644 assert!(offset >= last_offset);
5645 last_offset = offset;
5646
5647 let mut transaction = store1
5648 .new_transaction(
5649 lock_keys![LockKey::object(
5650 store1.store_object_id(),
5651 root_dir1.object_id()
5652 )],
5653 Options::default(),
5654 )
5655 .await
5656 .expect("new_transaction failed");
5657 let name = format!("file_{offset}");
5658 root_dir1
5659 .create_child_file(&mut transaction, &name)
5660 .await
5661 .expect("create_child_file failed");
5662 transaction.commit().await.expect("commit failed");
5663 }
5664
5665 store1.flush().await.expect("flush failed");
5667
5668 {
5671 let mut transaction = store1
5672 .new_transaction(
5673 lock_keys![LockKey::object(
5674 store1.store_object_id(),
5675 root_dir1.object_id()
5676 )],
5677 Options::default(),
5678 )
5679 .await
5680 .expect("new_transaction failed");
5681 root_dir1
5682 .create_child_file(&mut transaction, "file_after_flush")
5683 .await
5684 .expect("create_child_file failed");
5685 transaction.commit().await.expect("commit failed");
5686 }
5687 store1.store_object_id()
5688 };
5689
5690 fs.close().await.expect("Close failed");
5691 let device = fs.take_device().await;
5692 (store1_id, device)
5693 };
5694 device.reopen(false);
5695
5696 log::info!("Opening filesystem");
5697 let fs = FxFilesystemBuilder::new()
5698 .journal_options(JournalOptions { reclaim_size: 32_768, ..Default::default() })
5699 .open(device)
5700 .await
5701 .expect("open failed");
5702 log::info!("Opened filesystem, getting root volume");
5703 let root_vol = root_volume(fs.clone()).await.expect("root_volume failed");
5704 log::info!("Got root volume");
5705
5706 log::info!("Re-opening store2");
5707 let store2 = root_vol
5709 .volume("test2", StoreOptions { crypt: Some(crypt2), ..StoreOptions::default() })
5710 .await
5711 .expect("volume failed");
5712 log::info!("Re-opened store2");
5713
5714 let stalling_crypt1 = Arc::new(StallingCrypt::new(crypt1));
5716 let stalled_rx = stalling_crypt1.stall_on_unwrap(unwrap_stall_index);
5717
5718 let store1 = fs.object_manager().store(store1_id).unwrap();
5720
5721 log::info!("Spawning store1 unlock task");
5722 let store1_clone = store1.clone();
5724 let stalling_crypt1_clone = stalling_crypt1.clone();
5725 let unlock_join_handle = fasync::Task::spawn(async move {
5726 log::info!("store1 unlock task started");
5727 store1_clone.unlock(stalling_crypt1_clone).await.expect("unlock failed");
5728 log::info!("store1 unlock task finished");
5729 });
5730
5731 let continue_tx = futures::select! {
5733 res = stalled_rx.fuse() => {
5734 log::info!("Stalled at index {}", unwrap_stall_index);
5735 Some(res.expect("stalled_rx failed"))
5736 }
5737 _ = unlock_join_handle.fuse() => {
5738 log::info!("Unlock completed without stalling at index {}", unwrap_stall_index);
5739 None
5740 }
5741 };
5742
5743 let stalled = continue_tx.is_some();
5744
5745 if let Some(continue_tx) = continue_tx {
5746 log::info!("Writing to store2 while stalled at index {}", unwrap_stall_index);
5747 let root_dir2 = Directory::open(&store2, store2.root_directory_object_id())
5749 .await
5750 .expect("open failed");
5751 let long_name = "a".repeat(255);
5752 let mut i = 0;
5753 while store2.counters.lock().num_flushes < 3 {
5754 if i > 200 {
5755 panic!(
5756 "Failed to trigger 3 compactions after 200 transactions. Flushes: {}",
5757 store2.counters.lock().num_flushes
5758 );
5759 }
5760 let mut transaction = store2
5761 .new_transaction(
5762 lock_keys![LockKey::object(
5763 store2.store_object_id(),
5764 root_dir2.object_id()
5765 )],
5766 Options::default(),
5767 )
5768 .await
5769 .expect("new_transaction failed");
5770 root_dir2
5771 .create_child_file(&mut transaction, &format!("{}-{:03}", long_name, i))
5772 .await
5773 .expect("create_child_file failed");
5774 transaction.commit().await.expect("commit failed");
5775 i += 1;
5776 fasync::Timer::new(std::time::Duration::from_millis(5)).await;
5777 }
5778
5779 log::info!("Unblocking store1 at index {}", unwrap_stall_index);
5780 let _ = continue_tx.send(());
5782 }
5783
5784 fs.close().await.expect("Close failed");
5785 log::info!(
5786 "Finished run_unlock_stall_test for index {}, stalled: {}",
5787 unwrap_stall_index,
5788 stalled
5789 );
5790 stalled
5791 }
5792
5793 #[fuchsia::test(threads = 10)]
5794 async fn test_unlock_replay_stall_does_not_block_other_stores() {
5795 let mut unwrap_stall_index = 0;
5796 loop {
5797 let stalled = run_unlock_stall_test(unwrap_stall_index).await;
5798 if !stalled {
5799 break;
5800 }
5801 unwrap_stall_index += 1;
5802 }
5803 }
5804
5805 #[fuchsia::test(threads = 10)]
5806 async fn test_unlock_flush_race() {
5807 let device = DeviceHolder::new(FakeDevice::new(16384, TEST_DEVICE_BLOCK_SIZE));
5808 let crypt = Arc::new(new_insecure_crypt());
5809
5810 let (store1_id, device) = {
5812 let (store1_id, fs) = {
5813 let fs = FxFilesystemBuilder::new()
5814 .format(true)
5815 .open(device)
5816 .await
5817 .expect("open failed");
5818 let root_vol = root_volume(fs.clone()).await.expect("root_volume failed");
5819 let store1 = root_vol
5820 .new_volume(
5821 "test1",
5822 NewChildStoreOptions {
5823 options: StoreOptions {
5824 crypt: Some(crypt.clone()),
5825 ..StoreOptions::default()
5826 },
5827 ..Default::default()
5828 },
5829 )
5830 .await
5831 .expect("new_volume failed");
5832
5833 let root_dir = Directory::open(&store1, store1.root_directory_object_id())
5834 .await
5835 .expect("open failed");
5836 let mut transaction = store1
5837 .new_transaction(
5838 lock_keys![LockKey::object(store1.store_object_id(), root_dir.object_id())],
5839 Options::default(),
5840 )
5841 .await
5842 .expect("new_transaction failed");
5843 root_dir
5844 .create_child_file(&mut transaction, "file1")
5845 .await
5846 .expect("create_child_file failed");
5847 transaction.commit().await.expect("commit failed");
5848
5849 (store1.store_object_id(), fs)
5850 };
5851 fs.close().await.expect("Close failed");
5852 let device = fs.take_device().await;
5853 (store1_id, device)
5854 };
5855 device.reopen(false);
5856
5857 let fs = FxFilesystemBuilder::new().open(device).await.expect("open failed");
5859
5860 let store1 = fs.object_manager().store(store1_id).unwrap();
5861
5862 let store1_clone = store1.clone();
5865 let _guard = CALLBACK_UNLOCK_RESOURCES_ACQUIRED.set(move || {
5866 futures::executor::block_on(store1_clone.flush()).expect("flush failed");
5867 });
5868
5869 store1.unlock(crypt).await.expect("unlock failed");
5870
5871 fs.journal().force_compact().await.expect("compact failed");
5872
5873 fsck(fs.clone()).await.expect("fsck failed");
5874
5875 fs.close().await.expect("Close failed");
5876 }
5877}