1pub mod allocator;
6pub mod caching_object_handle;
7pub mod data_object_handle;
8pub mod directory;
9pub mod extent;
10mod extent_mapping_iterator;
11mod extent_record;
12pub mod flush;
13use crate::filesystem::FlushReason;
14pub mod graveyard;
15mod install;
16pub mod journal;
17mod key_manager;
18pub(crate) mod merge;
19pub mod object_manager;
20pub mod object_record;
21pub mod project_id;
22mod store_object_handle;
23pub mod transaction;
24mod tree;
25mod tree_cache;
26pub mod volume;
27
28pub use data_object_handle::{
29 DataObjectHandle, DataObjectState, DirectWriter, FileExtent, FsverityStateInner, RangeType,
30};
31pub use directory::Directory;
32pub use object_record::{ChildValue, DirType, ObjectDescriptor, PosixAttributes, Timestamp};
33pub use store_object_handle::{MAX_INLINE_XATTR_SIZE, SetExtendedAttributeMode, StoreObjectHandle};
34
35use crate::errors::FxfsError;
36use crate::filesystem::{
37 ApplyContext, ApplyMode, FxFilesystem, JournalingObject, MAX_FILE_SIZE, SyncOptions,
38 TruncateGuard,
39};
40use crate::log::*;
41use crate::lsm_tree::cache::ObjectCache;
42use crate::lsm_tree::types::{Existence, Item, ItemRef, LayerIterator};
43use crate::lsm_tree::{LSMTree, Query, open_layers};
44use crate::object_handle::{INVALID_OBJECT_ID, ObjectHandle, ObjectProperties, ReadObjectHandle};
45use crate::object_store::allocator::Allocator;
46use crate::object_store::graveyard::Graveyard;
47use crate::object_store::journal::{JournalCheckpoint, JournalCheckpointV32, JournaledTransaction};
48use crate::object_store::key_manager::KeyManager;
49use crate::object_store::transaction::{
50 AssocObj, AssociatedObject, LockKey, LockKeys, ObjectMutationIterator, ObjectStoreMutation,
51 Operation, Options, Transaction, WriteGuard, lock_keys,
52};
53use crate::serialized_types::{
54 AES_JOURNAL_ENCRYPTION_VERSION, DEFAULT_MAX_SERIALIZED_RECORD_SIZE, Version, Versioned,
55 VersionedLatest,
56};
57use anyhow::{Context, Error, anyhow, bail, ensure};
58use async_trait::async_trait;
59use fidl_fuchsia_io as fio;
60use fprint::TypeFingerprint;
61use fuchsia_sync::Mutex;
62use fxfs_crypto::ff1::Ff1;
63use fxfs_crypto::{
64 CipherHolder, Crypt, JournalCipher, JournalXtsCipher, KeyPurpose, ObjectType, StreamCipher,
65 UnwrappedKey, WrappingKeyId, key_to_cipher,
66};
67use rand::Rng as _;
68use scopeguard::ScopeGuard;
69use serde::{Deserialize, Serialize};
70use std::collections::HashSet;
71use std::fmt;
72use std::num::NonZero;
73use std::sync::atomic::{AtomicBool, AtomicU64, Ordering};
74use std::sync::{Arc, OnceLock, Weak};
75use storage_device::Device;
76use storage_units::BlockSize;
77use uuid::Uuid;
78
79pub use extent::Extent;
80pub use extent_record::{ExtentMode, ExtentValue};
81pub use object_record::{
82 AttributeId, AttributeKey, EncryptionKey, EncryptionKeys, ExtendedAttributeValue,
83 FsverityMetadata, FxfsKey, FxfsKeyV49, ObjectAttributes, ObjectKey, ObjectKeyData, ObjectKind,
84 ObjectValue, ProjectProperty, RootDigest,
85};
86pub use project_id::{ProjectId, ProjectIdExt};
87pub use transaction::Mutation;
88
89const OBJECT_ID_HI_MASK: u64 = 0xffffffff00000000;
92
93const TRANSACTION_MUTATION_THRESHOLD: usize = 200;
95
96const CACHED_KEYS_LIMIT: usize = 2;
104
105pub const VOLUME_DATA_KEY_ID: u64 = 0;
111pub const FSCRYPT_KEY_ID: u64 = 1;
112
113pub trait HandleOwner: AsRef<ObjectStore> + Send + Sync + 'static {}
116
117pub type StoreInfo = StoreInfoV52;
120
121#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize, TypeFingerprint, Versioned)]
122pub struct StoreInfoV52 {
123 guid: [u8; 16],
125
126 last_object_id: LastObjectIdInfo,
132
133 pub layers: Vec<u64>,
136
137 root_directory_object_id: u64,
139
140 graveyard_directory_object_id: u64,
142
143 object_count: u64,
146
147 mutations_key: Option<FxfsKeyV49>,
149
150 mutations_cipher_offset: u64,
153
154 pub encrypted_mutations_object_id: u64,
157
158 internal_directory_object_id: u64,
161}
162
163#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, TypeFingerprint)]
164enum LastObjectIdInfo {
165 Unencrypted {
166 id: u64,
167 },
168 Encrypted {
169 id: u64,
171
172 key: FxfsKeyV49,
177 },
178 Low32Bit,
179}
180
181impl Default for LastObjectIdInfo {
182 fn default() -> Self {
183 LastObjectIdInfo::Unencrypted { id: 0 }
184 }
185}
186
187impl StoreInfo {
188 pub fn parent_objects(&self) -> Vec<u64> {
190 let mut objects = self.layers.to_vec();
193 if self.encrypted_mutations_object_id != INVALID_OBJECT_ID {
194 objects.push(self.encrypted_mutations_object_id);
195 }
196 objects
197 }
198}
199
200pub const MAX_STORE_INFO_SERIALIZED_SIZE: usize = 131072;
203
204pub const MAX_ENCRYPTED_MUTATIONS_SIZE: usize = 8 * journal::DEFAULT_RECLAIM_SIZE as usize;
208
209#[derive(Default)]
210pub struct HandleOptions {
211 pub skip_journal_checks: bool,
213 pub skip_checksums: bool,
216 pub skip_fsverity: bool,
219}
220
221pub struct ObjectEncryptionOptions {
223 pub permanent: bool,
228 pub key_id: u64,
229 pub key: EncryptionKey,
230 pub unwrapped_key: UnwrappedKey,
231}
232
233pub struct StoreOptions {
234 pub crypt: Option<Arc<dyn Crypt>>,
236}
237
238impl Default for StoreOptions {
239 fn default() -> Self {
240 Self { crypt: None }
241 }
242}
243
244#[derive(Default)]
245pub struct NewChildStoreOptions {
246 pub options: StoreOptions,
247
248 pub object_id: u64,
251
252 pub reserve_32bit_object_ids: bool,
255
256 pub low_32_bit_object_ids: bool,
259
260 pub guid: Option<[u8; 16]>,
262}
263
264pub type EncryptedMutations = EncryptedMutationsV49;
265
266#[derive(Clone, Default, Deserialize, Serialize, TypeFingerprint)]
267pub struct EncryptedMutationsV49 {
268 transactions: Vec<(JournalCheckpointV32, u64)>,
274
275 #[serde(with = "crate::zerocopy_serialization")]
277 data: Vec<u8>,
278
279 mutations_key_roll: Vec<(usize, FxfsKeyV49)>,
282}
283
284impl std::fmt::Debug for EncryptedMutations {
285 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
286 f.debug_struct("EncryptedMutations")
287 .field("transactions", &self.transactions)
288 .field("len", &self.data.len())
289 .field(
290 "mutations_key_roll",
291 &self.mutations_key_roll.iter().map(|k| k.0).collect::<Vec<usize>>(),
292 )
293 .finish()
294 }
295}
296
297impl Versioned for EncryptedMutations {
298 fn max_serialized_size() -> Option<u64> {
299 Some(MAX_ENCRYPTED_MUTATIONS_SIZE as u64)
300 }
301}
302
303impl EncryptedMutations {
304 fn from_replayed_mutations(
305 store_object_id: u64,
306 transactions: Vec<JournaledTransaction>,
307 ) -> Self {
308 let mut this = Self::default();
309 for JournaledTransaction { checkpoint, non_root_mutations, .. } in transactions {
310 for (object_id, mutation) in non_root_mutations {
311 if store_object_id == object_id {
312 if let Mutation::EncryptedObjectStore(data) = mutation {
313 this.push(&checkpoint, data);
314 } else if let Mutation::UpdateMutationsKey(key) = mutation {
315 this.mutations_key_roll.push((this.data.len(), key.into()));
316 }
317 }
318 }
319 }
320 this
321 }
322
323 fn extend(&mut self, other: &EncryptedMutations) {
324 self.transactions.extend_from_slice(&other.transactions[..]);
325 self.mutations_key_roll.extend(
326 other
327 .mutations_key_roll
328 .iter()
329 .map(|(offset, key)| (offset + self.data.len(), key.clone())),
330 );
331 self.data.extend_from_slice(&other.data[..]);
332 }
333
334 fn push(&mut self, checkpoint: &JournalCheckpoint, data: Box<[u8]>) {
335 let len = data.len();
336 self.data.append(&mut data.into());
337 if checkpoint.version >= AES_JOURNAL_ENCRYPTION_VERSION {
338 if let Some((last_checkpoint, total_len)) = self.transactions.last_mut() {
340 if last_checkpoint.file_offset == checkpoint.file_offset {
341 *total_len += len as u64;
342 return;
343 }
344 }
345 self.transactions.push((checkpoint.clone(), len as u64));
346 } else {
347 if let Some((last_checkpoint, count)) = self.transactions.last_mut() {
349 if last_checkpoint.file_offset == checkpoint.file_offset {
350 *count += 1;
351 return;
352 }
353 }
354 self.transactions.push((checkpoint.clone(), 1));
355 }
356 }
357}
358
359pub enum LockState {
360 Locked,
361 Unencrypted,
362 Unlocked {
363 crypt: Arc<dyn Crypt>,
364 cached_keys: Vec<(NonZero<u64>, EncryptionKey, UnwrappedKey)>,
365 mutations_cipher: JournalCipher,
366 },
367
368 UnlockedReadOnly(Arc<dyn Crypt>),
371
372 Invalid,
375
376 Unknown,
379
380 Locking,
383
384 Unlocking,
387
388 Deleted,
390}
391
392impl fmt::Debug for LockState {
393 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
394 formatter.write_str(match self {
395 LockState::Locked => "Locked",
396 LockState::Unencrypted => "Unencrypted",
397 LockState::Unlocked { .. } => "Unlocked",
398 LockState::UnlockedReadOnly(..) => "UnlockedReadOnly",
399 LockState::Invalid => "Invalid",
400 LockState::Unknown => "Unknown",
401 LockState::Locking => "Locking",
402 LockState::Unlocking => "Unlocking",
403 LockState::Deleted => "Deleted",
404 })
405 }
406}
407
408enum LastObjectId {
409 Pending,
411
412 Unencrypted {
413 id: u64,
414 },
415
416 Encrypted {
417 id: u64,
419
420 cipher: Box<Ff1>,
422 },
423
424 Low32Bit {
425 reserved: HashSet<u32>,
426 unreserved: Vec<u32>,
427 },
428}
429
430impl LastObjectId {
431 fn uses_reserved_ids(&self) -> bool {
433 matches!(self, LastObjectId::Low32Bit { .. })
434 }
435
436 fn try_get_next(&mut self) -> Option<NonZero<u64>> {
440 match self {
441 LastObjectId::Unencrypted { id } => {
442 NonZero::new(id.wrapping_add(1)).inspect(|next| *id = next.get())
443 }
444 LastObjectId::Encrypted { id, cipher } => {
445 let mut next = *id;
446 let hi = next & OBJECT_ID_HI_MASK;
447 loop {
448 if next as u32 == u32::MAX {
449 return None;
450 }
451 next += 1;
452 let candidate = hi | cipher.encrypt(next as u32) as u64;
453 if let Some(candidate) = NonZero::new(candidate) {
454 *id = next;
455 return Some(candidate);
456 }
457 }
458 }
459 _ => None,
460 }
461 }
462
463 fn peek_next(&self) -> u64 {
465 match self {
466 LastObjectId::Unencrypted { id } => id.wrapping_add(1),
467 LastObjectId::Encrypted { id, cipher } => {
468 let mut next = *id;
469 let hi = next & OBJECT_ID_HI_MASK;
470 loop {
471 if next as u32 == u32::MAX {
472 return INVALID_OBJECT_ID;
473 }
474 next += 1;
475 let candidate = hi | cipher.encrypt(next as u32) as u64;
476 if candidate != INVALID_OBJECT_ID {
477 return candidate;
478 }
479 }
480 }
481 _ => INVALID_OBJECT_ID,
482 }
483 }
484
485 fn id(&self) -> u64 {
487 match self {
488 LastObjectId::Unencrypted { id } | LastObjectId::Encrypted { id, .. } => *id,
489 _ => INVALID_OBJECT_ID,
490 }
491 }
492
493 fn is_reserved(&self, id: u64) -> bool {
495 match self {
496 LastObjectId::Low32Bit { reserved, .. } => {
497 if let Ok(id) = id.try_into() {
498 reserved.contains(&id)
499 } else {
500 false
501 }
502 }
503 _ => false,
504 }
505 }
506
507 fn reserve(&mut self, id: u64) {
509 match self {
510 LastObjectId::Low32Bit { reserved, .. } => {
511 assert!(reserved.insert(id.try_into().unwrap()))
512 }
513 _ => unreachable!(),
514 }
515 }
516
517 fn unreserve(&mut self, id: u64) {
519 match self {
520 LastObjectId::Low32Bit { unreserved, .. } => {
521 unreserved.push(id.try_into().unwrap())
540 }
541 _ => {}
542 }
543 }
544
545 fn drain_unreserved(&mut self) {
547 match self {
548 LastObjectId::Low32Bit { reserved, unreserved } => {
549 for u in unreserved.drain(..) {
550 assert!(reserved.remove(&u));
551 }
552 }
553 _ => {}
554 }
555 }
556}
557
558pub struct ReservedId<'a>(&'a ObjectStore, NonZero<u64>);
559
560impl<'a> ReservedId<'a> {
561 pub fn new(store: &'a ObjectStore, id: NonZero<u64>) -> Self {
562 Self(store, id)
563 }
564
565 pub fn get(&self) -> u64 {
566 self.1.get()
567 }
568
569 #[must_use]
571 pub fn release(self) -> NonZero<u64> {
572 let id = self.1;
573 std::mem::forget(self);
574 id
575 }
576}
577
578impl Drop for ReservedId<'_> {
579 fn drop(&mut self) {
580 self.0.last_object_id.lock().unreserve(self.1.get());
581 }
582}
583
584pub struct ObjectStore {
589 parent_store: Option<Arc<ObjectStore>>,
590 store_object_id: u64,
591 device: Arc<dyn Device>,
592 block_size: BlockSize,
593 filesystem: Weak<FxFilesystem>,
594 store_info: Mutex<Option<StoreInfo>>,
596 tree: LSMTree<ObjectKey, ObjectValue>,
597
598 store_info_handle: OnceLock<DataObjectHandle<ObjectStore>>,
603
604 lock_state: Mutex<LockState>,
607 pub key_manager: KeyManager,
608
609 trace: AtomicBool,
611
612 counters: Mutex<ObjectStoreCounters>,
614
615 device_read_ops: AtomicU64,
617 device_write_ops: AtomicU64,
618 logical_read_ops: AtomicU64,
619 logical_write_ops: AtomicU64,
620 graveyard_entries: AtomicU64,
621
622 last_object_id: Mutex<LastObjectId>,
625
626 flush_callback: Mutex<Option<Box<dyn Fn(&ObjectStore) + Send + Sync + 'static>>>,
629}
630
631#[derive(Clone, Default)]
632struct ObjectStoreCounters {
633 mutations_applied: u64,
634 mutations_dropped: u64,
635 num_flushes: u64,
636 last_flush_time: Option<std::time::SystemTime>,
637}
638
639impl ObjectStore {
640 fn new(
641 parent_store: Option<Arc<ObjectStore>>,
642 store_object_id: u64,
643 filesystem: Arc<FxFilesystem>,
644 store_info: Option<StoreInfo>,
645 object_cache: Option<Box<dyn ObjectCache<ObjectKey, ObjectValue>>>,
646 lock_state: LockState,
647 last_object_id: LastObjectId,
648 ) -> Arc<ObjectStore> {
649 let device = filesystem.device();
650 let block_size = filesystem.block_size();
651 Arc::new(ObjectStore {
652 parent_store,
653 store_object_id,
654 device,
655 block_size,
656 filesystem: Arc::downgrade(&filesystem),
657 store_info: Mutex::new(store_info),
658 tree: LSMTree::new(merge::merge, object_cache),
659 store_info_handle: OnceLock::new(),
660 lock_state: Mutex::new(lock_state),
661 key_manager: KeyManager::new(),
662 trace: AtomicBool::new(false),
663 counters: Mutex::new(ObjectStoreCounters::default()),
664 device_read_ops: AtomicU64::new(0),
665 device_write_ops: AtomicU64::new(0),
666 logical_read_ops: AtomicU64::new(0),
667 logical_write_ops: AtomicU64::new(0),
668 graveyard_entries: AtomicU64::new(0),
669 last_object_id: Mutex::new(last_object_id),
670 flush_callback: Mutex::new(None),
671 })
672 }
673
674 fn new_empty(
675 parent_store: Option<Arc<ObjectStore>>,
676 store_object_id: u64,
677 filesystem: Arc<FxFilesystem>,
678 object_cache: Option<Box<dyn ObjectCache<ObjectKey, ObjectValue>>>,
679 ) -> Arc<Self> {
680 Self::new(
681 parent_store,
682 store_object_id,
683 filesystem,
684 Some(StoreInfo::default()),
685 object_cache,
686 LockState::Unencrypted,
687 LastObjectId::Unencrypted { id: 0 },
688 )
689 }
690
691 pub fn new_root_parent(
694 device: Arc<dyn Device>,
695 block_size: BlockSize,
696 store_object_id: u64,
697 ) -> Self {
698 ObjectStore {
699 parent_store: None,
700 store_object_id,
701 device,
702 block_size,
703 filesystem: Weak::<FxFilesystem>::new(),
704 store_info: Mutex::new(Some(StoreInfo::default())),
705 tree: LSMTree::new(merge::merge, None),
706 store_info_handle: OnceLock::new(),
707 lock_state: Mutex::new(LockState::Unencrypted),
708 key_manager: KeyManager::new(),
709 trace: AtomicBool::new(false),
710 counters: Mutex::new(ObjectStoreCounters::default()),
711 device_read_ops: AtomicU64::new(0),
712 device_write_ops: AtomicU64::new(0),
713 logical_read_ops: AtomicU64::new(0),
714 logical_write_ops: AtomicU64::new(0),
715 graveyard_entries: AtomicU64::new(0),
716 last_object_id: Mutex::new(LastObjectId::Unencrypted { id: 0 }),
717 flush_callback: Mutex::new(None),
718 }
719 }
720
721 pub fn attach_filesystem(mut this: ObjectStore, filesystem: Arc<FxFilesystem>) -> ObjectStore {
724 this.filesystem = Arc::downgrade(&filesystem);
725 this
726 }
727
728 pub async fn new_transaction<'a>(
731 &self,
732 locks: LockKeys,
733 options: Options<'a>,
734 ) -> Result<Transaction<'a>, Error> {
735 let fs = self.filesystem();
736 Transaction::new(fs, options, locks).await
737 }
738
739 async fn pre_cache_keys(&self) -> Result<(), Error> {
741 let crypt = match &*self.lock_state.lock() {
742 LockState::Unlocked { cached_keys, crypt, .. }
743 if cached_keys.len() < CACHED_KEYS_LIMIT =>
744 {
745 crypt.clone()
746 }
747 _ => return Ok(()),
748 };
749 loop {
750 let parent_store = self.parent_store.as_ref().unwrap();
751
752 assert!(!parent_store.last_object_id.lock().uses_reserved_ids());
755
756 let raw_id = {
759 let reserved_id = parent_store
760 .maybe_get_next_object_id()
761 .expect("maybe_get_next_object_id failed on parent store");
762 reserved_id.release()
763 };
764
765 let (wrapped, unwrapped) = match crypt.create_key(raw_id.get(), KeyPurpose::Data).await
766 {
767 Ok(v) => v,
768 Err(error) => {
769 log::warn!(
770 error:?,
771 store_id = self.store_object_id();
772 "Failed to pre-cache key"
773 );
774 return Err(error.into());
775 }
776 };
777
778 let mut lock_state = self.lock_state.lock();
779 if let LockState::Unlocked { cached_keys, .. } = &mut *lock_state {
780 cached_keys.push((raw_id, EncryptionKey::Fxfs(wrapped), unwrapped));
781 if cached_keys.len() >= CACHED_KEYS_LIMIT {
782 break;
783 }
784 } else {
785 break;
787 }
788 }
789 Ok(())
790 }
791
792 async fn new_child_store(
802 self: &Arc<Self>,
803 transaction: &mut Transaction<'_>,
804 options: NewChildStoreOptions,
805 object_cache: Option<Box<dyn ObjectCache<ObjectKey, ObjectValue>>>,
806 ) -> Result<Arc<Self>, Error> {
807 ensure!(
808 !options.reserve_32bit_object_ids || !options.low_32_bit_object_ids,
809 FxfsError::InvalidArgs
810 );
811 let handle = if let Some(object_id) = NonZero::new(options.object_id) {
812 self.update_last_object_id(object_id.get());
813 let handle = ObjectStore::create_object_with_id(
814 self,
815 transaction,
816 ReservedId::new(self, object_id),
817 HandleOptions::default(),
818 None,
819 )?;
820 handle
821 } else {
822 ObjectStore::create_object(self, transaction, HandleOptions::default(), None).await?
823 };
824 let filesystem = self.filesystem();
825 let id = if options.reserve_32bit_object_ids { 0x1_0000_0000 } else { 0 };
826 let (last_object_id, last_object_id_in_memory) = if options.low_32_bit_object_ids {
827 (
828 LastObjectIdInfo::Low32Bit,
829 LastObjectId::Low32Bit { reserved: HashSet::new(), unreserved: Vec::new() },
830 )
831 } else if let Some(crypt) = &options.options.crypt {
832 let (object_id_wrapped, object_id_unwrapped) =
833 crypt.create_key(handle.object_id(), KeyPurpose::Metadata).await?;
834 (
835 LastObjectIdInfo::Encrypted { id, key: object_id_wrapped },
836 LastObjectId::Encrypted { id, cipher: Box::new(Ff1::new(&object_id_unwrapped)) },
837 )
838 } else {
839 (LastObjectIdInfo::Unencrypted { id }, LastObjectId::Unencrypted { id })
840 };
841 let store = if let Some(crypt) = options.options.crypt {
842 let (wrapped_key, unwrapped_key) =
843 crypt.create_key(handle.object_id(), KeyPurpose::Metadata).await?;
844 Self::new(
845 Some(self.clone()),
846 handle.object_id(),
847 filesystem.clone(),
848 Some(StoreInfo {
849 mutations_key: Some(wrapped_key),
850 last_object_id,
851 guid: options.guid.unwrap_or_else(|| *Uuid::new_v4().as_bytes()),
852 ..Default::default()
853 }),
854 object_cache,
855 LockState::Unlocked {
856 crypt,
857 cached_keys: Vec::new(),
858 mutations_cipher: JournalCipher::new_aes256_xts(&unwrapped_key, 0),
859 },
860 last_object_id_in_memory,
861 )
862 } else {
863 Self::new(
864 Some(self.clone()),
865 handle.object_id(),
866 filesystem.clone(),
867 Some(StoreInfo {
868 last_object_id,
869 guid: options.guid.unwrap_or_else(|| *Uuid::new_v4().as_bytes()),
870 ..Default::default()
871 }),
872 object_cache,
873 LockState::Unencrypted,
874 last_object_id_in_memory,
875 )
876 };
877 assert!(store.store_info_handle.set(handle).is_ok());
878 Ok(store)
879 }
880
881 async fn create<'a>(
884 self: &'a Arc<Self>,
885 transaction: &mut Transaction<'a>,
886 ) -> Result<(), Error> {
887 let buf = {
888 let graveyard_directory_object_id = Graveyard::create(transaction, &self).await?;
890 let root_directory = Directory::create(transaction, &self, None).await?;
891
892 let serialized_info = {
893 let mut store_info = self.store_info.lock();
894 let store_info = store_info.as_mut().unwrap();
895
896 store_info.graveyard_directory_object_id = graveyard_directory_object_id;
897 store_info.root_directory_object_id = root_directory.object_id();
898
899 let mut serialized_info = Vec::new();
900 store_info.serialize_with_version(&mut serialized_info)?;
901 serialized_info
902 };
903 let mut buf = self.device.allocate_buffer(serialized_info.len()).await;
904 buf.copy_from_slice(&serialized_info[..]);
905 buf
906 };
907
908 if self.filesystem().options().image_builder_mode.is_some() {
909 Ok(())
913 } else {
914 self.store_info_handle.get().unwrap().txn_write(transaction, 0u64, buf.as_ref()).await
915 }
916 }
917
918 pub fn set_trace(&self, trace: bool) {
919 let old_value = self.trace.swap(trace, Ordering::Relaxed);
920 if trace != old_value {
921 info!(store_id = self.store_object_id(), trace; "OS: trace",);
922 }
923 }
924
925 pub fn set_flush_callback<F: Fn(&ObjectStore) + Send + Sync + 'static>(&self, callback: F) {
928 let mut flush_callback = self.flush_callback.lock();
929 *flush_callback = Some(Box::new(callback));
930 }
931
932 pub fn is_root(&self) -> bool {
933 if let Some(parent) = &self.parent_store {
934 parent.parent_store.is_none()
935 } else {
936 false
938 }
939 }
940
941 pub fn record_data(self: &Arc<Self>, root: &fuchsia_inspect::Node) {
943 let counters = self.counters.lock();
945 if let Some(store_info) = self.store_info() {
946 root.record_string("guid", Uuid::from_bytes(store_info.guid).to_string());
947 };
948 root.record_uint("store_object_id", self.store_object_id);
949 root.record_uint("mutations_applied", counters.mutations_applied);
950 root.record_uint("mutations_dropped", counters.mutations_dropped);
951 root.record_uint("num_flushes", counters.num_flushes);
952 if let Some(last_flush_time) = counters.last_flush_time.as_ref() {
953 root.record_uint(
954 "last_flush_time_ms",
955 last_flush_time
956 .duration_since(std::time::UNIX_EPOCH)
957 .unwrap_or(std::time::Duration::ZERO)
958 .as_millis()
959 .try_into()
960 .unwrap_or(0u64),
961 );
962 }
963 root.record_uint("device_read_ops", self.device_read_ops.load(Ordering::Relaxed));
964 root.record_uint("device_write_ops", self.device_write_ops.load(Ordering::Relaxed));
965 root.record_uint("logical_read_ops", self.logical_read_ops.load(Ordering::Relaxed));
966 root.record_uint("logical_write_ops", self.logical_write_ops.load(Ordering::Relaxed));
967 root.record_uint("graveyard_entries", self.graveyard_entries.load(Ordering::Relaxed));
968 {
969 let last_object_id = self.last_object_id.lock();
970 root.record_uint("object_id_hi", last_object_id.id() >> 32);
971 root.record_bool(
972 "low_32_bit_object_ids",
973 matches!(&*last_object_id, LastObjectId::Low32Bit { .. }),
974 );
975 }
976
977 let this = self.clone();
978 root.record_child("lsm_tree", move |node| this.tree().record_inspect_data(node));
979 }
980
981 pub fn device(&self) -> &Arc<dyn Device> {
982 &self.device
983 }
984
985 pub fn block_size(&self) -> BlockSize {
986 self.block_size
987 }
988
989 pub fn filesystem(&self) -> Arc<FxFilesystem> {
990 self.filesystem.upgrade().unwrap()
991 }
992
993 pub fn store_object_id(&self) -> u64 {
994 self.store_object_id
995 }
996
997 pub fn tree(&self) -> &LSMTree<ObjectKey, ObjectValue> {
998 &self.tree
999 }
1000
1001 pub fn root_directory_object_id(&self) -> u64 {
1002 self.store_info.lock().as_ref().unwrap().root_directory_object_id
1003 }
1004
1005 pub fn guid(&self) -> [u8; 16] {
1006 self.store_info.lock().as_ref().unwrap().guid
1007 }
1008
1009 pub fn graveyard_directory_object_id(&self) -> u64 {
1010 self.store_info.lock().as_ref().unwrap().graveyard_directory_object_id
1011 }
1012
1013 fn set_graveyard_directory_object_id(&self, oid: u64) {
1014 assert_eq!(
1015 std::mem::replace(
1016 &mut self.store_info.lock().as_mut().unwrap().graveyard_directory_object_id,
1017 oid
1018 ),
1019 INVALID_OBJECT_ID
1020 );
1021 }
1022
1023 pub fn object_count(&self) -> u64 {
1024 self.store_info.lock().as_ref().unwrap().object_count
1025 }
1026
1027 pub(crate) fn unencrypted_last_object_id(&self) -> u64 {
1029 self.last_object_id.lock().id()
1030 }
1031
1032 pub fn key_manager(&self) -> &KeyManager {
1033 &self.key_manager
1034 }
1035
1036 pub fn clear_caches(&self) {
1039 self.tree.clear_cache();
1040 self.key_manager.clear_cached_keys();
1041 }
1042
1043 pub fn parent_store(&self) -> Option<&Arc<ObjectStore>> {
1044 self.parent_store.as_ref()
1045 }
1046
1047 pub fn crypt(&self) -> Option<Arc<dyn Crypt>> {
1049 match &*self.lock_state.lock() {
1050 LockState::Locked => panic!("Store is locked"),
1051 LockState::Invalid
1052 | LockState::Unencrypted
1053 | LockState::Locking
1054 | LockState::Unlocking
1055 | LockState::Deleted => None,
1056 LockState::Unlocked { crypt, .. } => Some(crypt.clone()),
1057 LockState::UnlockedReadOnly(crypt) => Some(crypt.clone()),
1058 LockState::Unknown => {
1059 panic!("Store is of unknown lock state; has the journal been replayed yet?")
1060 }
1061 }
1062 }
1063
1064 pub fn get_internal_directory_id(self: &Arc<Self>) -> Result<u64, Error> {
1067 if let Some(store_info) = self.store_info.lock().as_ref() {
1068 if store_info.internal_directory_object_id == INVALID_OBJECT_ID {
1069 Err(FxfsError::NotFound.into())
1070 } else {
1071 Ok(store_info.internal_directory_object_id)
1072 }
1073 } else {
1074 Err(FxfsError::Unavailable.into())
1075 }
1076 }
1077
1078 pub async fn get_or_create_internal_directory_id(self: &Arc<Self>) -> Result<u64, Error> {
1079 let mut transaction = self
1081 .new_transaction(
1082 lock_keys![LockKey::InternalDirectory { store_object_id: self.store_object_id }],
1083 Options::default(),
1084 )
1085 .await?;
1086 let obj_id = self.store_info.lock().as_ref().unwrap().internal_directory_object_id;
1087 if obj_id != INVALID_OBJECT_ID {
1088 return Ok(obj_id);
1089 }
1090
1091 let directory = Directory::create(&mut transaction, self, None).await?;
1093
1094 transaction.add(self.store_object_id, Mutation::CreateInternalDir(directory.object_id()));
1095 transaction.commit().await?;
1096 Ok(directory.object_id())
1097 }
1098
1099 async fn get_file_size(&self, object_id: u64) -> Result<u64, Error> {
1101 self.tree
1102 .find_map(
1103 &ObjectKey::attribute(object_id, AttributeId::DATA, AttributeKey::Attribute),
1104 |item| match item.value {
1105 ObjectValue::Attribute { size, .. } => Ok(*size),
1106 _ => Err(anyhow!(FxfsError::NotFile)),
1107 },
1108 )
1109 .await?
1110 .ok_or(FxfsError::NotFound)?
1111 }
1112
1113 #[cfg(feature = "migration")]
1114 pub fn last_object_id(&self) -> u64 {
1115 self.last_object_id.lock().id()
1116 }
1117
1118 #[cfg(feature = "migration")]
1120 pub fn mark_allocated(
1121 &self,
1122 transaction: &mut Transaction<'_>,
1123 store_object_id: u64,
1124 device_range: std::ops::Range<u64>,
1125 ) -> Result<(), Error> {
1126 self.allocator().mark_allocated(transaction, store_object_id, device_range)
1127 }
1128
1129 pub async fn open_object<S: HandleOwner>(
1136 owner: &Arc<S>,
1137 obj_id: u64,
1138 options: HandleOptions,
1139 crypt: Option<Arc<dyn Crypt>>,
1140 ) -> Result<DataObjectHandle<S>, Error> {
1141 let store = owner.as_ref().as_ref();
1142 let mut fsverity_descriptor = None;
1143 let mut overwrite_ranges = Vec::new();
1144 let value = store
1145 .tree
1146 .find_value(&ObjectKey::attribute(obj_id, AttributeId::DATA, AttributeKey::Attribute))
1147 .await?
1148 .ok_or(FxfsError::NotFound)?;
1149
1150 let (size, track_overwrite_extents) = match value {
1151 ObjectValue::Attribute { size, has_overwrite_extents } => (size, has_overwrite_extents),
1152 ObjectValue::VerifiedAttribute { size, fsverity_metadata } => {
1153 if !options.skip_fsverity {
1154 fsverity_descriptor = Some(fsverity_metadata);
1155 }
1156 (size, false)
1160 }
1161 _ => bail!(anyhow!(FxfsError::Inconsistent).context("open_object: Expected attibute")),
1162 };
1163
1164 ensure!(size <= MAX_FILE_SIZE, FxfsError::Inconsistent);
1165
1166 if track_overwrite_extents {
1167 let layer_set = store.tree.layer_set();
1168 let mut merger = layer_set.merger();
1169 let mut iter = merger
1170 .query(Query::FullRange(&ObjectKey::attribute(
1171 obj_id,
1172 AttributeId::DATA,
1173 AttributeKey::Extent(Extent::search_key_from_offset(0)),
1174 )))
1175 .await?;
1176 loop {
1177 match iter.get() {
1178 Some(ItemRef {
1179 key:
1180 ObjectKey {
1181 object_id,
1182 data:
1183 ObjectKeyData::Attribute(
1184 AttributeId::DATA,
1185 AttributeKey::Extent(extent),
1186 ),
1187 },
1188 value,
1189 ..
1190 }) if *object_id == obj_id => {
1191 match value {
1192 ObjectValue::Extent(ExtentValue::None)
1193 | ObjectValue::Extent(ExtentValue::Some {
1194 mode: ExtentMode::Raw,
1195 ..
1196 })
1197 | ObjectValue::Extent(ExtentValue::Some {
1198 mode: ExtentMode::Cow(_),
1199 ..
1200 }) => (),
1201 ObjectValue::Extent(ExtentValue::Some {
1202 mode: ExtentMode::OverwritePartial(_),
1203 ..
1204 })
1205 | ObjectValue::Extent(ExtentValue::Some {
1206 mode: ExtentMode::Overwrite,
1207 ..
1208 }) => overwrite_ranges.push(extent.clone().into()),
1209 _ => bail!(
1210 anyhow!(FxfsError::Inconsistent)
1211 .context("open_object: Expected extent")
1212 ),
1213 }
1214 iter.advance().await?;
1215 }
1216 _ => break,
1217 }
1218 }
1219 }
1220
1221 let permanent = if let Some(crypt) = crypt {
1224 store
1225 .key_manager
1226 .get_keys(
1227 obj_id,
1228 crypt.as_ref(),
1229 &mut Some(async || store.get_keys(obj_id).await),
1230 true,
1231 false,
1232 )
1233 .await?;
1234 true
1235 } else {
1236 false
1237 };
1238 let data_object_handle = DataObjectHandle::new(
1239 owner.clone(),
1240 obj_id,
1241 permanent,
1242 AttributeId::DATA,
1243 size,
1244 options,
1245 false,
1246 &overwrite_ranges,
1247 );
1248 if let Some(descriptor) = fsverity_descriptor {
1249 data_object_handle
1250 .set_fsverity_state_some(descriptor)
1251 .await
1252 .context("Invalid or mismatched merkle tree")?;
1253 }
1254 Ok(data_object_handle)
1255 }
1256
1257 pub fn create_object_with_id<S: HandleOwner>(
1258 owner: &Arc<S>,
1259 transaction: &mut Transaction<'_>,
1260 reserved_object_id: ReservedId<'_>,
1261 options: HandleOptions,
1262 encryption_options: Option<ObjectEncryptionOptions>,
1263 ) -> Result<DataObjectHandle<S>, Error> {
1264 let store = owner.as_ref().as_ref();
1265 debug_assert!(store.crypt().is_none() || encryption_options.is_some());
1267 let now = Timestamp::now();
1268 let object_id = reserved_object_id.get();
1269 assert!(
1270 transaction
1271 .add(
1272 store.store_object_id(),
1273 Mutation::insert_object(
1274 ObjectKey::object(reserved_object_id.release().get()),
1275 ObjectValue::file(
1276 1,
1277 0,
1278 now.clone(),
1279 now.clone(),
1280 now.clone(),
1281 now,
1282 None,
1283 None
1284 ),
1285 ),
1286 )
1287 .is_none()
1288 );
1289 let mut permanent_keys = false;
1290 if let Some(ObjectEncryptionOptions { permanent, key_id, key, unwrapped_key }) =
1291 encryption_options
1292 {
1293 permanent_keys = permanent;
1294 let cipher = key_to_cipher(&key, &unwrapped_key)?;
1295 transaction.add(
1296 store.store_object_id(),
1297 Mutation::insert_object(
1298 ObjectKey::keys(object_id),
1299 ObjectValue::keys(vec![(key_id, key)].into()),
1300 ),
1301 );
1302 store.key_manager.insert(
1303 object_id,
1304 Arc::new(vec![(key_id, CipherHolder::Cipher(cipher))].into()),
1305 permanent,
1306 );
1307 }
1308 transaction.add(
1309 store.store_object_id(),
1310 Mutation::insert_object(
1311 ObjectKey::attribute(object_id, AttributeId::DATA, AttributeKey::Attribute),
1312 ObjectValue::attribute(0, false),
1314 ),
1315 );
1316 Ok(DataObjectHandle::new(
1317 owner.clone(),
1318 object_id,
1319 permanent_keys,
1320 AttributeId::DATA,
1321 0,
1322 options,
1323 false,
1324 &[],
1325 ))
1326 }
1327
1328 pub async fn create_object<S: HandleOwner>(
1334 owner: &Arc<S>,
1335 mut transaction: &mut Transaction<'_>,
1336 options: HandleOptions,
1337 wrapping_key_id: Option<WrappingKeyId>,
1338 ) -> Result<DataObjectHandle<S>, Error> {
1339 let store = owner.as_ref().as_ref();
1340 let object_id = store.get_next_object_id().await?;
1341 let crypt = store.crypt();
1342 let encryption_options = if let Some(crypt) = crypt {
1343 let key_id =
1344 if wrapping_key_id.is_some() { FSCRYPT_KEY_ID } else { VOLUME_DATA_KEY_ID };
1345 let (key, unwrapped_key) = if let Some(wrapping_key_id) = wrapping_key_id {
1346 crypt.create_key_with_id(object_id.get(), wrapping_key_id, ObjectType::File).await?
1347 } else {
1348 let (fxfs_key, unwrapped_key) =
1349 crypt.create_key(object_id.get(), KeyPurpose::Data).await?;
1350 (EncryptionKey::Fxfs(fxfs_key), unwrapped_key)
1351 };
1352 Some(ObjectEncryptionOptions { permanent: false, key_id, key, unwrapped_key })
1353 } else {
1354 None
1355 };
1356 ObjectStore::create_object_with_id(
1357 owner,
1358 &mut transaction,
1359 object_id,
1360 options,
1361 encryption_options,
1362 )
1363 }
1364
1365 pub(crate) async fn create_object_with_key<S: HandleOwner>(
1371 owner: &Arc<S>,
1372 mut transaction: &mut Transaction<'_>,
1373 object_id: ReservedId<'_>,
1374 options: HandleOptions,
1375 key: EncryptionKey,
1376 unwrapped_key: UnwrappedKey,
1377 ) -> Result<DataObjectHandle<S>, Error> {
1378 ObjectStore::create_object_with_id(
1379 owner,
1380 &mut transaction,
1381 object_id,
1382 options,
1383 Some(ObjectEncryptionOptions {
1384 permanent: true,
1385 key_id: VOLUME_DATA_KEY_ID,
1386 key,
1387 unwrapped_key,
1388 }),
1389 )
1390 }
1391
1392 pub async fn adjust_refs(
1395 &self,
1396 transaction: &mut Transaction<'_>,
1397 object_id: u64,
1398 delta: i64,
1399 ) -> Result<bool, Error> {
1400 self.adjust_refs_impl(transaction, object_id, delta, true).await
1401 }
1402
1403 pub async fn adjust_refs_impl(
1407 &self,
1408 transaction: &mut Transaction<'_>,
1409 object_id: u64,
1410 delta: i64,
1411 add_to_graveyard: bool,
1412 ) -> Result<bool, Error> {
1413 let mut mutation = self.txn_get_object_mutation(transaction, object_id).await?;
1414 let refs = if let ObjectValue::Object {
1415 kind:
1416 ObjectKind::File { refs, .. }
1417 | ObjectKind::Symlink { refs, .. }
1418 | ObjectKind::EncryptedSymlink { refs, .. },
1419 ..
1420 } = &mut mutation.item.value
1421 {
1422 *refs =
1423 refs.checked_add_signed(delta).ok_or_else(|| anyhow!("refs underflow/overflow"))?;
1424 refs
1425 } else {
1426 bail!(FxfsError::NotFile);
1427 };
1428 if *refs == 0 {
1429 if add_to_graveyard {
1430 self.add_to_graveyard(transaction, object_id);
1431
1432 if delta != -1 {
1435 *refs = 1;
1436 transaction.add(self.store_object_id, Mutation::ObjectStore(mutation));
1437 }
1438
1439 }
1442 Ok(true)
1443 } else {
1444 transaction.add(self.store_object_id, Mutation::ObjectStore(mutation));
1445 Ok(false)
1446 }
1447 }
1448
1449 pub async fn tombstone_object(
1452 &self,
1453 object_id: u64,
1454 txn_options: Options<'_>,
1455 truncate_guard: Option<&TruncateGuard<'_>>,
1456 ) -> Result<(), Error> {
1457 debug_assert!(
1458 self.tree.exists(&ObjectKey::object(object_id)).await?,
1459 "Tombstoning missing object"
1460 );
1461 debug_assert!(
1462 self.tree
1463 .exists(&ObjectKey::graveyard_entry(
1464 self.graveyard_directory_object_id(),
1465 object_id
1466 ))
1467 .await?,
1468 "Tombstoning object not in graveyard"
1469 );
1470 self.key_manager.remove(object_id).await;
1471 let _fs;
1472 let _guard;
1473 let truncate_guard = match truncate_guard {
1474 Some(guard) => guard,
1475 None => {
1476 _fs = self.filesystem();
1477 _guard = _fs.truncate_guard(self.store_object_id, object_id).await;
1478 &_guard
1479 }
1480 };
1481 self.trim_or_tombstone(object_id, true, txn_options, truncate_guard).await
1482 }
1483
1484 pub async fn trim(
1487 &self,
1488 object_id: u64,
1489 truncate_guard: &TruncateGuard<'_>,
1490 ) -> Result<(), Error> {
1491 assert!(self.parent_store.as_ref().unwrap().parent_store.is_some());
1494
1495 self.trim_or_tombstone(
1496 object_id,
1497 false,
1498 Options { borrow_metadata_space: true, ..Default::default() },
1499 truncate_guard,
1500 )
1501 .await
1502 }
1503
1504 async fn trim_or_tombstone(
1506 &self,
1507 object_id: u64,
1508 for_tombstone: bool,
1509 txn_options: Options<'_>,
1510 _truncate_guard: &TruncateGuard<'_>,
1511 ) -> Result<(), Error> {
1512 let mut next_attribute = Some(AttributeId::SORTED_START);
1513 while let Some(attribute_id) = next_attribute.take() {
1514 let mut transaction = self
1515 .new_transaction(
1516 lock_keys![
1517 LockKey::object_attribute(self.store_object_id, object_id, attribute_id),
1518 LockKey::object(self.store_object_id, object_id),
1519 ],
1520 txn_options,
1521 )
1522 .await?;
1523
1524 match self
1525 .trim_some(
1526 &mut transaction,
1527 object_id,
1528 attribute_id,
1529 if for_tombstone {
1530 TrimMode::Tombstone(TombstoneMode::Object)
1531 } else {
1532 TrimMode::UseSize
1533 },
1534 )
1535 .await?
1536 {
1537 TrimResult::Incomplete => next_attribute = Some(attribute_id),
1538 TrimResult::Done(None) => {
1539 if for_tombstone
1540 || matches!(
1541 self.tree
1542 .find_value(&ObjectKey::graveyard_entry(
1543 self.graveyard_directory_object_id(),
1544 object_id,
1545 ))
1546 .await?,
1547 Some(ObjectValue::Trim)
1548 )
1549 {
1550 self.remove_from_graveyard(&mut transaction, object_id);
1551 }
1552 if for_tombstone && attribute_id != AttributeId::DATA {
1555 self.remove_attribute_from_graveyard(
1556 &mut transaction,
1557 object_id,
1558 attribute_id,
1559 );
1560 }
1561 }
1562 TrimResult::Done(id) => {
1563 if for_tombstone && attribute_id != AttributeId::DATA {
1566 self.remove_attribute_from_graveyard(
1567 &mut transaction,
1568 object_id,
1569 attribute_id,
1570 );
1571 }
1572 next_attribute = id;
1573 }
1574 }
1575
1576 if !transaction.mutations().is_empty() {
1577 transaction.commit().await?;
1578 }
1579 }
1580 Ok(())
1581 }
1582
1583 pub async fn tombstone_attribute(
1585 &self,
1586 object_id: u64,
1587 attribute_id: AttributeId,
1588 txn_options: Options<'_>,
1589 ) -> Result<(), Error> {
1590 debug_assert!(
1592 self.tree
1593 .exists(&ObjectKey::attribute(object_id, attribute_id, AttributeKey::Attribute))
1594 .await?,
1595 "Tombstoning missing attribute"
1596 );
1597 debug_assert!(
1598 self.tree
1599 .exists(&ObjectKey::graveyard_attribute_entry(
1600 self.graveyard_directory_object_id(),
1601 object_id,
1602 attribute_id
1603 ))
1604 .await?,
1605 "Tombstoning attribute not in graveyard"
1606 );
1607 let mut trim_result = TrimResult::Incomplete;
1608 while matches!(trim_result, TrimResult::Incomplete) {
1609 let mut transaction = self
1610 .new_transaction(
1611 lock_keys![
1612 LockKey::object_attribute(self.store_object_id, object_id, attribute_id),
1613 LockKey::object(self.store_object_id, object_id),
1614 ],
1615 txn_options,
1616 )
1617 .await?;
1618 trim_result = self
1619 .trim_some(
1620 &mut transaction,
1621 object_id,
1622 attribute_id,
1623 TrimMode::Tombstone(TombstoneMode::Attribute),
1624 )
1625 .await?;
1626 if let TrimResult::Done(..) = trim_result {
1627 self.remove_attribute_from_graveyard(&mut transaction, object_id, attribute_id)
1628 }
1629 if !transaction.mutations().is_empty() {
1630 transaction.commit().await?;
1631 }
1632 }
1633 Ok(())
1634 }
1635
1636 pub async fn trim_some(
1640 &self,
1641 transaction: &mut Transaction<'_>,
1642 object_id: u64,
1643 attribute_id: AttributeId,
1644 mode: TrimMode,
1645 ) -> Result<TrimResult, Error> {
1646 let layer_set = self.tree.layer_set();
1647 let mut merger = layer_set.merger();
1648
1649 let aligned_offset = match mode {
1650 TrimMode::FromOffset(offset) => {
1651 self.block_size.align_up(offset).ok_or(FxfsError::Inconsistent)?
1652 }
1653 TrimMode::Tombstone(..) => 0,
1654 TrimMode::UseSize => {
1655 let iter = merger
1656 .query(Query::FullRange(&ObjectKey::attribute(
1657 object_id,
1658 attribute_id,
1659 AttributeKey::Attribute,
1660 )))
1661 .await?;
1662 if let Some(item_ref) = iter.get() {
1663 if item_ref.key.object_id != object_id {
1664 return Ok(TrimResult::Done(None));
1665 }
1666
1667 if let ItemRef {
1668 key:
1669 ObjectKey {
1670 data:
1671 ObjectKeyData::Attribute(size_attribute_id, AttributeKey::Attribute),
1672 ..
1673 },
1674 value: ObjectValue::Attribute { size, .. },
1675 ..
1676 } = item_ref
1677 {
1678 if *size_attribute_id != attribute_id {
1681 return Ok(TrimResult::Done(Some(*size_attribute_id)));
1682 }
1683 self.block_size.align_up(*size).ok_or(FxfsError::Inconsistent)?
1684 } else {
1685 return Ok(TrimResult::Done(Some(attribute_id.next())));
1689 }
1690 } else {
1691 return Ok(TrimResult::Done(None));
1693 }
1694 }
1695 };
1696
1697 let mut iter = merger
1699 .query(Query::FullRange(&ObjectKey::from_extent(
1700 object_id,
1701 attribute_id,
1702 Extent::search_key_from_offset(aligned_offset),
1703 )))
1704 .await?;
1705 let mut end = 0;
1706 let allocator = self.allocator();
1707 let mut result = TrimResult::Done(None);
1708 let mut deallocated = 0;
1709 let block_size = self.block_size;
1710
1711 while let Some(item_ref) = iter.get() {
1712 if item_ref.key.object_id != object_id {
1713 break;
1714 }
1715 if let ObjectKey {
1716 data: ObjectKeyData::Attribute(extent_attribute_id, attribute_key),
1717 ..
1718 } = item_ref.key
1719 {
1720 if *extent_attribute_id != attribute_id {
1721 result = TrimResult::Done(Some(*extent_attribute_id));
1722 break;
1723 }
1724 if let (
1725 AttributeKey::Extent(extent),
1726 ObjectValue::Extent(ExtentValue::Some { device_offset, .. }),
1727 ) = (attribute_key, item_ref.value)
1728 {
1729 let start = std::cmp::max(extent.start, aligned_offset);
1730 ensure!(start < extent.end, FxfsError::Inconsistent);
1731 let device_offset = device_offset
1732 .checked_add(start - extent.start)
1733 .ok_or(FxfsError::Inconsistent)?;
1734 end = extent.end;
1735 let len = end - start;
1736 let device_range = device_offset..device_offset + len;
1737 ensure!(block_size.is_aligned(&device_range), FxfsError::Inconsistent);
1738 allocator.deallocate(transaction, self.store_object_id, device_range).await?;
1739 deallocated += len;
1740 if transaction.mutations().len() >= TRANSACTION_MUTATION_THRESHOLD {
1742 result = TrimResult::Incomplete;
1743 break;
1744 }
1745 }
1746 }
1747 iter.advance().await?;
1748 }
1749
1750 let finished_tombstone_object = matches!(mode, TrimMode::Tombstone(TombstoneMode::Object))
1751 && matches!(result, TrimResult::Done(None));
1752 let finished_tombstone_attribute =
1753 matches!(mode, TrimMode::Tombstone(TombstoneMode::Attribute))
1754 && !matches!(result, TrimResult::Incomplete);
1755 let mut object_mutation = None;
1756 let nodes = if finished_tombstone_object { -1 } else { 0 };
1757 if nodes != 0 || deallocated != 0 {
1758 let mutation = self.txn_get_object_mutation(transaction, object_id).await?;
1759 if let ObjectValue::Object { attributes: ObjectAttributes { project_id, .. }, .. } =
1760 mutation.item.value
1761 {
1762 if let Some(project_id) = project_id {
1763 transaction.add(
1764 self.store_object_id,
1765 Mutation::merge_object(
1766 ObjectKey::project_usage(self.root_directory_object_id(), project_id),
1767 ObjectValue::BytesAndNodes {
1768 bytes: -i64::try_from(deallocated).unwrap(),
1769 nodes,
1770 },
1771 ),
1772 );
1773 }
1774 object_mutation = Some(mutation);
1775 } else {
1776 panic!("Inconsistent object type.");
1777 }
1778 }
1779
1780 if finished_tombstone_object {
1783 transaction.add(
1784 self.store_object_id,
1785 Mutation::merge_object(ObjectKey::object(object_id), ObjectValue::None),
1786 );
1787 } else {
1788 if finished_tombstone_attribute {
1789 transaction.add(
1790 self.store_object_id,
1791 Mutation::merge_object(
1792 ObjectKey::attribute(object_id, attribute_id, AttributeKey::Attribute),
1793 ObjectValue::None,
1794 ),
1795 );
1796 }
1797 if deallocated > 0 {
1798 let mut mutation = match object_mutation {
1799 Some(mutation) => mutation,
1800 None => self.txn_get_object_mutation(transaction, object_id).await?,
1801 };
1802 transaction.add(
1803 self.store_object_id,
1804 Mutation::merge_object(
1805 ObjectKey::extent(object_id, attribute_id, aligned_offset..end),
1806 ObjectValue::deleted_extent(),
1807 ),
1808 );
1809 if let ObjectValue::Object {
1811 attributes: ObjectAttributes { allocated_size, .. },
1812 ..
1813 } = &mut mutation.item.value
1814 {
1815 *allocated_size = allocated_size.checked_sub(deallocated).ok_or_else(|| {
1817 anyhow!(FxfsError::Inconsistent).context("Allocated size overflow")
1818 })?;
1819 } else {
1820 panic!("Unexpected object value");
1821 }
1822 transaction.add(self.store_object_id, Mutation::ObjectStore(mutation));
1823 }
1824 }
1825 Ok(result)
1826 }
1827
1828 pub fn parent_objects(&self) -> Vec<u64> {
1832 assert!(self.store_info_handle.get().is_some());
1833 self.store_info.lock().as_ref().unwrap().parent_objects()
1834 }
1835
1836 pub fn root_objects(&self) -> Vec<u64> {
1838 let mut objects = Vec::new();
1839 let store_info = self.store_info.lock();
1840 let info = store_info.as_ref().unwrap();
1841 if info.root_directory_object_id != INVALID_OBJECT_ID {
1842 objects.push(info.root_directory_object_id);
1843 }
1844 if info.graveyard_directory_object_id != INVALID_OBJECT_ID {
1845 objects.push(info.graveyard_directory_object_id);
1846 }
1847 if info.internal_directory_object_id != INVALID_OBJECT_ID {
1848 objects.push(info.internal_directory_object_id);
1849 }
1850 objects
1851 }
1852
1853 pub fn store_info(&self) -> Option<StoreInfo> {
1854 self.store_info.lock().as_ref().cloned()
1855 }
1856
1857 pub fn store_info_handle_object_id(&self) -> Option<u64> {
1859 self.store_info_handle.get().map(|h| h.object_id())
1860 }
1861
1862 pub fn graveyard_count(&self) -> u64 {
1863 self.graveyard_entries.load(Ordering::Relaxed)
1864 }
1865
1866 async fn open(
1868 parent_store: &Arc<ObjectStore>,
1869 store_object_id: u64,
1870 object_cache: Option<Box<dyn ObjectCache<ObjectKey, ObjectValue>>>,
1871 ) -> Result<Arc<ObjectStore>, Error> {
1872 let handle =
1873 ObjectStore::open_object(parent_store, store_object_id, HandleOptions::default(), None)
1874 .await?;
1875
1876 let info = load_store_info(parent_store, store_object_id).await?;
1877 let is_encrypted = info.mutations_key.is_some();
1878
1879 let mut total_layer_size = 0;
1880 let last_object_id;
1881
1882 if is_encrypted {
1887 for &oid in &info.layers {
1888 total_layer_size += parent_store.get_file_size(oid).await?;
1889 }
1890 if info.encrypted_mutations_object_id != INVALID_OBJECT_ID {
1891 total_layer_size += layer_size_from_encrypted_mutations_size(
1892 parent_store.get_file_size(info.encrypted_mutations_object_id).await?,
1893 );
1894 }
1895 last_object_id = LastObjectId::Pending;
1896 ensure!(
1897 matches!(
1898 info.last_object_id,
1899 LastObjectIdInfo::Encrypted { .. } | LastObjectIdInfo::Low32Bit { .. }
1900 ),
1901 FxfsError::Inconsistent
1902 );
1903 } else {
1904 last_object_id = match info.last_object_id {
1905 LastObjectIdInfo::Unencrypted { id } => LastObjectId::Unencrypted { id },
1906 LastObjectIdInfo::Low32Bit => {
1907 LastObjectId::Low32Bit { reserved: HashSet::new(), unreserved: Vec::new() }
1908 }
1909 _ => bail!(FxfsError::Inconsistent),
1910 };
1911 }
1912
1913 let fs = parent_store.filesystem();
1914
1915 let store = ObjectStore::new(
1916 Some(parent_store.clone()),
1917 store_object_id,
1918 fs.clone(),
1919 if is_encrypted { None } else { Some(info) },
1920 object_cache,
1921 if is_encrypted { LockState::Locked } else { LockState::Unencrypted },
1922 last_object_id,
1923 );
1924
1925 assert!(store.store_info_handle.set(handle).is_ok(), "Failed to set store_info_handle!");
1926
1927 if !is_encrypted {
1928 let object_tree_layer_object_ids =
1929 store.store_info.lock().as_ref().unwrap().layers.clone();
1930 total_layer_size = store
1931 .tree
1932 .append_layers(&parent_store, object_tree_layer_object_ids, None)
1933 .await
1934 .context("Failed to read object store layers")?;
1935 }
1936
1937 fs.object_manager().update_reservation(
1938 store_object_id,
1939 tree::reservation_amount_from_layer_size(total_layer_size),
1940 );
1941
1942 Ok(store)
1943 }
1944
1945 async fn load_store_info(&self) -> Result<StoreInfo, Error> {
1946 load_store_info_from_handle(self.store_info_handle.get().unwrap()).await
1947 }
1948
1949 pub async fn unlock(self: &Arc<Self>, crypt: Arc<dyn Crypt>) -> Result<(), Error> {
1952 self.unlock_inner(crypt, false).await
1953 }
1954
1955 pub async fn unlock_read_only(self: &Arc<Self>, crypt: Arc<dyn Crypt>) -> Result<(), Error> {
1963 self.unlock_inner(crypt, true).await
1964 }
1965
1966 async fn unlock_inner(
1968 self: &Arc<Self>,
1969 crypt: Arc<dyn Crypt>,
1970 read_only: bool,
1971 ) -> Result<(), Error> {
1972 #[derive(Debug, PartialEq)]
1977 struct CryptFields {
1978 mutations_key: Option<FxfsKey>,
1979 mutations_cipher_offset: u64,
1980 last_object_id: LastObjectIdInfo,
1981 layers: Vec<u64>,
1982 }
1983 impl From<&StoreInfo> for CryptFields {
1984 fn from(info: &StoreInfo) -> Self {
1985 Self {
1986 mutations_key: info.mutations_key.clone(),
1987 mutations_cipher_offset: info.mutations_cipher_offset,
1988 last_object_id: info.last_object_id.clone(),
1989 layers: info.layers.clone(),
1990 }
1991 }
1992 }
1993
1994 assert!(read_only || !self.filesystem().options().read_only);
1996 match &*self.lock_state.lock() {
1997 LockState::Locked => {}
1998 LockState::Unencrypted => bail!(FxfsError::InvalidArgs),
1999 LockState::Invalid | LockState::Deleted => bail!(FxfsError::Internal),
2000 LockState::Unlocked { .. } | LockState::UnlockedReadOnly(..) => {
2001 bail!(FxfsError::AlreadyBound)
2002 }
2003 LockState::Unknown => panic!("Store was unlocked before replay"),
2004 LockState::Locking => panic!("Store is being locked"),
2005 LockState::Unlocking => panic!("Store is being unlocked"),
2006 }
2007
2008 let mut last_num_flushes = self.counters.lock().num_flushes;
2011 let mut store_info = self.load_store_info().await?;
2012 let crypt_fields = CryptFields::from(&store_info);
2013
2014 let mut update_store_info = async |store_info: &mut StoreInfo| -> Result<(), Error> {
2015 let new_num_flushes = self.counters.lock().num_flushes;
2016 if last_num_flushes == new_num_flushes {
2017 return Ok(());
2018 }
2019 last_num_flushes = new_num_flushes;
2020 *store_info = self.load_store_info().await?;
2021 if crypt_fields != CryptFields::from(&*store_info) {
2022 return Err(
2023 anyhow!(FxfsError::Inconsistent).context("Crypt fields changed during unlock")
2024 );
2025 }
2026 Ok(())
2027 };
2028
2029 let (layers, _) = open_layers(
2031 self.parent_store.as_ref().unwrap(),
2032 store_info.layers.iter().cloned(),
2033 Some(crypt.clone()),
2034 )
2035 .await
2036 .context("Failed to read object tree layer file contents")?;
2037
2038 let wrapped_key =
2040 fxfs_crypto::WrappedKey::Fxfs(store_info.mutations_key.clone().unwrap().into());
2041 let unwrapped_key = crypt
2042 .unwrap_key(&wrapped_key, self.store_object_id)
2043 .await
2044 .context("Failed to unwrap mutations keys")?;
2045
2046 let last_object_id_cipher = match &store_info.last_object_id {
2048 LastObjectIdInfo::Encrypted { id: _, key } => {
2049 let wrapped_key = fxfs_crypto::WrappedKey::Fxfs(key.clone().into());
2050 let unwrapped = crypt
2051 .unwrap_key(&wrapped_key, self.store_object_id)
2052 .await
2053 .context("Failed to unwrap last object ID key")?;
2054 Some(Box::new(Ff1::new(&unwrapped)))
2055 }
2056 _ => None,
2057 };
2058
2059 let (new_wrapped_mutations_key, new_unwrapped_mutations_key) =
2061 crypt.create_key(self.store_object_id, KeyPurpose::Metadata).await?;
2062
2063 let mut keys_to_cache = Vec::new();
2065 if !read_only && !self.filesystem().options().read_only {
2066 let parent_store = self.parent_store.as_ref().unwrap();
2067 for _ in 0..CACHED_KEYS_LIMIT {
2068 let raw_id = {
2069 let reserved_id = parent_store
2070 .maybe_get_next_object_id()
2071 .expect("maybe_get_next_object_id failed on parent store");
2072 reserved_id.release()
2073 };
2074 let (wrapped, unwrapped) = crypt
2075 .create_key(raw_id.get(), KeyPurpose::Data)
2076 .await
2077 .context("Failed to pre-cache key during unlock")?;
2078 keys_to_cache.push((raw_id, EncryptionKey::Fxfs(wrapped), unwrapped));
2079 }
2080 }
2081
2082 let do_not_use_crypt = crypt;
2085
2086 let fs = self.filesystem();
2087 let guard =
2088 fs.lock_manager().write_lock(lock_keys![LockKey::flush(self.store_object_id())]).await;
2089
2090 update_store_info(&mut store_info).await?;
2091
2092 let mut mutations = {
2094 if store_info.encrypted_mutations_object_id == INVALID_OBJECT_ID {
2095 EncryptedMutations::default()
2096 } else {
2097 let parent_store = self.parent_store.as_ref().unwrap();
2098 let handle = ObjectStore::open_object(
2099 &parent_store,
2100 store_info.encrypted_mutations_object_id,
2101 HandleOptions::default(),
2102 None,
2103 )
2104 .await?;
2105 let mut cursor = std::io::Cursor::new(
2106 handle
2107 .contents(MAX_ENCRYPTED_MUTATIONS_SIZE)
2108 .await
2109 .context(FxfsError::Inconsistent)?,
2110 );
2111 let mut mutations = EncryptedMutations::deserialize_with_version(&mut cursor)
2112 .context("Failed to deserialize EncryptedMutations")?
2113 .0;
2114 let len = cursor.get_ref().len() as u64;
2115 while cursor.position() < len {
2116 mutations.extend(
2117 &EncryptedMutations::deserialize_with_version(&mut cursor)
2118 .context("Failed to deserialize EncryptedMutations")?
2119 .0,
2120 );
2121 }
2122 mutations
2123 }
2124 };
2125
2126 let journaled = EncryptedMutations::from_replayed_mutations(
2128 self.store_object_id,
2129 fs.journal()
2130 .read_transactions_for_object(self.store_object_id)
2131 .await
2132 .context("Failed to read encrypted mutations from journal")?,
2133 );
2134 mutations.extend(&journaled);
2135
2136 std::mem::drop(guard);
2138
2139 let crypt = do_not_use_crypt;
2141
2142 self.filesystem().hooks().on_unlock_resources_acquired();
2143
2144 let EncryptedMutations { transactions, mut data, mutations_key_roll } = mutations;
2147
2148 let mut unwrapped_key_rolls = Vec::with_capacity(mutations_key_roll.len());
2149 for (offset, key) in mutations_key_roll {
2150 let unwrapped = crypt
2151 .unwrap_key(&fxfs_crypto::WrappedKey::Fxfs(key.into()), self.store_object_id)
2152 .await
2153 .context("Failed to unwrap mutations keys")?;
2154 unwrapped_key_rolls.push((offset, unwrapped));
2155 }
2156
2157 let mut mutations_to_apply = Vec::new();
2158
2159 let split_idx = transactions
2163 .partition_point(|(checkpoint, _)| checkpoint.version < AES_JOURNAL_ENCRYPTION_VERSION);
2164 let (chacha_transactions, aes_transactions) = transactions.split_at(split_idx);
2165 let data_offset = if chacha_transactions.is_empty() {
2166 0
2167 } else {
2168 let aes_len = aes_transactions
2169 .iter()
2170 .try_fold(0usize, |total, (_, next)| total.checked_add(*next as usize))
2171 .ok_or(FxfsError::Inconsistent)?;
2172 ensure!(aes_len <= data.len(), FxfsError::Inconsistent);
2173 data.len() - aes_len
2174 };
2175 let (chacha_data, aes_data) = data.split_at_mut(data_offset);
2176
2177 let split_key_idx =
2180 unwrapped_key_rolls.partition_point(|(offset, _)| *offset < data_offset);
2181 let aes_key_rolls: Vec<(usize, UnwrappedKey)> = unwrapped_key_rolls
2182 .split_off(split_key_idx)
2183 .into_iter()
2184 .map(|(offset, key)| (offset - data_offset, key))
2185 .collect();
2186 let chacha_key_rolls = unwrapped_key_rolls;
2187 let mut cipher_sequence_number = store_info.mutations_cipher_offset;
2188
2189 if !chacha_transactions.is_empty() {
2190 ensure!(store_info.mutations_cipher_offset <= u32::MAX as u64, FxfsError::Inconsistent);
2191 let mut cipher = StreamCipher::new(&unwrapped_key, cipher_sequence_number);
2192 mutations_to_apply.append(&mut Self::decrypt_mutations_chacha20(
2193 &mut cipher,
2194 chacha_transactions,
2195 chacha_data,
2196 &chacha_key_rolls,
2197 )?);
2198 cipher_sequence_number = cipher.offset();
2199 }
2200
2201 if !aes_transactions.is_empty() {
2202 let mut cipher = JournalXtsCipher::new(&unwrapped_key, cipher_sequence_number);
2203 mutations_to_apply.append(&mut Self::decrypt_mutations_aes256_xts(
2204 &mut cipher,
2205 aes_transactions,
2206 aes_data,
2207 &aes_key_rolls,
2208 )?);
2209 cipher_sequence_number = cipher.current_tweak();
2210 }
2211
2212 let do_not_use_crypt = crypt;
2215
2216 let guard =
2217 fs.lock_manager().write_lock(lock_keys![LockKey::flush(self.store_object_id())]).await;
2218
2219 update_store_info(&mut store_info).await?;
2220
2221 let _ = std::mem::replace(&mut *self.lock_state.lock(), LockState::Unlocking);
2222
2223 store_info.mutations_key = Some(new_wrapped_mutations_key);
2224 *self.store_info.lock() = Some(store_info.clone());
2225
2226 let clean_up = scopeguard::guard((), |_| {
2227 *self.lock_state.lock() = LockState::Locked;
2228 *self.store_info.lock() = None;
2229 *self.last_object_id.lock() = LastObjectId::Pending;
2230 self.tree.reset();
2232 });
2233
2234 self.tree.append_open_layers(layers);
2236
2237 match &store_info.last_object_id {
2239 LastObjectIdInfo::Encrypted { id, .. } => {
2240 *self.last_object_id.lock() =
2241 LastObjectId::Encrypted { id: *id, cipher: last_object_id_cipher.unwrap() };
2242 }
2243 LastObjectIdInfo::Low32Bit => {
2244 *self.last_object_id.lock() = LastObjectId::Low32Bit {
2245 reserved: Default::default(),
2246 unreserved: Default::default(),
2247 }
2248 }
2249 _ => unreachable!(),
2250 }
2251
2252 for (checkpoint, mutation) in mutations_to_apply {
2254 let context = ApplyContext { mode: ApplyMode::Replay, checkpoint };
2255 self.apply_mutation(mutation, &context, AssocObj::None)
2256 .context("failed to apply encrypted mutation")?;
2257 }
2258
2259 *self.lock_state.lock() = if read_only {
2261 LockState::UnlockedReadOnly(do_not_use_crypt)
2262 } else {
2263 LockState::Unlocked {
2264 crypt: do_not_use_crypt,
2265 cached_keys: keys_to_cache,
2266 mutations_cipher: JournalCipher::new_aes256_xts(
2267 &new_unwrapped_mutations_key,
2268 cipher_sequence_number,
2269 ),
2270 }
2271 };
2272
2273 std::mem::drop(guard);
2277
2278 if !read_only && !self.filesystem().options().read_only {
2279 self.flush_with_reason(FlushReason::EncryptedMutations).await?;
2280
2281 let _ = self.filesystem().graveyard().initial_reap(&self).await?;
2283 }
2284
2285 Ok(ScopeGuard::into_inner(clean_up))
2287 }
2288
2289 fn decrypt_mutations_aes256_xts(
2290 cipher: &mut JournalXtsCipher,
2291 transactions: &[(JournalCheckpoint, u64)],
2292 data: &mut [u8],
2293 key_rolls: &[(usize, UnwrappedKey)],
2294 ) -> Result<Vec<(JournalCheckpoint, Mutation)>, Error> {
2295 let mut mutations_to_apply = Vec::new();
2296 let mut key_roll_iter = key_rolls.iter().peekable();
2297 let mut offset = 0;
2298
2299 for (checkpoint, chunk_len) in transactions {
2300 ensure!(checkpoint.version >= AES_JOURNAL_ENCRYPTION_VERSION, FxfsError::Inconsistent);
2301 while let Some((roll_offset, unwrapped_key)) = key_roll_iter.peek() {
2302 if offset >= *roll_offset {
2303 key_roll_iter.next();
2304 *cipher = JournalXtsCipher::new(unwrapped_key, cipher.current_tweak());
2305 } else {
2306 break;
2307 }
2308 }
2309 let chunk_len = *chunk_len as usize;
2310 ensure!(offset + chunk_len <= data.len(), FxfsError::Inconsistent);
2311 let chunk = &mut data[offset..offset + chunk_len];
2312 let transaction =
2313 EncryptedTransaction::decrypt_and_deserialize(cipher, chunk, checkpoint.version)?;
2314 for mutation in transaction.0 {
2315 mutations_to_apply.push((checkpoint.clone(), mutation));
2316 }
2317 offset += chunk_len;
2318 }
2319 Ok(mutations_to_apply)
2320 }
2321
2322 fn decrypt_mutations_chacha20(
2323 cipher: &mut StreamCipher,
2324 transactions: &[(JournalCheckpoint, u64)],
2325 data: &mut [u8],
2326 key_rolls: &[(usize, UnwrappedKey)],
2327 ) -> Result<Vec<(JournalCheckpoint, Mutation)>, Error> {
2328 let mut mutations_to_apply = Vec::new();
2329 let mut slice = &mut data[..];
2330 let mut last_offset = 0;
2331 for (offset, unwrapped_key) in key_rolls {
2332 let split_offset = offset.checked_sub(last_offset).ok_or(FxfsError::Inconsistent)?;
2333 ensure!(split_offset <= slice.len(), FxfsError::Inconsistent);
2334 last_offset = *offset;
2335 let (old, new) = slice.split_at_mut(split_offset);
2336 cipher.decrypt(old);
2337 *cipher = StreamCipher::new(unwrapped_key, 0);
2338 slice = new;
2339 }
2340 cipher.decrypt(slice);
2341
2342 let mut cursor = std::io::Cursor::new(&*data);
2343 for (checkpoint, count) in transactions {
2344 for _ in 0..*count {
2345 let mutation = Mutation::deserialize_from_version(&mut cursor, checkpoint.version)
2346 .context("failed to deserialize encrypted mutation")?;
2347 mutations_to_apply.push((checkpoint.clone(), mutation));
2348 }
2349 }
2350 Ok(mutations_to_apply)
2351 }
2352
2353 pub fn is_locked(&self) -> bool {
2354 matches!(
2355 *self.lock_state.lock(),
2356 LockState::Locked | LockState::Locking | LockState::Unknown
2357 )
2358 }
2359
2360 pub fn is_unlocked(&self) -> bool {
2363 matches!(
2364 *self.lock_state.lock(),
2365 LockState::Unlocked { .. } | LockState::UnlockedReadOnly(..) | LockState::Unlocking
2366 )
2367 }
2368
2369 pub fn is_unknown(&self) -> bool {
2370 matches!(*self.lock_state.lock(), LockState::Unknown)
2371 }
2372
2373 pub fn is_encrypted(&self) -> bool {
2374 self.store_info.lock().as_ref().unwrap().mutations_key.is_some()
2375 }
2376
2377 pub async fn lock(&self) -> Result<(), Error> {
2383 let keys = lock_keys![LockKey::flush(self.store_object_id())];
2386 let fs = self.filesystem();
2387 let _guard = fs.lock_manager().write_lock(keys).await;
2388
2389 {
2390 let mut lock_state = self.lock_state.lock();
2391 if let LockState::Unlocked { .. } = &*lock_state {
2392 *lock_state = LockState::Locking;
2393 } else {
2394 panic!("Unexpected lock state: {:?}", *lock_state);
2395 }
2396 }
2397
2398 let sync_result =
2403 self.filesystem().sync(SyncOptions { flush_device: true, ..Default::default() }).await;
2404
2405 *self.lock_state.lock() = if let Err(error) = &sync_result {
2406 error!(error:?; "Failed to sync journal; store will no longer be usable");
2407 LockState::Invalid
2408 } else {
2409 LockState::Locked
2410 };
2411 self.key_manager.clear();
2412 *self.store_info.lock() = None;
2413 *self.last_object_id.lock() = LastObjectId::Pending;
2414 self.tree.reset();
2415
2416 sync_result
2417 }
2418
2419 pub fn lock_read_only(&self) {
2423 *self.lock_state.lock() = LockState::Locked;
2424 *self.store_info.lock() = None;
2425 *self.last_object_id.lock() = LastObjectId::Pending;
2426 self.tree.reset();
2427 }
2428
2429 fn maybe_get_next_object_id(&self) -> Option<ReservedId<'_>> {
2432 self.last_object_id.lock().try_get_next().map(|id| ReservedId::new(self, id))
2433 }
2434
2435 pub(super) async fn get_next_object_id(&self) -> Result<ReservedId<'_>, Error> {
2439 {
2440 let mut last_object_id = self.last_object_id.lock();
2441 if let Some(id) = last_object_id.try_get_next() {
2442 return Ok(ReservedId::new(self, id));
2443 }
2444 ensure!(
2445 !matches!(&*last_object_id, LastObjectId::Unencrypted { .. }),
2446 FxfsError::Inconsistent
2447 );
2448 }
2449
2450 let parent_store = self.parent_store().unwrap();
2451
2452 let mut transaction = parent_store
2457 .new_transaction(
2458 lock_keys![LockKey::object(parent_store.store_object_id, self.store_object_id)],
2459 Options {
2460 skip_journal_checks: true,
2463 borrow_metadata_space: true,
2464 ..Default::default()
2465 },
2466 )
2467 .await?;
2468
2469 let mut next_id_hi = 0;
2470
2471 let is_low_32_bit = {
2472 let mut last_object_id = self.last_object_id.lock();
2473 if let Some(id) = last_object_id.try_get_next() {
2474 return Ok(ReservedId::new(self, id));
2476 }
2477
2478 match &*last_object_id {
2479 LastObjectId::Encrypted { id, .. } => {
2480 next_id_hi =
2483 id.checked_add(1 << 32).ok_or(FxfsError::Inconsistent)? & OBJECT_ID_HI_MASK;
2484
2485 info!(store_id = self.store_object_id; "Rolling object ID key");
2486
2487 false
2488 }
2489 LastObjectId::Low32Bit { .. } => true,
2490 _ => unreachable!(),
2491 }
2492 };
2493
2494 if is_low_32_bit {
2495 self.last_object_id.lock().drain_unreserved();
2499
2500 let layer_set = self.tree.layer_set();
2501 let mut key = ObjectKey::object(0);
2502 loop {
2503 let next_id = rand::rng().next_u32() as u64;
2504 let Some(next_id) = NonZero::new(next_id) else { continue };
2505 if self.last_object_id.lock().is_reserved(next_id.get()) {
2506 continue;
2507 }
2508 key.object_id = next_id.get();
2509 if layer_set.key_exists(&key).await? == Existence::Missing {
2510 self.last_object_id.lock().reserve(next_id.get());
2511 return Ok(ReservedId::new(self, next_id));
2512 }
2513 }
2514 } else {
2515 let (object_id_wrapped, object_id_unwrapped) = self
2517 .crypt()
2518 .unwrap()
2519 .create_key(self.store_object_id, KeyPurpose::Metadata)
2520 .await?;
2521
2522 let new_store_info = StoreInfo {
2539 last_object_id: LastObjectIdInfo::Encrypted {
2540 id: next_id_hi,
2541 key: object_id_wrapped.clone(),
2542 },
2543 ..self.load_store_info().await?
2544 };
2545
2546 self.write_store_info(&mut transaction, &new_store_info).await?;
2547
2548 transaction
2549 .commit_with_callback(|_| {
2550 self.store_info.lock().as_mut().unwrap().last_object_id =
2551 new_store_info.last_object_id;
2552 match &mut *self.last_object_id.lock() {
2553 LastObjectId::Encrypted { id, cipher } => {
2554 **cipher = Ff1::new(&object_id_unwrapped);
2555 *id = next_id_hi;
2556 ReservedId::new(
2557 self,
2558 NonZero::new(next_id_hi | cipher.encrypt(0) as u64).unwrap(),
2559 )
2560 }
2561 _ => unreachable!(),
2562 }
2563 })
2564 .await
2565 }
2566 }
2567
2568 pub(crate) fn query_next_object_id(&self) -> u64 {
2571 self.last_object_id.lock().peek_next()
2572 }
2573
2574 fn allocator(&self) -> Arc<Allocator> {
2575 self.filesystem().allocator()
2576 }
2577
2578 async fn txn_get_object_mutation(
2584 &self,
2585 transaction: &Transaction<'_>,
2586 object_id: u64,
2587 ) -> Result<ObjectStoreMutation, Error> {
2588 if let Some(mutation) =
2589 transaction.get_object_mutation(self.store_object_id, ObjectKey::object(object_id))
2590 {
2591 Ok(mutation.clone())
2592 } else {
2593 Ok(ObjectStoreMutation {
2594 item: self
2595 .tree
2596 .find(&ObjectKey::object(object_id))
2597 .await?
2598 .ok_or(FxfsError::Inconsistent)
2599 .context("Object id missing")?,
2600 op: Operation::ReplaceOrInsert,
2601 })
2602 }
2603 }
2604
2605 #[cfg(feature = "migration")]
2608 pub async fn get_object_mutation(
2609 &self,
2610 transaction: &Transaction<'_>,
2611 object_id: u64,
2612 ) -> Result<ObjectStoreMutation, Error> {
2613 self.txn_get_object_mutation(transaction, object_id).await
2614 }
2615
2616 fn update_last_object_id(&self, object_id: u64) {
2617 let mut last_object_id = self.last_object_id.lock();
2618 match &mut *last_object_id {
2619 LastObjectId::Pending => unreachable!(),
2620 LastObjectId::Unencrypted { id } => {
2621 if object_id > *id {
2622 *id = object_id
2623 }
2624 }
2625 LastObjectId::Encrypted { id, cipher } => {
2626 let object_id =
2633 object_id & OBJECT_ID_HI_MASK | cipher.decrypt(object_id as u32) as u64;
2634 if object_id > *id {
2635 *id = object_id;
2636 }
2637 }
2638 LastObjectId::Low32Bit { .. } => {}
2639 }
2640 }
2641
2642 pub fn to_unencrypted_object_id(&self, object_id: u64) -> Option<u64> {
2645 let last_object_id = self.last_object_id.lock();
2646 match &*last_object_id {
2647 LastObjectId::Pending => None,
2648 LastObjectId::Unencrypted { .. } | LastObjectId::Low32Bit { .. } => Some(object_id),
2649 LastObjectId::Encrypted { id, cipher } => {
2650 if id & OBJECT_ID_HI_MASK != object_id & OBJECT_ID_HI_MASK {
2651 None
2652 } else {
2653 Some(object_id & OBJECT_ID_HI_MASK | cipher.decrypt(object_id as u32) as u64)
2654 }
2655 }
2656 }
2657 }
2658
2659 pub fn add_to_graveyard(&self, transaction: &mut Transaction<'_>, object_id: u64) {
2661 let graveyard_id = self.graveyard_directory_object_id();
2662 assert_ne!(graveyard_id, INVALID_OBJECT_ID);
2663 transaction.add(
2664 self.store_object_id,
2665 Mutation::replace_or_insert_object(
2666 ObjectKey::graveyard_entry(graveyard_id, object_id),
2667 ObjectValue::Some,
2668 ),
2669 );
2670 }
2671
2672 pub fn remove_from_graveyard(&self, transaction: &mut Transaction<'_>, object_id: u64) {
2685 transaction.add(
2686 self.store_object_id,
2687 Mutation::replace_or_insert_object(
2688 ObjectKey::graveyard_entry(self.graveyard_directory_object_id(), object_id),
2689 ObjectValue::None,
2690 ),
2691 );
2692 }
2693
2694 pub fn remove_attribute_from_graveyard(
2699 &self,
2700 transaction: &mut Transaction<'_>,
2701 object_id: u64,
2702 attribute_id: AttributeId,
2703 ) {
2704 transaction.add(
2705 self.store_object_id,
2706 Mutation::replace_or_insert_object(
2707 ObjectKey::graveyard_attribute_entry(
2708 self.graveyard_directory_object_id(),
2709 object_id,
2710 attribute_id,
2711 ),
2712 ObjectValue::None,
2713 ),
2714 );
2715 }
2716
2717 pub async fn read_encrypted_symlink(
2722 &self,
2723 object_id: u64,
2724 link: Vec<u8>,
2725 ) -> Result<Vec<u8>, Error> {
2726 let mut link = link;
2727 let key = self
2728 .key_manager()
2729 .get_fscrypt_key(object_id, self.crypt().unwrap().as_ref(), async || {
2730 self.get_keys(object_id).await
2731 })
2732 .await?;
2733 if let Some(key) = key.into_cipher() {
2734 key.decrypt_symlink(object_id, &mut link)?;
2735 Ok(link)
2736 } else {
2737 let proxy_filename =
2739 fscrypt::proxy_filename::ProxyFilename::new_with_hash_code(0, &link);
2740 let proxy_filename_str: String = proxy_filename.into();
2741 Ok(proxy_filename_str.into_bytes())
2742 }
2743 }
2744
2745 pub async fn read_symlink(&self, object_id: u64) -> Result<Vec<u8>, Error> {
2747 match self.tree.find_value(&ObjectKey::object(object_id)).await? {
2748 None => bail!(FxfsError::NotFound),
2749 Some(ObjectValue::Object {
2750 kind: ObjectKind::EncryptedSymlink { link, .. }, ..
2751 }) => self.read_encrypted_symlink(object_id, link.into_vec()).await,
2752 Some(ObjectValue::Object { kind: ObjectKind::Symlink { link, .. }, .. }) => {
2753 Ok(link.into_vec())
2754 }
2755 Some(value) => Err(anyhow!(FxfsError::Inconsistent)
2756 .context(format!("Unexpected value in symlink lookup: {value:?}"))),
2757 }
2758 }
2759
2760 fn fail_on_illegal_keys(&self, keys: &EncryptionKeys) -> Result<(), Error> {
2764 if !self.is_root() {
2765 return Ok(());
2766 }
2767
2768 for key in keys.iter() {
2769 if !matches!(key.1, EncryptionKey::Fxfs(_)) {
2770 return Err(
2771 anyhow!(FxfsError::IntegrityError).context("Illegal key type in root store")
2772 );
2773 }
2774 }
2775 Ok(())
2776 }
2777
2778 pub async fn get_keys(&self, object_id: u64) -> Result<EncryptionKeys, Error> {
2781 self.tree
2782 .find_map(&ObjectKey::keys(object_id), |item| match item.value {
2783 ObjectValue::Keys(keys) => {
2784 self.fail_on_illegal_keys(keys)?;
2785 Ok(keys.clone())
2786 }
2787 _ => Err(anyhow!(FxfsError::Inconsistent).context("open_object: Expected keys")),
2788 })
2789 .await?
2790 .ok_or(FxfsError::Inconsistent)?
2791 }
2792
2793 pub async fn update_attributes<'a>(
2794 &self,
2795 transaction: &mut Transaction<'a>,
2796 object_id: u64,
2797 node_attributes: Option<&fio::MutableNodeAttributes>,
2798 change_time: Option<Timestamp>,
2799 ) -> Result<(), Error> {
2800 if change_time.is_none() {
2801 if let Some(attributes) = node_attributes {
2802 let empty_attributes = fio::MutableNodeAttributes { ..Default::default() };
2803 if *attributes == empty_attributes {
2804 return Ok(());
2805 }
2806 } else {
2807 return Ok(());
2808 }
2809 }
2810 let mut mutation = self.txn_get_object_mutation(transaction, object_id).await?;
2811 if let ObjectValue::Object { ref mut attributes, .. } = mutation.item.value {
2812 if let Some(time) = change_time {
2813 attributes.change_time = time;
2814 }
2815 if let Some(node_attributes) = node_attributes {
2816 if let Some(time) = node_attributes.creation_time {
2817 attributes.creation_time = Timestamp::from_nanos(time);
2818 }
2819 if let Some(time) = node_attributes.modification_time {
2820 attributes.modification_time = Timestamp::from_nanos(time);
2821 }
2822 if let Some(time) = node_attributes.access_time {
2823 attributes.access_time = Timestamp::from_nanos(time);
2824 }
2825 if node_attributes.mode.is_some()
2826 || node_attributes.uid.is_some()
2827 || node_attributes.gid.is_some()
2828 || node_attributes.rdev.is_some()
2829 {
2830 if let Some(a) = &mut attributes.posix_attributes {
2831 if let Some(mode) = node_attributes.mode {
2832 a.mode = mode;
2833 }
2834 if let Some(uid) = node_attributes.uid {
2835 a.uid = uid;
2836 }
2837 if let Some(gid) = node_attributes.gid {
2838 a.gid = gid;
2839 }
2840 if let Some(rdev) = node_attributes.rdev {
2841 a.rdev = rdev;
2842 }
2843 } else {
2844 attributes.posix_attributes = Some(PosixAttributes {
2845 mode: node_attributes.mode.unwrap_or_default(),
2846 uid: node_attributes.uid.unwrap_or_default(),
2847 gid: node_attributes.gid.unwrap_or_default(),
2848 rdev: node_attributes.rdev.unwrap_or_default(),
2849 });
2850 }
2851 }
2852 }
2853 } else {
2854 bail!(
2855 anyhow!(FxfsError::Inconsistent)
2856 .context("ObjectStore.update_attributes: Expected object value")
2857 );
2858 };
2859 transaction.add(self.store_object_id(), Mutation::ObjectStore(mutation));
2860 Ok(())
2861 }
2862
2863 pub async fn update_access_time(
2869 &self,
2870 object_id: u64,
2871 props: &mut ObjectProperties,
2872 precondition: impl FnOnce() -> bool,
2873 ) -> Result<(), Error> {
2874 let access_time = props.access_time.as_nanos();
2875 let modification_time = props.modification_time.as_nanos();
2876 let change_time = props.change_time.as_nanos();
2877 let now = Timestamp::now();
2878 if access_time <= modification_time
2879 || access_time <= change_time
2880 || access_time
2881 < now.as_nanos()
2882 - Timestamp::from(std::time::Duration::from_secs(24 * 60 * 60)).as_nanos()
2883 {
2884 let mut transaction = self
2885 .new_transaction(
2886 lock_keys![LockKey::object(self.store_object_id, object_id,)],
2887 Options { borrow_metadata_space: true, ..Default::default() },
2888 )
2889 .await?;
2890 if precondition() {
2891 self.update_attributes(
2892 &mut transaction,
2893 object_id,
2894 Some(&fio::MutableNodeAttributes {
2895 access_time: Some(now.as_nanos()),
2896 ..Default::default()
2897 }),
2898 None,
2899 )
2900 .await?;
2901 transaction.commit().await?;
2902 props.access_time = now;
2903 }
2904 }
2905 Ok(())
2906 }
2907
2908 async fn write_store_info<'a>(
2909 &'a self,
2910 transaction: &mut Transaction<'a>,
2911 info: &StoreInfo,
2912 ) -> Result<(), Error> {
2913 let mut serialized_info = Vec::new();
2914 info.serialize_with_version(&mut serialized_info)?;
2915 let mut buf = self.device.allocate_buffer(serialized_info.len()).await;
2916 buf.copy_from_slice(&serialized_info);
2917 self.store_info_handle.get().unwrap().txn_write(transaction, 0u64, buf.as_ref()).await
2918 }
2919
2920 pub fn mark_deleted(&self) {
2921 *self.lock_state.lock() = LockState::Deleted;
2922 }
2923
2924 #[cfg(test)]
2925 pub(crate) fn test_set_last_object_id(&self, object_id: u64) {
2926 match &mut *self.last_object_id.lock() {
2927 LastObjectId::Encrypted { id, .. } => *id = object_id,
2928 _ => unreachable!(),
2929 }
2930 }
2931
2932 pub async fn get_attribute_size(
2935 &self,
2936 object_id: u64,
2937 attribute_id: AttributeId,
2938 ) -> Result<u64, Error> {
2939 let size = self
2940 .tree
2941 .find_map(
2942 &ObjectKey::attribute(object_id, attribute_id, AttributeKey::Attribute),
2943 |item| match item.value {
2944 ObjectValue::Attribute { size, .. }
2945 | ObjectValue::VerifiedAttribute { size, .. } => Ok(*size),
2946 _ => Err(anyhow!(FxfsError::Inconsistent)),
2947 },
2948 )
2949 .await?
2950 .ok_or(FxfsError::NotFound)??;
2951 Ok(size)
2952 }
2953}
2954
2955#[async_trait]
2956impl JournalingObject for ObjectStore {
2957 fn apply_mutation(
2958 &self,
2959 mutation: Mutation,
2960 context: &ApplyContext<'_, '_>,
2961 _assoc_obj: AssocObj<'_>,
2962 ) -> Result<(), Error> {
2963 match &*self.lock_state.lock() {
2964 LockState::Locked | LockState::Locking => {
2965 ensure!(
2966 matches!(mutation, Mutation::BeginFlush | Mutation::EndFlush)
2967 || matches!(
2968 mutation,
2969 Mutation::EncryptedObjectStore(_) | Mutation::UpdateMutationsKey(_)
2970 if context.mode.is_replay()
2971 ),
2972 anyhow!(FxfsError::Inconsistent)
2973 .context(format!("Unexpected mutation for encrypted store: {mutation:?}"))
2974 );
2975 }
2976 LockState::Invalid
2977 | LockState::Unlocking
2978 | LockState::Unencrypted
2979 | LockState::Unlocked { .. }
2980 | LockState::UnlockedReadOnly(..)
2981 | LockState::Deleted => {}
2982 lock_state @ _ => panic!("Unexpected lock state: {lock_state:?}"),
2983 }
2984 match mutation {
2985 Mutation::ObjectStore(ObjectStoreMutation { item, op }) => {
2986 match op {
2987 Operation::Insert => {
2988 let mut unreserve_id = INVALID_OBJECT_ID;
2989 if matches!(item.value, ObjectValue::Object { .. }) {
2992 {
2993 let info = &mut self.store_info.lock();
2994 let object_count = &mut info.as_mut().unwrap().object_count;
2995 *object_count = object_count.saturating_add(1);
2996 }
2997 if context.mode.is_replay() {
2998 self.update_last_object_id(item.key.object_id);
2999 } else {
3000 unreserve_id = item.key.object_id;
3001 }
3002 } else if !context.mode.is_replay()
3003 && matches!(
3004 item.key.data,
3005 ObjectKeyData::GraveyardEntry { .. }
3006 | ObjectKeyData::GraveyardAttributeEntry { .. }
3007 )
3008 {
3009 if matches!(item.value, ObjectValue::Some | ObjectValue::Trim) {
3010 self.graveyard_entries.fetch_add(1, Ordering::Relaxed);
3011 } else if matches!(item.value, ObjectValue::None) {
3012 self.graveyard_entries.fetch_sub(1, Ordering::Relaxed);
3013 }
3014 }
3015 self.tree.insert(item)?;
3016 if unreserve_id != INVALID_OBJECT_ID {
3017 self.last_object_id.lock().unreserve(unreserve_id);
3019 }
3020 }
3021 Operation::ReplaceOrInsert => {
3022 if !context.mode.is_replay()
3023 && matches!(
3024 item.key.data,
3025 ObjectKeyData::GraveyardEntry { .. }
3026 | ObjectKeyData::GraveyardAttributeEntry { .. }
3027 )
3028 {
3029 if matches!(item.value, ObjectValue::Some | ObjectValue::Trim) {
3030 self.graveyard_entries.fetch_add(1, Ordering::Relaxed);
3031 } else if matches!(item.value, ObjectValue::None) {
3032 self.graveyard_entries.fetch_sub(1, Ordering::Relaxed);
3033 }
3034 }
3035 self.tree.replace_or_insert(item);
3036 }
3037 Operation::Merge => {
3038 if item.is_tombstone() {
3039 let info = &mut self.store_info.lock();
3040 let object_count = &mut info.as_mut().unwrap().object_count;
3041 *object_count = object_count.saturating_sub(1);
3042 if !context.mode.is_replay() {
3043 let _ = self.key_manager.remove(item.key.object_id);
3050 }
3051 }
3052 if !context.mode.is_replay()
3053 && matches!(
3054 item.key.data,
3055 ObjectKeyData::GraveyardEntry { .. }
3056 | ObjectKeyData::GraveyardAttributeEntry { .. }
3057 )
3058 {
3059 if matches!(item.value, ObjectValue::Some | ObjectValue::Trim) {
3060 self.graveyard_entries.fetch_add(1, Ordering::Relaxed);
3061 } else if matches!(item.value, ObjectValue::None) {
3062 self.graveyard_entries.fetch_sub(1, Ordering::Relaxed);
3063 }
3064 }
3065 let lower_bound = item.key.key_for_merge_into();
3066 self.tree.merge_into(item, &lower_bound);
3067 }
3068 }
3069 }
3070 Mutation::BeginFlush => {
3071 ensure!(self.parent_store.is_some(), FxfsError::Inconsistent);
3072 self.tree.seal();
3073 }
3074 Mutation::EndFlush => ensure!(self.parent_store.is_some(), FxfsError::Inconsistent),
3075 Mutation::EncryptedObjectStore(_) | Mutation::UpdateMutationsKey(_) => {
3076 ensure!(
3078 !matches!(&*self.lock_state.lock(), LockState::Unencrypted),
3079 FxfsError::Inconsistent
3080 );
3081 }
3082 Mutation::CreateInternalDir(object_id) => {
3083 ensure!(object_id != INVALID_OBJECT_ID, FxfsError::Inconsistent);
3084 self.store_info.lock().as_mut().unwrap().internal_directory_object_id = object_id;
3085 }
3086 _ => bail!("unexpected mutation: {:?}", mutation),
3087 }
3088 self.counters.lock().mutations_applied += 1;
3089 Ok(())
3090 }
3091
3092 fn drop_mutation(&self, mutation: Mutation, _transaction: &Transaction<'_>) {
3093 self.counters.lock().mutations_dropped += 1;
3094 if let Mutation::ObjectStore(ObjectStoreMutation {
3095 item: Item { key: ObjectKey { object_id, .. }, value: ObjectValue::Object { .. }, .. },
3096 op: Operation::Insert,
3097 }) = mutation
3098 {
3099 self.last_object_id.lock().unreserve(object_id);
3100 }
3101 }
3102
3103 async fn prepare_commit<'a>(
3104 &self,
3105 filesystem: &'a FxFilesystem,
3106 _transaction: &Transaction<'_>,
3107 ) -> Result<Option<WriteGuard<'a>>, Error> {
3108 if !matches!(&*self.lock_state.lock(), LockState::Unlocked { .. }) {
3110 return Ok(None);
3111 }
3112
3113 let keys = lock_keys![LockKey::pre_cache_keys(self.store_object_id())];
3117 let guard = filesystem.lock_manager().write_lock(keys).await;
3118
3119 self.pre_cache_keys().await?;
3120
3121 Ok(Some(guard))
3122 }
3123
3124 async fn flush(&self, reason: FlushReason) -> Result<Version, Error> {
3131 self.flush_with_reason(reason).await
3132 }
3133
3134 fn write_mutations(
3135 &self,
3136 mutations: ObjectMutationIterator<'_, '_>,
3137 mut writer: journal::Writer<'_>,
3138 ) {
3139 let mut lock_state = self.lock_state.lock();
3140 if let LockState::Unlocked { mutations_cipher, .. } = &mut *lock_state {
3141 let mut encrypted_transaction = EncryptedTransaction::new();
3142 for mutation in mutations.cloned() {
3143 match mutation {
3148 Mutation::ObjectStore(_) | Mutation::CreateInternalDir(_) => {
3159 encrypted_transaction.0.push(mutation)
3160 }
3161 Mutation::EncryptedObjectStore(_) | Mutation::UpdateMutationsKey(_) => {
3166 debug_assert!(
3167 false,
3168 "Only this method should generate encrypted mutations"
3169 );
3170 }
3171 Mutation::Allocator(_)
3177 | Mutation::BeginFlush
3178 | Mutation::EndFlush
3179 | Mutation::DeleteVolume
3180 | Mutation::UpdateBorrowed(_) => {
3181 writer.write(mutation);
3182 }
3183 }
3184 }
3185 if !encrypted_transaction.0.is_empty() {
3186 if mutations_cipher.key_is_new() {
3188 writer.write(Mutation::update_mutations_key(
3189 self.store_info
3190 .lock()
3191 .as_ref()
3192 .unwrap()
3193 .mutations_key
3194 .as_ref()
3195 .unwrap()
3196 .clone(),
3197 ));
3198 }
3199 for encrypted in encrypted_transaction.serialize_and_encrypt(mutations_cipher) {
3200 writer.write(Mutation::EncryptedObjectStore(encrypted));
3201 }
3202 }
3203 } else {
3204 for mutation in mutations {
3205 writer.write(mutation.clone());
3206 }
3207 }
3208 }
3209}
3210
3211pub type EncryptedTransaction = EncryptedTransactionV57;
3214
3215static_assertions::const_assert!(EncryptedTransaction::MAX_CHUNK_SIZE % 16 == 0);
3216impl EncryptedTransaction {
3217 const MAX_CHUNK_SIZE: usize = DEFAULT_MAX_SERIALIZED_RECORD_SIZE as usize - 48;
3222
3223 fn new() -> Self {
3224 Self(Vec::new())
3225 }
3226
3227 fn serialize_and_encrypt<'a>(
3228 &self,
3229 cipher: &'a mut JournalCipher,
3230 ) -> impl Iterator<Item = Box<[u8]>> + 'a {
3231 let mut buffer = Vec::new();
3232 self.serialize_into(&mut buffer).unwrap();
3233 (0..buffer.len()).step_by(Self::MAX_CHUNK_SIZE).map(move |offset| {
3235 let end = std::cmp::min(offset + Self::MAX_CHUNK_SIZE, buffer.len());
3236 Box::from(cipher.encrypt(&buffer[offset..end]))
3237 })
3238 }
3239
3240 fn decrypt_and_deserialize(
3241 cipher: &mut JournalXtsCipher,
3242 data: &mut [u8],
3243 version: Version,
3244 ) -> Result<Self, Error> {
3245 let (sub_chunks, remainder) = data.as_chunks_mut::<{ Self::MAX_CHUNK_SIZE }>();
3247 for chunk in sub_chunks {
3248 cipher.decrypt(chunk.as_mut_slice());
3249 }
3250 if remainder.len() > 0 {
3251 cipher.decrypt(remainder);
3252 }
3253 let mut chunk_cursor = std::io::Cursor::new(&*data);
3254 Self::deserialize_from_version(&mut chunk_cursor, version)
3255 .context("failed to deserialize encrypted transaction")
3256 }
3257}
3258
3259#[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd, Serialize, Deserialize)]
3263pub struct EncryptedTransactionV57(pub Vec<Mutation>);
3264
3265impl TypeFingerprint for EncryptedTransactionV57 {
3266 fn fingerprint() -> String {
3267 format!(
3268 "struct{{MAX_CHUNK_SIZE: {}, {}}}",
3269 Self::MAX_CHUNK_SIZE,
3271 Vec::<Mutation>::fingerprint()
3272 )
3273 }
3274}
3275
3276impl Versioned for EncryptedTransactionV57 {
3277 fn max_serialized_size() -> Option<u64> {
3280 None
3281 }
3282}
3283
3284impl Drop for ObjectStore {
3285 fn drop(&mut self) {
3286 let mut last_object_id = self.last_object_id.lock();
3287 last_object_id.drain_unreserved();
3288 match &*last_object_id {
3289 LastObjectId::Low32Bit { reserved, .. } => debug_assert!(reserved.is_empty()),
3290 _ => {}
3291 }
3292 }
3293}
3294
3295impl HandleOwner for ObjectStore {}
3296
3297impl AsRef<ObjectStore> for ObjectStore {
3298 fn as_ref(&self) -> &ObjectStore {
3299 self
3300 }
3301}
3302
3303fn layer_size_from_encrypted_mutations_size(size: u64) -> u64 {
3304 size * 3
3312}
3313
3314impl AssociatedObject for ObjectStore {}
3315
3316#[derive(Debug)]
3318pub enum TrimMode {
3319 UseSize,
3321
3322 FromOffset(u64),
3324
3325 Tombstone(TombstoneMode),
3327}
3328
3329#[derive(Debug)]
3331pub enum TombstoneMode {
3332 Object,
3333 Attribute,
3334}
3335
3336#[derive(Debug)]
3338pub enum TrimResult {
3339 Incomplete,
3341
3342 Done(Option<AttributeId>),
3345}
3346
3347pub async fn load_store_info(
3349 parent: &Arc<ObjectStore>,
3350 store_object_id: u64,
3351) -> Result<StoreInfo, Error> {
3352 load_store_info_from_handle(
3353 &ObjectStore::open_object(parent, store_object_id, HandleOptions::default(), None).await?,
3354 )
3355 .await
3356}
3357
3358async fn load_store_info_from_handle(
3359 handle: &DataObjectHandle<impl HandleOwner>,
3360) -> Result<StoreInfo, Error> {
3361 Ok(if handle.get_size() > 0 {
3362 let serialized_info = handle.contents(MAX_STORE_INFO_SERIALIZED_SIZE).await?;
3363 let mut cursor = std::io::Cursor::new(serialized_info);
3364 let (store_info, _) = StoreInfo::deserialize_with_version(&mut cursor)
3365 .context("Failed to deserialize StoreInfo")?;
3366 store_info
3367 } else {
3368 StoreInfo::default()
3370 })
3371}
3372
3373#[cfg(test)]
3374mod tests {
3375 use super::{
3376 AttributeId, DirectWriter, EncryptedMutations, FsverityMetadata, HandleOptions,
3377 LastObjectId, LastObjectIdInfo, LockKey, LockState, MAX_STORE_INFO_SERIALIZED_SIZE,
3378 Mutation, NewChildStoreOptions, OBJECT_ID_HI_MASK, ObjectEncryptionOptions, ObjectStore,
3379 RootDigest, StoreInfo, StoreOptions,
3380 };
3381 use crate::errors::FxfsError;
3382 use crate::filesystem::{
3383 FlushReason, ForceMajor, FxFilesystem, FxFilesystemBuilder, OpenFxFilesystem,
3384 };
3385 use crate::fsck::{fsck, fsck_volume};
3386 use crate::hooks::{Hooks, HooksHandle};
3387 use crate::lsm_tree::Query;
3388 use crate::lsm_tree::types::{ItemRef, LayerIterator};
3389 use crate::object_handle::{INVALID_OBJECT_ID, ObjectHandle, WriteBytes, WriteObjectHandle};
3390 use crate::object_store::directory::{Directory, replace_child};
3391 use crate::object_store::journal::{JournalCheckpoint, JournalOptions};
3392 use crate::object_store::object_record::{
3393 AttributeKey, ObjectDescriptor, ObjectKey, ObjectKind, ObjectValue,
3394 };
3395 use crate::object_store::store_object_handle::MAX_INLINE_XATTR_SIZE;
3396 use crate::object_store::transaction::{Options, lock_keys};
3397 use crate::object_store::volume::root_volume;
3398 use crate::serialized_types::{
3399 DEFAULT_MAX_SERIALIZED_RECORD_SIZE, Version, Versioned, VersionedLatest,
3400 };
3401 use crate::testing;
3402 use assert_matches::assert_matches;
3403 use async_trait::async_trait;
3404 use fuchsia_async as fasync;
3405 use fuchsia_sync::Mutex;
3406 use futures::channel::oneshot;
3407 use futures::{FutureExt, join};
3408 use fxfs_crypto::ff1::Ff1;
3409 use fxfs_crypto::{
3410 Crypt, EncryptionKey, FXFS_KEY_SIZE, FXFS_WRAPPED_KEY_SIZE, FxfsKey, JournalCipher,
3411 KeyPurpose, ObjectType, StreamCipher, UnwrappedKey, WrappedKey, WrappedKeyBytes,
3412 WrappingKeyId,
3413 };
3414 use fxfs_insecure_crypto::new_insecure_crypt;
3415 use std::sync::Arc;
3416 use std::sync::atomic::{AtomicBool, AtomicIsize, Ordering};
3417 use std::time::Duration;
3418 use storage_device::DeviceHolder;
3419 use storage_device::fake_device::FakeDevice;
3420 use test_case::test_case;
3421 use zx_status as zx;
3422
3423 const TEST_DEVICE_BLOCK_SIZE: u32 = 512;
3424
3425 async fn test_filesystem_with_hooks(hooks: Arc<HooksHandle>) -> OpenFxFilesystem {
3426 let device = DeviceHolder::new(FakeDevice::new(8192, TEST_DEVICE_BLOCK_SIZE));
3427 FxFilesystemBuilder::new()
3428 .hooks(hooks)
3429 .format(true)
3430 .open(device)
3431 .await
3432 .expect("open failed")
3433 }
3434
3435 async fn test_filesystem() -> OpenFxFilesystem {
3436 test_filesystem_with_hooks(Default::default()).await
3437 }
3438
3439 #[fuchsia::test]
3440 async fn test_verified_file_with_verified_attribute() {
3441 let fs: OpenFxFilesystem = test_filesystem().await;
3442 let mut transaction = fs
3443 .root_store()
3444 .new_transaction(lock_keys![], Options::default())
3445 .await
3446 .expect("new_transaction failed");
3447 let store = fs.root_store();
3448 let object = Arc::new(
3449 ObjectStore::create_object(&store, &mut transaction, HandleOptions::default(), None)
3450 .await
3451 .expect("create_object failed"),
3452 );
3453
3454 transaction.add(
3455 store.store_object_id(),
3456 Mutation::replace_or_insert_object(
3457 ObjectKey::attribute(
3458 object.object_id(),
3459 AttributeId::DATA,
3460 AttributeKey::Attribute,
3461 ),
3462 ObjectValue::verified_attribute(
3463 0,
3464 FsverityMetadata::Internal(RootDigest::Sha256([0; 32]), vec![]),
3465 ),
3466 ),
3467 );
3468
3469 transaction.add(
3470 store.store_object_id(),
3471 Mutation::replace_or_insert_object(
3472 ObjectKey::attribute(
3473 object.object_id(),
3474 AttributeId::FSVERITY_MERKLE,
3475 AttributeKey::Attribute,
3476 ),
3477 ObjectValue::attribute(0, false),
3478 ),
3479 );
3480
3481 transaction.commit().await.unwrap();
3482
3483 let handle =
3484 ObjectStore::open_object(&store, object.object_id(), HandleOptions::default(), None)
3485 .await
3486 .expect("open_object failed");
3487
3488 assert!(handle.is_verified_file());
3489
3490 fs.close().await.expect("Close failed");
3491 }
3492
3493 #[fuchsia::test]
3494 async fn test_verified_file_without_verified_attribute() {
3495 let fs: OpenFxFilesystem = test_filesystem().await;
3496 let mut transaction = fs
3497 .root_store()
3498 .new_transaction(lock_keys![], Options::default())
3499 .await
3500 .expect("new_transaction failed");
3501 let store = fs.root_store();
3502 let object = Arc::new(
3503 ObjectStore::create_object(&store, &mut transaction, HandleOptions::default(), None)
3504 .await
3505 .expect("create_object failed"),
3506 );
3507
3508 transaction.commit().await.unwrap();
3509
3510 let handle =
3511 ObjectStore::open_object(&store, object.object_id(), HandleOptions::default(), None)
3512 .await
3513 .expect("open_object failed");
3514
3515 assert!(!handle.is_verified_file());
3516
3517 fs.close().await.expect("Close failed");
3518 }
3519
3520 #[fuchsia::test]
3521 async fn test_create_and_open_store() {
3522 let fs = test_filesystem().await;
3523 let store_id = {
3524 let root_volume = root_volume(fs.clone()).await.expect("root_volume failed");
3525 root_volume
3526 .new_volume(
3527 "test",
3528 NewChildStoreOptions {
3529 options: StoreOptions { crypt: Some(Arc::new(new_insecure_crypt())) },
3530 ..Default::default()
3531 },
3532 )
3533 .await
3534 .expect("new_volume failed")
3535 .store_object_id()
3536 };
3537
3538 fs.close().await.expect("close failed");
3539 let device = fs.take_device().await;
3540 device.reopen(false);
3541 let fs = FxFilesystem::open(device).await.expect("open failed");
3542
3543 {
3544 let store = fs.object_manager().store(store_id).expect("store not found");
3545 store.unlock(Arc::new(new_insecure_crypt())).await.expect("unlock failed");
3546 }
3547 fs.close().await.expect("Close failed");
3548 }
3549
3550 #[fuchsia::test]
3551 async fn test_create_and_open_internal_dir() {
3552 let fs = test_filesystem().await;
3553 let dir_id;
3554 let store_id;
3555 {
3556 let root_volume = root_volume(fs.clone()).await.expect("root_volume failed");
3557 let store = root_volume
3558 .new_volume(
3559 "test",
3560 NewChildStoreOptions {
3561 options: StoreOptions { crypt: Some(Arc::new(new_insecure_crypt())) },
3562 ..Default::default()
3563 },
3564 )
3565 .await
3566 .expect("new_volume failed");
3567 dir_id =
3568 store.get_or_create_internal_directory_id().await.expect("Create internal dir");
3569 store_id = store.store_object_id();
3570 }
3571
3572 fs.close().await.expect("close failed");
3573 let device = fs.take_device().await;
3574 device.reopen(false);
3575 let fs = FxFilesystem::open(device).await.expect("open failed");
3576
3577 {
3578 let store = fs.object_manager().store(store_id).expect("store not found");
3579 store.unlock(Arc::new(new_insecure_crypt())).await.expect("unlock failed");
3580 assert_eq!(
3581 dir_id,
3582 store.get_or_create_internal_directory_id().await.expect("Retrieving dir")
3583 );
3584 let obj = store
3585 .tree()
3586 .find_value(&ObjectKey::object(dir_id))
3587 .await
3588 .expect("Searching tree for dir")
3589 .unwrap();
3590 assert_matches!(obj, ObjectValue::Object { kind: ObjectKind::Directory { .. }, .. });
3591 }
3592 fs.close().await.expect("Close failed");
3593 }
3594
3595 #[fuchsia::test]
3596 async fn test_create_and_open_internal_dir_unencrypted() {
3597 let fs = test_filesystem().await;
3598 let dir_id;
3599 let store_id;
3600 {
3601 let root_volume = root_volume(fs.clone()).await.expect("root_volume failed");
3602 let store = root_volume
3603 .new_volume("test", NewChildStoreOptions::default())
3604 .await
3605 .expect("new_volume failed");
3606 dir_id =
3607 store.get_or_create_internal_directory_id().await.expect("Create internal dir");
3608 store_id = store.store_object_id();
3609 }
3610
3611 fs.close().await.expect("close failed");
3612 let device = fs.take_device().await;
3613 device.reopen(false);
3614 let fs = FxFilesystem::open(device).await.expect("open failed");
3615
3616 {
3617 let store = fs.object_manager().store(store_id).expect("store not found");
3618 assert_eq!(
3619 dir_id,
3620 store.get_or_create_internal_directory_id().await.expect("Retrieving dir")
3621 );
3622 let obj = store
3623 .tree()
3624 .find_value(&ObjectKey::object(dir_id))
3625 .await
3626 .expect("Searching tree for dir")
3627 .unwrap();
3628 assert_matches!(obj, ObjectValue::Object { kind: ObjectKind::Directory { .. }, .. });
3629 }
3630 fs.close().await.expect("Close failed");
3631 }
3632
3633 #[fuchsia::test(threads = 10)]
3634 async fn test_old_layers_are_purged() {
3635 let fs = test_filesystem().await;
3636
3637 let store = fs.root_store();
3638 let mut transaction = fs
3639 .root_store()
3640 .new_transaction(lock_keys![], Options::default())
3641 .await
3642 .expect("new_transaction failed");
3643 let object = Arc::new(
3644 ObjectStore::create_object(&store, &mut transaction, HandleOptions::default(), None)
3645 .await
3646 .expect("create_object failed"),
3647 );
3648 transaction.commit().await.expect("commit failed");
3649
3650 store.flush().await.expect("flush failed");
3651
3652 let mut buf = object.allocate_buffer(5).await;
3653 buf.copy_from_slice(b"hello");
3654 object.write_or_append(Some(0), buf.as_ref()).await.expect("write failed");
3655
3656 let layer_set = store.tree().layer_set();
3658
3659 let done = Mutex::new(false);
3660 let mut object_id = 0;
3661
3662 join!(
3663 async {
3664 store.flush().await.expect("flush failed");
3665 assert!(*done.lock());
3666 },
3667 async {
3668 fasync::Timer::new(Duration::from_secs(1)).await;
3670 *done.lock() = true;
3671 object_id = layer_set.layers.last().unwrap().handle().unwrap().object_id();
3672 std::mem::drop(layer_set);
3673 }
3674 );
3675
3676 if let Err(e) = ObjectStore::open_object(
3677 &store.parent_store.as_ref().unwrap(),
3678 object_id,
3679 HandleOptions::default(),
3680 store.crypt(),
3681 )
3682 .await
3683 {
3684 assert!(FxfsError::NotFound.matches(&e));
3685 } else {
3686 panic!("open_object succeeded");
3687 }
3688 }
3689
3690 #[fuchsia::test]
3691 async fn test_tombstone_deletes_data() {
3692 let fs = test_filesystem().await;
3693 let root_store = fs.root_store();
3694 let child_id = {
3695 let mut transaction = fs
3696 .root_store()
3697 .new_transaction(lock_keys![], Options::default())
3698 .await
3699 .expect("new_transaction failed");
3700 let child = ObjectStore::create_object(
3701 &root_store,
3702 &mut transaction,
3703 HandleOptions::default(),
3704 None,
3705 )
3706 .await
3707 .expect("create_object failed");
3708 root_store.add_to_graveyard(&mut transaction, child.object_id());
3709 transaction.commit().await.expect("commit failed");
3710
3711 let mut buffer = child.allocate_buffer(8192).await;
3713 buffer.fill(0xaa);
3714 child.write_or_append(Some(0), buffer.as_ref()).await.expect("write failed");
3715
3716 child.object_id()
3717 };
3718
3719 root_store
3720 .tombstone_object(child_id, Options::default(), None)
3721 .await
3722 .expect("tombstone failed");
3723
3724 fsck(fs.clone()).await.expect("fsck failed");
3726 }
3727
3728 #[fuchsia::test]
3729 async fn test_tombstone_purges_keys() {
3730 let fs = test_filesystem().await;
3731 let root_volume = root_volume(fs.clone()).await.expect("root_volume failed");
3732 let store = root_volume
3733 .new_volume(
3734 "test",
3735 NewChildStoreOptions {
3736 options: StoreOptions {
3737 crypt: Some(Arc::new(new_insecure_crypt())),
3738 ..StoreOptions::default()
3739 },
3740 ..NewChildStoreOptions::default()
3741 },
3742 )
3743 .await
3744 .expect("new_volume failed");
3745 let mut transaction = fs
3746 .root_store()
3747 .new_transaction(lock_keys![], Options::default())
3748 .await
3749 .expect("new_transaction failed");
3750 let child =
3751 ObjectStore::create_object(&store, &mut transaction, HandleOptions::default(), None)
3752 .await
3753 .expect("create_object failed");
3754 store.add_to_graveyard(&mut transaction, child.object_id());
3755 transaction.commit().await.expect("commit failed");
3756 assert!(store.key_manager.get(child.object_id()).await.unwrap().is_some());
3757 store
3758 .tombstone_object(child.object_id(), Options::default(), None)
3759 .await
3760 .expect("tombstone_object failed");
3761 assert!(store.key_manager.get(child.object_id()).await.unwrap().is_none());
3762 fs.close().await.expect("close failed");
3763 }
3764
3765 #[fuchsia::test]
3766 async fn test_major_compaction_discards_unnecessary_records() {
3767 let fs = test_filesystem().await;
3768 let root_store = fs.root_store();
3769 let child_id = {
3770 let mut transaction = fs
3771 .root_store()
3772 .new_transaction(lock_keys![], Options::default())
3773 .await
3774 .expect("new_transaction failed");
3775 let child = ObjectStore::create_object(
3776 &root_store,
3777 &mut transaction,
3778 HandleOptions::default(),
3779 None,
3780 )
3781 .await
3782 .expect("create_object failed");
3783 root_store.add_to_graveyard(&mut transaction, child.object_id());
3784 transaction.commit().await.expect("commit failed");
3785
3786 let mut buffer = child.allocate_buffer(8192).await;
3788 buffer.fill(0xaa);
3789 child.write_or_append(Some(0), buffer.as_ref()).await.expect("write failed");
3790
3791 child.object_id()
3792 };
3793
3794 root_store
3795 .tombstone_object(child_id, Options::default(), None)
3796 .await
3797 .expect("tombstone failed");
3798 {
3799 let layers = root_store.tree.layer_set();
3800 let mut merger = layers.merger();
3801 let iter = merger
3802 .query(Query::FullRange(&ObjectKey::object(child_id)))
3803 .await
3804 .expect("seek failed");
3805 match iter.get() {
3807 Some(ItemRef { key: ObjectKey { object_id, .. }, .. })
3808 if *object_id == child_id => {}
3809 _ => panic!("Objects should still be in the tree."),
3810 }
3811 }
3812 root_store.flush().await.expect("flush failed");
3813
3814 let layers = root_store.tree.layer_set();
3816 let mut merger = layers.merger();
3817 let iter = merger
3818 .query(Query::FullRange(&ObjectKey::object(child_id)))
3819 .await
3820 .expect("seek failed");
3821 match iter.get() {
3822 None => {}
3823 Some(ItemRef { key: ObjectKey { object_id, .. }, .. }) => {
3824 assert_ne!(*object_id, child_id)
3825 }
3826 }
3827 }
3828
3829 #[fuchsia::test]
3830 async fn test_overlapping_extents_in_different_layers() {
3831 let fs = test_filesystem().await;
3832 let store = fs.root_store();
3833
3834 let mut transaction = store
3835 .new_transaction(
3836 lock_keys![LockKey::object(
3837 store.store_object_id(),
3838 store.root_directory_object_id()
3839 )],
3840 Options::default(),
3841 )
3842 .await
3843 .expect("new_transaction failed");
3844 let root_directory =
3845 Directory::open(&store, store.root_directory_object_id()).await.expect("open failed");
3846 let object = root_directory
3847 .create_child_file(&mut transaction, "test")
3848 .await
3849 .expect("create_child_file failed");
3850 transaction.commit().await.expect("commit failed");
3851
3852 let buf = object.allocate_buffer(16384).await;
3853 object.write_or_append(Some(0), buf.as_ref()).await.expect("write failed");
3854
3855 store.flush().await.expect("flush failed");
3856
3857 object.write_or_append(Some(0), buf.subslice(0..4096)).await.expect("write failed");
3858
3859 object.write_or_append(Some(0), buf.as_ref()).await.expect("write failed");
3863
3864 fsck(fs.clone()).await.expect("fsck failed");
3865 }
3866
3867 #[fuchsia::test(threads = 10)]
3868 async fn test_encrypted_mutations() {
3869 async fn one_iteration(
3870 fs: OpenFxFilesystem,
3871 crypt: Arc<dyn Crypt>,
3872 iteration: u64,
3873 ) -> OpenFxFilesystem {
3874 async fn reopen(fs: OpenFxFilesystem) -> OpenFxFilesystem {
3875 fs.close().await.expect("Close failed");
3876 let device = fs.take_device().await;
3877 device.reopen(false);
3878 FxFilesystem::open(device).await.expect("FS open failed")
3879 }
3880
3881 let fs = reopen(fs).await;
3882
3883 let (store_object_id, object_id) = {
3884 let root_volume = root_volume(fs.clone()).await.expect("root_volume failed");
3885 let store = root_volume
3886 .volume(
3887 "test",
3888 StoreOptions { crypt: Some(crypt.clone()), ..StoreOptions::default() },
3889 )
3890 .await
3891 .expect("volume failed");
3892
3893 let mut transaction = fs
3894 .root_store()
3895 .new_transaction(
3896 lock_keys![LockKey::object(
3897 store.store_object_id(),
3898 store.root_directory_object_id(),
3899 )],
3900 Options::default(),
3901 )
3902 .await
3903 .expect("new_transaction failed");
3904 let root_directory = Directory::open(&store, store.root_directory_object_id())
3905 .await
3906 .expect("open failed");
3907 let object = root_directory
3908 .create_child_file(&mut transaction, &format!("test {}", iteration))
3909 .await
3910 .expect("create_child_file failed");
3911 transaction.commit().await.expect("commit failed");
3912
3913 let mut buf = object.allocate_buffer(1000).await;
3914 for (i, byte) in buf.as_mut_ptr_slice().iter_as_mut::<u8>().enumerate() {
3915 byte.write(i as u8);
3916 }
3917 object.write_or_append(Some(0), buf.as_ref()).await.expect("write failed");
3918
3919 (store.store_object_id(), object.object_id())
3920 };
3921
3922 let fs = reopen(fs).await;
3923
3924 let check_object = |fs: Arc<FxFilesystem>| {
3925 let crypt = crypt.clone();
3926 async move {
3927 let root_volume = root_volume(fs).await.expect("root_volume failed");
3928 let volume = root_volume
3929 .volume(
3930 "test",
3931 StoreOptions { crypt: Some(crypt), ..StoreOptions::default() },
3932 )
3933 .await
3934 .expect("volume failed");
3935
3936 let object = ObjectStore::open_object(
3937 &volume,
3938 object_id,
3939 HandleOptions::default(),
3940 None,
3941 )
3942 .await
3943 .expect("open_object failed");
3944 let mut buf = object.allocate_buffer(1000).await;
3945 assert_eq!(object.read(0, buf.as_mut()).await.expect("read failed"), 1000);
3946 for (i, byte) in buf.as_ptr_slice().iter_as::<u8>().enumerate() {
3947 assert_eq!(byte, i as u8);
3948 }
3949 }
3950 };
3951
3952 check_object(fs.clone()).await;
3953
3954 let fs = reopen(fs).await;
3955
3956 fs.object_manager()
3959 .flush(FlushReason::Journal(ForceMajor::False))
3960 .await
3961 .expect("flush failed");
3962
3963 assert_ne!(
3964 fs.object_manager()
3965 .store(store_object_id)
3966 .unwrap()
3967 .load_store_info()
3968 .await
3969 .expect("load_store_info failed")
3970 .encrypted_mutations_object_id,
3971 INVALID_OBJECT_ID
3972 );
3973
3974 check_object(fs.clone()).await;
3975
3976 assert_eq!(
3979 fs.object_manager()
3980 .store(store_object_id)
3981 .unwrap()
3982 .load_store_info()
3983 .await
3984 .expect("load_store_info failed")
3985 .encrypted_mutations_object_id,
3986 INVALID_OBJECT_ID
3987 );
3988
3989 let fs = reopen(fs).await;
3990
3991 fsck(fs.clone()).await.expect("fsck failed");
3992
3993 let fs = reopen(fs).await;
3994
3995 check_object(fs.clone()).await;
3996
3997 fs
3998 }
3999
4000 let mut fs = test_filesystem().await;
4001 let crypt = Arc::new(new_insecure_crypt());
4002
4003 {
4004 let root_volume = root_volume(fs.clone()).await.expect("root_volume failed");
4005 let _store = root_volume
4006 .new_volume(
4007 "test",
4008 NewChildStoreOptions {
4009 options: StoreOptions {
4010 crypt: Some(crypt.clone()),
4011 ..StoreOptions::default()
4012 },
4013 ..Default::default()
4014 },
4015 )
4016 .await
4017 .expect("new_volume failed");
4018 }
4019
4020 for i in 0..5 {
4022 fs = one_iteration(fs, crypt.clone(), i).await;
4023 }
4024 }
4025
4026 #[test_case(true; "with a flush")]
4027 #[test_case(false; "without a flush")]
4028 #[fuchsia::test(threads = 10)]
4029 async fn test_object_id_cipher_roll(with_flush: bool) {
4030 let fs = test_filesystem().await;
4031 let crypt = Arc::new(new_insecure_crypt());
4032
4033 let expected_key = {
4034 let root_volume = root_volume(fs.clone()).await.expect("root_volume failed");
4035 let store = root_volume
4036 .new_volume(
4037 "test",
4038 NewChildStoreOptions {
4039 options: StoreOptions {
4040 crypt: Some(crypt.clone()),
4041 ..StoreOptions::default()
4042 },
4043 ..Default::default()
4044 },
4045 )
4046 .await
4047 .expect("new_volume failed");
4048
4049 let root_dir_id = store.root_directory_object_id();
4052 let root_dir =
4053 Arc::new(Directory::open(&store, root_dir_id).await.expect("open failed"));
4054 let mut transaction = store
4055 .new_transaction(
4056 lock_keys![LockKey::object(store.store_object_id(), root_dir_id)],
4057 Options::default(),
4058 )
4059 .await
4060 .expect("new_transaction failed");
4061 for i in 0..10 {
4062 root_dir.create_child_file(&mut transaction, &format!("file {i}")).await.unwrap();
4063 }
4064 transaction.commit().await.expect("commit failed");
4065
4066 let orig_store_info = store.store_info().unwrap();
4067
4068 {
4070 let mut last_object_id = store.last_object_id.lock();
4071 match &mut *last_object_id {
4072 LastObjectId::Encrypted { id, .. } => {
4073 assert_eq!(*id & OBJECT_ID_HI_MASK, 0);
4074 *id |= 0xffffffff;
4075 }
4076 _ => unreachable!(),
4077 }
4078 }
4079
4080 let mut transaction = store
4081 .new_transaction(
4082 lock_keys![LockKey::object(
4083 store.store_object_id(),
4084 store.root_directory_object_id()
4085 )],
4086 Options::default(),
4087 )
4088 .await
4089 .expect("new_transaction failed");
4090 let root_directory = Directory::open(&store, store.root_directory_object_id())
4091 .await
4092 .expect("open failed");
4093 let object = root_directory
4094 .create_child_file(&mut transaction, "test")
4095 .await
4096 .expect("create_child_file failed");
4097 transaction.commit().await.expect("commit failed");
4098
4099 assert_eq!(object.object_id() & OBJECT_ID_HI_MASK, 1u64 << 32);
4100
4101 let key = match (
4103 store.store_info().unwrap().last_object_id,
4104 orig_store_info.last_object_id,
4105 ) {
4106 (
4107 LastObjectIdInfo::Encrypted { key, id },
4108 LastObjectIdInfo::Encrypted { key: orig_key, .. },
4109 ) => {
4110 assert_ne!(key, orig_key);
4111 assert_eq!(id, 1u64 << 32);
4112 key
4113 }
4114 _ => unreachable!(),
4115 };
4116
4117 if with_flush {
4118 fs.journal().force_compact().await.unwrap();
4119 }
4120
4121 let last_object_id = store.last_object_id.lock();
4122 assert_eq!(last_object_id.id(), 1u64 << 32);
4123 key
4124 };
4125
4126 fs.close().await.expect("Close failed");
4127 let device = fs.take_device().await;
4128 device.reopen(false);
4129 let fs = FxFilesystem::open(device).await.expect("open failed");
4130 let root_volume = root_volume(fs.clone()).await.expect("root_volume failed");
4131 let store = root_volume
4132 .volume("test", StoreOptions { crypt: Some(crypt.clone()), ..StoreOptions::default() })
4133 .await
4134 .expect("volume failed");
4135
4136 assert_matches!(store.store_info().unwrap().last_object_id, LastObjectIdInfo::Encrypted { key, .. } if key == expected_key);
4137 assert_eq!(store.last_object_id.lock().id(), 1u64 << 32);
4138
4139 fsck(fs.clone()).await.expect("fsck failed");
4140 fsck_volume(&fs, store.store_object_id(), None).await.expect("fsck_volume failed");
4141 }
4142
4143 #[fuchsia::test(threads = 2)]
4144 async fn test_race_object_id_cipher_roll_and_flush() {
4145 let fs = test_filesystem().await;
4146 let crypt = Arc::new(new_insecure_crypt());
4147
4148 let root_volume = root_volume(fs.clone()).await.expect("root_volume failed");
4149 let store = root_volume
4150 .new_volume(
4151 "test",
4152 NewChildStoreOptions {
4153 options: StoreOptions { crypt: Some(crypt.clone()), ..StoreOptions::default() },
4154 ..Default::default()
4155 },
4156 )
4157 .await
4158 .expect("new_volume failed");
4159
4160 assert!(matches!(&*store.last_object_id.lock(), LastObjectId::Encrypted { .. }));
4161
4162 let root_dir_id = store.root_directory_object_id();
4165 let root_dir = Arc::new(Directory::open(&store, root_dir_id).await.expect("open failed"));
4166
4167 let _executor_tasks = testing::force_executor_threads_to_run(2).await;
4168
4169 for j in 0..100 {
4170 let mut transaction = store
4171 .new_transaction(
4172 lock_keys![LockKey::object(store.store_object_id(), root_dir_id)],
4173 Options::default(),
4174 )
4175 .await
4176 .expect("new_transaction failed");
4177 root_dir.create_child_file(&mut transaction, &format!("file {j}")).await.unwrap();
4178 transaction.commit().await.expect("commit failed");
4179
4180 let task = {
4181 let fs = fs.clone();
4182 fasync::Task::spawn(async move {
4183 fs.journal().force_compact().await.unwrap();
4184 })
4185 };
4186
4187 {
4189 let mut last_object_id = store.last_object_id.lock();
4190 let LastObjectId::Encrypted { id, .. } = &mut *last_object_id else {
4191 unreachable!()
4192 };
4193 assert_eq!(*id >> 32, j);
4194 *id |= 0xffffffff;
4195 }
4196
4197 let mut transaction = store
4198 .new_transaction(
4199 lock_keys![LockKey::object(
4200 store.store_object_id(),
4201 store.root_directory_object_id()
4202 )],
4203 Options::default(),
4204 )
4205 .await
4206 .expect("new_transaction failed");
4207 let root_directory = Directory::open(&store, store.root_directory_object_id())
4208 .await
4209 .expect("open failed");
4210 root_directory
4211 .create_child_file(&mut transaction, "test {j}")
4212 .await
4213 .expect("create_child_file failed");
4214 transaction.commit().await.expect("commit failed");
4215
4216 task.await;
4217
4218 let new_store_info = store.load_store_info().await.unwrap();
4220
4221 let LastObjectIdInfo::Encrypted { id, key } = new_store_info.last_object_id else {
4222 unreachable!()
4223 };
4224 assert_eq!(id >> 32, j + 1);
4225 let LastObjectIdInfo::Encrypted { key: in_memory_key, .. } =
4226 store.store_info().unwrap().last_object_id
4227 else {
4228 unreachable!()
4229 };
4230 assert_eq!(key, in_memory_key);
4231 }
4232
4233 fs.close().await.expect("Close failed");
4234 }
4235
4236 #[fuchsia::test]
4237 async fn test_object_id_no_roll_for_unencrypted_store() {
4238 let fs = test_filesystem().await;
4239
4240 {
4241 let root_volume = root_volume(fs.clone()).await.expect("root_volume failed");
4242 let store = root_volume
4243 .new_volume("test", NewChildStoreOptions::default())
4244 .await
4245 .expect("new_volume failed");
4246
4247 {
4249 let mut last_object_id = store.last_object_id.lock();
4250 match &mut *last_object_id {
4251 LastObjectId::Unencrypted { id } => {
4252 assert_eq!(*id & OBJECT_ID_HI_MASK, 0);
4253 *id |= 0xffffffff;
4254 }
4255 _ => unreachable!(),
4256 }
4257 }
4258
4259 let mut transaction = store
4260 .new_transaction(
4261 lock_keys![LockKey::object(
4262 store.store_object_id(),
4263 store.root_directory_object_id()
4264 )],
4265 Options::default(),
4266 )
4267 .await
4268 .expect("new_transaction failed");
4269 let root_directory = Directory::open(&store, store.root_directory_object_id())
4270 .await
4271 .expect("open failed");
4272 let object = root_directory
4273 .create_child_file(&mut transaction, "test")
4274 .await
4275 .expect("create_child_file failed");
4276 transaction.commit().await.expect("commit failed");
4277
4278 assert_eq!(object.object_id(), 0x1_0000_0000);
4279
4280 assert_matches!(
4282 store.store_info().unwrap().last_object_id,
4283 LastObjectIdInfo::Unencrypted { .. }
4284 );
4285
4286 assert_eq!(store.last_object_id.lock().id(), 0x1_0000_0000);
4287 };
4288
4289 fs.close().await.expect("Close failed");
4290 let device = fs.take_device().await;
4291 device.reopen(false);
4292 let fs = FxFilesystem::open(device).await.expect("open failed");
4293 let root_volume = root_volume(fs.clone()).await.expect("root_volume failed");
4294 let store =
4295 root_volume.volume("test", StoreOptions::default()).await.expect("volume failed");
4296
4297 assert_eq!(store.last_object_id.lock().id(), 0x1_0000_0000);
4298 }
4299
4300 #[fuchsia::test]
4301 fn test_object_id_is_not_invalid_object_id() {
4302 let key = UnwrappedKey::new(vec![0; FXFS_KEY_SIZE]);
4303 let mut last_object_id =
4305 LastObjectId::Encrypted { id: 1106634047, cipher: Box::new(Ff1::new(&key)) };
4306 assert!(last_object_id.try_get_next().is_some());
4307 assert!(last_object_id.try_get_next().is_some());
4308 }
4309
4310 #[fuchsia::test]
4311 async fn test_last_object_id_is_correct_after_unlock() {
4312 let fs = test_filesystem().await;
4313 let crypt = Arc::new(new_insecure_crypt());
4314
4315 let root_volume = root_volume(fs.clone()).await.expect("root_volume failed");
4316 let store = root_volume
4317 .new_volume(
4318 "test",
4319 NewChildStoreOptions {
4320 options: StoreOptions { crypt: Some(crypt.clone()), ..StoreOptions::default() },
4321 ..Default::default()
4322 },
4323 )
4324 .await
4325 .expect("new_volume failed");
4326
4327 let mut transaction = store
4328 .new_transaction(
4329 lock_keys![LockKey::object(
4330 store.store_object_id(),
4331 store.root_directory_object_id()
4332 )],
4333 Options::default(),
4334 )
4335 .await
4336 .expect("new_transaction failed");
4337 let root_directory =
4338 Directory::open(&store, store.root_directory_object_id()).await.expect("open failed");
4339 root_directory
4340 .create_child_file(&mut transaction, "test")
4341 .await
4342 .expect("create_child_file failed");
4343 transaction.commit().await.expect("commit failed");
4344
4345 fs.journal().force_compact().await.unwrap();
4347
4348 let last_object_id = store.last_object_id.lock().id();
4349
4350 store.lock().await.unwrap();
4351 store.unlock(crypt.clone()).await.unwrap();
4352
4353 assert_eq!(store.last_object_id.lock().id(), last_object_id);
4354 }
4355
4356 #[fuchsia::test(threads = 20)]
4357 async fn test_race_when_rolling_last_object_id_cipher() {
4358 const NUM_THREADS: usize = 20;
4361
4362 let fs = test_filesystem().await;
4363 let crypt = Arc::new(new_insecure_crypt());
4364
4365 let root_volume = root_volume(fs.clone()).await.expect("root_volume failed");
4366 let store = root_volume
4367 .new_volume(
4368 "test",
4369 NewChildStoreOptions {
4370 options: StoreOptions { crypt: Some(crypt.clone()), ..StoreOptions::default() },
4371 ..Default::default()
4372 },
4373 )
4374 .await
4375 .expect("new_volume failed");
4376
4377 let store_id = store.store_object_id();
4378 let root_dir_id = store.root_directory_object_id();
4379
4380 let root_directory =
4381 Arc::new(Directory::open(&store, root_dir_id).await.expect("open failed"));
4382
4383 let mut directories = Vec::new();
4385 for _ in 0..NUM_THREADS {
4386 let mut transaction = fs
4387 .root_store()
4388 .new_transaction(
4389 lock_keys![LockKey::object(store_id, root_dir_id,)],
4390 Options::default(),
4391 )
4392 .await
4393 .expect("new_transaction failed");
4394 directories.push(
4395 root_directory
4396 .create_child_dir(&mut transaction, "test")
4397 .await
4398 .expect("create_child_file failed"),
4399 );
4400 transaction.commit().await.expect("commit failed");
4401 }
4402
4403 match &mut *store.last_object_id.lock() {
4405 LastObjectId::Encrypted { id, .. } => *id |= 0xffff_ffff,
4406 _ => unreachable!(),
4407 }
4408
4409 let scope = fasync::Scope::new();
4410
4411 let _executor_tasks = testing::force_executor_threads_to_run(NUM_THREADS).await;
4412
4413 for dir in directories {
4414 let fs = fs.clone();
4415 scope.spawn(async move {
4416 let mut transaction = fs
4417 .root_store()
4418 .new_transaction(
4419 lock_keys![LockKey::object(store_id, dir.object_id(),)],
4420 Options::default(),
4421 )
4422 .await
4423 .expect("new_transaction failed");
4424 dir.create_child_file(&mut transaction, "test")
4425 .await
4426 .expect("create_child_file failed");
4427 transaction.commit().await.expect("commit failed");
4428 });
4429 }
4430
4431 scope.on_no_tasks().await;
4432
4433 assert_eq!(store.last_object_id.lock().id(), 0x1_0000_0000 + NUM_THREADS as u64 - 1);
4434 }
4435
4436 #[fuchsia::test(threads = 10)]
4437 async fn test_lock_store() {
4438 let fs = test_filesystem().await;
4439 let crypt = Arc::new(new_insecure_crypt());
4440
4441 let root_volume = root_volume(fs.clone()).await.expect("root_volume failed");
4442 let store = root_volume
4443 .new_volume(
4444 "test",
4445 NewChildStoreOptions {
4446 options: StoreOptions { crypt: Some(crypt.clone()), ..StoreOptions::default() },
4447 ..NewChildStoreOptions::default()
4448 },
4449 )
4450 .await
4451 .expect("new_volume failed");
4452 let mut transaction = store
4453 .new_transaction(
4454 lock_keys![LockKey::object(
4455 store.store_object_id(),
4456 store.root_directory_object_id()
4457 )],
4458 Options::default(),
4459 )
4460 .await
4461 .expect("new_transaction failed");
4462 let root_directory =
4463 Directory::open(&store, store.root_directory_object_id()).await.expect("open failed");
4464 root_directory
4465 .create_child_file(&mut transaction, "test")
4466 .await
4467 .expect("create_child_file failed");
4468 transaction.commit().await.expect("commit failed");
4469 store.lock().await.expect("lock failed");
4470
4471 store.unlock(crypt).await.expect("unlock failed");
4472 root_directory.lookup("test").await.expect("lookup failed").expect("not found");
4473 }
4474
4475 #[fuchsia::test(threads = 10)]
4476 async fn test_unlock_read_only() {
4477 let fs = test_filesystem().await;
4478 let crypt = Arc::new(new_insecure_crypt());
4479
4480 let root_volume = root_volume(fs.clone()).await.expect("root_volume failed");
4481 let store = root_volume
4482 .new_volume(
4483 "test",
4484 NewChildStoreOptions {
4485 options: StoreOptions { crypt: Some(crypt.clone()), ..StoreOptions::default() },
4486 ..NewChildStoreOptions::default()
4487 },
4488 )
4489 .await
4490 .expect("new_volume failed");
4491 let mut transaction = store
4492 .new_transaction(
4493 lock_keys![LockKey::object(
4494 store.store_object_id(),
4495 store.root_directory_object_id()
4496 )],
4497 Options::default(),
4498 )
4499 .await
4500 .expect("new_transaction failed");
4501 let root_directory =
4502 Directory::open(&store, store.root_directory_object_id()).await.expect("open failed");
4503 root_directory
4504 .create_child_file(&mut transaction, "test")
4505 .await
4506 .expect("create_child_file failed");
4507 transaction.commit().await.expect("commit failed");
4508 store.lock().await.expect("lock failed");
4509
4510 store.unlock_read_only(crypt.clone()).await.expect("unlock failed");
4511 root_directory.lookup("test").await.expect("lookup failed").expect("not found");
4512 store.lock_read_only();
4513 store.unlock_read_only(crypt).await.expect("unlock failed");
4514 root_directory.lookup("test").await.expect("lookup failed").expect("not found");
4515 }
4516
4517 #[fuchsia::test]
4518 async fn test_mutations_cipher_dropped_on_lock() {
4519 let fs = test_filesystem().await;
4520 let crypt = Arc::new(new_insecure_crypt());
4521
4522 let root_volume = root_volume(fs.clone()).await.expect("root_volume failed");
4523 let store = root_volume
4524 .new_volume(
4525 "test",
4526 NewChildStoreOptions {
4527 options: StoreOptions { crypt: Some(crypt.clone()), ..StoreOptions::default() },
4528 ..NewChildStoreOptions::default()
4529 },
4530 )
4531 .await
4532 .expect("new_volume failed");
4533
4534 assert_matches!(*store.lock_state.lock(), LockState::Unlocked { .. });
4537 assert!(matches!(&*store.last_object_id.lock(), LastObjectId::Encrypted { .. }));
4538
4539 store.lock().await.expect("lock failed");
4542 assert_matches!(*store.lock_state.lock(), LockState::Locked);
4543 assert!(matches!(&*store.last_object_id.lock(), LastObjectId::Pending));
4544
4545 store.unlock(crypt).await.expect("unlock failed");
4548 assert_matches!(*store.lock_state.lock(), LockState::Unlocked { .. });
4549 assert!(matches!(&*store.last_object_id.lock(), LastObjectId::Encrypted { .. }));
4550 }
4551
4552 #[fuchsia::test(threads = 10)]
4553 async fn test_key_rolled_when_unlocked() {
4554 let fs = test_filesystem().await;
4555 let crypt = Arc::new(new_insecure_crypt());
4556
4557 let object_id;
4558 {
4559 let root_volume = root_volume(fs.clone()).await.expect("root_volume failed");
4560 let store = root_volume
4561 .new_volume(
4562 "test",
4563 NewChildStoreOptions {
4564 options: StoreOptions {
4565 crypt: Some(crypt.clone()),
4566 ..StoreOptions::default()
4567 },
4568 ..Default::default()
4569 },
4570 )
4571 .await
4572 .expect("new_volume failed");
4573 let mut transaction = store
4574 .new_transaction(
4575 lock_keys![LockKey::object(
4576 store.store_object_id(),
4577 store.root_directory_object_id()
4578 )],
4579 Options::default(),
4580 )
4581 .await
4582 .expect("new_transaction failed");
4583 let root_directory = Directory::open(&store, store.root_directory_object_id())
4584 .await
4585 .expect("open failed");
4586 object_id = root_directory
4587 .create_child_file(&mut transaction, "test")
4588 .await
4589 .expect("create_child_file failed")
4590 .object_id();
4591 transaction.commit().await.expect("commit failed");
4592 }
4593
4594 fs.close().await.expect("Close failed");
4595 let mut device = fs.take_device().await;
4596
4597 for _ in 0..100 {
4600 device.reopen(false);
4601 let fs = FxFilesystem::open(device).await.expect("open failed");
4602 {
4603 let root_volume = root_volume(fs.clone()).await.expect("root_volume failed");
4604 let store = root_volume
4605 .volume(
4606 "test",
4607 StoreOptions { crypt: Some(crypt.clone()), ..StoreOptions::default() },
4608 )
4609 .await
4610 .expect("open_volume failed");
4611
4612 {
4614 let lock_state = store.lock_state.lock();
4615 let LockState::Unlocked { mutations_cipher, .. } = &*lock_state else {
4616 panic!("Unexpected lock state: {lock_state:?}");
4617 };
4618 assert!(mutations_cipher.key_is_new());
4619 }
4620
4621 let handle =
4623 ObjectStore::open_object(&store, object_id, HandleOptions::default(), None)
4624 .await
4625 .expect("open_object failed");
4626 let buffer = handle.allocate_buffer(100).await;
4627 handle
4628 .write_or_append(Some(0), buffer.as_ref())
4629 .await
4630 .expect("write_or_append failed");
4631 }
4632 fs.close().await.expect("Close failed");
4633 device = fs.take_device().await;
4634 }
4635 }
4636
4637 #[test]
4638 fn test_store_info_max_serialized_size() {
4639 let info = StoreInfo {
4640 guid: [0xff; 16],
4641 last_object_id: LastObjectIdInfo::Encrypted {
4642 id: 0x1234567812345678,
4643 key: FxfsKey {
4644 wrapping_key_id: 0x1234567812345678u128.to_le_bytes(),
4645 key: WrappedKeyBytes::from([0xff; FXFS_WRAPPED_KEY_SIZE]),
4646 },
4647 },
4648 layers: vec![0x1234567812345678; 120],
4653 root_directory_object_id: 0x1234567812345678,
4654 graveyard_directory_object_id: 0x1234567812345678,
4655 object_count: 0x1234567812345678,
4656 mutations_key: Some(FxfsKey {
4657 wrapping_key_id: 0x1234567812345678u128.to_le_bytes(),
4658 key: WrappedKeyBytes::from([0xff; FXFS_WRAPPED_KEY_SIZE]),
4659 }),
4660 mutations_cipher_offset: 0x1234567812345678,
4661 encrypted_mutations_object_id: 0x1234567812345678,
4662 internal_directory_object_id: INVALID_OBJECT_ID,
4663 };
4664 let mut serialized_info = Vec::new();
4665 info.serialize_with_version(&mut serialized_info).unwrap();
4666 assert!(
4667 serialized_info.len() <= MAX_STORE_INFO_SERIALIZED_SIZE,
4668 "{}",
4669 serialized_info.len()
4670 );
4671 }
4672
4673 async fn reopen_after_crypt_failure_inner(read_only: bool) {
4674 let fs = test_filesystem().await;
4675 let root_volume = root_volume(fs.clone()).await.expect("root_volume failed");
4676
4677 let store = {
4678 let crypt = Arc::new(new_insecure_crypt());
4679 let store = root_volume
4680 .new_volume(
4681 "vol",
4682 NewChildStoreOptions {
4683 options: StoreOptions {
4684 crypt: Some(crypt.clone()),
4685 ..StoreOptions::default()
4686 },
4687 ..Default::default()
4688 },
4689 )
4690 .await
4691 .expect("new_volume failed");
4692 let root_directory = Directory::open(&store, store.root_directory_object_id())
4693 .await
4694 .expect("open failed");
4695 let mut transaction = fs
4696 .root_store()
4697 .new_transaction(
4698 lock_keys![LockKey::object(
4699 store.store_object_id(),
4700 root_directory.object_id()
4701 )],
4702 Options::default(),
4703 )
4704 .await
4705 .expect("new_transaction failed");
4706 root_directory
4707 .create_child_file(&mut transaction, "test")
4708 .await
4709 .expect("create_child_file failed");
4710 transaction.commit().await.expect("commit failed");
4711
4712 crypt.shutdown();
4713 let mut transaction = fs
4714 .root_store()
4715 .new_transaction(
4716 lock_keys![LockKey::object(
4717 store.store_object_id(),
4718 root_directory.object_id()
4719 )],
4720 Options::default(),
4721 )
4722 .await
4723 .expect("new_transaction failed");
4724 root_directory
4725 .create_child_file(&mut transaction, "test2")
4726 .await
4727 .map(|_| ())
4728 .expect_err("create_child_file should fail");
4729 store.lock().await.expect("lock failed");
4730 store
4731 };
4732
4733 let crypt = Arc::new(new_insecure_crypt());
4734 if read_only {
4735 store.unlock_read_only(crypt).await.expect("unlock failed");
4736 } else {
4737 store.unlock(crypt).await.expect("unlock failed");
4738 }
4739 let root_directory =
4740 Directory::open(&store, store.root_directory_object_id()).await.expect("open failed");
4741 root_directory.lookup("test").await.expect("lookup failed").expect("not found");
4742 }
4743
4744 #[fuchsia::test(threads = 10)]
4745 async fn test_reopen_after_crypt_failure() {
4746 reopen_after_crypt_failure_inner(false).await;
4747 }
4748
4749 #[fuchsia::test(threads = 10)]
4750 async fn test_reopen_read_only_after_crypt_failure() {
4751 reopen_after_crypt_failure_inner(true).await;
4752 }
4753
4754 #[fuchsia::test(threads = 10)]
4755 #[should_panic(expected = "Insufficient reservation space")]
4756 #[cfg(debug_assertions)]
4757 async fn large_transaction_causes_panic_in_debug_builds() {
4758 let fs = test_filesystem().await;
4759 let root_volume = root_volume(fs.clone()).await.expect("root_volume failed");
4760 let store = root_volume
4761 .new_volume("vol", NewChildStoreOptions::default())
4762 .await
4763 .expect("new_volume failed");
4764 let root_directory =
4765 Directory::open(&store, store.root_directory_object_id()).await.expect("open failed");
4766 let mut transaction = fs
4767 .root_store()
4768 .new_transaction(
4769 lock_keys![LockKey::object(store.store_object_id(), root_directory.object_id())],
4770 Options::default(),
4771 )
4772 .await
4773 .expect("transaction");
4774 for i in 0..500 {
4775 root_directory
4776 .create_symlink(&mut transaction, b"link", &format!("{}", i))
4777 .await
4778 .expect("symlink");
4779 }
4780 assert_eq!(transaction.commit().await.expect("commit"), 0);
4781 }
4782
4783 #[fuchsia::test]
4784 async fn test_crypt_failure_does_not_fuse_journal() {
4785 let fs = test_filesystem().await;
4786
4787 {
4788 let root_volume = root_volume(fs.clone()).await.expect("root_volume failed");
4791 let store1 = root_volume
4792 .new_volume(
4793 "vol1",
4794 NewChildStoreOptions {
4795 options: StoreOptions {
4796 crypt: Some(Arc::new(new_insecure_crypt())),
4797 ..StoreOptions::default()
4798 },
4799 ..Default::default()
4800 },
4801 )
4802 .await
4803 .expect("new_volume failed");
4804 let crypt = Arc::new(new_insecure_crypt());
4805 let store2 = root_volume
4806 .new_volume(
4807 "vol2",
4808 NewChildStoreOptions {
4809 options: StoreOptions { crypt: Some(crypt.clone()) },
4810 ..Default::default()
4811 },
4812 )
4813 .await
4814 .expect("new_volume failed");
4815 for store in [&store1, &store2] {
4816 let root_directory = Directory::open(store, store.root_directory_object_id())
4817 .await
4818 .expect("open failed");
4819 let mut transaction = store
4820 .new_transaction(
4821 lock_keys![LockKey::object(
4822 store.store_object_id(),
4823 root_directory.object_id()
4824 )],
4825 Options::default(),
4826 )
4827 .await
4828 .expect("new_transaction failed");
4829 root_directory
4830 .create_child_file(&mut transaction, "test")
4831 .await
4832 .expect("create_child_file failed");
4833 transaction.commit().await.expect("commit failed");
4834 }
4835
4836 crypt.shutdown();
4838
4839 fs.journal().force_compact().await.expect("compact failed");
4842
4843 let root_directory2 = Directory::open(&store2, store2.root_directory_object_id())
4846 .await
4847 .expect("open failed");
4848 let (child_id, _, _) = root_directory2
4849 .lookup("test")
4850 .await
4851 .expect("lookup failed")
4852 .expect("test file not found");
4853 let mut transaction2 = store2
4854 .new_transaction(
4855 lock_keys![
4856 LockKey::object(store2.store_object_id(), root_directory2.object_id()),
4857 LockKey::object(store2.store_object_id(), child_id),
4858 ],
4859 Options::default(),
4860 )
4861 .await
4862 .expect("new_transaction failed");
4863 replace_child(&mut transaction2, None, (&root_directory2, "test"))
4864 .await
4865 .expect("replace_child failed");
4866 assert!(transaction2.commit().await.is_err());
4867
4868 let root_directory1 = Directory::open(&store1, store1.root_directory_object_id())
4870 .await
4871 .expect("open failed");
4872 let mut transaction1 = store1
4873 .new_transaction(
4874 lock_keys![LockKey::object(
4875 store1.store_object_id(),
4876 root_directory1.object_id()
4877 )],
4878 Options::default(),
4879 )
4880 .await
4881 .expect("new_transaction failed");
4882 root_directory1
4883 .create_child_file(&mut transaction1, "test2")
4884 .await
4885 .expect("create_child_file failed");
4886 transaction1.commit().await.expect("commit failed");
4887
4888 fs.journal().force_compact().await.expect("compact failed");
4890 }
4891
4892 fs.close().await.expect("close failed");
4894 let device = fs.take_device().await;
4895 device.reopen(false);
4896 let fs = FxFilesystem::open(device).await.expect("open failed");
4897 let root_volume = root_volume(fs.clone()).await.expect("root_volume failed");
4898
4899 let store1 = root_volume
4901 .volume(
4902 "vol1",
4903 StoreOptions {
4904 crypt: Some(Arc::new(new_insecure_crypt())),
4905 ..StoreOptions::default()
4906 },
4907 )
4908 .await
4909 .expect("volume failed");
4910 let root_directory1 =
4911 Directory::open(&store1, store1.root_directory_object_id()).await.expect("open failed");
4912 assert!(root_directory1.lookup("test").await.expect("lookup failed").is_some());
4913 assert!(root_directory1.lookup("test2").await.expect("lookup failed").is_some());
4914
4915 let store2 = root_volume
4917 .volume(
4918 "vol2",
4919 StoreOptions {
4920 crypt: Some(Arc::new(new_insecure_crypt())),
4921 ..StoreOptions::default()
4922 },
4923 )
4924 .await
4925 .expect("volume failed");
4926 let root_directory2 =
4927 Directory::open(&store2, store2.root_directory_object_id()).await.expect("open failed");
4928 assert!(root_directory2.lookup("test").await.expect("lookup failed").is_some());
4929 assert!(root_directory2.lookup("test2").await.expect("lookup failed").is_none());
4930
4931 fs.close().await.expect("close failed");
4932 }
4933
4934 #[fuchsia::test]
4935 async fn test_crypt_failure_during_unlock_race() {
4936 let fs = test_filesystem().await;
4937
4938 let store_object_id = {
4939 let root_volume = root_volume(fs.clone()).await.expect("root_volume failed");
4940 let store = root_volume
4941 .new_volume(
4942 "vol",
4943 NewChildStoreOptions {
4944 options: StoreOptions { crypt: Some(Arc::new(new_insecure_crypt())) },
4945 ..Default::default()
4946 },
4947 )
4948 .await
4949 .expect("new_volume failed");
4950 let root_directory = Directory::open(&store, store.root_directory_object_id())
4951 .await
4952 .expect("open failed");
4953 let mut transaction = fs
4954 .root_store()
4955 .new_transaction(
4956 lock_keys![LockKey::object(
4957 store.store_object_id(),
4958 root_directory.object_id()
4959 )],
4960 Options::default(),
4961 )
4962 .await
4963 .expect("new_transaction failed");
4964 root_directory
4965 .create_child_file(&mut transaction, "test")
4966 .await
4967 .expect("create_child_file failed");
4968 transaction.commit().await.expect("commit failed");
4969 store.store_object_id()
4970 };
4971
4972 fs.close().await.expect("close failed");
4973 let device = fs.take_device().await;
4974 device.reopen(false);
4975
4976 let fs = FxFilesystem::open(device).await.expect("open failed");
4977 {
4978 let fs_clone = fs.clone();
4979 let root_volume = root_volume(fs.clone()).await.expect("root_volume failed");
4980
4981 let crypt = Arc::new(new_insecure_crypt());
4982 let crypt_clone = crypt.clone();
4983 join!(
4984 async move {
4985 let _ =
4987 root_volume.volume("vol", StoreOptions { crypt: Some(crypt_clone) }).await;
4988 },
4989 async move {
4990 let keys = lock_keys![LockKey::flush(store_object_id)];
4993 let _ = fs_clone.lock_manager().write_lock(keys).await;
4994 crypt.shutdown();
4995 }
4996 );
4997 }
4998
4999 fs.close().await.expect("close failed");
5000 let device = fs.take_device().await;
5001 device.reopen(false);
5002
5003 let fs = FxFilesystem::open(device).await.expect("open failed");
5004 let root_volume = root_volume(fs.clone()).await.expect("root_volume failed");
5005 let store = root_volume
5006 .volume(
5007 "vol",
5008 StoreOptions {
5009 crypt: Some(Arc::new(new_insecure_crypt())),
5010 ..StoreOptions::default()
5011 },
5012 )
5013 .await
5014 .expect("open volume failed");
5015 let root_directory =
5016 Directory::open(&store, store.root_directory_object_id()).await.expect("open failed");
5017 assert!(root_directory.lookup("test").await.expect("lookup failed").is_some());
5018
5019 fs.close().await.expect("close failed");
5020 }
5021
5022 #[fuchsia::test]
5023 async fn test_low_32_bit_object_ids() {
5024 let device = DeviceHolder::new(FakeDevice::new(16384, TEST_DEVICE_BLOCK_SIZE));
5025 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
5026
5027 {
5028 let root_vol = root_volume(fs.clone()).await.expect("root_volume failed");
5029
5030 let store = root_vol
5031 .new_volume(
5032 "test",
5033 NewChildStoreOptions { low_32_bit_object_ids: true, ..Default::default() },
5034 )
5035 .await
5036 .expect("new_volume failed");
5037
5038 let root_dir = Directory::open(&store, store.root_directory_object_id())
5039 .await
5040 .expect("open failed");
5041
5042 let mut ids = std::collections::HashSet::new();
5043
5044 for i in 0..100 {
5045 let mut transaction = fs
5046 .root_store()
5047 .new_transaction(
5048 lock_keys![LockKey::object(store.store_object_id(), root_dir.object_id())],
5049 Options::default(),
5050 )
5051 .await
5052 .expect("new_transaction failed");
5053
5054 for j in 0..100 {
5055 let object = root_dir
5056 .create_child_dir(&mut transaction, &format!("{i}.{j}"))
5057 .await
5058 .expect("create_child_file failed");
5059
5060 assert!(object.object_id() < 1 << 32);
5061 assert_ne!(object.object_id(), INVALID_OBJECT_ID);
5062 assert!(ids.insert(object.object_id()));
5063 }
5064
5065 transaction.commit().await.expect("commit failed");
5066 }
5067
5068 assert_matches!(store.store_info().unwrap().last_object_id, LastObjectIdInfo::Low32Bit);
5069
5070 fsck_volume(&fs, store.store_object_id(), None).await.expect("fsck_volume failed");
5071 }
5072
5073 fs.close().await.expect("Close failed");
5075 let device = fs.take_device().await;
5076 device.reopen(false);
5077 let fs = FxFilesystem::open(device).await.expect("open failed");
5078 let root_vol = root_volume(fs.clone()).await.expect("root_volume failed");
5079 let store = root_vol.volume("test", StoreOptions::default()).await.expect("volume failed");
5080
5081 let root_dir =
5083 Directory::open(&store, store.root_directory_object_id()).await.expect("open failed");
5084 let mut transaction = fs
5085 .root_store()
5086 .new_transaction(
5087 lock_keys![LockKey::object(store.store_object_id(), root_dir.object_id())],
5088 Options::default(),
5089 )
5090 .await
5091 .expect("new_transaction failed");
5092
5093 let object = root_dir
5094 .create_child_file(&mut transaction, "persistence_check")
5095 .await
5096 .expect("create_child_file failed");
5097 assert!(object.object_id() < 1 << 32);
5098
5099 transaction.commit().await.expect("commit failed");
5100
5101 assert_matches!(store.store_info().unwrap().last_object_id, LastObjectIdInfo::Low32Bit);
5102 }
5103
5104 struct StallingCrypt {
5105 delegate: Arc<dyn Crypt>,
5106 unwrap_stall_counter: AtomicIsize,
5107 unwrap_stalled_tx: Mutex<Option<oneshot::Sender<oneshot::Sender<()>>>>,
5108 create_key_stalled_tx: Mutex<Option<oneshot::Sender<oneshot::Sender<()>>>>,
5109 }
5110
5111 impl StallingCrypt {
5112 fn new(delegate: Arc<dyn Crypt>) -> Self {
5113 Self {
5114 delegate,
5115 unwrap_stall_counter: AtomicIsize::new(-1),
5116 unwrap_stalled_tx: Mutex::new(None),
5117 create_key_stalled_tx: Mutex::new(None),
5118 }
5119 }
5120
5121 fn stall_on_unwrap(
5122 self: &Arc<Self>,
5123 index: usize,
5124 ) -> oneshot::Receiver<oneshot::Sender<()>> {
5125 let (tx, rx) = oneshot::channel();
5126 self.unwrap_stall_counter.store(index as isize, Ordering::Relaxed);
5127 *self.unwrap_stalled_tx.lock() = Some(tx);
5128 rx
5129 }
5130
5131 fn stall_on_create_key(self: &Arc<Self>) -> oneshot::Receiver<oneshot::Sender<()>> {
5132 let (tx, rx) = oneshot::channel();
5133 *self.create_key_stalled_tx.lock() = Some(tx);
5134 rx
5135 }
5136 }
5137
5138 #[async_trait]
5139 impl Crypt for StallingCrypt {
5140 async fn create_key(
5141 &self,
5142 owner: u64,
5143 purpose: KeyPurpose,
5144 ) -> Result<(FxfsKey, UnwrappedKey), zx::Status> {
5145 if matches!(purpose, KeyPurpose::Data) {
5146 let stalled_tx = self.create_key_stalled_tx.lock().take();
5147 if let Some(tx) = stalled_tx {
5148 let (continue_tx, continue_rx) = oneshot::channel();
5149 let _ = tx.send(continue_tx);
5150 let _ = continue_rx.await;
5151 }
5152 }
5153 self.delegate.create_key(owner, purpose).await
5154 }
5155
5156 async fn unwrap_key(
5157 &self,
5158 wrapped_key: &WrappedKey,
5159 owner: u64,
5160 ) -> Result<UnwrappedKey, zx::Status> {
5161 let count = self.unwrap_stall_counter.fetch_sub(1, Ordering::Relaxed);
5162 log::info!("unwrap_key called, count was {}, owner {}", count, owner);
5163 if count == 0 {
5164 log::info!("unwrap_key stalling");
5165 let stalled_tx = self.unwrap_stalled_tx.lock().take();
5166 if let Some(tx) = stalled_tx {
5167 let (continue_tx, continue_rx) = oneshot::channel();
5168 let _ = tx.send(continue_tx);
5169 let _ = continue_rx.await;
5170 }
5171 log::info!("unwrap_key resumed");
5172 }
5173 self.delegate.unwrap_key(wrapped_key, owner).await
5174 }
5175
5176 async fn create_key_with_id(
5177 &self,
5178 owner: u64,
5179 wrapping_key_id: WrappingKeyId,
5180 object_type: ObjectType,
5181 ) -> Result<(EncryptionKey, UnwrappedKey), zx::Status> {
5182 self.delegate.create_key_with_id(owner, wrapping_key_id, object_type).await
5183 }
5184 }
5185
5186 #[fuchsia::test]
5187 async fn test_fsck_during_key_pre_cache_stall() {
5188 let device = DeviceHolder::new(FakeDevice::new(16384, TEST_DEVICE_BLOCK_SIZE));
5189 let fs = FxFilesystemBuilder::new().format(true).open(device).await.expect("open failed");
5190
5191 let crypt = Arc::new(StallingCrypt::new(Arc::new(new_insecure_crypt())));
5193
5194 let root_vol = root_volume(fs.clone()).await.expect("root_volume failed");
5195 let store = root_vol
5196 .new_volume(
5197 "test",
5198 NewChildStoreOptions {
5199 options: StoreOptions { crypt: Some(crypt.clone()), ..StoreOptions::default() },
5200 ..Default::default()
5201 },
5202 )
5203 .await
5204 .expect("new_volume failed");
5205
5206 let stalled_rx = crypt.stall_on_create_key();
5208
5209 {
5212 let mut lock_state = store.lock_state.lock();
5213 if let super::LockState::Unlocked { cached_keys, .. } = &mut *lock_state {
5214 cached_keys.clear();
5215 }
5216 }
5217
5218 let store_clone = store.clone();
5221 let root_dir_id = store.root_directory_object_id();
5222
5223 let tx_join_handle = fasync::Task::spawn(async move {
5224 let root_dir = Directory::open(&store_clone, root_dir_id).await.expect("open failed");
5225 let mut transaction = store_clone
5226 .new_transaction(
5227 lock_keys![LockKey::object(
5228 store_clone.store_object_id(),
5229 root_dir.object_id()
5230 )],
5231 Options::default(),
5232 )
5233 .await
5234 .expect("new_transaction failed");
5235 let name = "foo";
5236 root_dir
5237 .create_child_file(&mut transaction, name)
5238 .await
5239 .expect("create_child_file failed");
5240 transaction.commit().await.expect("commit failed");
5241 });
5242
5243 let continue_tx = stalled_rx.await.expect("stalled_rx failed");
5245
5246 fsck(fs.clone()).await.expect("fsck failed");
5248
5249 let _ = continue_tx.send(());
5251 tx_join_handle.await;
5252
5253 fs.close().await.expect("Close failed");
5254 }
5255
5256 #[fuchsia::test]
5257 async fn test_writes_to_other_store_not_blocked_by_stall() {
5258 let device = DeviceHolder::new(FakeDevice::new(16384, TEST_DEVICE_BLOCK_SIZE));
5259 let fs = FxFilesystemBuilder::new()
5260 .format(true)
5261 .journal_options(JournalOptions { reclaim_size: 32_768, ..Default::default() })
5262 .open(device)
5263 .await
5264 .expect("open failed");
5265
5266 let crypt1 = Arc::new(StallingCrypt::new(Arc::new(new_insecure_crypt())));
5269
5270 let crypt2 = Arc::new(new_insecure_crypt());
5272
5273 let root_vol = root_volume(fs.clone()).await.expect("root_volume failed");
5274
5275 let store1 = root_vol
5276 .new_volume(
5277 "test1",
5278 NewChildStoreOptions {
5279 options: StoreOptions {
5280 crypt: Some(crypt1.clone()),
5281 ..StoreOptions::default()
5282 },
5283 ..Default::default()
5284 },
5285 )
5286 .await
5287 .expect("new_volume failed");
5288
5289 store1.flush().await.expect("flush failed");
5290
5291 let store2 = root_vol
5292 .new_volume(
5293 "test2",
5294 NewChildStoreOptions {
5295 options: StoreOptions {
5296 crypt: Some(crypt2.clone()),
5297 ..StoreOptions::default()
5298 },
5299 ..Default::default()
5300 },
5301 )
5302 .await
5303 .expect("new_volume failed");
5304
5305 let stalled_rx = crypt1.stall_on_create_key();
5307
5308 {
5310 let mut lock_state = store1.lock_state.lock();
5311 if let super::LockState::Unlocked { cached_keys, .. } = &mut *lock_state {
5312 cached_keys.clear();
5313 }
5314 }
5315
5316 let store1_clone = store1.clone();
5319 let root_dir1_id = store1.root_directory_object_id();
5320
5321 let tx_join_handle = fasync::Task::spawn(async move {
5322 let root_dir1 =
5323 Directory::open(&store1_clone, root_dir1_id).await.expect("open failed");
5324 let mut transaction = store1_clone
5325 .new_transaction(
5326 lock_keys![LockKey::object(
5327 store1_clone.store_object_id(),
5328 root_dir1.object_id()
5329 )],
5330 Options::default(),
5331 )
5332 .await
5333 .expect("new_transaction failed");
5334 root_dir1
5335 .create_child_file(&mut transaction, "foo")
5336 .await
5337 .expect("create_child_file failed");
5338 transaction.commit().await.expect("commit failed");
5339 });
5340
5341 let continue_tx = stalled_rx.await.expect("stalled_rx failed");
5343
5344 let root_dir2 =
5346 Directory::open(&store2, store2.root_directory_object_id()).await.expect("open failed");
5347 let long_name = "a".repeat(255);
5348 let mut i = 0;
5349 while store2.counters.lock().num_flushes < 3 {
5350 if i > 200 {
5351 panic!(
5352 "Failed to trigger 3 compactions after 200 transactions. Flushes: {}",
5353 store2.counters.lock().num_flushes
5354 );
5355 }
5356 let mut transaction = store2
5357 .new_transaction(
5358 lock_keys![LockKey::object(store2.store_object_id(), root_dir2.object_id())],
5359 Options::default(),
5360 )
5361 .await
5362 .expect("new_transaction failed");
5363 root_dir2
5364 .create_child_file(&mut transaction, &format!("{}-{:03}", long_name, i))
5365 .await
5366 .expect("create_child_file failed");
5367 transaction.commit().await.expect("commit failed");
5368 i += 1;
5369 fasync::Timer::new(std::time::Duration::from_millis(5)).await;
5370 }
5371
5372 let _ = continue_tx.send(());
5374 tx_join_handle.await;
5375
5376 fs.close().await.expect("Close failed");
5377 }
5378
5379 #[fuchsia::test]
5380 async fn test_concurrent_transactions_exhaust_cached_keys() {
5381 let fs = test_filesystem().await;
5382
5383 let root_volume = root_volume(fs.clone()).await.expect("root_volume failed");
5384 let crypt = Arc::new(new_insecure_crypt());
5385 let store = root_volume
5386 .new_volume(
5387 "vol",
5388 NewChildStoreOptions {
5389 options: StoreOptions { crypt: Some(crypt.clone()), ..Default::default() },
5390 ..Default::default()
5391 },
5392 )
5393 .await
5394 .expect("new_volume failed");
5395
5396 let root_directory =
5397 Directory::open(&store, store.root_directory_object_id()).await.expect("open failed");
5398
5399 let mut transaction = store
5402 .new_transaction(
5403 lock_keys![LockKey::object(store.store_object_id(), root_directory.object_id())],
5404 Options::default(),
5405 )
5406 .await
5407 .expect("new_transaction failed");
5408 let dir1 = root_directory
5409 .create_child_dir(&mut transaction, "dir1")
5410 .await
5411 .expect("create_child_dir failed");
5412 let dir2 = root_directory
5413 .create_child_dir(&mut transaction, "dir2")
5414 .await
5415 .expect("create_child_dir failed");
5416 let dir3 = root_directory
5417 .create_child_dir(&mut transaction, "dir3")
5418 .await
5419 .expect("create_child_dir failed");
5420 transaction.commit().await.expect("commit failed");
5421
5422 let mut transaction1 = store
5428 .new_transaction(
5429 lock_keys![LockKey::object(store.store_object_id(), dir1.object_id())],
5430 Options::default(),
5431 )
5432 .await
5433 .expect("new_transaction 1 failed");
5434 dir1.create_child_file(&mut transaction1, "file1")
5435 .await
5436 .expect("create_child_file 1 failed");
5437
5438 let mut transaction2 = store
5440 .new_transaction(
5441 lock_keys![LockKey::object(store.store_object_id(), dir2.object_id())],
5442 Options::default(),
5443 )
5444 .await
5445 .expect("new_transaction 2 failed");
5446 dir2.create_child_file(&mut transaction2, "file2")
5447 .await
5448 .expect("create_child_file 2 failed");
5449
5450 let mut transaction3 = store
5452 .new_transaction(
5453 lock_keys![LockKey::object(store.store_object_id(), dir3.object_id())],
5454 Options::default(),
5455 )
5456 .await
5457 .expect("new_transaction 3 failed");
5458 dir3.create_child_file(&mut transaction3, "file3")
5459 .await
5460 .expect("create_child_file 3 failed");
5461
5462 crypt.shutdown();
5464
5465 transaction1.commit().await.expect("commit 1 failed");
5467 fs.journal().force_compact().await.expect("compact 1 failed");
5468
5469 assert!(transaction2.commit().await.is_err());
5472
5473 fs.close().await.expect("Close failed");
5474 }
5475
5476 #[fuchsia::test(threads = 10)]
5477 async fn test_key_exhaustion_race() {
5478 let fs;
5479 let in_hook = AtomicBool::new(false);
5480 let (mut hooks, fs_hooks) = Hooks::new();
5481 fs = test_filesystem_with_hooks(fs_hooks).await;
5482
5483 let root_volume = root_volume(fs.clone()).await.expect("root_volume failed");
5484 let crypt = Arc::new(new_insecure_crypt());
5485 let store = root_volume
5486 .new_volume(
5487 "vol",
5488 NewChildStoreOptions {
5489 options: StoreOptions { crypt: Some(crypt.clone()), ..Default::default() },
5490 ..Default::default()
5491 },
5492 )
5493 .await
5494 .expect("new_volume failed");
5495
5496 let root_directory =
5497 Directory::open(&store, store.root_directory_object_id()).await.expect("open failed");
5498
5499 let mut transaction = store
5501 .new_transaction(
5502 lock_keys![LockKey::object(store.store_object_id(), root_directory.object_id())],
5503 Options::default(),
5504 )
5505 .await
5506 .expect("new_transaction failed");
5507 root_directory
5508 .create_child_dir(&mut transaction, "dir")
5509 .await
5510 .expect("create_child_dir failed");
5511 transaction.commit().await.expect("commit failed");
5512
5513 hooks.set_before_commit(|| {
5514 if in_hook.swap(true, Ordering::Relaxed) {
5515 return;
5516 }
5517
5518 futures::executor::block_on(fs.journal().force_compact()).expect("compact failed");
5522 });
5523
5524 let mut transaction = store
5527 .new_transaction(
5528 lock_keys![LockKey::object(store.store_object_id(), root_directory.object_id())],
5529 Options::default(),
5530 )
5531 .await
5532 .expect("new_transaction failed");
5533 root_directory
5534 .create_child_file(&mut transaction, "file1")
5535 .await
5536 .expect("create_child_file failed");
5537
5538 transaction.commit().await.expect("commit failed");
5547
5548 fs.journal().force_compact().await.expect("compaction failed");
5553
5554 fs.close().await.expect("Close failed");
5555 }
5556
5557 #[fuchsia::test(threads = 10)]
5558 async fn test_unlock_pre_cache_stall_does_not_block_other_stores() {
5559 let device = DeviceHolder::new(FakeDevice::new(16384, TEST_DEVICE_BLOCK_SIZE));
5560 let fs = FxFilesystemBuilder::new()
5561 .format(true)
5562 .journal_options(JournalOptions { reclaim_size: 32_768, ..Default::default() })
5563 .open(device)
5564 .await
5565 .expect("open failed");
5566
5567 let crypt1 = Arc::new(StallingCrypt::new(Arc::new(new_insecure_crypt())));
5568 let crypt2 = Arc::new(new_insecure_crypt());
5569
5570 let root_vol = root_volume(fs.clone()).await.expect("root_volume failed");
5571
5572 let store1 = root_vol
5573 .new_volume(
5574 "test1",
5575 NewChildStoreOptions {
5576 options: StoreOptions {
5577 crypt: Some(crypt1.clone()),
5578 ..StoreOptions::default()
5579 },
5580 ..Default::default()
5581 },
5582 )
5583 .await
5584 .expect("new_volume failed");
5585
5586 {
5588 let mut transaction = store1
5589 .new_transaction(
5590 lock_keys![LockKey::object(
5591 store1.store_object_id(),
5592 store1.root_directory_object_id()
5593 )],
5594 Options::default(),
5595 )
5596 .await
5597 .expect("new_transaction failed");
5598 let root_dir1 = Directory::open(&store1, store1.root_directory_object_id())
5599 .await
5600 .expect("open failed");
5601 root_dir1
5602 .create_child_file(&mut transaction, "foo")
5603 .await
5604 .expect("create_child_file failed");
5605 transaction.commit().await.expect("commit failed");
5606 }
5607 store1.lock().await.expect("lock failed");
5608
5609 let store2 = root_vol
5610 .new_volume(
5611 "test2",
5612 NewChildStoreOptions {
5613 options: StoreOptions {
5614 crypt: Some(crypt2.clone()),
5615 ..StoreOptions::default()
5616 },
5617 ..Default::default()
5618 },
5619 )
5620 .await
5621 .expect("new_volume failed");
5622
5623 let stalled_rx = crypt1.stall_on_create_key();
5625
5626 let store1_clone = store1.clone();
5629 let crypt1_clone = crypt1.clone();
5630 let unlock_join_handle = fasync::Task::spawn(async move {
5631 store1_clone.unlock(crypt1_clone).await.expect("unlock failed");
5632 });
5633
5634 let continue_tx = stalled_rx.await.expect("stalled_rx failed");
5636
5637 let root_dir2 =
5640 Directory::open(&store2, store2.root_directory_object_id()).await.expect("open failed");
5641 let long_name = "a".repeat(255);
5642 let mut i = 0;
5643 while store2.counters.lock().num_flushes < 3 {
5644 if i > 200 {
5645 panic!(
5646 "Failed to trigger 3 compactions after 200 transactions. Flushes: {}",
5647 store2.counters.lock().num_flushes
5648 );
5649 }
5650 let mut transaction = store2
5651 .new_transaction(
5652 lock_keys![LockKey::object(store2.store_object_id(), root_dir2.object_id())],
5653 Options::default(),
5654 )
5655 .await
5656 .expect("new_transaction failed");
5657 root_dir2
5658 .create_child_file(&mut transaction, &format!("{}-{:03}", long_name, i))
5659 .await
5660 .expect("create_child_file failed");
5661 transaction.commit().await.expect("commit failed");
5662 i += 1;
5663 fasync::Timer::new(std::time::Duration::from_millis(5)).await;
5664 }
5665
5666 let _ = continue_tx.send(());
5668 unlock_join_handle.await;
5669
5670 fs.close().await.expect("Close failed");
5671 }
5672
5673 async fn run_unlock_stall_test(unwrap_stall_index: usize) -> bool {
5674 log::info!("Starting run_unlock_stall_test for index {}", unwrap_stall_index);
5675 let device = DeviceHolder::new(FakeDevice::new(16384, TEST_DEVICE_BLOCK_SIZE));
5676 let crypt1 = Arc::new(new_insecure_crypt());
5677 let crypt2 = Arc::new(new_insecure_crypt());
5678 let (store1_id, device) = {
5679 let fs = FxFilesystemBuilder::new()
5680 .format(true)
5681 .journal_options(JournalOptions { reclaim_size: 32_768, ..Default::default() })
5682 .open(device)
5683 .await
5684 .expect("open failed");
5685
5686 let store1_id = {
5687 let root_vol = root_volume(fs.clone()).await.expect("root_volume failed");
5688
5689 let store1 = root_vol
5690 .new_volume(
5691 "test1",
5692 NewChildStoreOptions {
5693 options: StoreOptions {
5694 crypt: Some(crypt1.clone()),
5695 ..StoreOptions::default()
5696 },
5697 ..Default::default()
5698 },
5699 )
5700 .await
5701 .expect("new_volume failed");
5702
5703 root_vol
5704 .new_volume(
5705 "test2",
5706 NewChildStoreOptions {
5707 options: StoreOptions {
5708 crypt: Some(crypt2.clone()),
5709 ..StoreOptions::default()
5710 },
5711 ..Default::default()
5712 },
5713 )
5714 .await
5715 .expect("new_volume failed");
5716
5717 let root_dir1 = Directory::open(&store1, store1.root_directory_object_id())
5718 .await
5719 .expect("open failed");
5720
5721 for i in 0..8 {
5722 let mut transaction = store1
5723 .new_transaction(
5724 lock_keys![LockKey::object(
5725 store1.store_object_id(),
5726 root_dir1.object_id()
5727 )],
5728 Options::default(),
5729 )
5730 .await
5731 .expect("new_transaction failed");
5732 let name = format!("file_{i}");
5733 root_dir1
5734 .create_child_file(&mut transaction, &name)
5735 .await
5736 .expect("create_child_file failed");
5737 transaction.commit().await.expect("commit failed");
5738 }
5739
5740 store1.flush().await.expect("flush failed");
5742
5743 {
5746 let mut transaction = store1
5747 .new_transaction(
5748 lock_keys![LockKey::object(
5749 store1.store_object_id(),
5750 root_dir1.object_id()
5751 )],
5752 Options::default(),
5753 )
5754 .await
5755 .expect("new_transaction failed");
5756 root_dir1
5757 .create_child_file(&mut transaction, "file_after_flush")
5758 .await
5759 .expect("create_child_file failed");
5760 transaction.commit().await.expect("commit failed");
5761 }
5762 store1.store_object_id()
5763 };
5764
5765 fs.close().await.expect("Close failed");
5766 let device = fs.take_device().await;
5767 (store1_id, device)
5768 };
5769 device.reopen(false);
5770
5771 log::info!("Opening filesystem");
5772 let fs = FxFilesystemBuilder::new()
5773 .journal_options(JournalOptions { reclaim_size: 32_768, ..Default::default() })
5774 .open(device)
5775 .await
5776 .expect("open failed");
5777 log::info!("Opened filesystem, getting root volume");
5778 let root_vol = root_volume(fs.clone()).await.expect("root_volume failed");
5779 log::info!("Got root volume");
5780
5781 log::info!("Re-opening store2");
5782 let store2 = root_vol
5784 .volume("test2", StoreOptions { crypt: Some(crypt2), ..StoreOptions::default() })
5785 .await
5786 .expect("volume failed");
5787 log::info!("Re-opened store2");
5788
5789 let stalling_crypt1 = Arc::new(StallingCrypt::new(crypt1));
5791 let stalled_rx = stalling_crypt1.stall_on_unwrap(unwrap_stall_index);
5792
5793 let store1 = fs.object_manager().store(store1_id).unwrap();
5795
5796 log::info!("Spawning store1 unlock task");
5797 let store1_clone = store1.clone();
5799 let stalling_crypt1_clone = stalling_crypt1.clone();
5800 let unlock_join_handle = fasync::Task::spawn(async move {
5801 log::info!("store1 unlock task started");
5802 store1_clone.unlock(stalling_crypt1_clone).await.expect("unlock failed");
5803 log::info!("store1 unlock task finished");
5804 });
5805
5806 let continue_tx = futures::select! {
5808 res = stalled_rx.fuse() => {
5809 log::info!("Stalled at index {}", unwrap_stall_index);
5810 Some(res.expect("stalled_rx failed"))
5811 }
5812 _ = unlock_join_handle.fuse() => {
5813 log::info!("Unlock completed without stalling at index {}", unwrap_stall_index);
5814 None
5815 }
5816 };
5817
5818 let stalled = continue_tx.is_some();
5819
5820 if let Some(continue_tx) = continue_tx {
5821 log::info!("Writing to store2 while stalled at index {}", unwrap_stall_index);
5822 let root_dir2 = Directory::open(&store2, store2.root_directory_object_id())
5824 .await
5825 .expect("open failed");
5826 let long_name = "a".repeat(255);
5827 let mut i = 0;
5828 while store2.counters.lock().num_flushes < 3 {
5829 if i > 200 {
5830 panic!(
5831 "Failed to trigger 3 compactions after 200 transactions. Flushes: {}",
5832 store2.counters.lock().num_flushes
5833 );
5834 }
5835 let mut transaction = store2
5836 .new_transaction(
5837 lock_keys![LockKey::object(
5838 store2.store_object_id(),
5839 root_dir2.object_id()
5840 )],
5841 Options::default(),
5842 )
5843 .await
5844 .expect("new_transaction failed");
5845 root_dir2
5846 .create_child_file(&mut transaction, &format!("{}-{:03}", long_name, i))
5847 .await
5848 .expect("create_child_file failed");
5849 transaction.commit().await.expect("commit failed");
5850 i += 1;
5851 fasync::Timer::new(std::time::Duration::from_millis(5)).await;
5852 }
5853
5854 log::info!("Unblocking store1 at index {}", unwrap_stall_index);
5855 let _ = continue_tx.send(());
5857 }
5858
5859 fs.close().await.expect("Close failed");
5860 log::info!(
5861 "Finished run_unlock_stall_test for index {}, stalled: {}",
5862 unwrap_stall_index,
5863 stalled
5864 );
5865 stalled
5866 }
5867
5868 #[fuchsia::test(threads = 10)]
5869 async fn test_unlock_replay_stall_does_not_block_other_stores() {
5870 let mut unwrap_stall_index = 0;
5871 loop {
5872 let stalled = run_unlock_stall_test(unwrap_stall_index).await;
5873 if !stalled {
5874 break;
5875 }
5876 unwrap_stall_index += 1;
5877 }
5878 }
5879
5880 #[fuchsia::test(threads = 10)]
5881 async fn test_unlock_flush_race() {
5882 let device = DeviceHolder::new(FakeDevice::new(16384, TEST_DEVICE_BLOCK_SIZE));
5883 let crypt = Arc::new(new_insecure_crypt());
5884
5885 let (store1_id, device) = {
5887 let (store1_id, fs) = {
5888 let fs = FxFilesystemBuilder::new()
5889 .format(true)
5890 .open(device)
5891 .await
5892 .expect("open failed");
5893 let root_vol = root_volume(fs.clone()).await.expect("root_volume failed");
5894 let store1 = root_vol
5895 .new_volume(
5896 "test1",
5897 NewChildStoreOptions {
5898 options: StoreOptions {
5899 crypt: Some(crypt.clone()),
5900 ..StoreOptions::default()
5901 },
5902 ..Default::default()
5903 },
5904 )
5905 .await
5906 .expect("new_volume failed");
5907
5908 let root_dir = Directory::open(&store1, store1.root_directory_object_id())
5909 .await
5910 .expect("open failed");
5911 let mut transaction = store1
5912 .new_transaction(
5913 lock_keys![LockKey::object(store1.store_object_id(), root_dir.object_id())],
5914 Options::default(),
5915 )
5916 .await
5917 .expect("new_transaction failed");
5918 root_dir
5919 .create_child_file(&mut transaction, "file1")
5920 .await
5921 .expect("create_child_file failed");
5922 transaction.commit().await.expect("commit failed");
5923
5924 (store1.store_object_id(), fs)
5925 };
5926 fs.close().await.expect("Close failed");
5927 let device = fs.take_device().await;
5928 (store1_id, device)
5929 };
5930 device.reopen(false);
5931
5932 let fs;
5934 let store1;
5935 let (mut hooks, fs_hooks) = Hooks::new();
5936 fs = FxFilesystemBuilder::new().hooks(fs_hooks).open(device).await.expect("open failed");
5937
5938 store1 = fs.object_manager().store(store1_id).unwrap();
5939
5940 hooks.set_unlock_resources_acquired(|| {
5943 futures::executor::block_on(store1.flush()).expect("flush failed");
5944 });
5945
5946 store1.unlock(crypt).await.expect("unlock failed");
5947
5948 fs.journal().force_compact().await.expect("compact failed");
5949
5950 fsck(fs.clone()).await.expect("fsck failed");
5951
5952 fs.close().await.expect("Close failed");
5953 }
5954
5955 #[fuchsia::test]
5956 async fn test_open_object_with_illegal_key_in_root_store() {
5957 let fs = test_filesystem().await;
5958 let crypt = Arc::new(new_insecure_crypt());
5959 let object_id = {
5960 let store = fs.root_store();
5961 let mut transaction = store
5962 .new_transaction(lock_keys![], Options::default())
5963 .await
5964 .expect("new_transaction failed");
5965
5966 let reserved_id = store.get_next_object_id().await.expect("get_next_object_id failed");
5967 let object_id = reserved_id.get();
5968
5969 let (fxfs_key, unwrapped_key) =
5970 crypt.create_key(object_id, KeyPurpose::Data).await.expect("create_key failed");
5971
5972 let handle = ObjectStore::create_object_with_id(
5973 &store,
5974 &mut transaction,
5975 reserved_id,
5976 HandleOptions::default(),
5977 Some(ObjectEncryptionOptions {
5978 permanent: false,
5979 key_id: 0,
5980 key: EncryptionKey::Fxfs(fxfs_key),
5981 unwrapped_key,
5982 }),
5983 )
5984 .expect("create_object_with_id failed");
5985 transaction.commit().await.expect("commit failed");
5986
5987 let buf = handle.allocate_buffer(fs.block_size().get() as usize).await;
5988 handle.write_or_append(None, buf.as_ref()).await.expect("Write some data");
5989
5990 let old_keys = store.get_keys(object_id).await.expect("Old keys should work fine");
5994 let mut new_keys =
5995 vec![(1, EncryptionKey::FscryptInoLblk32File { key_identifier: [0; 16] })];
5996 for key in old_keys.iter() {
5997 new_keys.push(key.clone());
5998 }
5999 let mut transaction = store
6000 .new_transaction(
6001 lock_keys![LockKey::Object {
6002 store_object_id: store.store_object_id,
6003 object_id
6004 }],
6005 Options::default(),
6006 )
6007 .await
6008 .expect("new_transaction failed");
6009 transaction.add(
6010 store.store_object_id(),
6011 Mutation::replace_or_insert_object(
6012 ObjectKey::keys(object_id),
6013 ObjectValue::keys(new_keys.into()),
6014 ),
6015 );
6016 transaction.commit().await.expect("commit failed");
6017
6018 object_id
6019 };
6020
6021 fs.close().await.expect("close failed");
6022 let device = fs.take_device().await;
6023 device.reopen(false);
6024 let fs = FxFilesystem::open(device).await.expect("open failed");
6025
6026 let store = fs.root_store();
6027 assert!(
6028 ObjectStore::open_object(&store, object_id, HandleOptions::default(), Some(crypt))
6029 .await
6030 .is_err()
6031 );
6032
6033 let res = store.get_keys(object_id).await;
6034 assert!(matches!(res, Err(e) if FxfsError::IntegrityError.matches(&e)));
6035 }
6036
6037 #[fuchsia::test]
6040 async fn test_encrypted_mutations_mixed_versions() {
6041 let fs = test_filesystem().await;
6042 let crypt = Arc::new(new_insecure_crypt());
6043
6044 let (store_object_id, root_dir_id, unwrapped_key) = {
6046 let root_volume = root_volume(fs.clone()).await.expect("root_volume failed");
6047 let store = root_volume
6048 .new_volume(
6049 "test",
6050 NewChildStoreOptions {
6051 options: StoreOptions {
6052 crypt: Some(crypt.clone()),
6053 ..StoreOptions::default()
6054 },
6055 ..Default::default()
6056 },
6057 )
6058 .await
6059 .expect("new_volume failed");
6060 let store_object_id = store.store_object_id();
6061 let root_dir_id = store.root_directory_object_id();
6062 let store_info = store.store_info().unwrap();
6063 let key = store_info.mutations_key.as_ref().unwrap().clone();
6064 let unwrapped_key = crypt
6065 .unwrap_key(&fxfs_crypto::WrappedKey::Fxfs(key.into()), store_object_id)
6066 .await
6067 .expect("unwrap_key failed");
6068
6069 fs.object_manager()
6071 .flush(FlushReason::Journal(ForceMajor::False))
6072 .await
6073 .expect("flush failed");
6074
6075 (store_object_id, root_dir_id, unwrapped_key)
6076 };
6077
6078 let store = fs.object_manager().store(store_object_id).unwrap();
6081 let (old_file_oid, chacha_offset) = {
6082 let mut transaction = store
6083 .new_transaction(
6084 lock_keys![LockKey::object(store_object_id, root_dir_id)],
6085 Options::default(),
6086 )
6087 .await
6088 .expect("new_transaction failed");
6089 let root_directory =
6090 Directory::open(&store, root_dir_id).await.expect("open root dir failed");
6091 let old_file = root_directory
6092 .create_child_file(&mut transaction, "old_file")
6093 .await
6094 .expect("create_child_file failed");
6095 let oid = old_file.object_id();
6096
6097 let mutations = transaction.take_mutations();
6098 let mut old_data = Vec::new();
6099 for item in &mutations {
6100 item.mutation.serialize_into(&mut old_data).expect("serialize failed");
6101 }
6102
6103 let mut stream_cipher = StreamCipher::new(&unwrapped_key, 0);
6104 stream_cipher.encrypt(&mut old_data);
6105
6106 let old_version = Version { major: 56, minor: 0 };
6107 let encrypted_mutations = EncryptedMutations {
6108 transactions: vec![(
6109 JournalCheckpoint { file_offset: 0, checksum: 0, version: old_version },
6110 mutations.len() as u64,
6111 )],
6112 data: old_data,
6113 mutations_key_roll: Vec::new(),
6114 };
6115
6116 let parent_store = store.parent_store().unwrap();
6118 let mut create_txn = parent_store
6119 .new_transaction(lock_keys![], Options::default())
6120 .await
6121 .expect("new_transaction failed");
6122 let handle = ObjectStore::create_object(
6123 &parent_store,
6124 &mut create_txn,
6125 HandleOptions::default(),
6126 None,
6127 )
6128 .await
6129 .expect("create_object failed");
6130 create_txn.commit().await.expect("commit failed");
6131
6132 let mut writer = DirectWriter::new(&handle, Options::default()).await;
6133 let mut buffer = Vec::new();
6134 encrypted_mutations.serialize_with_version(&mut buffer).expect("serialize failed");
6135 writer.write_bytes(&buffer).await.expect("write_bytes failed");
6136 writer.complete().await.expect("writer complete failed");
6137
6138 let mut store_info = store.load_store_info().await.unwrap();
6139 store_info.encrypted_mutations_object_id = handle.object_id();
6140 store_info.mutations_cipher_offset = 0;
6141
6142 let mut update_txn = parent_store
6143 .new_transaction(
6144 lock_keys![LockKey::object(
6145 parent_store.store_object_id(),
6146 store.store_info_handle_object_id().unwrap(),
6147 )],
6148 Options::default(),
6149 )
6150 .await
6151 .expect("new_transaction failed");
6152 store
6153 .write_store_info(&mut update_txn, &store_info)
6154 .await
6155 .expect("write_store_info failed");
6156 *store.store_info.lock() = Some(store_info);
6157 update_txn.commit().await.expect("commit failed");
6158
6159 (oid, stream_cipher.offset())
6160 };
6161
6162 let (new_wrapped_key, new_unwrapped_key) = crypt
6165 .create_key(store_object_id, KeyPurpose::Metadata)
6166 .await
6167 .expect("create_key failed");
6168 if let LockState::Unlocked { mutations_cipher, .. } = &mut *store.lock_state.lock() {
6169 *mutations_cipher = JournalCipher::new_aes256_xts(&new_unwrapped_key, chacha_offset);
6170 } else {
6171 panic!("Unexpected lock state");
6172 }
6173 store.store_info.lock().as_mut().unwrap().mutations_key = Some(new_wrapped_key);
6174
6175 let new_file_oid = {
6176 let mut transaction = store
6177 .new_transaction(
6178 lock_keys![LockKey::object(store_object_id, root_dir_id)],
6179 Options::default(),
6180 )
6181 .await
6182 .expect("new_transaction failed");
6183 let root_directory =
6184 Directory::open(&store, root_dir_id).await.expect("open root dir failed");
6185 let new_file = root_directory
6186 .create_child_file(&mut transaction, "new_file")
6187 .await
6188 .expect("create_child_file failed");
6189 transaction.commit().await.expect("commit failed");
6190 new_file.object_id()
6191 };
6192
6193 fs.close().await.expect("close failed");
6195 let device = fs.take_device().await;
6196 device.reopen(false);
6197 let fs = FxFilesystem::open(device).await.expect("FS open failed");
6198
6199 let root_volume = root_volume(fs.clone()).await.expect("root_volume failed");
6201 let volume = root_volume
6202 .volume("test", StoreOptions { crypt: Some(crypt.clone()), ..StoreOptions::default() })
6203 .await
6204 .expect("volume failed");
6205
6206 let root_directory =
6207 Directory::open(&volume, root_dir_id).await.expect("open root dir failed");
6208
6209 assert_eq!(
6210 root_directory.lookup("old_file").await.expect("lookup old_file failed"),
6211 Some((old_file_oid, ObjectDescriptor::File, false))
6212 );
6213
6214 assert_eq!(
6215 root_directory.lookup("new_file").await.expect("lookup new_file failed"),
6216 Some((new_file_oid, ObjectDescriptor::File, false))
6217 );
6218
6219 let old_file =
6220 ObjectStore::open_object(&volume, old_file_oid, HandleOptions::default(), None)
6221 .await
6222 .expect("open old_file failed");
6223 assert_eq!(old_file.object_id(), old_file_oid);
6224
6225 let new_file =
6226 ObjectStore::open_object(&volume, new_file_oid, HandleOptions::default(), None)
6227 .await
6228 .expect("open new_file failed");
6229 assert_eq!(new_file.object_id(), new_file_oid);
6230 }
6231
6232 #[test_case(false; "unencrypted")]
6233 #[test_case(true; "encrypted")]
6234 #[fuchsia::test]
6235 async fn test_large_mutations_in_transaction(encrypted: bool) {
6236 let fs = test_filesystem().await;
6237 let crypt = Arc::new(new_insecure_crypt());
6238
6239 let root_volume = root_volume(fs.clone()).await.expect("root_volume failed");
6240 let store = root_volume
6241 .new_volume(
6242 "test",
6243 NewChildStoreOptions {
6244 options: StoreOptions {
6245 crypt: if encrypted { Some(crypt.clone()) } else { None },
6246 ..StoreOptions::default()
6247 },
6248 ..Default::default()
6249 },
6250 )
6251 .await
6252 .expect("new_volume failed");
6253 let store_object_id = store.store_object_id();
6254 let root_dir_id = store.root_directory_object_id();
6255
6256 let root_dir = Directory::open(&store, root_dir_id).await.expect("open root dir failed");
6257 let mut transaction = store
6258 .new_transaction(
6259 lock_keys![LockKey::object(store_object_id, root_dir_id)],
6260 Options::default(),
6261 )
6262 .await
6263 .expect("new_transaction failed");
6264
6265 let file = root_dir
6266 .create_child_file(&mut transaction, "test_file")
6267 .await
6268 .expect("create_child_file failed");
6269
6270 let mut total_size = 0;
6274 let mut i = 0;
6275 while total_size <= DEFAULT_MAX_SERIALIZED_RECORD_SIZE {
6276 let name = format!("attr{i}").into_bytes();
6277 let mutation = Mutation::replace_or_insert_object(
6278 ObjectKey::extended_attribute(file.object_id(), name),
6279 ObjectValue::inline_extended_attribute(vec![0u8; MAX_INLINE_XATTR_SIZE]),
6280 );
6281 let mut buf = Vec::new();
6282 mutation.serialize_into(&mut buf).unwrap();
6283 total_size += buf.len() as u64;
6284 transaction.add(store_object_id, mutation);
6285 i += 1;
6286 }
6287
6288 transaction.commit().await.expect("commit should succeed");
6289
6290 if encrypted {
6291 store.lock().await.expect("lock failed");
6292 store.unlock(crypt).await.expect("unlock failed");
6293 }
6294
6295 for j in 0..i {
6296 let name = format!("attr{j}").into_bytes();
6297 let item = store
6298 .tree
6299 .find(&ObjectKey::extended_attribute(file.object_id(), name))
6300 .await
6301 .expect("find failed")
6302 .expect("attr not found");
6303 assert_eq!(
6304 item.value,
6305 ObjectValue::inline_extended_attribute(vec![0u8; MAX_INLINE_XATTR_SIZE])
6306 );
6307 }
6308 }
6309}