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