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