Skip to main content

fxfs/object_store/
store_object_handle.rs

1// Copyright 2023 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
5use crate::checksum::{Checksum, Checksums};
6use crate::errors::FxfsError;
7use crate::log::*;
8use crate::lsm_tree::Query;
9use crate::lsm_tree::merge::{Merger, MergerIterator};
10use crate::lsm_tree::types::{ItemRef, LayerIterator};
11use crate::object_handle::ObjectHandle;
12use crate::object_store::data_object_handle::WRITE_ATTR_BATCH_SIZE;
13use crate::object_store::extent_record::{
14    ExtentMode, ExtentValue, JOURNAL_CHECKSUM_BYTES_PER_BLOCK, MAX_JOURNAL_BYTES_PER_RANGE,
15};
16use crate::object_store::object_manager::ObjectManager;
17use crate::object_store::object_record::{
18    AttributeKey, BytesAndNodes, ExtendedAttributeValue, ObjectAttributes, ObjectItem, ObjectKey,
19    ObjectKeyData, ObjectKind, ObjectValue, Timestamp,
20};
21use crate::object_store::transaction::{
22    AssocObj, AssociatedObject, LockKey, Mutation, ObjectStoreMutation, Options, ReadGuard,
23    TRANSACTION_MAX_JOURNAL_USAGE, Transaction, lock_keys,
24};
25use crate::object_store::{
26    AttributeId, Extent, FSCRYPT_KEY_ID, FileExtent, HandleOptions, HandleOwner, ObjectStore,
27    TrimMode, TrimResult, VOLUME_DATA_KEY_ID,
28};
29use crate::range::RangeExt;
30use anyhow::{Context, Error, anyhow, bail, ensure};
31use assert_matches::assert_matches;
32use bit_vec::BitVec;
33use futures::future::try_join_all;
34use futures::stream::{FuturesOrdered, FuturesUnordered, unfold};
35use futures::{Stream, TryStreamExt, try_join};
36use fxfs_crypto::{
37    Cipher, CipherHolder, CipherSet, EncryptionKey, FindKeyResult, FxfsCipher, KeyPurpose,
38    MutPtrByteSlice,
39};
40use fxfs_trace::{TraceFutureExt, trace, trace_future_args};
41use static_assertions::const_assert;
42use std::cmp::min;
43use std::future::Future;
44use std::ops::Range;
45use std::sync::Arc;
46use std::sync::atomic::{self, AtomicBool, Ordering};
47use storage_device::buffer::{Buffer, BufferFuture, BufferRef, MutableBufferRef};
48use storage_device::{InlineCryptoOptions, ReadOptions, WriteFlags, WriteOptions};
49use storage_units::BlockSize;
50
51use fidl_fuchsia_io as fio;
52use fuchsia_async as fasync;
53
54/// Maximum size for an extended attribute name.
55pub const MAX_XATTR_NAME_SIZE: usize = 255;
56/// Maximum size an extended attribute can be before it's stored in an object attribute instead of
57/// inside the record directly.
58pub const MAX_INLINE_XATTR_SIZE: usize = 256;
59/// Maximum size for an extended attribute value. NB: the maximum size for an extended attribute is
60/// 64kB, which we rely on for correctness when deleting attributes, so ensure it's always
61/// enforced.
62pub const MAX_XATTR_VALUE_SIZE: usize = 64000;
63
64/// Zeroes blocks in 'buffer' based on `bitmap`, one bit per block from start of buffer.
65fn apply_bitmap_zeroing(
66    block_size: BlockSize,
67    bitmap: &bit_vec::BitVec,
68    mut buffer: MutableBufferRef<'_>,
69) {
70    let mut buf = buffer.as_mut_ptr_slice();
71    debug_assert_eq!(bitmap.len() as u64 * block_size, buf.len() as u64);
72    for (i, block) in bitmap.iter().enumerate() {
73        if !block {
74            let start = (i as u64 * block_size) as usize;
75            buf.subslice_mut(start..start + block_size.get() as usize).fill(0);
76        }
77    }
78}
79
80/// When writing, often the logic should be generic over whether or not checksums are generated.
81/// This provides that and a handy way to convert to the more general ExtentMode that eventually
82/// stores it on disk.
83#[derive(Debug, Clone, PartialEq)]
84pub enum MaybeChecksums {
85    None,
86    Fletcher(Vec<Checksum>),
87}
88
89impl MaybeChecksums {
90    pub fn maybe_as_ref(&self) -> Option<&[Checksum]> {
91        match self {
92            Self::None => None,
93            Self::Fletcher(sums) => Some(&sums),
94        }
95    }
96
97    pub fn split_off(&mut self, at: usize) -> Self {
98        match self {
99            Self::None => Self::None,
100            Self::Fletcher(sums) => Self::Fletcher(sums.split_off(at)),
101        }
102    }
103
104    pub fn to_mode(self) -> ExtentMode {
105        match self {
106            Self::None => ExtentMode::Raw,
107            Self::Fletcher(sums) => ExtentMode::Cow(Checksums::fletcher(sums)),
108        }
109    }
110
111    pub fn into_option(self) -> Option<Vec<Checksum>> {
112        match self {
113            Self::None => None,
114            Self::Fletcher(sums) => Some(sums),
115        }
116    }
117}
118
119/// The mode of operation when setting extended attributes. This is the same as the fidl definition
120/// but is replicated here so we don't have fuchsia.io structures in the api, so this can be used
121/// on host.
122#[derive(Debug, Clone, Copy, PartialEq, Eq)]
123pub enum SetExtendedAttributeMode {
124    /// Create the extended attribute if it doesn't exist, replace the value if it does.
125    Set,
126    /// Create the extended attribute if it doesn't exist, fail if it does.
127    Create,
128    /// Replace the extended attribute value if it exists, fail if it doesn't.
129    Replace,
130}
131
132impl From<fio::SetExtendedAttributeMode> for SetExtendedAttributeMode {
133    fn from(other: fio::SetExtendedAttributeMode) -> SetExtendedAttributeMode {
134        match other {
135            fio::SetExtendedAttributeMode::Set => SetExtendedAttributeMode::Set,
136            fio::SetExtendedAttributeMode::Create => SetExtendedAttributeMode::Create,
137            fio::SetExtendedAttributeMode::Replace => SetExtendedAttributeMode::Replace,
138        }
139    }
140}
141
142enum Encryption {
143    /// The object doesn't use encryption.
144    None,
145
146    /// The object has keys that are cached (which means unwrapping occurs on-demand) with
147    /// KeyManager.
148    CachedKeys,
149
150    /// The object has permanent keys registered with KeyManager.
151    PermanentKeys,
152}
153
154#[derive(PartialEq, Debug)]
155enum OverwriteBitmaps {
156    None,
157    Some {
158        /// The block bitmap of a partial overwrite extent in the tree.
159        extent_bitmap: BitVec,
160        /// A bitmap of the blocks written to by the current overwrite.
161        write_bitmap: BitVec,
162        /// BitVec doesn't have a slice equivalent, so for a particular section of the write we
163        /// keep track of an offset in the bitmaps to operate on.
164        bitmap_offset: usize,
165    },
166}
167
168impl OverwriteBitmaps {
169    fn new(extent_bitmap: BitVec) -> Self {
170        OverwriteBitmaps::Some {
171            write_bitmap: BitVec::from_elem(extent_bitmap.len(), false),
172            extent_bitmap,
173            bitmap_offset: 0,
174        }
175    }
176
177    fn is_none(&self) -> bool {
178        *self == OverwriteBitmaps::None
179    }
180
181    fn set_offset(&mut self, new_offset: usize) {
182        match self {
183            OverwriteBitmaps::None => (),
184            OverwriteBitmaps::Some { bitmap_offset, .. } => *bitmap_offset = new_offset,
185        }
186    }
187
188    fn get_from_extent_bitmap(&self, i: usize) -> Option<bool> {
189        match self {
190            OverwriteBitmaps::None => None,
191            OverwriteBitmaps::Some { extent_bitmap, bitmap_offset, .. } => {
192                extent_bitmap.get(*bitmap_offset + i)
193            }
194        }
195    }
196
197    fn set_in_write_bitmap(&mut self, i: usize, x: bool) {
198        match self {
199            OverwriteBitmaps::None => (),
200            OverwriteBitmaps::Some { write_bitmap, bitmap_offset, .. } => {
201                write_bitmap.set(*bitmap_offset + i, x)
202            }
203        }
204    }
205
206    fn take_bitmaps(self) -> Option<(BitVec, BitVec)> {
207        match self {
208            OverwriteBitmaps::None => None,
209            OverwriteBitmaps::Some { extent_bitmap, write_bitmap, .. } => {
210                Some((extent_bitmap, write_bitmap))
211            }
212        }
213    }
214}
215
216/// When writing to Overwrite ranges, we need to emit whether a set of checksums for a device range
217/// is the first write to that region or not. This tracks one such range so we can use it after the
218/// write to break up the returned checksum list.
219#[derive(PartialEq, Debug)]
220struct ChecksumRangeChunk {
221    checksum_range: Range<usize>,
222    device_range: Range<u64>,
223    is_first_write: bool,
224}
225
226impl ChecksumRangeChunk {
227    fn group_first_write_ranges(
228        bitmaps: &mut OverwriteBitmaps,
229        block_size: BlockSize,
230        write_device_range: Range<u64>,
231    ) -> Vec<ChecksumRangeChunk> {
232        let write_block_len = (write_device_range.length().unwrap() / block_size) as usize;
233        if bitmaps.is_none() {
234            // If there is no bitmap, then the overwrite range is fully written to. However, we
235            // could still be within the journal flush window where one of the blocks was written
236            // to for the first time to put it in this state, so we still need to emit the
237            // checksums in case replay needs them.
238            vec![ChecksumRangeChunk {
239                checksum_range: 0..write_block_len,
240                device_range: write_device_range,
241                is_first_write: false,
242            }]
243        } else {
244            let mut checksum_ranges = vec![ChecksumRangeChunk {
245                checksum_range: 0..0,
246                device_range: write_device_range.start..write_device_range.start,
247                is_first_write: !bitmaps.get_from_extent_bitmap(0).unwrap(),
248            }];
249            let mut working_range = checksum_ranges.last_mut().unwrap();
250            for i in 0..write_block_len {
251                bitmaps.set_in_write_bitmap(i, true);
252
253                // bitmap.get returning true means the block is initialized and therefore has been
254                // written to before.
255                if working_range.is_first_write != bitmaps.get_from_extent_bitmap(i).unwrap() {
256                    // is_first_write is tracking opposite of what comes back from the bitmap, so
257                    // if the are still opposites we continue our current range.
258                    working_range.checksum_range.end += 1;
259                    working_range.device_range.end += block_size;
260                } else {
261                    // If they are the same, then we need to make a new chunk.
262                    let new_chunk = ChecksumRangeChunk {
263                        checksum_range: working_range.checksum_range.end
264                            ..working_range.checksum_range.end + 1,
265                        device_range: working_range.device_range.end
266                            ..working_range.device_range.end + block_size,
267                        is_first_write: !working_range.is_first_write,
268                    };
269                    checksum_ranges.push(new_chunk);
270                    working_range = checksum_ranges.last_mut().unwrap();
271                }
272            }
273            checksum_ranges
274        }
275    }
276}
277
278/// StoreObjectHandle is the lowest-level, untyped handle to an object with the id [`object_id`] in
279/// a particular store, [`owner`]. It provides functionality shared across all objects, such as
280/// reading and writing attributes and managing encryption keys.
281///
282/// Since it's untyped, it doesn't do any object kind validation, and is generally meant to
283/// implement higher-level typed handles.
284///
285/// For file-like objects with a data attribute, DataObjectHandle implements traits and helpers for
286/// doing more complex extent management and caches the content size.
287///
288/// For directory-like objects, Directory knows how to add and remove child objects and enumerate
289/// its children.
290pub struct StoreObjectHandle<S: HandleOwner> {
291    owner: Arc<S>,
292    object_id: u64,
293    options: HandleOptions,
294    trace: AtomicBool,
295    encryption: Encryption,
296}
297
298impl<S: HandleOwner> ObjectHandle for StoreObjectHandle<S> {
299    fn set_trace(&self, v: bool) {
300        info!(store_id = self.store().store_object_id, oid = self.object_id(), trace = v; "trace");
301        self.trace.store(v, atomic::Ordering::Relaxed);
302    }
303
304    fn object_id(&self) -> u64 {
305        return self.object_id;
306    }
307
308    fn allocate_buffer(&self, size: usize) -> BufferFuture<'_> {
309        self.store().device.allocate_buffer(size)
310    }
311
312    fn block_size(&self) -> BlockSize {
313        self.store().block_size()
314    }
315}
316
317static WATCHDOG_BACKTRACE_ENABLED: AtomicBool = AtomicBool::new(false);
318
319/// Enables triggering a `fxfs-watchdog:<op>-300s` backtrace request when an I/O request in
320/// `StoreObjectHandle` has been blocked for 5 minutes.
321pub fn enable_watchdog_backtrace(enabled: bool) {
322    WATCHDOG_BACKTRACE_ENABLED.store(enabled, Ordering::Relaxed);
323}
324
325struct Watchdog {
326    _task: fasync::Task<()>,
327}
328
329impl Watchdog {
330    fn new(increment_seconds: u64, cb: impl Fn(u64) + Send + 'static) -> Self {
331        Self {
332            _task: fasync::Task::spawn(
333                async move {
334                    let increment = increment_seconds.try_into().unwrap();
335                    let mut fired_counter = 0;
336                    let mut next_wake = fasync::MonotonicInstant::now();
337                    loop {
338                        next_wake += std::time::Duration::from_secs(increment).into();
339                        // If this isn't being scheduled this will purposely result in fast looping
340                        // when it does. This will be insightful about the state of the thread and
341                        // task scheduling.
342                        if fasync::MonotonicInstant::now() < next_wake {
343                            fasync::Timer::new(next_wake).await;
344                        }
345                        fired_counter += 1;
346                        cb(fired_counter);
347                    }
348                }
349                .trace(trace_future_args!("StoreObjectHandle::Watchdog")),
350            ),
351        }
352    }
353
354    /// Warns every 10 seconds while an I/O request of kind `op` is blocked. If
355    /// `WATCHDOG_BACKTRACE_ENABLED` is set, also requests a backtrace after 5 minutes from a
356    /// short-lived thread named after the request (e.g. "fxfs-watchdog:Write-300s"), so that none
357    /// of the executor's threads stop.
358    fn io(op: &'static str) -> Self {
359        Self::new(10, move |count| {
360            warn!("{op} I/O request blocked for {} seconds", count * 10);
361            #[cfg(all(target_os = "fuchsia", not(doc)))]
362            if count == 30 && WATCHDOG_BACKTRACE_ENABLED.load(Ordering::Relaxed) {
363                let _ = std::thread::Builder::new()
364                    .name(format!("fxfs-watchdog:{op}-{}s", count * 10))
365                    .spawn(::debug::backtrace_request_all_threads);
366            }
367        })
368    }
369}
370
371impl<S: HandleOwner> StoreObjectHandle<S> {
372    /// Make a new StoreObjectHandle for the object with id [`object_id`] in store [`owner`].
373    pub fn new(
374        owner: Arc<S>,
375        object_id: u64,
376        permanent_keys: bool,
377        options: HandleOptions,
378        trace: bool,
379    ) -> Self {
380        let encryption = if permanent_keys {
381            Encryption::PermanentKeys
382        } else if owner.as_ref().as_ref().is_encrypted() {
383            Encryption::CachedKeys
384        } else {
385            Encryption::None
386        };
387        Self { owner, object_id, encryption, options, trace: AtomicBool::new(trace) }
388    }
389
390    pub fn owner(&self) -> &Arc<S> {
391        &self.owner
392    }
393
394    pub fn store(&self) -> &ObjectStore {
395        self.owner.as_ref().as_ref()
396    }
397
398    pub fn trace(&self) -> bool {
399        self.trace.load(atomic::Ordering::Relaxed)
400    }
401
402    pub fn is_encrypted(&self) -> bool {
403        !matches!(self.encryption, Encryption::None)
404    }
405
406    /// Get the default set of transaction options for this object. This is mostly the overall
407    /// default, modified by any [`HandleOptions`] held by this handle.
408    pub fn default_transaction_options<'b>(&self) -> Options<'b> {
409        Options { skip_journal_checks: self.options.skip_journal_checks, ..Default::default() }
410    }
411
412    pub async fn new_transaction_with_options<'b>(
413        &self,
414        attribute_id: AttributeId,
415        options: Options<'b>,
416    ) -> Result<Transaction<'b>, Error> {
417        Ok(self
418            .store()
419            .new_transaction(
420                lock_keys![
421                    LockKey::object_attribute(
422                        self.store().store_object_id(),
423                        self.object_id(),
424                        attribute_id,
425                    ),
426                    LockKey::object(self.store().store_object_id(), self.object_id()),
427                ],
428                options,
429            )
430            .await?)
431    }
432
433    pub async fn new_transaction<'b>(
434        &self,
435        attribute_id: AttributeId,
436    ) -> Result<Transaction<'b>, Error> {
437        self.new_transaction_with_options(attribute_id, self.default_transaction_options()).await
438    }
439
440    // If |transaction| has an impending mutation for the underlying object, returns that.
441    // Otherwise, looks up the object from the tree.
442    async fn txn_get_object_mutation(
443        &self,
444        transaction: &Transaction<'_>,
445    ) -> Result<ObjectStoreMutation, Error> {
446        self.store().txn_get_object_mutation(transaction, self.object_id()).await
447    }
448
449    // Returns the amount deallocated.
450    async fn deallocate_old_extents(
451        &self,
452        transaction: &mut Transaction<'_>,
453        attribute_id: AttributeId,
454        range: Range<u64>,
455    ) -> Result<u64, Error> {
456        let block_size = self.block_size();
457        assert!(block_size.is_aligned(&range));
458        if range.start == range.end {
459            return Ok(0);
460        }
461        let tree = &self.store().tree;
462        let layer_set = tree.layer_set();
463        let key = Extent(range);
464        let query_key =
465            ObjectKey::attribute(self.object_id(), attribute_id, AttributeKey::Extent(key.clone()));
466        let mut merger = layer_set.merger();
467        let mut iter = merger.query(Query::LimitedRange(&query_key)).await?;
468        let allocator = self.store().allocator();
469        let mut deallocated = 0;
470        let trace = self.trace();
471        while let Some(ItemRef {
472            key:
473                ObjectKey {
474                    object_id,
475                    data: ObjectKeyData::Attribute(attr_id, AttributeKey::Extent(extent_key)),
476                },
477            value: ObjectValue::Extent(value),
478            ..
479        }) = iter.get()
480        {
481            if *object_id != self.object_id() || *attr_id != attribute_id {
482                break;
483            }
484            let Some(overlap) = key.overlap(extent_key) else {
485                break;
486            };
487            if let ExtentValue::Some { device_offset, .. } = value {
488                let range = device_offset + overlap.start - extent_key.start
489                    ..device_offset + overlap.end - extent_key.start;
490                ensure!(block_size.is_aligned(&range), FxfsError::Inconsistent);
491                if trace {
492                    info!(
493                        store_id = self.store().store_object_id(),
494                        oid = self.object_id(),
495                        device_range:? = range,
496                        len = range.end - range.start,
497                        extent_key:?;
498                        "D",
499                    );
500                }
501                allocator.deallocate(transaction, self.store().store_object_id(), range).await?;
502                deallocated += overlap.end - overlap.start;
503            }
504            iter.advance().await?;
505        }
506        Ok(deallocated)
507    }
508
509    // Writes aligned data (that should already be encrypted) to the given offset and computes
510    // checksums if requested. The aligned data must be from a single logical file range.
511    //
512    // `flags` are forwarded to the underlying device as `WriteOptions::flags` (e.g.
513    // `WriteFlags::PRE_BARRIER`).
514    async fn write_aligned(
515        &self,
516        buf: BufferRef<'_>,
517        device_offset: u64,
518        crypt_ctx: Option<(u64, u8)>,
519        flags: WriteFlags,
520    ) -> Result<MaybeChecksums, Error> {
521        if self.trace() {
522            info!(
523                store_id = self.store().store_object_id(),
524                oid = self.object_id(),
525                device_range:? = (device_offset..device_offset + buf.len() as u64),
526                len = buf.len();
527                "W",
528            );
529        }
530        let store = self.store();
531        store.device_write_ops.fetch_add(1, Ordering::Relaxed);
532        let _watchdog = Watchdog::io("Write");
533
534        let (opts, compute_checksums) = match crypt_ctx {
535            Some((dun, slot)) => {
536                if !store.filesystem().options().barriers_enabled {
537                    return Err(anyhow!(FxfsError::InvalidArgs)
538                        .context("Barriers must be enabled for inline encrypted writes."));
539                }
540                (
541                    WriteOptions { inline_crypto: InlineCryptoOptions::enabled(slot, dun), flags },
542                    false,
543                )
544            }
545            None => (WriteOptions { flags, ..Default::default() }, !self.options.skip_checksums),
546        };
547
548        if compute_checksums {
549            let mut checksums = Vec::new();
550            try_join!(store.device.write_with_opts(device_offset, buf, opts), async {
551                let block_size = self.block_size().get() as usize;
552                for chunk in buf.as_ptr_slice().chunks(block_size) {
553                    checksums.push(crate::checksum::fletcher64_ptr(chunk, 0));
554                }
555                Ok(())
556            })?;
557            Ok(MaybeChecksums::Fletcher(checksums))
558        } else {
559            store.device.write_with_opts(device_offset, buf, opts).await?;
560            Ok(MaybeChecksums::None)
561        }
562    }
563
564    /// Flushes the underlying device.  This is expensive and should be used sparingly.
565    pub async fn flush_device(&self) -> Result<(), Error> {
566        let _watchdog = Watchdog::io("Flush");
567        self.store().device().flush().await
568    }
569
570    pub async fn update_allocated_size(
571        &self,
572        transaction: &mut Transaction<'_>,
573        allocated: u64,
574        deallocated: u64,
575    ) -> Result<(), Error> {
576        if allocated == deallocated {
577            return Ok(());
578        }
579        let mut mutation = self.txn_get_object_mutation(transaction).await?;
580        if let ObjectValue::Object {
581            attributes: ObjectAttributes { project_id, allocated_size, .. },
582            ..
583        } = &mut mutation.item.value
584        {
585            // The only way for these to fail are if the volume is inconsistent.
586            *allocated_size = allocated_size
587                .checked_add(allocated)
588                .ok_or_else(|| anyhow!(FxfsError::Inconsistent).context("Allocated size overflow"))?
589                .checked_sub(deallocated)
590                .ok_or_else(|| {
591                    anyhow!(FxfsError::Inconsistent).context("Allocated size underflow")
592                })?;
593
594            if let Some(project_id) = project_id {
595                // The allocated and deallocated shouldn't exceed the max size of the file which is
596                // bound within i64.
597                let diff = i64::try_from(allocated).unwrap() - i64::try_from(deallocated).unwrap();
598                transaction.merge_bytes_and_nodes(
599                    self.store().store_object_id(),
600                    ObjectKey::project_usage(self.store().root_directory_object_id(), *project_id),
601                    BytesAndNodes { bytes: diff, nodes: 0 },
602                );
603            }
604        } else {
605            // This can occur when the object mutation is created from an object in the tree which
606            // was corrupt.
607            bail!(anyhow!(FxfsError::Inconsistent).context("Unexpected object value"));
608        }
609        transaction.add(self.store().store_object_id, Mutation::ObjectStore(mutation));
610        Ok(())
611    }
612
613    pub async fn update_attributes<'a>(
614        &self,
615        transaction: &mut Transaction<'a>,
616        node_attributes: Option<&fio::MutableNodeAttributes>,
617        change_time: Option<Timestamp>,
618    ) -> Result<(), Error> {
619        if let Some(&fio::MutableNodeAttributes { selinux_context: Some(ref context), .. }) =
620            node_attributes
621        {
622            if let fio::SelinuxContext::Data(context) = context {
623                self.set_extended_attribute_impl(
624                    "security.selinux".into(),
625                    context.clone(),
626                    SetExtendedAttributeMode::Set,
627                    transaction,
628                )
629                .await?;
630            } else {
631                return Err(anyhow!(FxfsError::InvalidArgs)
632                    .context("Only set SELinux context with `data` member."));
633            }
634        }
635        self.store()
636            .update_attributes(transaction, self.object_id, node_attributes, change_time)
637            .await
638    }
639
640    /// Zeroes the given range.  The range must be aligned.  Returns the amount of data deallocated.
641    pub async fn zero(
642        &self,
643        transaction: &mut Transaction<'_>,
644        attribute_id: AttributeId,
645        range: Range<u64>,
646    ) -> Result<(), Error> {
647        let deallocated =
648            self.deallocate_old_extents(transaction, attribute_id, range.clone()).await?;
649        if deallocated > 0 {
650            self.update_allocated_size(transaction, 0, deallocated).await?;
651            transaction.add(
652                self.store().store_object_id,
653                Mutation::merge_object(
654                    ObjectKey::extent(self.object_id(), attribute_id, range),
655                    ObjectValue::Extent(ExtentValue::deleted_extent()),
656                ),
657            );
658        }
659        Ok(())
660    }
661
662    // Returns a new aligned buffer (reading the head and tail blocks if necessary) with a copy of
663    // the data from `buf`.
664    pub async fn align_buffer(
665        &self,
666        attribute_id: AttributeId,
667        offset: u64,
668        buf: BufferRef<'_>,
669    ) -> Result<(std::ops::Range<u64>, Buffer<'_>), Error> {
670        let block_size = self.block_size();
671        let end = offset + buf.len() as u64;
672        let aligned = block_size.align_range_outwards(offset..end).ok_or(FxfsError::TooBig)?;
673
674        let mut aligned_buf =
675            self.store().device.allocate_buffer((aligned.end - aligned.start) as usize).await;
676
677        // Deal with head alignment.
678        if aligned.start < offset {
679            let mut head_block = aligned_buf.subslice_mut(0..block_size.get() as usize);
680            let read =
681                self.read_aligned(attribute_id, aligned.start, head_block.reborrow()).await?;
682            let len = head_block.len();
683            head_block.subslice_mut(read..len).fill(0);
684        }
685
686        // Deal with tail alignment.
687        if aligned.end > end {
688            let end_block_offset = aligned.end - block_size;
689            // There's no need to read the tail block if we read it as part of the head block.
690            if offset <= end_block_offset {
691                let mut tail_block =
692                    aligned_buf.subslice_mut(aligned_buf.len() - block_size.get() as usize..);
693                let read = self
694                    .read_aligned(attribute_id, end_block_offset, tail_block.reborrow())
695                    .await?;
696                let len = tail_block.len();
697                tail_block.subslice_mut(read..len).fill(0);
698            }
699        }
700
701        aligned_buf
702            .subslice_mut((offset - aligned.start) as usize..(end - aligned.start) as usize)
703            .copy_from_buffer(buf);
704
705        Ok((aligned, aligned_buf))
706    }
707
708    /// Trim an attribute's extents, potentially adding a graveyard trim entry if more trimming is
709    /// needed, so the transaction can be committed without worrying about leaking data.
710    ///
711    /// This doesn't update the size stored in the attribute value - the caller is responsible for
712    /// doing that to keep the size up to date.
713    pub async fn shrink(
714        &self,
715        transaction: &mut Transaction<'_>,
716        attribute_id: AttributeId,
717        size: u64,
718    ) -> Result<NeedsTrim, Error> {
719        let store = self.store();
720        let needs_trim = matches!(
721            store
722                .trim_some(transaction, self.object_id(), attribute_id, TrimMode::FromOffset(size))
723                .await?,
724            TrimResult::Incomplete
725        );
726        if needs_trim {
727            // Add the object to the graveyard in case the following transactions don't get
728            // replayed.
729            let graveyard_id = store.graveyard_directory_object_id();
730            // Check if the object is already in the graveyard.
731            let in_graveyard = store
732                .tree
733                .find_map(&ObjectKey::graveyard_entry(graveyard_id, self.object_id()), |item| {
734                    matches!(item.value, ObjectValue::Some | ObjectValue::Trim)
735                })
736                .await?
737                .unwrap_or(false);
738            if !in_graveyard {
739                transaction.add(
740                    store.store_object_id,
741                    Mutation::replace_or_insert_object(
742                        ObjectKey::graveyard_entry(graveyard_id, self.object_id()),
743                        ObjectValue::Trim,
744                    ),
745                );
746            }
747        }
748        Ok(NeedsTrim(needs_trim))
749    }
750
751    /// Reads and decrypts a singular logical range.
752    pub async fn read_and_decrypt(
753        &self,
754        attribute_id: AttributeId,
755        device_offset: u64,
756        file_offset: u64,
757        mut buffer: MutableBufferRef<'_>,
758        key_id: u64,
759    ) -> Result<(), Error> {
760        let store = self.store();
761        store.device_read_ops.fetch_add(1, Ordering::Relaxed);
762
763        let _watchdog = Watchdog::io("Read");
764
765        let (_key_id, key) = self.get_key(Some(key_id)).await?;
766        if let Some(key) = key {
767            if let Some((dun, slot)) =
768                key.crypt_ctx(self.object_id, attribute_id.raw(), file_offset)
769            {
770                store
771                    .device
772                    .read_with_opts(
773                        device_offset as u64,
774                        buffer.reborrow(),
775                        ReadOptions { inline_crypto: InlineCryptoOptions::enabled(slot, dun) },
776                    )
777                    .await?;
778            } else {
779                store.device.read(device_offset, buffer.reborrow()).await?;
780                key.decrypt(
781                    self.object_id,
782                    attribute_id.raw(),
783                    device_offset,
784                    file_offset,
785                    buffer.as_mut_ptr_slice(),
786                )?;
787            }
788        } else {
789            store.device.read(device_offset, buffer.reborrow()).await?;
790        }
791
792        Ok(())
793    }
794
795    /// Returns the specified key. If `key_id` is None, it will try and return the fscrypt key if
796    /// it is present, or the volume key if it isn't. If the fscrypt key is present, but the key
797    /// cannot be unwrapped, then this will return `FxfsError::NoKey`. If the volume is not
798    /// encrypted, this returns None.
799    pub async fn get_key(
800        &self,
801        key_id: Option<u64>,
802    ) -> Result<(u64, Option<Arc<dyn Cipher>>), Error> {
803        let store = self.store();
804        let result = match self.encryption {
805            Encryption::None => (VOLUME_DATA_KEY_ID, None),
806            Encryption::CachedKeys => {
807                if let Some(key_id) = key_id {
808                    (
809                        key_id,
810                        Some(
811                            store
812                                .key_manager
813                                .get_key(
814                                    self.object_id,
815                                    store.crypt().ok_or_else(|| anyhow!("No crypt!"))?.as_ref(),
816                                    async || store.get_keys(self.object_id).await,
817                                    key_id,
818                                )
819                                .await?,
820                        ),
821                    )
822                } else {
823                    let (key_id, key) = store
824                        .key_manager
825                        .get_fscrypt_key_if_present(
826                            self.object_id,
827                            store.crypt().ok_or_else(|| anyhow!("No crypt!"))?.as_ref(),
828                            async || store.get_keys(self.object_id).await,
829                        )
830                        .await?;
831                    (key_id, Some(key))
832                }
833            }
834            Encryption::PermanentKeys => {
835                (VOLUME_DATA_KEY_ID, Some(store.key_manager.get(self.object_id).await?.unwrap()))
836            }
837        };
838
839        // Ensure that if the key we receive uses inline encryption, barriers should be enabled.
840        if let Some(ref key) = result.1 {
841            if key.crypt_ctx(self.object_id, 0, 0).is_some() {
842                if !store.filesystem().options().barriers_enabled {
843                    return Err(anyhow!(FxfsError::InvalidArgs)
844                        .context("Barriers must be enabled for inline encrypted writes."));
845                }
846            }
847        }
848
849        Ok(result)
850    }
851
852    /// Returns a stream of extents for the given attribute ID, mapping logical offsets to device
853    /// offsets. Extents are sorted by logical offset and non-overlapping. Extents with no physical
854    /// backing are skipped.
855    pub async fn extent_stream<'a, 'b>(
856        &'a self,
857        merger: &'b mut Merger<'a, ObjectKey, ObjectValue>,
858        attribute_id: AttributeId,
859    ) -> Result<impl Stream<Item = Result<FileExtent, Error>> + 'b, Error> {
860        let object_id = self.object_id();
861        let iter = merger
862            .query(Query::FullRange(&ObjectKey::attribute(
863                object_id,
864                attribute_id,
865                AttributeKey::Extent(Extent::search_key_from_offset(0)),
866            )))
867            .await?;
868        Ok(unfold(
869            (iter, object_id, attribute_id),
870            |(mut iter, object_id, attribute_id)| async move {
871                loop {
872                    match iter.get() {
873                        Some(ItemRef {
874                            key:
875                                ObjectKey {
876                                    object_id: id,
877                                    data:
878                                        ObjectKeyData::Attribute(
879                                            attr_id,
880                                            AttributeKey::Extent(extent_key),
881                                        ),
882                                },
883                            value: ObjectValue::Extent(extent_value),
884                            ..
885                        }) if *id == object_id && *attr_id == attribute_id => {
886                            let logical_range = extent_key.0.clone();
887                            let device_range = match extent_value {
888                                ExtentValue::Some { device_offset, .. } => {
889                                    let len = logical_range.end - logical_range.start;
890                                    Some(*device_offset..*device_offset + len)
891                                }
892                                // Extent with no physical backing (e.g. deleted extent).
893                                ExtentValue::None => None,
894                            };
895
896                            // Advance the iterator before returning so the next invocation sees the
897                            // following entry.
898                            if let Err(e) = iter.advance().await {
899                                return Some((Err(e.into()), (iter, object_id, attribute_id)));
900                            }
901
902                            if let Some(device_range) = device_range {
903                                return Some((
904                                    Ok(FileExtent::new(logical_range.start, device_range).unwrap()),
905                                    (iter, object_id, attribute_id),
906                                ));
907                            } else {
908                                // Skip extents with no physical backing; loop to check the next
909                                // entry.
910                                continue;
911                            }
912                        }
913                        // No more entries matching this object_id and attribute_id.
914                        _ => return None,
915                    }
916                }
917            },
918        ))
919    }
920
921    /// This will only work for a non-permanent volume data key. This is designed to be used with
922    /// extended attributes where we'll only create the key on demand for directories and encrypted
923    /// files.
924    async fn get_or_create_key(
925        &self,
926        transaction: &mut Transaction<'_>,
927    ) -> Result<Arc<dyn Cipher>, Error> {
928        let store = self.store();
929
930        // Fast path: try and get keys from the cache.
931        if let Some(key) = store.key_manager.get(self.object_id).await.context("get failed")? {
932            return Ok(key);
933        }
934
935        let crypt = store.crypt().ok_or_else(|| anyhow!("No crypt!"))?;
936
937        // Next, see if the keys are already created.
938        let (mut encryption_keys, mut cipher_set) = if let Some(value) =
939            store.tree.find_value(&ObjectKey::keys(self.object_id)).await.context("find failed")?
940        {
941            if let ObjectValue::Keys(encryption_keys) = value {
942                let cipher_set = store
943                    .key_manager
944                    .get_keys(
945                        self.object_id,
946                        crypt.as_ref(),
947                        &mut Some(async || Ok(encryption_keys.clone())),
948                        /* permanent= */ false,
949                        /* force= */ false,
950                    )
951                    .await
952                    .context("get_keys failed")?;
953                match cipher_set.find_key(VOLUME_DATA_KEY_ID) {
954                    FindKeyResult::NotFound => {}
955                    FindKeyResult::Unavailable => return Err(FxfsError::NoKey.into()),
956                    FindKeyResult::Key(key) => return Ok(key),
957                }
958                (encryption_keys, (*cipher_set).clone())
959            } else {
960                return Err(anyhow!(FxfsError::Inconsistent));
961            }
962        } else {
963            Default::default()
964        };
965
966        // Proceed to create the key.  The transaction holds the required locks.
967        let (key, unwrapped_key) = crypt.create_key(self.object_id, KeyPurpose::Data).await?;
968        let cipher: Arc<dyn Cipher> = Arc::new(FxfsCipher::new(&unwrapped_key));
969
970        // Add new cipher to cloned cipher set. This will replace existing one
971        // if transaction is successful.
972        cipher_set.add_key(VOLUME_DATA_KEY_ID, CipherHolder::Cipher(cipher.clone()));
973        let cipher_set = Arc::new(cipher_set);
974
975        // Arrange for the CipherSet to be added to the cache when (and if) the transaction
976        // commits.
977        struct UnwrappedKeys {
978            object_id: u64,
979            new_keys: Arc<CipherSet>,
980        }
981
982        impl AssociatedObject for UnwrappedKeys {
983            fn will_apply_mutation(
984                &self,
985                _mutation: &Mutation,
986                object_id: u64,
987                manager: &ObjectManager,
988            ) {
989                manager.store(object_id).unwrap().key_manager.insert(
990                    self.object_id,
991                    self.new_keys.clone(),
992                    /* permanent= */ false,
993                );
994            }
995        }
996
997        encryption_keys.insert(VOLUME_DATA_KEY_ID, EncryptionKey::Fxfs(key).into());
998
999        transaction.add_with_object(
1000            store.store_object_id(),
1001            Mutation::replace_or_insert_object(
1002                ObjectKey::keys(self.object_id),
1003                ObjectValue::keys(encryption_keys),
1004            ),
1005            AssocObj::Owned(Box::new(UnwrappedKeys {
1006                object_id: self.object_id,
1007                new_keys: cipher_set,
1008            })),
1009        );
1010
1011        Ok(cipher)
1012    }
1013
1014    /// Reads up to `buf.len()` bytes from attribute `attribute_id` starting at `offset`.
1015    ///
1016    /// Both `offset` and `buf.len()` must be aligned to the object's `block_size()`.
1017    ///
1018    /// Returns the number of bytes read. If `offset >= size`, returns 0. Holes/sparse extents
1019    /// within the read range are zero-filled. Callers should not make any assumptions about the
1020    /// contents of the buffer past the returned read amount.
1021    pub async fn read_aligned(
1022        &self,
1023        attribute_id: AttributeId,
1024        offset: u64,
1025        mut buf: MutableBufferRef<'_>,
1026    ) -> Result<usize, Error> {
1027        let block_size = self.block_size();
1028        ensure!(block_size.is_aligned(offset), FxfsError::InvalidArgs);
1029        ensure!(block_size.is_aligned(buf.len() as u64), FxfsError::InvalidArgs);
1030        let fs = self.store().filesystem();
1031        let guard = fs
1032            .lock_manager()
1033            .read_lock(lock_keys![LockKey::object_attribute(
1034                self.store().store_object_id(),
1035                self.object_id(),
1036                attribute_id,
1037            )])
1038            .await;
1039
1040        let key = ObjectKey::attribute(self.object_id(), attribute_id, AttributeKey::Attribute);
1041        let size = self
1042            .store()
1043            .tree()
1044            .find_map(&key, |item| match item.value {
1045                ObjectValue::Attribute { size, .. } => Ok(*size),
1046                _ => Err(anyhow!(FxfsError::Inconsistent)),
1047            })
1048            .await?
1049            .transpose()?
1050            .unwrap_or(0);
1051        if offset >= size {
1052            return Ok(0);
1053        }
1054        let length = min(buf.len() as u64, size - offset) as usize;
1055        let aligned_length =
1056            block_size.align_up(length as u64).ok_or(FxfsError::Inconsistent)? as usize;
1057        buf = buf.subslice_mut(0..aligned_length);
1058        self.read_aligned_unchecked(attribute_id, offset, buf, &guard).await?;
1059        Ok(length)
1060    }
1061
1062    /// Read `buf.len()` bytes from the attribute `attribute_id`, starting at `offset`, into `buf`.
1063    /// It's required that a read lock on this attribute id is taken before this is called.
1064    ///
1065    /// Both `offset` and `buf.len()` must be aligned to the object's `block_size()`.
1066    ///
1067    /// This function doesn't do any size checking - any portion of `buf` past the end of the file
1068    /// will be filled with zeros. The caller is responsible for enforcing the file size on reads.
1069    /// This is because, just looking at the extents, we can't tell the difference between the file
1070    /// actually ending and there just being a section at the end with no data (since attributes
1071    /// are sparse).
1072    pub async fn read_aligned_unchecked(
1073        &self,
1074        attribute_id: AttributeId,
1075        offset: u64,
1076        buf: MutableBufferRef<'_>,
1077        _guard: &ReadGuard<'_>,
1078    ) -> Result<(), Error> {
1079        if buf.is_empty() {
1080            return Ok(());
1081        }
1082        let end_offset = offset + buf.len() as u64;
1083        let tree = &self.store().tree;
1084        let layer_set = tree.layer_set();
1085        let mut merger = layer_set.merger();
1086        let iter = merger
1087            .query(Query::LimitedRange(&ObjectKey::extent(
1088                self.object_id(),
1089                attribute_id,
1090                offset..end_offset,
1091            )))
1092            .await?;
1093        self.read_aligned_impl(attribute_id, offset, buf, iter, /* decrypt: */ true).await
1094    }
1095
1096    /// Reads an entire attribute.
1097    pub async fn read_attr(&self, attribute_id: AttributeId) -> Result<Option<Box<[u8]>>, Error> {
1098        let store = self.store();
1099        let tree = &store.tree;
1100        let layer_set = tree.layer_set();
1101        let mut merger = layer_set.merger();
1102        let key = ObjectKey::attribute(self.object_id(), attribute_id, AttributeKey::Attribute);
1103        let iter = merger.query(Query::FullRange(&key)).await?;
1104        match iter.get() {
1105            Some(item) if item.key == &key => match item.value {
1106                ObjectValue::Attribute { .. } => Ok(Some(self.read_attr_from_iter(iter).await?)),
1107                // Attribute was deleted.
1108                ObjectValue::None => Ok(None),
1109                _ => Err(FxfsError::Inconsistent.into()),
1110            },
1111            _ => Ok(None),
1112        }
1113    }
1114
1115    /// Reads an entire attribute pointed to by `iter`. `iter` must be pointing to the
1116    /// `AttributeKey::Attribute` of the attribute.
1117    pub async fn read_attr_from_iter(
1118        &self,
1119        iter: MergerIterator<'_, '_, ObjectKey, ObjectValue>,
1120    ) -> Result<Box<[u8]>, Error> {
1121        self.read_attr_from_iter_impl(iter, /* decrypt: */ true).await
1122    }
1123
1124    /// Reads an entire attribute pointed to by `iter` without decrypting it. `iter` must be
1125    /// pointing to the `AttributeKey::Attribute` of the attribute.
1126    pub async fn read_raw_attr_from_iter(
1127        &self,
1128        iter: MergerIterator<'_, '_, ObjectKey, ObjectValue>,
1129    ) -> Result<Box<[u8]>, Error> {
1130        self.read_attr_from_iter_impl(iter, /* decrypt: */ false).await
1131    }
1132
1133    async fn read_attr_from_iter_impl(
1134        &self,
1135        mut iter: MergerIterator<'_, '_, ObjectKey, ObjectValue>,
1136        decrypt: bool,
1137    ) -> Result<Box<[u8]>, Error> {
1138        let (mut buffer, size, attribute_id) = match iter.get() {
1139            Some(ItemRef {
1140                key:
1141                    ObjectKey {
1142                        object_id,
1143                        data: ObjectKeyData::Attribute(attribute_id, AttributeKey::Attribute),
1144                    },
1145                value: ObjectValue::Attribute { size, .. },
1146                ..
1147            }) if *object_id == self.object_id => {
1148                // TODO(https://fxbug.dev/42073113): size > max buffer size
1149                (
1150                    self.store()
1151                        .device
1152                        .allocate_buffer(self.block_size().align_up(*size).unwrap() as usize)
1153                        .await,
1154                    *size as usize,
1155                    *attribute_id,
1156                )
1157            }
1158            _ => bail!(FxfsError::InvalidArgs),
1159        };
1160        iter.advance().await?;
1161        self.read_aligned_impl(attribute_id, 0, buffer.as_mut(), iter, decrypt).await?;
1162        Ok(buffer.as_ref().subslice(0..size).to_vec().into_boxed_slice())
1163    }
1164
1165    /// Reads block-aligned data from `offset` for attribute `attribute_id` into `buf` using `iter`.
1166    ///
1167    /// Both `offset` and `buf.len()` must be aligned to the object's `block_size()`, and `buf`'s
1168    /// memory buffer range start must be aligned to the device block size.
1169    ///
1170    /// Extents from `iter` are read (and decrypted if `decrypt` is true) in parallel. Holes and any
1171    /// unallocated portions within `buf` are zero-filled.
1172    async fn read_aligned_impl(
1173        &self,
1174        attribute_id: AttributeId,
1175        mut offset: u64,
1176        mut buf: MutableBufferRef<'_>,
1177        mut iter: MergerIterator<'_, '_, ObjectKey, ObjectValue>,
1178        decrypt: bool,
1179    ) -> Result<(), Error> {
1180        if buf.is_empty() {
1181            return Ok(());
1182        }
1183        let block_size = self.block_size();
1184        debug_assert!(block_size.is_aligned(offset));
1185        debug_assert!(block_size.is_aligned(buf.len() as u64));
1186        let device_block_size = self.store().device.block_size() as u64;
1187        debug_assert!(buf.range().start as u64 % device_block_size == 0);
1188
1189        self.store().logical_read_ops.fetch_add(1, Ordering::Relaxed);
1190
1191        let mut reads = Vec::new();
1192        loop {
1193            let (mut extent_key, mut device_offset, key_id, mode) = match iter.get() {
1194                Some(ItemRef {
1195                    key:
1196                        ObjectKey {
1197                            object_id,
1198                            data:
1199                                ObjectKeyData::Attribute(attr_id, AttributeKey::Extent(extent_key)),
1200                        },
1201                    value: ObjectValue::Extent(extent_value),
1202                    ..
1203                }) if *object_id == self.object_id && *attr_id == attribute_id => {
1204                    match extent_value {
1205                        ExtentValue::Some { device_offset, mode, key_id } => {
1206                            ensure!(extent_key.is_valid(), FxfsError::Inconsistent);
1207                            ensure!(block_size.is_aligned(extent_key), FxfsError::Inconsistent);
1208                            ensure!(
1209                                device_offset % device_block_size == 0,
1210                                FxfsError::Inconsistent
1211                            );
1212                            // The iterator shouldn't start entirely before the offset.
1213                            ensure!(extent_key.end > offset, FxfsError::Inconsistent);
1214                            (extent_key.0.clone(), *device_offset, *key_id, mode)
1215                        }
1216                        ExtentValue::None => {
1217                            // Treat deleted extents like holes.
1218                            iter.advance().await?;
1219                            continue;
1220                        }
1221                    }
1222                }
1223                _ => break,
1224            };
1225            if extent_key.start > offset {
1226                // Zero fill holes in the attribute.
1227                let split = std::cmp::min((extent_key.start - offset) as usize, buf.len());
1228                let (mut to_zero, remaining) = buf.split_at_mut(split);
1229                to_zero.fill(0);
1230                buf = remaining;
1231                if buf.is_empty() {
1232                    break;
1233                }
1234                offset = extent_key.start;
1235            }
1236
1237            let mut bitmap_offset = 0;
1238            if extent_key.start < offset {
1239                let diff = offset - extent_key.start;
1240                extent_key.start = offset;
1241                device_offset += diff;
1242                bitmap_offset = diff;
1243            }
1244            if (extent_key.end - extent_key.start) > buf.len() as u64 {
1245                extent_key.end = extent_key.start + buf.len() as u64;
1246            }
1247            let (mut to_read, remaining) =
1248                buf.split_at_mut((extent_key.end - extent_key.start) as usize);
1249            buf = remaining;
1250            let maybe_bitmap = match mode {
1251                ExtentMode::OverwritePartial(bitmap) => {
1252                    let mut read_bitmap =
1253                        bitmap.clone().split_off((bitmap_offset / block_size) as usize);
1254                    read_bitmap.truncate(((to_read.len() as u64) / block_size) as usize);
1255                    Some(read_bitmap)
1256                }
1257                _ => None,
1258            };
1259            reads.push(async move {
1260                if decrypt {
1261                    self.read_and_decrypt(
1262                        attribute_id,
1263                        device_offset,
1264                        extent_key.start,
1265                        to_read.reborrow(),
1266                        key_id,
1267                    )
1268                    .await?;
1269                } else {
1270                    let store = self.store();
1271                    store.device_read_ops.fetch_add(1, Ordering::Relaxed);
1272                    let _watchdog = Watchdog::io("Read");
1273                    store.device.read(device_offset, to_read.reborrow()).await?;
1274                }
1275                if let Some(bitmap) = maybe_bitmap {
1276                    apply_bitmap_zeroing(block_size, &bitmap, to_read);
1277                }
1278                Ok::<(), Error>(())
1279            });
1280            if buf.is_empty() {
1281                break;
1282            }
1283            offset = extent_key.end;
1284            iter.advance().await?;
1285        }
1286        match reads.len() {
1287            0 => {}
1288            1 => reads.pop().unwrap().await?,
1289            _ => {
1290                try_join_all(reads).await?;
1291            }
1292        }
1293        buf.fill(0);
1294        Ok(())
1295    }
1296
1297    /// Writes potentially unaligned data at `device_offset` and returns checksums if requested.
1298    /// The data will be encrypted if necessary.  `buf` is mutable as an optimization, since the
1299    /// write may require encryption, we can encrypt the buffer in-place rather than copying to
1300    /// another buffer if the write is already aligned.
1301    ///
1302    /// NOTE: This will not create keys if they are missing (it will fail with an error if that
1303    /// happens to be the case).
1304    pub async fn write_at(
1305        &self,
1306        attribute_id: AttributeId,
1307        offset: u64,
1308        buf: MutableBufferRef<'_>,
1309        key_id: Option<u64>,
1310        device_offset: u64,
1311    ) -> Result<MaybeChecksums, Error> {
1312        self.write_at_with_flags(
1313            attribute_id,
1314            offset,
1315            buf,
1316            key_id,
1317            device_offset,
1318            WriteFlags::empty(),
1319        )
1320        .await
1321    }
1322
1323    /// Same as `write_at`, but allows passing `WriteFlags` (such as `WriteFlags::PRE_BARRIER`) to
1324    /// the underlying device write.
1325    pub async fn write_at_with_flags(
1326        &self,
1327        attribute_id: AttributeId,
1328        offset: u64,
1329        buf: MutableBufferRef<'_>,
1330        key_id: Option<u64>,
1331        mut device_offset: u64,
1332        flags: WriteFlags,
1333    ) -> Result<MaybeChecksums, Error> {
1334        let mut transfer_buf;
1335        let block_size = self.block_size();
1336        let (range, mut transfer_buf_ref) =
1337            if offset % block_size == 0 && buf.len() as u64 % block_size == 0 {
1338                (offset..offset + buf.len() as u64, buf)
1339            } else {
1340                let (range, buf) = self.align_buffer(attribute_id, offset, buf.as_ref()).await?;
1341                transfer_buf = buf;
1342                device_offset -= offset - range.start;
1343                (range, transfer_buf.as_mut())
1344            };
1345
1346        let mut crypt_ctx = None;
1347        if let (_, Some(key)) = self.get_key(key_id).await? {
1348            if let Some(ctx) = key.crypt_ctx(self.object_id, attribute_id.raw(), range.start) {
1349                crypt_ctx = Some(ctx);
1350            } else {
1351                key.encrypt(
1352                    self.object_id,
1353                    attribute_id.raw(),
1354                    device_offset,
1355                    range.start,
1356                    transfer_buf_ref.as_mut_ptr_slice(),
1357                )?;
1358            }
1359        }
1360        self.write_aligned(transfer_buf_ref.as_ref(), device_offset, crypt_ctx, flags).await
1361    }
1362
1363    /// Writes to multiple ranges with data provided in `buf`. This function is specifically
1364    /// designed for migration purposes, allowing raw writes to the device without updating
1365    /// object metadata like allocated size or mtime. It's essential for scenarios where
1366    /// data needs to be transferred directly without triggering standard filesystem operations.
1367    #[cfg(feature = "migration")]
1368    pub async fn raw_multi_write(
1369        &self,
1370        transaction: &mut Transaction<'_>,
1371        attribute_id: AttributeId,
1372        key_id: Option<u64>,
1373        encrypt: bool,
1374        ranges: &[Range<u64>],
1375        buf: MutableBufferRef<'_>,
1376    ) -> Result<(), Error> {
1377        self.multi_write_internal(transaction, attribute_id, key_id, encrypt, ranges, buf).await?;
1378        Ok(())
1379    }
1380
1381    /// This is a low-level write function that writes to multiple ranges. Users should generally
1382    /// use `multi_write` instead of this function as this does not update the object's allocated
1383    /// size, mtime, atime, etc.
1384    ///
1385    /// Returns (allocated, deallocated) bytes on success.
1386    async fn multi_write_internal(
1387        &self,
1388        transaction: &mut Transaction<'_>,
1389        attribute_id: AttributeId,
1390        key_id: Option<u64>,
1391        encrypt: bool,
1392        ranges: &[Range<u64>],
1393        mut buf: MutableBufferRef<'_>,
1394    ) -> Result<(u64, u64), Error> {
1395        if buf.is_empty() {
1396            return Ok((0, 0));
1397        }
1398        let block_size = self.block_size();
1399        debug_assert!(
1400            transaction.skip_journal_checks
1401                || (buf.len() / block_size.get() as usize) * JOURNAL_CHECKSUM_BYTES_PER_BLOCK
1402                    + ranges.len() * MAX_JOURNAL_BYTES_PER_RANGE
1403                    <= TRANSACTION_MAX_JOURNAL_USAGE as usize,
1404            "Write is too large for a single transaction; callers must break up writes"
1405        );
1406        let store = self.store();
1407        let store_id = store.store_object_id();
1408
1409        // The only key we allow to be created on-the-fly is a non permanent key wrapped with the
1410        // volume data key.
1411        let (key_id, key) = if !encrypt {
1412            (key_id.unwrap_or(VOLUME_DATA_KEY_ID), None)
1413        } else if key_id == Some(VOLUME_DATA_KEY_ID)
1414            && matches!(self.encryption, Encryption::CachedKeys)
1415        {
1416            (
1417                VOLUME_DATA_KEY_ID,
1418                Some(
1419                    self.get_or_create_key(transaction)
1420                        .await
1421                        .context("get_or_create_key failed")?,
1422                ),
1423            )
1424        } else {
1425            self.get_key(key_id).await?
1426        };
1427        if let Some(key) = &key {
1428            if !key.supports_inline_encryption() {
1429                let mut slice = buf.as_mut_ptr_slice();
1430                for r in ranges {
1431                    let l = r.end - r.start;
1432                    let (head, tail) = slice.split_at_mut(l as usize);
1433                    key.encrypt(
1434                        self.object_id,
1435                        attribute_id.raw(),
1436                        0, /* TODO(https://fxbug.dev/421269588): plumb through device_offset. */
1437                        r.start,
1438                        MutPtrByteSlice::from(head),
1439                    )?;
1440                    slice = tail;
1441                }
1442            }
1443        }
1444
1445        let mut allocated = 0;
1446        let allocator = store.allocator();
1447        let trace = self.trace();
1448        let mut writes = FuturesOrdered::new();
1449
1450        let mut logical_ranges = ranges.iter();
1451        let mut current_range = logical_ranges.next().unwrap().clone();
1452
1453        while !buf.is_empty() {
1454            let mut device_range = allocator
1455                .allocate(transaction, store_id, buf.len() as u64)
1456                .await
1457                .context("allocation failed")?;
1458            if trace {
1459                info!(
1460                    store_id,
1461                    oid = self.object_id(),
1462                    device_range:?,
1463                    len = device_range.end - device_range.start;
1464                    "A",
1465                );
1466            }
1467            let mut device_range_len = device_range.end - device_range.start;
1468            allocated += device_range_len;
1469            // If inline encryption is NOT supported, this loop should only happen once.
1470            while device_range_len > 0 {
1471                if current_range.end <= current_range.start {
1472                    current_range = logical_ranges.next().unwrap().clone();
1473                }
1474                let (crypt_ctx, split) = if let Some(key) = &key {
1475                    if key.supports_inline_encryption() {
1476                        let split = std::cmp::min(
1477                            current_range.end - current_range.start,
1478                            device_range_len,
1479                        );
1480                        let crypt_ctx =
1481                            key.crypt_ctx(self.object_id, attribute_id.raw(), current_range.start);
1482                        current_range.start += split;
1483                        (crypt_ctx, split)
1484                    } else {
1485                        (None, device_range_len)
1486                    }
1487                } else {
1488                    (None, device_range_len)
1489                };
1490
1491                let (head, tail) = buf.split_at_mut(split as usize);
1492                buf = tail;
1493
1494                writes.push_back(async move {
1495                    let len = head.len() as u64;
1496                    Result::<_, Error>::Ok((
1497                        device_range.start,
1498                        len,
1499                        self.write_aligned(
1500                            head.as_ref(),
1501                            device_range.start,
1502                            crypt_ctx,
1503                            WriteFlags::empty(),
1504                        )
1505                        .await?,
1506                    ))
1507                });
1508                device_range.start += split;
1509                device_range_len = device_range.end - device_range.start;
1510            }
1511        }
1512
1513        self.store().logical_write_ops.fetch_add(1, Ordering::Relaxed);
1514        let ((mutations, checksums), deallocated) = try_join!(
1515            async {
1516                let mut current_range = 0..0;
1517                let mut mutations = Vec::new();
1518                let mut out_checksums = Vec::new();
1519                let mut ranges = ranges.iter();
1520                while let Some((mut device_offset, mut len, mut checksums)) =
1521                    writes.try_next().await?
1522                {
1523                    while len > 0 {
1524                        if current_range.end <= current_range.start {
1525                            current_range = ranges.next().unwrap().clone();
1526                        }
1527                        let chunk_len = std::cmp::min(len, current_range.end - current_range.start);
1528                        let tail = checksums.split_off((chunk_len / block_size) as usize);
1529                        if let Some(checksums) = checksums.maybe_as_ref() {
1530                            out_checksums.push((
1531                                device_offset..device_offset + chunk_len,
1532                                checksums.to_owned(),
1533                            ));
1534                        }
1535                        mutations.push(Mutation::merge_object(
1536                            ObjectKey::extent(
1537                                self.object_id(),
1538                                attribute_id,
1539                                current_range.start..current_range.start + chunk_len,
1540                            ),
1541                            ObjectValue::Extent(ExtentValue::new(
1542                                device_offset,
1543                                checksums.to_mode(),
1544                                key_id,
1545                            )),
1546                        ));
1547                        checksums = tail;
1548                        device_offset += chunk_len;
1549                        len -= chunk_len;
1550                        current_range.start += chunk_len;
1551                    }
1552                }
1553                Result::<_, Error>::Ok((mutations, out_checksums))
1554            },
1555            async {
1556                let mut deallocated = 0;
1557                for r in ranges {
1558                    deallocated +=
1559                        self.deallocate_old_extents(transaction, attribute_id, r.clone()).await?;
1560                }
1561                Result::<_, Error>::Ok(deallocated)
1562            }
1563        )?;
1564
1565        for m in mutations {
1566            transaction.add(store_id, m);
1567        }
1568
1569        // Only store checksums in the journal if barriers are not enabled.
1570        if !store.filesystem().options().barriers_enabled {
1571            for (r, c) in checksums {
1572                transaction.add_checksum(store_id, r, c, true);
1573            }
1574        }
1575        Ok((allocated, deallocated))
1576    }
1577
1578    /// Writes to multiple ranges with data provided in `buf`.  The buffer can be modified in place
1579    /// if encryption takes place.  The ranges must all be aligned and no change to content size is
1580    /// applied; the caller is responsible for updating size if required.  If `key_id` is None, it
1581    /// means pick the default key for the object which is the fscrypt key if present, or the volume
1582    /// data key, or no key if it's an unencrypted file.
1583    pub async fn multi_write(
1584        &self,
1585        transaction: &mut Transaction<'_>,
1586        attribute_id: AttributeId,
1587        key_id: Option<u64>,
1588        ranges: &[Range<u64>],
1589        buf: MutableBufferRef<'_>,
1590    ) -> Result<(), Error> {
1591        let (allocated, deallocated) = self
1592            .multi_write_internal(
1593                transaction,
1594                attribute_id,
1595                key_id,
1596                /* encrypt: */ true,
1597                ranges,
1598                buf,
1599            )
1600            .await?;
1601        if allocated == 0 && deallocated == 0 {
1602            return Ok(());
1603        }
1604        self.update_allocated_size(transaction, allocated, deallocated).await
1605    }
1606
1607    /// Write data to overwrite extents with the provided set of ranges. This makes a strong
1608    /// assumption that the ranges are actually going to be already allocated overwrite extents and
1609    /// will error out or do something wrong if they aren't. It also assumes the ranges passed to
1610    /// it are sorted.
1611    pub async fn multi_overwrite<'a>(
1612        &'a self,
1613        transaction: &mut Transaction<'a>,
1614        attr_id: AttributeId,
1615        ranges: &[Range<u64>],
1616        mut buf: MutableBufferRef<'_>,
1617    ) -> Result<(), Error> {
1618        if buf.is_empty() {
1619            return Ok(());
1620        }
1621        let block_size = self.block_size();
1622        let store = self.store();
1623        let tree = store.tree();
1624        let store_id = store.store_object_id();
1625
1626        let (key_id, key) = self.get_key(None).await?;
1627        if let Some(key) = &key {
1628            if !key.supports_inline_encryption() {
1629                let mut slice = buf.as_mut_ptr_slice();
1630                for r in ranges {
1631                    let l = r.end - r.start;
1632                    let (head, tail) = slice.split_at_mut(l as usize);
1633                    key.encrypt(
1634                        self.object_id,
1635                        attr_id.raw(),
1636                        0, /* TODO(https://fxbug.dev/421269588): plumb through device_offset. */
1637                        r.start,
1638                        MutPtrByteSlice::from(head),
1639                    )?;
1640                    slice = tail;
1641                }
1642            }
1643        }
1644
1645        let mut range_iter = ranges.iter();
1646        // There should be at least one range if the buffer has data in it
1647        let mut target_range = range_iter.next().unwrap().clone();
1648        let mut mutations = Vec::new();
1649        let writes = FuturesUnordered::new();
1650
1651        let layer_set = tree.layer_set();
1652        let mut merger = layer_set.merger();
1653        let mut iter = merger
1654            .query(Query::LimitedRange(&ObjectKey::extent(
1655                self.object_id(),
1656                attr_id,
1657                target_range.start..ranges.last().unwrap().end,
1658            )))
1659            .await?;
1660
1661        loop {
1662            match iter.get() {
1663                Some(ItemRef {
1664                    key:
1665                        ObjectKey {
1666                            object_id,
1667                            data:
1668                                ObjectKeyData::Attribute(attribute_id, AttributeKey::Extent(extent)),
1669                        },
1670                    value: ObjectValue::Extent(extent_value),
1671                    ..
1672                }) if *object_id == self.object_id() && *attribute_id == attr_id => {
1673                    // If this extent ends before the target range starts (not possible on the
1674                    // first loop because of the query parameters but possible on further loops),
1675                    // advance until we find a the next one we care about.
1676                    if extent.end <= target_range.start {
1677                        iter.advance().await?;
1678                        continue;
1679                    }
1680                    let (device_offset, mode) = match extent_value {
1681                        ExtentValue::None => {
1682                            return Err(anyhow!(FxfsError::Inconsistent)).with_context(|| {
1683                                format!(
1684                                    "multi_overwrite failed: target_range ({}, {}) overlaps with \
1685                                deleted extent found at ({}, {})",
1686                                    target_range.start, target_range.end, extent.start, extent.end,
1687                                )
1688                            });
1689                        }
1690                        ExtentValue::Some { device_offset, mode, .. } => (device_offset, mode),
1691                    };
1692                    // The ranges passed to this function should already by allocated, so
1693                    // extent records should exist for them.
1694                    if extent.start > target_range.start {
1695                        return Err(anyhow!(FxfsError::Inconsistent)).with_context(|| {
1696                            format!(
1697                                "multi_overwrite failed: target range ({}, {}) starts before first \
1698                            extent found at ({}, {})",
1699                                target_range.start, target_range.end, extent.start, extent.end,
1700                            )
1701                        });
1702                    }
1703                    let mut bitmap = match mode {
1704                        ExtentMode::Raw | ExtentMode::Cow(_) => {
1705                            return Err(anyhow!(FxfsError::Inconsistent)).with_context(|| {
1706                                format!(
1707                                    "multi_overwrite failed: \
1708                            extent from ({}, {}) which overlaps target range ({}, {}) had the \
1709                            wrong extent mode",
1710                                    extent.start, extent.end, target_range.start, target_range.end,
1711                                )
1712                            });
1713                        }
1714                        ExtentMode::OverwritePartial(bitmap) => {
1715                            OverwriteBitmaps::new(bitmap.clone())
1716                        }
1717                        ExtentMode::Overwrite => OverwriteBitmaps::None,
1718                    };
1719                    loop {
1720                        let offset_within_extent = target_range.start - extent.start;
1721                        let bitmap_offset = offset_within_extent / block_size;
1722                        let write_device_offset = *device_offset + offset_within_extent;
1723                        let write_end = min(extent.end, target_range.end);
1724                        let write_len = write_end - target_range.start;
1725                        let write_device_range =
1726                            write_device_offset..write_device_offset + write_len;
1727                        let (current_buf, remaining_buf) = buf.split_at_mut(write_len as usize);
1728
1729                        bitmap.set_offset(bitmap_offset as usize);
1730                        let checksum_ranges = ChecksumRangeChunk::group_first_write_ranges(
1731                            &mut bitmap,
1732                            block_size,
1733                            write_device_range,
1734                        );
1735
1736                        let crypt_ctx = if let Some(key) = &key {
1737                            key.crypt_ctx(self.object_id, attr_id.raw(), target_range.start)
1738                        } else {
1739                            None
1740                        };
1741
1742                        writes.push(async move {
1743                            let maybe_checksums = self
1744                                .write_aligned(
1745                                    current_buf.as_ref(),
1746                                    write_device_offset,
1747                                    crypt_ctx,
1748                                    WriteFlags::empty(),
1749                                )
1750                                .await?;
1751                            Ok::<_, Error>(match maybe_checksums {
1752                                MaybeChecksums::None => Vec::new(),
1753                                MaybeChecksums::Fletcher(checksums) => checksum_ranges
1754                                    .into_iter()
1755                                    .map(
1756                                        |ChecksumRangeChunk {
1757                                             checksum_range,
1758                                             device_range,
1759                                             is_first_write,
1760                                         }| {
1761                                            (
1762                                                device_range,
1763                                                checksums[checksum_range].to_vec(),
1764                                                is_first_write,
1765                                            )
1766                                        },
1767                                    )
1768                                    .collect(),
1769                            })
1770                        });
1771                        buf = remaining_buf;
1772                        target_range.start += write_len;
1773                        if target_range.start == target_range.end {
1774                            match range_iter.next() {
1775                                None => break,
1776                                Some(next_range) => target_range = next_range.clone(),
1777                            }
1778                        }
1779                        if extent.end <= target_range.start {
1780                            break;
1781                        }
1782                    }
1783                    if let Some((mut bitmap, write_bitmap)) = bitmap.take_bitmaps() {
1784                        if bitmap.or(&write_bitmap) {
1785                            let mode = if bitmap.all() {
1786                                ExtentMode::Overwrite
1787                            } else {
1788                                ExtentMode::OverwritePartial(bitmap)
1789                            };
1790                            mutations.push(Mutation::merge_object(
1791                                ObjectKey::extent(self.object_id(), attr_id, extent.clone().into()),
1792                                ObjectValue::Extent(ExtentValue::new(*device_offset, mode, key_id)),
1793                            ))
1794                        }
1795                    }
1796                    if target_range.start == target_range.end {
1797                        break;
1798                    }
1799                    iter.advance().await?;
1800                }
1801                // We've either run past the end of the existing extents or something is wrong with
1802                // the tree. The main section should break if it finishes the ranges, so either
1803                // case, this is an error.
1804                _ => bail!(anyhow!(FxfsError::Internal).context(
1805                    "found a non-extent object record while there were still ranges to process"
1806                )),
1807            }
1808        }
1809
1810        let checksums = writes.try_collect::<Vec<_>>().await?;
1811        // Only store checksums in the journal if barriers are not enabled.
1812        if !store.filesystem().options().barriers_enabled {
1813            for (r, c, first_write) in checksums.into_iter().flatten() {
1814                transaction.add_checksum(store_id, r, c, first_write);
1815            }
1816        }
1817
1818        for m in mutations {
1819            transaction.add(store_id, m);
1820        }
1821
1822        Ok(())
1823    }
1824
1825    /// Writes an attribute that should not already exist and therefore does not require trimming.
1826    /// Breaks up the write into multiple transactions if `data.len()` is larger than
1827    /// `WRITE_ATTR_BATCH_SIZE`. This always writes using a key wrapped with the volume data key.
1828    #[trace]
1829    pub async fn write_new_attr(
1830        &self,
1831        transaction: &mut Transaction<'_>,
1832        attribute_id: AttributeId,
1833        data: &[u8],
1834    ) -> Result<(), Error> {
1835        self.write_new_attr_impl(
1836            transaction,
1837            attribute_id,
1838            VOLUME_DATA_KEY_ID,
1839            /* encrypt: */ true,
1840            data,
1841        )
1842        .await
1843    }
1844
1845    /// Writes a new attribute that has already been encrypted with `key_id`, without performing
1846    /// encryption again.
1847    pub async fn write_new_attr_pre_encrypted(
1848        &self,
1849        transaction: &mut Transaction<'_>,
1850        attribute_id: AttributeId,
1851        key_id: u64,
1852        data: &[u8],
1853    ) -> Result<(), Error> {
1854        self.write_new_attr_impl(transaction, attribute_id, key_id, /* encrypt: */ false, data)
1855            .await
1856    }
1857
1858    async fn write_new_attr_impl(
1859        &self,
1860        transaction: &mut Transaction<'_>,
1861        attribute_id: AttributeId,
1862        key_id: u64,
1863        encrypt: bool,
1864        data: &[u8],
1865    ) -> Result<(), Error> {
1866        transaction.add(
1867            self.store().store_object_id,
1868            Mutation::replace_or_insert_object(
1869                ObjectKey::attribute(self.object_id(), attribute_id, AttributeKey::Attribute),
1870                ObjectValue::attribute(data.len() as u64, false),
1871            ),
1872        );
1873        let chunks = data.chunks(WRITE_ATTR_BATCH_SIZE);
1874        let num_chunks = chunks.len();
1875        if num_chunks > 1 {
1876            transaction.add(
1877                self.store().store_object_id,
1878                Mutation::replace_or_insert_object(
1879                    ObjectKey::graveyard_attribute_entry(
1880                        self.store().graveyard_directory_object_id(),
1881                        self.object_id(),
1882                        attribute_id,
1883                    ),
1884                    ObjectValue::Some,
1885                ),
1886            );
1887        }
1888        let mut start_offset = 0;
1889        for (i, chunk) in chunks.enumerate() {
1890            let rounded_len = self.block_size().align_up(chunk.len() as u64).unwrap();
1891            let mut buffer = self.store().device.allocate_buffer(rounded_len as usize).await;
1892            let mut slice = buffer.as_mut_ptr_slice();
1893            slice.subslice_mut(0..chunk.len()).copy_from_slice(chunk);
1894            slice.subslice_mut(chunk.len()..slice.len()).fill(0);
1895            let (allocated, deallocated) = self
1896                .multi_write_internal(
1897                    transaction,
1898                    attribute_id,
1899                    Some(key_id),
1900                    encrypt,
1901                    &[start_offset..start_offset + rounded_len],
1902                    buffer.as_mut(),
1903                )
1904                .await?;
1905            if allocated != 0 || deallocated != 0 {
1906                self.update_allocated_size(transaction, allocated, deallocated).await?;
1907            }
1908            start_offset += rounded_len;
1909            // Do not commit the last chunk.
1910            if i < num_chunks - 1 {
1911                transaction.commit_and_continue().await?;
1912            }
1913        }
1914        if num_chunks > 1 {
1915            self.store().remove_attribute_from_graveyard(
1916                transaction,
1917                self.object_id(),
1918                attribute_id,
1919            );
1920        }
1921        Ok(())
1922    }
1923
1924    /// Writes an entire attribute. Returns whether or not the attribute needs to continue being
1925    /// trimmed - if the new data is shorter than the old data, this will trim any extents beyond
1926    /// the end of the new size, but if there were too many for a single transaction, a commit
1927    /// needs to be made before trimming again, so the responsibility is left to the caller so as
1928    /// to not accidentally split the transaction when it's not in a consistent state.  This will
1929    /// write using the volume data key; the fscrypt key is not supported.
1930    pub async fn write_attr(
1931        &self,
1932        transaction: &mut Transaction<'_>,
1933        attribute_id: AttributeId,
1934        data: &[u8],
1935    ) -> Result<NeedsTrim, Error> {
1936        let rounded_len = self.block_size().align_up(data.len() as u64).unwrap();
1937        let store = self.store();
1938        let tree = store.tree();
1939        let should_trim = tree
1940            .find_map(
1941                &ObjectKey::attribute(self.object_id(), attribute_id, AttributeKey::Attribute),
1942                |item| match item.value {
1943                    ObjectValue::Attribute { size: _, has_overwrite_extents: true } => {
1944                        Err(anyhow!(FxfsError::Inconsistent)
1945                            .context("write_attr on an attribute with overwrite extents"))
1946                    }
1947                    ObjectValue::Attribute { size, .. } => Ok((data.len() as u64) < *size),
1948                    _ => Err(FxfsError::Inconsistent.into()),
1949                },
1950            )
1951            .await?
1952            .transpose()?
1953            .unwrap_or(false);
1954        let mut buffer = self.store().device.allocate_buffer(rounded_len as usize).await;
1955        let mut slice = buffer.as_mut_ptr_slice();
1956        slice.subslice_mut(0..data.len()).copy_from_slice(data);
1957        slice.subslice_mut(data.len()..slice.len()).fill(0);
1958        self.multi_write(
1959            transaction,
1960            attribute_id,
1961            Some(VOLUME_DATA_KEY_ID),
1962            &[0..rounded_len],
1963            buffer.as_mut(),
1964        )
1965        .await?;
1966        transaction.add(
1967            self.store().store_object_id,
1968            Mutation::replace_or_insert_object(
1969                ObjectKey::attribute(self.object_id(), attribute_id, AttributeKey::Attribute),
1970                ObjectValue::attribute(data.len() as u64, false),
1971            ),
1972        );
1973        if should_trim {
1974            self.shrink(transaction, attribute_id, data.len() as u64).await
1975        } else {
1976            Ok(NeedsTrim(false))
1977        }
1978    }
1979
1980    pub async fn list_extended_attributes(&self) -> Result<Vec<Vec<u8>>, Error> {
1981        let layer_set = self.store().tree().layer_set();
1982        let mut merger = layer_set.merger();
1983        // Seek to the first extended attribute key for this object.
1984        let mut iter = merger
1985            .query(Query::FullRange(&ObjectKey::extended_attribute(self.object_id(), Vec::new())))
1986            .await?;
1987        let mut out = Vec::new();
1988        while let Some(item) = iter.get() {
1989            // Skip deleted extended attributes.
1990            if item.value != &ObjectValue::None {
1991                match item.key {
1992                    ObjectKey { object_id, data: ObjectKeyData::ExtendedAttribute { name } }
1993                        if *object_id == self.object_id() =>
1994                    {
1995                        out.push(name.clone());
1996                    }
1997                    // Once we hit a record belonging to another object, or one that is not an
1998                    // extended attribute key, we have reached the end of this object's extended
1999                    // attributes. Subsequent objects' records will start with lower variants
2000                    // (e.g. ObjectKeyData::Object) which trigger this break.
2001                    _ => break,
2002                }
2003            }
2004            iter.advance().await?;
2005        }
2006        Ok(out)
2007    }
2008
2009    /// Looks up the values for the extended attribute `fio::SELINUX_CONTEXT_NAME`, returning it
2010    /// if it is found inline. If it is not inline, it will request use of the
2011    /// `get_extended_attributes` method. If the entry doesn't exist at all, returns None.
2012    pub async fn get_inline_selinux_context(&self) -> Result<Option<fio::SelinuxContext>, Error> {
2013        // This optimization is only useful as long as the attribute is smaller than inline sizes.
2014        // Avoid reading the data out of the attributes.
2015        const_assert!(fio::MAX_SELINUX_CONTEXT_ATTRIBUTE_LEN as usize <= MAX_INLINE_XATTR_SIZE);
2016        self.store()
2017            .tree()
2018            .find_map(
2019                &ObjectKey::extended_attribute(self.object_id(), fio::SELINUX_CONTEXT_NAME.into()),
2020                |item| match item.value {
2021                    ObjectValue::ExtendedAttribute(ExtendedAttributeValue::Inline(value)) => {
2022                        Ok(fio::SelinuxContext::Data(value.clone()))
2023                    }
2024                    ObjectValue::ExtendedAttribute(ExtendedAttributeValue::AttributeId(_)) => {
2025                        Ok(fio::SelinuxContext::UseExtendedAttributes(fio::EmptyStruct {}))
2026                    }
2027                    _ => Err(anyhow!(FxfsError::Inconsistent).context(
2028                        "get_inline_extended_attribute: Expected ExtendedAttribute value",
2029                    )),
2030                },
2031            )
2032            .await?
2033            .transpose()
2034    }
2035
2036    pub async fn get_extended_attribute(&self, name: Vec<u8>) -> Result<Vec<u8>, Error> {
2037        let value = self
2038            .store()
2039            .tree()
2040            .find_value(&ObjectKey::extended_attribute(self.object_id(), name))
2041            .await?
2042            .ok_or(FxfsError::NotFound)?;
2043        match value {
2044            ObjectValue::ExtendedAttribute(ExtendedAttributeValue::Inline(value)) => Ok(value),
2045            ObjectValue::ExtendedAttribute(ExtendedAttributeValue::AttributeId(id)) => {
2046                ensure!(id.is_xattr(), FxfsError::Inconsistent);
2047                Ok(self.read_attr(id).await?.ok_or(FxfsError::Inconsistent)?.into_vec())
2048            }
2049            _ => {
2050                bail!(
2051                    anyhow!(FxfsError::Inconsistent)
2052                        .context("get_extended_attribute: Expected ExtendedAttribute value")
2053                )
2054            }
2055        }
2056    }
2057
2058    pub async fn set_extended_attribute(
2059        &self,
2060        name: Vec<u8>,
2061        value: Vec<u8>,
2062        mode: SetExtendedAttributeMode,
2063    ) -> Result<(), Error> {
2064        let store = self.store();
2065        // NB: We need to take this lock before we potentially look up the value to prevent racing
2066        // with another set.
2067        let keys = lock_keys![LockKey::object(store.store_object_id(), self.object_id())];
2068        let mut transaction = store.new_transaction(keys, Options::default()).await?;
2069        self.set_extended_attribute_impl(name, value, mode, &mut transaction).await?;
2070        transaction.commit().await?;
2071        Ok(())
2072    }
2073
2074    async fn set_extended_attribute_impl(
2075        &self,
2076        name: Vec<u8>,
2077        value: Vec<u8>,
2078        mode: SetExtendedAttributeMode,
2079        transaction: &mut Transaction<'_>,
2080    ) -> Result<(), Error> {
2081        ensure!(name.len() <= MAX_XATTR_NAME_SIZE, FxfsError::TooBig);
2082        ensure!(value.len() <= MAX_XATTR_VALUE_SIZE, FxfsError::TooBig);
2083        let tree = self.store().tree();
2084        let object_key = ObjectKey::extended_attribute(self.object_id(), name);
2085
2086        let existing_attribute_id = {
2087            let find_result = tree
2088                .find_map(&object_key, |item| match item.value {
2089                    ObjectValue::ExtendedAttribute(ExtendedAttributeValue::Inline(..)) => Ok(None),
2090                    ObjectValue::ExtendedAttribute(ExtendedAttributeValue::AttributeId(id)) => {
2091                        ensure!(id.is_xattr(), FxfsError::Inconsistent);
2092                        Ok(Some(*id))
2093                    }
2094                    _ => Err(anyhow!(FxfsError::Inconsistent)
2095                        .context("expected extended attribute value")),
2096                })
2097                .await?;
2098            let (found, existing_attribute_id) = match find_result {
2099                Some(id) => (true, id?),
2100                None => (false, None),
2101            };
2102            match mode {
2103                SetExtendedAttributeMode::Create if found => {
2104                    bail!(FxfsError::AlreadyExists)
2105                }
2106                SetExtendedAttributeMode::Replace if !found => {
2107                    bail!(FxfsError::NotFound)
2108                }
2109                _ => (),
2110            }
2111            existing_attribute_id
2112        };
2113
2114        if let Some(attribute_id) = existing_attribute_id {
2115            // If we already have an attribute id allocated for this extended attribute, we always
2116            // use it, even if the value has shrunk enough to be stored inline. We don't need to
2117            // worry about trimming here for the same reason we don't need to worry about it when
2118            // we delete xattrs - they simply aren't large enough to ever need more than one
2119            // transaction.
2120            let _ = self.write_attr(transaction, attribute_id, &value).await?;
2121        } else if value.len() <= MAX_INLINE_XATTR_SIZE {
2122            transaction.add(
2123                self.store().store_object_id(),
2124                Mutation::replace_or_insert_object(
2125                    object_key,
2126                    ObjectValue::inline_extended_attribute(value),
2127                ),
2128            );
2129        } else {
2130            // If there isn't an existing attribute id and we are going to store the value in
2131            // an attribute, find the next empty attribute id in the range. We search for fxfs
2132            // attribute records specifically, instead of the extended attribute records, because
2133            // even if the extended attribute record is removed the attribute may not be fully
2134            // trimmed yet.
2135            let mut attribute_id = AttributeId::XATTR_RANGE_START;
2136            let layer_set = tree.layer_set();
2137            let mut merger = layer_set.merger();
2138            let key = ObjectKey::attribute(self.object_id(), attribute_id, AttributeKey::Attribute);
2139            let mut iter = merger.query(Query::FullRange(&key)).await?;
2140            loop {
2141                match iter.get() {
2142                    // None means the key passed to seek wasn't found. That means the first
2143                    // attribute is available and we can just stop right away.
2144                    None => break,
2145                    Some(ItemRef {
2146                        key: ObjectKey { object_id, data: ObjectKeyData::Attribute(attr_id, _) },
2147                        value,
2148                        ..
2149                    }) if *object_id == self.object_id() => {
2150                        if matches!(value, ObjectValue::None) {
2151                            // This attribute was once used but is now deleted, so it's safe to use
2152                            // again.
2153                            break;
2154                        }
2155                        if attribute_id < *attr_id {
2156                            // We found a gap - use it.
2157                            break;
2158                        } else if attribute_id == *attr_id {
2159                            // This attribute id is in use, try the next one.
2160                            attribute_id = attribute_id.next();
2161                            if attribute_id == AttributeId::XATTR_RANGE_END {
2162                                bail!(FxfsError::NoSpace);
2163                            }
2164                        }
2165                        // If we don't hit either of those cases, we are still moving through the
2166                        // extent keys for the current attribute, so just keep advancing until the
2167                        // attribute id changes.
2168                    }
2169                    // As we are working our way through the iterator, if we hit anything that
2170                    // doesn't have our object id or attribute key data, we've gone past the end of
2171                    // this section and can stop.
2172                    _ => break,
2173                }
2174                iter.advance().await?;
2175            }
2176
2177            // We know this won't need trimming because it's a new attribute.
2178            let _ = self.write_attr(transaction, attribute_id, &value).await?;
2179            transaction.add(
2180                self.store().store_object_id(),
2181                Mutation::replace_or_insert_object(
2182                    object_key,
2183                    ObjectValue::extended_attribute(attribute_id),
2184                ),
2185            );
2186        }
2187
2188        Ok(())
2189    }
2190
2191    pub async fn remove_extended_attribute(&self, name: Vec<u8>) -> Result<(), Error> {
2192        let store = self.store();
2193        let tree = store.tree();
2194        let object_key = ObjectKey::extended_attribute(self.object_id(), name);
2195
2196        // NB: The API says we have to return an error if the attribute doesn't exist, so we have
2197        // to look it up first to make sure we have a record of it before we delete it. Make sure
2198        // we take a lock and make a transaction before we do so we don't race with other
2199        // operations.
2200        let keys = lock_keys![LockKey::object(store.store_object_id(), self.object_id())];
2201        let mut transaction = store.new_transaction(keys, Options::default()).await?;
2202
2203        let attribute_to_delete = tree
2204            .find_map(&object_key, |item| match item.value {
2205                ObjectValue::ExtendedAttribute(ExtendedAttributeValue::AttributeId(id)) => {
2206                    ensure!(id.is_xattr(), FxfsError::Inconsistent);
2207                    Ok(Some(*id))
2208                }
2209                ObjectValue::ExtendedAttribute(ExtendedAttributeValue::Inline(..)) => Ok(None),
2210                _ => Err(anyhow!(FxfsError::Inconsistent)
2211                    .context("remove_extended_attribute: Expected ExtendedAttribute value")),
2212            })
2213            .await?
2214            .ok_or(FxfsError::NotFound)??;
2215
2216        transaction.add(
2217            store.store_object_id(),
2218            Mutation::replace_or_insert_object(object_key, ObjectValue::None),
2219        );
2220
2221        // If the attribute wasn't stored inline, we need to deallocate all the extents too. This
2222        // would normally need to interact with the graveyard for correctness - if there are too
2223        // many extents to delete to fit in a single transaction then we could potentially have
2224        // consistency issues. However, the maximum size of an extended attribute is small enough
2225        // that it will never come close to that limit even in the worst case, so we just delete
2226        // everything in one shot.
2227        if let Some(attribute_id) = attribute_to_delete {
2228            let trim_result = store
2229                .trim_some(
2230                    &mut transaction,
2231                    self.object_id(),
2232                    attribute_id,
2233                    TrimMode::FromOffset(0),
2234                )
2235                .await?;
2236            // In case you didn't read the comment above - this should not be used to delete
2237            // arbitrary attributes!
2238            assert_matches!(trim_result, TrimResult::Done(_));
2239            transaction.add(
2240                store.store_object_id(),
2241                Mutation::replace_or_insert_object(
2242                    ObjectKey::attribute(self.object_id, attribute_id, AttributeKey::Attribute),
2243                    ObjectValue::None,
2244                ),
2245            );
2246        }
2247
2248        transaction.commit().await?;
2249        Ok(())
2250    }
2251
2252    /// Returns a future that will pre-fetches the keys so as to avoid paying the performance
2253    /// penalty later. Must ensure that the object is not removed before the future completes.
2254    pub fn pre_fetch_keys(&self) -> Option<impl Future<Output = ()> + use<S>> {
2255        if let Encryption::CachedKeys = self.encryption {
2256            let owner = self.owner.clone();
2257            let object_id = self.object_id;
2258            Some(async move {
2259                let store = owner.as_ref().as_ref();
2260                if let Some(crypt) = store.crypt() {
2261                    let _ = store
2262                        .key_manager
2263                        .get_keys(
2264                            object_id,
2265                            crypt.as_ref(),
2266                            &mut Some(async || store.get_keys(object_id).await),
2267                            /* permanent= */ false,
2268                            /* force= */ false,
2269                        )
2270                        .await;
2271                }
2272            })
2273        } else {
2274            None
2275        }
2276    }
2277
2278    /// When the symlink is unlocked, this function decrypts `link` and returns a bag of bytes that
2279    /// is identical to that which was passed in as the target on `create_symlink`.
2280    /// If the symlink is locked, this function hashes the encrypted `link` with Sha256 in order to
2281    /// get a standard length and then base64 encodes the hash and returns that to the caller.
2282    pub async fn read_encrypted_symlink(&self, link: Vec<u8>) -> Result<Vec<u8>, Error> {
2283        self.store().read_encrypted_symlink(self.object_id, link).await
2284    }
2285
2286    /// Returns the link of a symlink object.
2287    pub async fn read_symlink(&self) -> Result<Vec<u8>, Error> {
2288        let store = self.store();
2289        match store.tree.find(&ObjectKey::object(self.object_id)).await? {
2290            None | Some(ObjectItem { value: ObjectValue::None, .. }) => bail!(FxfsError::NotFound),
2291            Some(ObjectItem {
2292                value: ObjectValue::Object { kind: ObjectKind::EncryptedSymlink { link, .. }, .. },
2293                ..
2294            }) => store.read_encrypted_symlink(self.object_id, link.into_vec()).await,
2295            Some(ObjectItem {
2296                value: ObjectValue::Object { kind: ObjectKind::Symlink { link, .. }, .. },
2297                ..
2298            }) => Ok(link.into_vec()),
2299            Some(ObjectItem {
2300                value: ObjectValue::Object { kind: ObjectKind::NonInlineSymlink { .. }, .. },
2301                ..
2302            }) => self.read_non_inline_symlink().await,
2303            Some(item) => Err(anyhow!(FxfsError::Inconsistent)
2304                .context(format!("Unexpected item in symlink lookup: {item:?}"))),
2305        }
2306    }
2307
2308    pub(crate) async fn read_non_inline_symlink(&self) -> Result<Vec<u8>, Error> {
2309        // Both fscrypt and non-fscrypt spilled symlinks use `NonInlineSymlink`. In LSM-tree key
2310        // order, `ObjectKeyData::Keys` (if present) immediately follows `ObjectKeyData::Object`
2311        // and precedes `AttributeId::DATA`. We check whether `FSCRYPT_KEY_ID` is present to
2312        // determine how `AttributeId::DATA` was encrypted:
2313        // - If `FSCRYPT_KEY_ID` is present, the target was encrypted in fscrypt symlink mode
2314        //   (`encrypt_symlink`) and written pre-encrypted to `AttributeId::DATA`. Normal attribute
2315        //   reads (`read_attr_from_iter`) use data-mode decryption (`Cipher::decrypt`), which is
2316        //   unsupported for the fscrypt symlink cipher and would also fail when the key is locked,
2317        //   so we read the raw ciphertext without decrypting and let `read_encrypted_symlink`
2318        //   decrypt it (or return a `ProxyFilename` if locked).
2319        // - Otherwise, the attribute uses standard Fxfs volume data key encryption
2320        //   (`VOLUME_DATA_KEY_ID`), which `read_attr_from_iter` decrypts directly.
2321        let tree = &self.store().tree;
2322        let layer_set = tree.layer_set();
2323        let mut merger = layer_set.merger();
2324        let mut iter = merger.query(Query::FullRange(&ObjectKey::keys(self.object_id))).await?;
2325        let mut is_fscrypt = false;
2326        loop {
2327            match iter.get() {
2328                Some(ItemRef {
2329                    key: ObjectKey { object_id, data: ObjectKeyData::Keys },
2330                    value: ObjectValue::Keys(keys),
2331                    ..
2332                }) if *object_id == self.object_id => {
2333                    is_fscrypt = keys.get(FSCRYPT_KEY_ID).is_some();
2334                }
2335                Some(ItemRef {
2336                    key:
2337                        ObjectKey {
2338                            object_id,
2339                            data:
2340                                ObjectKeyData::Attribute(AttributeId::DATA, AttributeKey::Attribute),
2341                        },
2342                    value: ObjectValue::Attribute { .. },
2343                    ..
2344                }) if *object_id == self.object_id => break,
2345                _ => bail!(FxfsError::Inconsistent),
2346            }
2347            iter.advance().await?;
2348        }
2349        if is_fscrypt {
2350            let link = self.read_attr_from_iter_impl(iter, /* decrypt: */ false).await?.into_vec();
2351            self.read_encrypted_symlink(link).await
2352        } else {
2353            Ok(self.read_attr_from_iter(iter).await?.into_vec())
2354        }
2355    }
2356}
2357
2358impl<S: HandleOwner> Drop for StoreObjectHandle<S> {
2359    fn drop(&mut self) {
2360        if self.is_encrypted() {
2361            let _ = self.store().key_manager.remove(self.object_id);
2362        }
2363    }
2364}
2365
2366/// When truncating an object, sometimes it might not be possible to complete the transaction in a
2367/// single transaction, in which case the caller needs to finish trimming the object in subsequent
2368/// transactions (by calling ObjectStore::trim).
2369#[must_use]
2370pub struct NeedsTrim(pub bool);
2371
2372#[cfg(test)]
2373mod tests {
2374    use super::{ChecksumRangeChunk, OverwriteBitmaps};
2375    use crate::errors::FxfsError;
2376    use crate::filesystem::{FxFilesystem, OpenFxFilesystem};
2377    use crate::object_handle::{ObjectHandle, WriteObjectHandle};
2378    use crate::object_store::data_object_handle::WRITE_ATTR_BATCH_SIZE;
2379    use crate::object_store::transaction::{Mutation, Options, lock_keys};
2380    use crate::object_store::{
2381        AttributeId, AttributeKey, DataObjectHandle, Directory, HandleOptions, LockKey, ObjectKey,
2382        ObjectStore, ObjectValue, SetExtendedAttributeMode, StoreObjectHandle,
2383    };
2384    use bit_vec::BitVec;
2385    use fuchsia_async as fasync;
2386    use futures::{TryStreamExt, join};
2387    use std::sync::Arc;
2388    use storage_device::DeviceHolder;
2389    use storage_device::fake_device::FakeDevice;
2390    use storage_units::BlockSize;
2391
2392    const TEST_DEVICE_BLOCK_SIZE: u32 = 512;
2393    const TEST_OBJECT_NAME: &str = "foo";
2394
2395    fn is_error(actual: anyhow::Error, expected: FxfsError) {
2396        assert_eq!(*actual.root_cause().downcast_ref::<FxfsError>().unwrap(), expected)
2397    }
2398
2399    async fn test_filesystem() -> OpenFxFilesystem {
2400        let device = DeviceHolder::new(FakeDevice::new(16384, TEST_DEVICE_BLOCK_SIZE));
2401        FxFilesystem::new_empty(device).await.expect("new_empty failed")
2402    }
2403
2404    async fn test_filesystem_and_empty_object() -> (OpenFxFilesystem, DataObjectHandle<ObjectStore>)
2405    {
2406        let fs = test_filesystem().await;
2407        let store = fs.root_store();
2408
2409        let mut transaction = fs
2410            .root_store()
2411            .new_transaction(
2412                lock_keys![LockKey::object(
2413                    store.store_object_id(),
2414                    store.root_directory_object_id()
2415                )],
2416                Options::default(),
2417            )
2418            .await
2419            .expect("new_transaction failed");
2420
2421        let object =
2422            ObjectStore::create_object(&store, &mut transaction, HandleOptions::default(), None)
2423                .await
2424                .expect("create_object failed");
2425
2426        let root_directory =
2427            Directory::open(&store, store.root_directory_object_id()).await.expect("open failed");
2428        root_directory
2429            .add_child_file(&mut transaction, TEST_OBJECT_NAME, &object)
2430            .await
2431            .expect("add_child_file failed");
2432
2433        transaction.commit().await.expect("commit failed");
2434
2435        (fs, object)
2436    }
2437
2438    #[fuchsia::test]
2439    async fn test_extent_stream() {
2440        let (fs, object) = test_filesystem_and_empty_object().await;
2441
2442        // Write 8KiB at offset 0 and 8KiB at offset 16KiB, leaving a hole in between.
2443        let mut buf = object.allocate_buffer(8192).await;
2444        buf.as_mut_ptr_slice().fill(0xaa);
2445        object.write_or_append(Some(0), buf.as_ref()).await.expect("write failed");
2446        object.write_or_append(Some(16384), buf.as_ref()).await.expect("write failed");
2447
2448        let basic = StoreObjectHandle::new(
2449            object.owner().clone(),
2450            object.object_id(),
2451            /* permanent_keys: */ false,
2452            HandleOptions::default(),
2453            false,
2454        );
2455
2456        let store = fs.root_store();
2457        let layer_set = store.tree.layer_set();
2458        let mut merger = layer_set.merger();
2459
2460        let stream = basic
2461            .extent_stream(&mut merger, AttributeId::DATA)
2462            .await
2463            .expect("extent_stream failed");
2464
2465        let result: Vec<_> = stream.try_collect().await.expect("stream item error");
2466
2467        // Expect 2 physical mappings
2468        assert_eq!(result.len(), 2);
2469        assert_eq!(result[0].logical_offset(), 0);
2470        assert_eq!(result[0].length(), 8192);
2471        assert_eq!(result[1].logical_offset(), 16384);
2472        assert_eq!(result[1].length(), 8192);
2473    }
2474
2475    #[fuchsia::test(threads = 3)]
2476    async fn extended_attribute_double_remove() {
2477        // This test is intended to trip a potential race condition in remove. Removing an
2478        // attribute that doesn't exist is an error, so we need to check before we remove, but if
2479        // we aren't careful, two parallel removes might both succeed in the check and then both
2480        // remove the value.
2481        let (fs, object) = test_filesystem_and_empty_object().await;
2482        let basic = Arc::new(StoreObjectHandle::new(
2483            object.owner().clone(),
2484            object.object_id(),
2485            /* permanent_keys: */ false,
2486            HandleOptions::default(),
2487            false,
2488        ));
2489        let basic_a = basic.clone();
2490        let basic_b = basic.clone();
2491
2492        basic
2493            .set_extended_attribute(
2494                b"security.selinux".to_vec(),
2495                b"bar".to_vec(),
2496                SetExtendedAttributeMode::Set,
2497            )
2498            .await
2499            .expect("failed to set attribute");
2500
2501        // Try to remove the attribute twice at the same time. One should succeed in the race and
2502        // return Ok, and the other should fail the race and return NOT_FOUND.
2503        let a_task = fasync::Task::spawn(async move {
2504            basic_a.remove_extended_attribute(b"security.selinux".to_vec()).await
2505        });
2506        let b_task = fasync::Task::spawn(async move {
2507            basic_b.remove_extended_attribute(b"security.selinux".to_vec()).await
2508        });
2509        match join!(a_task, b_task) {
2510            (Ok(()), Ok(())) => panic!("both remove calls succeeded"),
2511            (Err(_), Err(_)) => panic!("both remove calls failed"),
2512
2513            (Ok(()), Err(e)) => is_error(e, FxfsError::NotFound),
2514            (Err(e), Ok(())) => is_error(e, FxfsError::NotFound),
2515        }
2516
2517        fs.close().await.expect("Close failed");
2518    }
2519
2520    #[fuchsia::test(threads = 3)]
2521    async fn extended_attribute_double_create() {
2522        // This test is intended to trip a potential race in set when using the create flag,
2523        // similar to above. If the create mode is set, we need to check that the attribute isn't
2524        // already created, but if two parallel creates both succeed in that check, and we aren't
2525        // careful with locking, they will both succeed and one will overwrite the other.
2526        let (fs, object) = test_filesystem_and_empty_object().await;
2527        let basic = Arc::new(StoreObjectHandle::new(
2528            object.owner().clone(),
2529            object.object_id(),
2530            /* permanent_keys: */ false,
2531            HandleOptions::default(),
2532            false,
2533        ));
2534        let basic_a = basic.clone();
2535        let basic_b = basic.clone();
2536
2537        // Try to set the attribute twice at the same time. One should succeed in the race and
2538        // return Ok, and the other should fail the race and return ALREADY_EXISTS.
2539        let a_task = fasync::Task::spawn(async move {
2540            basic_a
2541                .set_extended_attribute(
2542                    b"security.selinux".to_vec(),
2543                    b"one".to_vec(),
2544                    SetExtendedAttributeMode::Create,
2545                )
2546                .await
2547        });
2548        let b_task = fasync::Task::spawn(async move {
2549            basic_b
2550                .set_extended_attribute(
2551                    b"security.selinux".to_vec(),
2552                    b"two".to_vec(),
2553                    SetExtendedAttributeMode::Create,
2554                )
2555                .await
2556        });
2557        match join!(a_task, b_task) {
2558            (Ok(()), Ok(())) => panic!("both set calls succeeded"),
2559            (Err(_), Err(_)) => panic!("both set calls failed"),
2560
2561            (Ok(()), Err(e)) => {
2562                assert_eq!(
2563                    basic
2564                        .get_extended_attribute(b"security.selinux".to_vec())
2565                        .await
2566                        .expect("failed to get xattr"),
2567                    b"one"
2568                );
2569                is_error(e, FxfsError::AlreadyExists);
2570            }
2571            (Err(e), Ok(())) => {
2572                assert_eq!(
2573                    basic
2574                        .get_extended_attribute(b"security.selinux".to_vec())
2575                        .await
2576                        .expect("failed to get xattr"),
2577                    b"two"
2578                );
2579                is_error(e, FxfsError::AlreadyExists);
2580            }
2581        }
2582
2583        fs.close().await.expect("Close failed");
2584    }
2585
2586    struct TestAttr {
2587        name: Vec<u8>,
2588        value: Vec<u8>,
2589    }
2590
2591    impl TestAttr {
2592        fn new(name: impl AsRef<[u8]>, value: impl AsRef<[u8]>) -> Self {
2593            Self { name: name.as_ref().to_vec(), value: value.as_ref().to_vec() }
2594        }
2595        fn name(&self) -> Vec<u8> {
2596            self.name.clone()
2597        }
2598        fn value(&self) -> Vec<u8> {
2599            self.value.clone()
2600        }
2601    }
2602
2603    #[fuchsia::test]
2604    async fn extended_attributes() {
2605        let (fs, object) = test_filesystem_and_empty_object().await;
2606
2607        let test_attr = TestAttr::new(b"security.selinux", b"foo");
2608
2609        assert_eq!(object.list_extended_attributes().await.unwrap(), Vec::<Vec<u8>>::new());
2610        is_error(
2611            object.get_extended_attribute(test_attr.name()).await.unwrap_err(),
2612            FxfsError::NotFound,
2613        );
2614
2615        object
2616            .set_extended_attribute(
2617                test_attr.name(),
2618                test_attr.value(),
2619                SetExtendedAttributeMode::Set,
2620            )
2621            .await
2622            .unwrap();
2623        assert_eq!(object.list_extended_attributes().await.unwrap(), vec![test_attr.name()]);
2624        assert_eq!(
2625            object.get_extended_attribute(test_attr.name()).await.unwrap(),
2626            test_attr.value()
2627        );
2628
2629        object.remove_extended_attribute(test_attr.name()).await.unwrap();
2630        assert_eq!(object.list_extended_attributes().await.unwrap(), Vec::<Vec<u8>>::new());
2631        is_error(
2632            object.get_extended_attribute(test_attr.name()).await.unwrap_err(),
2633            FxfsError::NotFound,
2634        );
2635
2636        // Make sure we can object the same attribute being set again.
2637        object
2638            .set_extended_attribute(
2639                test_attr.name(),
2640                test_attr.value(),
2641                SetExtendedAttributeMode::Set,
2642            )
2643            .await
2644            .unwrap();
2645        assert_eq!(object.list_extended_attributes().await.unwrap(), vec![test_attr.name()]);
2646        assert_eq!(
2647            object.get_extended_attribute(test_attr.name()).await.unwrap(),
2648            test_attr.value()
2649        );
2650
2651        object.remove_extended_attribute(test_attr.name()).await.unwrap();
2652        assert_eq!(object.list_extended_attributes().await.unwrap(), Vec::<Vec<u8>>::new());
2653        is_error(
2654            object.get_extended_attribute(test_attr.name()).await.unwrap_err(),
2655            FxfsError::NotFound,
2656        );
2657
2658        fs.close().await.expect("close failed");
2659    }
2660
2661    #[fuchsia::test]
2662    async fn extended_attribute_invalid_id_range() {
2663        let (fs, object) = test_filesystem_and_empty_object().await;
2664
2665        let store = object.owner();
2666        let mut transaction = store
2667            .new_transaction(
2668                lock_keys![LockKey::object(store.store_object_id(), object.object_id())],
2669                Options::default(),
2670            )
2671            .await
2672            .unwrap();
2673        transaction.add(
2674            store.store_object_id(),
2675            Mutation::replace_or_insert_object(
2676                ObjectKey::extended_attribute(object.object_id(), b"bad_attr".to_vec()),
2677                ObjectValue::extended_attribute(AttributeId::DATA),
2678            ),
2679        );
2680        transaction.commit().await.unwrap();
2681
2682        is_error(
2683            object.get_extended_attribute(b"bad_attr".to_vec()).await.unwrap_err(),
2684            FxfsError::Inconsistent,
2685        );
2686        is_error(
2687            object
2688                .set_extended_attribute(
2689                    b"bad_attr".to_vec(),
2690                    b"new_val".to_vec(),
2691                    SetExtendedAttributeMode::Set,
2692                )
2693                .await
2694                .unwrap_err(),
2695            FxfsError::Inconsistent,
2696        );
2697        is_error(
2698            object.remove_extended_attribute(b"bad_attr".to_vec()).await.unwrap_err(),
2699            FxfsError::Inconsistent,
2700        );
2701
2702        fs.close().await.expect("close failed");
2703    }
2704
2705    #[fuchsia::test]
2706    async fn large_extended_attribute() {
2707        let (fs, object) = test_filesystem_and_empty_object().await;
2708
2709        let test_attr = TestAttr::new(b"security.selinux", vec![3u8; 300]);
2710
2711        object
2712            .set_extended_attribute(
2713                test_attr.name(),
2714                test_attr.value(),
2715                SetExtendedAttributeMode::Set,
2716            )
2717            .await
2718            .unwrap();
2719        assert_eq!(
2720            object.get_extended_attribute(test_attr.name()).await.unwrap(),
2721            test_attr.value()
2722        );
2723
2724        // Probe the fxfs attributes to make sure it did the expected thing. This relies on inside
2725        // knowledge of how the attribute id is chosen.
2726        assert_eq!(
2727            object
2728                .read_attr(AttributeId::XATTR_RANGE_START)
2729                .await
2730                .expect("read_attr failed")
2731                .expect("read_attr returned none")
2732                .into_vec(),
2733            test_attr.value()
2734        );
2735
2736        object.remove_extended_attribute(test_attr.name()).await.unwrap();
2737        is_error(
2738            object.get_extended_attribute(test_attr.name()).await.unwrap_err(),
2739            FxfsError::NotFound,
2740        );
2741
2742        // Make sure we can object the same attribute being set again.
2743        object
2744            .set_extended_attribute(
2745                test_attr.name(),
2746                test_attr.value(),
2747                SetExtendedAttributeMode::Set,
2748            )
2749            .await
2750            .unwrap();
2751        assert_eq!(
2752            object.get_extended_attribute(test_attr.name()).await.unwrap(),
2753            test_attr.value()
2754        );
2755        object.remove_extended_attribute(test_attr.name()).await.unwrap();
2756        is_error(
2757            object.get_extended_attribute(test_attr.name()).await.unwrap_err(),
2758            FxfsError::NotFound,
2759        );
2760
2761        fs.close().await.expect("close failed");
2762    }
2763
2764    #[fuchsia::test]
2765    async fn multiple_extended_attributes() {
2766        let (fs, object) = test_filesystem_and_empty_object().await;
2767
2768        let attrs = [
2769            TestAttr::new(b"security.selinux", b"foo"),
2770            TestAttr::new(b"large.attribute", vec![3u8; 300]),
2771            TestAttr::new(b"an.attribute", b"asdf"),
2772            TestAttr::new(b"user.big", vec![5u8; 288]),
2773            TestAttr::new(b"user.tiny", b"smol"),
2774            TestAttr::new(b"this string doesn't matter", b"the quick brown fox etc"),
2775            TestAttr::new(b"also big", vec![7u8; 500]),
2776            TestAttr::new(b"all.ones", vec![1u8; 11111]),
2777        ];
2778
2779        for i in 0..attrs.len() {
2780            object
2781                .set_extended_attribute(
2782                    attrs[i].name(),
2783                    attrs[i].value(),
2784                    SetExtendedAttributeMode::Set,
2785                )
2786                .await
2787                .unwrap();
2788            assert_eq!(
2789                object.get_extended_attribute(attrs[i].name()).await.unwrap(),
2790                attrs[i].value()
2791            );
2792        }
2793
2794        for i in 0..attrs.len() {
2795            // Make sure expected attributes are still available.
2796            let mut found_attrs = object.list_extended_attributes().await.unwrap();
2797            let mut expected_attrs: Vec<Vec<u8>> = attrs.iter().skip(i).map(|a| a.name()).collect();
2798            found_attrs.sort();
2799            expected_attrs.sort();
2800            assert_eq!(found_attrs, expected_attrs);
2801            for j in i..attrs.len() {
2802                assert_eq!(
2803                    object.get_extended_attribute(attrs[j].name()).await.unwrap(),
2804                    attrs[j].value()
2805                );
2806            }
2807
2808            object.remove_extended_attribute(attrs[i].name()).await.expect("failed to remove");
2809            is_error(
2810                object.get_extended_attribute(attrs[i].name()).await.unwrap_err(),
2811                FxfsError::NotFound,
2812            );
2813        }
2814
2815        fs.close().await.expect("close failed");
2816    }
2817
2818    #[fuchsia::test]
2819    async fn multiple_extended_attributes_delete() {
2820        let (fs, object) = test_filesystem_and_empty_object().await;
2821        let store = object.owner().clone();
2822
2823        let attrs = [
2824            TestAttr::new(b"security.selinux", b"foo"),
2825            TestAttr::new(b"large.attribute", vec![3u8; 300]),
2826            TestAttr::new(b"an.attribute", b"asdf"),
2827            TestAttr::new(b"user.big", vec![5u8; 288]),
2828            TestAttr::new(b"user.tiny", b"smol"),
2829            TestAttr::new(b"this string doesn't matter", b"the quick brown fox etc"),
2830            TestAttr::new(b"also big", vec![7u8; 500]),
2831            TestAttr::new(b"all.ones", vec![1u8; 11111]),
2832        ];
2833
2834        for i in 0..attrs.len() {
2835            object
2836                .set_extended_attribute(
2837                    attrs[i].name(),
2838                    attrs[i].value(),
2839                    SetExtendedAttributeMode::Set,
2840                )
2841                .await
2842                .unwrap();
2843            assert_eq!(
2844                object.get_extended_attribute(attrs[i].name()).await.unwrap(),
2845                attrs[i].value()
2846            );
2847        }
2848
2849        // Unlink the file
2850        let root_directory =
2851            Directory::open(object.owner(), object.store().root_directory_object_id())
2852                .await
2853                .expect("open failed");
2854        let mut transaction = fs
2855            .root_store()
2856            .new_transaction(
2857                lock_keys![
2858                    LockKey::object(store.store_object_id(), store.root_directory_object_id()),
2859                    LockKey::object(store.store_object_id(), object.object_id()),
2860                ],
2861                Options::default(),
2862            )
2863            .await
2864            .expect("new_transaction failed");
2865        crate::object_store::directory::replace_child(
2866            &mut transaction,
2867            None,
2868            (&root_directory, TEST_OBJECT_NAME),
2869        )
2870        .await
2871        .expect("replace_child failed");
2872        transaction.commit().await.unwrap();
2873        store.tombstone_object(object.object_id(), Options::default(), None).await.unwrap();
2874
2875        crate::fsck::fsck(fs.clone()).await.unwrap();
2876
2877        fs.close().await.expect("close failed");
2878    }
2879
2880    #[fuchsia::test]
2881    async fn extended_attribute_changing_sizes() {
2882        let (fs, object) = test_filesystem_and_empty_object().await;
2883
2884        let test_name = b"security.selinux";
2885        let test_small_attr = TestAttr::new(test_name, b"smol");
2886        let test_large_attr = TestAttr::new(test_name, vec![3u8; 300]);
2887
2888        object
2889            .set_extended_attribute(
2890                test_small_attr.name(),
2891                test_small_attr.value(),
2892                SetExtendedAttributeMode::Set,
2893            )
2894            .await
2895            .unwrap();
2896        assert_eq!(
2897            object.get_extended_attribute(test_small_attr.name()).await.unwrap(),
2898            test_small_attr.value()
2899        );
2900
2901        // With a small attribute, we don't expect it to write to an fxfs attribute.
2902        assert!(
2903            object
2904                .read_attr(AttributeId::XATTR_RANGE_START)
2905                .await
2906                .expect("read_attr failed")
2907                .is_none()
2908        );
2909
2910        crate::fsck::fsck(fs.clone()).await.unwrap();
2911
2912        object
2913            .set_extended_attribute(
2914                test_large_attr.name(),
2915                test_large_attr.value(),
2916                SetExtendedAttributeMode::Set,
2917            )
2918            .await
2919            .unwrap();
2920        assert_eq!(
2921            object.get_extended_attribute(test_large_attr.name()).await.unwrap(),
2922            test_large_attr.value()
2923        );
2924
2925        // Once the value is above the threshold, we expect it to get upgraded to an fxfs
2926        // attribute.
2927        assert_eq!(
2928            object
2929                .read_attr(AttributeId::XATTR_RANGE_START)
2930                .await
2931                .expect("read_attr failed")
2932                .expect("read_attr returned none")
2933                .into_vec(),
2934            test_large_attr.value()
2935        );
2936
2937        crate::fsck::fsck(fs.clone()).await.unwrap();
2938
2939        object
2940            .set_extended_attribute(
2941                test_small_attr.name(),
2942                test_small_attr.value(),
2943                SetExtendedAttributeMode::Set,
2944            )
2945            .await
2946            .unwrap();
2947        assert_eq!(
2948            object.get_extended_attribute(test_small_attr.name()).await.unwrap(),
2949            test_small_attr.value()
2950        );
2951
2952        // Even though we are back under the threshold, we still expect it to be stored in an fxfs
2953        // attribute, because we don't downgrade to inline once we've allocated one.
2954        assert_eq!(
2955            object
2956                .read_attr(AttributeId::XATTR_RANGE_START)
2957                .await
2958                .expect("read_attr failed")
2959                .expect("read_attr returned none")
2960                .into_vec(),
2961            test_small_attr.value()
2962        );
2963
2964        crate::fsck::fsck(fs.clone()).await.unwrap();
2965
2966        object.remove_extended_attribute(test_small_attr.name()).await.expect("failed to remove");
2967
2968        crate::fsck::fsck(fs.clone()).await.unwrap();
2969
2970        fs.close().await.expect("close failed");
2971    }
2972
2973    #[fuchsia::test]
2974    async fn extended_attribute_max_size() {
2975        let (fs, object) = test_filesystem_and_empty_object().await;
2976
2977        let test_attr = TestAttr::new(
2978            vec![3u8; super::MAX_XATTR_NAME_SIZE],
2979            vec![1u8; super::MAX_XATTR_VALUE_SIZE],
2980        );
2981
2982        object
2983            .set_extended_attribute(
2984                test_attr.name(),
2985                test_attr.value(),
2986                SetExtendedAttributeMode::Set,
2987            )
2988            .await
2989            .unwrap();
2990        assert_eq!(
2991            object.get_extended_attribute(test_attr.name()).await.unwrap(),
2992            test_attr.value()
2993        );
2994        assert_eq!(object.list_extended_attributes().await.unwrap(), vec![test_attr.name()]);
2995        object.remove_extended_attribute(test_attr.name()).await.unwrap();
2996
2997        fs.close().await.expect("close failed");
2998    }
2999
3000    #[fuchsia::test]
3001    async fn extended_attribute_remove_then_create() {
3002        let (fs, object) = test_filesystem_and_empty_object().await;
3003
3004        let test_attr = TestAttr::new(
3005            vec![3u8; super::MAX_XATTR_NAME_SIZE],
3006            vec![1u8; super::MAX_XATTR_VALUE_SIZE],
3007        );
3008
3009        object
3010            .set_extended_attribute(
3011                test_attr.name(),
3012                test_attr.value(),
3013                SetExtendedAttributeMode::Create,
3014            )
3015            .await
3016            .unwrap();
3017        fs.journal().force_compact().await.unwrap();
3018        object.remove_extended_attribute(test_attr.name()).await.unwrap();
3019        object
3020            .set_extended_attribute(
3021                test_attr.name(),
3022                test_attr.value(),
3023                SetExtendedAttributeMode::Create,
3024            )
3025            .await
3026            .unwrap();
3027
3028        assert_eq!(
3029            object.get_extended_attribute(test_attr.name()).await.unwrap(),
3030            test_attr.value()
3031        );
3032
3033        fs.close().await.expect("close failed");
3034    }
3035
3036    #[fuchsia::test]
3037    async fn large_extended_attribute_max_number() {
3038        let (fs, object) = test_filesystem_and_empty_object().await;
3039
3040        let max_xattrs = AttributeId::XATTR_RANGE_END.raw() - AttributeId::XATTR_RANGE_START.raw();
3041        for i in 0..max_xattrs {
3042            let test_attr = TestAttr::new(format!("{}", i).as_bytes(), vec![0x3; 300]);
3043            object
3044                .set_extended_attribute(
3045                    test_attr.name(),
3046                    test_attr.value(),
3047                    SetExtendedAttributeMode::Set,
3048                )
3049                .await
3050                .unwrap_or_else(|_| panic!("failed to set xattr number {}", i));
3051        }
3052
3053        // That should have taken up all the attributes we've allocated to extended attributes, so
3054        // this one should return ERR_NO_SPACE.
3055        match object
3056            .set_extended_attribute(
3057                b"one.too.many".to_vec(),
3058                vec![0x3; 300],
3059                SetExtendedAttributeMode::Set,
3060            )
3061            .await
3062        {
3063            Ok(()) => panic!("set should not succeed"),
3064            Err(e) => is_error(e, FxfsError::NoSpace),
3065        }
3066
3067        // But inline attributes don't need an attribute number, so it should work fine.
3068        object
3069            .set_extended_attribute(
3070                b"this.is.okay".to_vec(),
3071                b"small value".to_vec(),
3072                SetExtendedAttributeMode::Set,
3073            )
3074            .await
3075            .unwrap();
3076
3077        // And updating existing ones should be okay.
3078        object
3079            .set_extended_attribute(b"11".to_vec(), vec![0x4; 300], SetExtendedAttributeMode::Set)
3080            .await
3081            .unwrap();
3082        object
3083            .set_extended_attribute(
3084                b"12".to_vec(),
3085                vec![0x1; 300],
3086                SetExtendedAttributeMode::Replace,
3087            )
3088            .await
3089            .unwrap();
3090
3091        // And we should be able to remove an attribute and set another one.
3092        object.remove_extended_attribute(b"5".to_vec()).await.unwrap();
3093        object
3094            .set_extended_attribute(
3095                b"new attr".to_vec(),
3096                vec![0x3; 300],
3097                SetExtendedAttributeMode::Set,
3098            )
3099            .await
3100            .unwrap();
3101
3102        fs.close().await.expect("close failed");
3103    }
3104
3105    #[fuchsia::test]
3106    async fn write_attr_trims_beyond_new_end() {
3107        // When writing, multi_write will deallocate old extents that overlap with the new data,
3108        // but it doesn't trim anything beyond that, since it doesn't know what the total size will
3109        // be. write_attr does know, because it writes the whole attribute at once, so we need to
3110        // make sure it cleans up properly.
3111        let (fs, object) = test_filesystem_and_empty_object().await;
3112
3113        let block_size = fs.block_size();
3114        let buf_size = block_size * 2;
3115        let attribute_id = AttributeId::TEST_ID;
3116
3117        let mut transaction = (*object).new_transaction(attribute_id).await.unwrap();
3118        let mut buffer = object.allocate_buffer(buf_size as usize).await;
3119        buffer.fill(3);
3120        // Writing two separate ranges, even if they are contiguous, forces them to be separate
3121        // extent records.
3122        object
3123            .multi_write(
3124                &mut transaction,
3125                attribute_id,
3126                &[0..block_size.get(), block_size.get()..block_size * 2],
3127                buffer.as_mut(),
3128            )
3129            .await
3130            .unwrap();
3131        transaction.add(
3132            object.store().store_object_id,
3133            Mutation::replace_or_insert_object(
3134                ObjectKey::attribute(object.object_id(), attribute_id, AttributeKey::Attribute),
3135                ObjectValue::attribute(block_size * 2, false),
3136            ),
3137        );
3138        transaction.commit().await.unwrap();
3139
3140        crate::fsck::fsck(fs.clone()).await.unwrap();
3141
3142        let mut transaction = (*object).new_transaction(attribute_id).await.unwrap();
3143        let needs_trim = (*object)
3144            .write_attr(&mut transaction, attribute_id, &vec![3u8; block_size.get() as usize])
3145            .await
3146            .unwrap();
3147        assert!(!needs_trim.0);
3148        transaction.commit().await.unwrap();
3149
3150        crate::fsck::fsck(fs.clone()).await.unwrap();
3151
3152        fs.close().await.expect("close failed");
3153    }
3154
3155    #[fuchsia::test]
3156    async fn write_new_attr_multiple_txns() {
3157        let (fs, object) = test_filesystem_and_empty_object().await;
3158        let merkle_tree = vec![1; 3 * WRITE_ATTR_BATCH_SIZE];
3159        let mut transaction = (*object).new_transaction(AttributeId::TEST_ID).await.unwrap();
3160        object
3161            .write_new_attr(&mut transaction, AttributeId::TEST_ID, &merkle_tree)
3162            .await
3163            .expect("failed to write merkle attribute");
3164        transaction.commit().await.unwrap();
3165        assert_eq!(
3166            object.read_attr(AttributeId::TEST_ID).await.expect("read_attr failed"),
3167            Some(merkle_tree.into())
3168        );
3169
3170        fs.close().await.expect("close failed");
3171    }
3172
3173    // Running on target only, to use fake time features in the executor.
3174    #[cfg(target_os = "fuchsia")]
3175    #[fuchsia::test(allow_stalls = false)]
3176    async fn test_watchdog() {
3177        use super::Watchdog;
3178        use fuchsia_async::{MonotonicDuration, MonotonicInstant, TestExecutor};
3179        use std::sync::mpsc::channel;
3180
3181        TestExecutor::advance_to(make_time(0)).await;
3182        let (sender, receiver) = channel();
3183
3184        fn make_time(time_secs: i64) -> MonotonicInstant {
3185            MonotonicInstant::from_nanos(0) + MonotonicDuration::from_seconds(time_secs)
3186        }
3187
3188        {
3189            let _watchdog = Watchdog::new(10, move |count| {
3190                sender.send(count).expect("Sending value");
3191            });
3192
3193            // Too early.
3194            TestExecutor::advance_to(make_time(5)).await;
3195            receiver.try_recv().expect_err("Should not have message");
3196
3197            // First message.
3198            TestExecutor::advance_to(make_time(10)).await;
3199            assert_eq!(1, receiver.recv().expect("Receiving"));
3200
3201            // Too early for the next.
3202            TestExecutor::advance_to(make_time(15)).await;
3203            receiver.try_recv().expect_err("Should not have message");
3204
3205            // Missed one. They'll be spooled up.
3206            TestExecutor::advance_to(make_time(30)).await;
3207            assert_eq!(2, receiver.recv().expect("Receiving"));
3208            assert_eq!(3, receiver.recv().expect("Receiving"));
3209        }
3210
3211        // Watchdog is dropped, nothing should trigger.
3212        TestExecutor::advance_to(make_time(100)).await;
3213        receiver.recv().expect_err("Watchdog should be gone");
3214    }
3215
3216    #[fuchsia::test]
3217    fn test_checksum_range_chunk() {
3218        let block_size = BlockSize::SIZE_4KIB;
3219
3220        // No bitmap means one chunk that covers the whole range
3221        assert_eq!(
3222            ChecksumRangeChunk::group_first_write_ranges(
3223                &mut OverwriteBitmaps::None,
3224                block_size,
3225                block_size * 2..block_size * 5,
3226            ),
3227            vec![ChecksumRangeChunk {
3228                checksum_range: 0..3,
3229                device_range: block_size * 2..block_size * 5,
3230                is_first_write: false,
3231            }],
3232        );
3233
3234        let mut bitmaps = OverwriteBitmaps::new(BitVec::from_bytes(&[0b11110000]));
3235        assert_eq!(
3236            ChecksumRangeChunk::group_first_write_ranges(
3237                &mut bitmaps,
3238                block_size,
3239                block_size * 2..block_size * 5,
3240            ),
3241            vec![ChecksumRangeChunk {
3242                checksum_range: 0..3,
3243                device_range: block_size * 2..block_size * 5,
3244                is_first_write: false,
3245            }],
3246        );
3247        assert_eq!(
3248            bitmaps.take_bitmaps(),
3249            Some((BitVec::from_bytes(&[0b11110000]), BitVec::from_bytes(&[0b11100000])))
3250        );
3251
3252        let mut bitmaps = OverwriteBitmaps::new(BitVec::from_bytes(&[0b11110000]));
3253        bitmaps.set_offset(2);
3254        assert_eq!(
3255            ChecksumRangeChunk::group_first_write_ranges(
3256                &mut bitmaps,
3257                block_size,
3258                block_size * 2..block_size * 5,
3259            ),
3260            vec![
3261                ChecksumRangeChunk {
3262                    checksum_range: 0..2,
3263                    device_range: block_size * 2..block_size * 4,
3264                    is_first_write: false,
3265                },
3266                ChecksumRangeChunk {
3267                    checksum_range: 2..3,
3268                    device_range: block_size * 4..block_size * 5,
3269                    is_first_write: true,
3270                },
3271            ],
3272        );
3273        assert_eq!(
3274            bitmaps.take_bitmaps(),
3275            Some((BitVec::from_bytes(&[0b11110000]), BitVec::from_bytes(&[0b00111000])))
3276        );
3277
3278        let mut bitmaps = OverwriteBitmaps::new(BitVec::from_bytes(&[0b11110000]));
3279        bitmaps.set_offset(4);
3280        assert_eq!(
3281            ChecksumRangeChunk::group_first_write_ranges(
3282                &mut bitmaps,
3283                block_size,
3284                block_size * 2..block_size * 5,
3285            ),
3286            vec![ChecksumRangeChunk {
3287                checksum_range: 0..3,
3288                device_range: block_size * 2..block_size * 5,
3289                is_first_write: true,
3290            }],
3291        );
3292        assert_eq!(
3293            bitmaps.take_bitmaps(),
3294            Some((BitVec::from_bytes(&[0b11110000]), BitVec::from_bytes(&[0b00001110])))
3295        );
3296
3297        let mut bitmaps = OverwriteBitmaps::new(BitVec::from_bytes(&[0b01010101]));
3298        assert_eq!(
3299            ChecksumRangeChunk::group_first_write_ranges(
3300                &mut bitmaps,
3301                block_size,
3302                block_size * 2..block_size * 10,
3303            ),
3304            vec![
3305                ChecksumRangeChunk {
3306                    checksum_range: 0..1,
3307                    device_range: block_size * 2..block_size * 3,
3308                    is_first_write: true,
3309                },
3310                ChecksumRangeChunk {
3311                    checksum_range: 1..2,
3312                    device_range: block_size * 3..block_size * 4,
3313                    is_first_write: false,
3314                },
3315                ChecksumRangeChunk {
3316                    checksum_range: 2..3,
3317                    device_range: block_size * 4..block_size * 5,
3318                    is_first_write: true,
3319                },
3320                ChecksumRangeChunk {
3321                    checksum_range: 3..4,
3322                    device_range: block_size * 5..block_size * 6,
3323                    is_first_write: false,
3324                },
3325                ChecksumRangeChunk {
3326                    checksum_range: 4..5,
3327                    device_range: block_size * 6..block_size * 7,
3328                    is_first_write: true,
3329                },
3330                ChecksumRangeChunk {
3331                    checksum_range: 5..6,
3332                    device_range: block_size * 7..block_size * 8,
3333                    is_first_write: false,
3334                },
3335                ChecksumRangeChunk {
3336                    checksum_range: 6..7,
3337                    device_range: block_size * 8..block_size * 9,
3338                    is_first_write: true,
3339                },
3340                ChecksumRangeChunk {
3341                    checksum_range: 7..8,
3342                    device_range: block_size * 9..block_size * 10,
3343                    is_first_write: false,
3344                },
3345            ],
3346        );
3347        assert_eq!(
3348            bitmaps.take_bitmaps(),
3349            Some((BitVec::from_bytes(&[0b01010101]), BitVec::from_bytes(&[0b11111111])))
3350        );
3351    }
3352
3353    #[fuchsia::test]
3354    async fn test_read_large_buffer_excessive_partitions() {
3355        let (_fs, object) = test_filesystem_and_empty_object().await;
3356
3357        // Write 5 MiB of data so that reading it spans > MAX_HASH_PARTITIONS (5 > 4 partitions).
3358        let size = 5 * 1024 * 1024;
3359        let mut buf = object.allocate_buffer(size).await;
3360        buf.as_mut_ptr_slice().fill(0xab);
3361        object.write_or_append(Some(0), buf.as_ref()).await.expect("write failed");
3362
3363        // Flush to create persistent layers with bloom filters.
3364        object.owner().flush().await.expect("flush failed");
3365
3366        // Read the entire 5 MiB buffer back.
3367        let mut read_buf = object.allocate_buffer(size).await;
3368        assert_eq!(object.read_aligned(0, read_buf.as_mut()).await.expect("read failed"), size);
3369        assert_eq!(&read_buf.as_ptr_slice().to_vec()[..], &buf.as_ptr_slice().to_vec()[..]);
3370    }
3371
3372    #[fuchsia::test]
3373    #[should_panic(expected = "Write is too large for a single transaction")]
3374    #[cfg(debug_assertions)]
3375    async fn test_multi_write_single_transaction_too_large_panics() {
3376        use super::JOURNAL_CHECKSUM_BYTES_PER_BLOCK;
3377        use crate::object_store::transaction::TRANSACTION_MAX_JOURNAL_USAGE;
3378
3379        let device = DeviceHolder::new(FakeDevice::new(32768, TEST_DEVICE_BLOCK_SIZE));
3380        let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
3381        let store = fs.root_store();
3382        let mut transaction = store
3383            .new_transaction(
3384                lock_keys![LockKey::object(
3385                    store.store_object_id(),
3386                    store.root_directory_object_id()
3387                )],
3388                Options::default(),
3389            )
3390            .await
3391            .expect("new_txn");
3392        let object =
3393            ObjectStore::create_object(&store, &mut transaction, HandleOptions::default(), None)
3394                .await
3395                .expect("create_object failed");
3396        transaction.commit().await.expect("commit");
3397
3398        // Writing enough blocks that their journal checksums alone equal
3399        // `TRANSACTION_MAX_JOURNAL_USAGE` will exceed `TRANSACTION_MAX_JOURNAL_USAGE` once the
3400        // extent record overhead (`MAX_JOURNAL_BYTES_PER_RANGE`) is added.
3401        let num_blocks = TRANSACTION_MAX_JOURNAL_USAGE as usize / JOURNAL_CHECKSUM_BYTES_PER_BLOCK;
3402        let write_len = num_blocks * fs.block_size().get() as usize;
3403        let mut buf = object.allocate_buffer(write_len).await;
3404        buf.fill(0x11);
3405        let mut transaction = object.new_transaction().await.expect("new_txn");
3406        object
3407            .multi_write(&mut transaction, AttributeId::DATA, &[0..write_len as u64], buf.as_mut())
3408            .await
3409            .expect("multi_write");
3410    }
3411}