Skip to main content

fxfs/
object_store.rs

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