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