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