Skip to main content

fxfs_platform_testing/fuchsia/
volumes_directory.rs

1// Copyright 2022 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::fuchsia::component::map_to_raw_status;
6use crate::fuchsia::directory::FxDirectory;
7use crate::fuchsia::errors::map_to_status;
8use crate::fuchsia::fxblob::{BlobDirectory, Identifier};
9use crate::fuchsia::memory_pressure::{MemoryPressureLevel, MemoryPressureMonitor};
10use crate::fuchsia::profile::new_profile_state;
11use crate::fuchsia::remote_volume::UnmountFn;
12use crate::fuchsia::volume::{FxVolume, FxVolumeAndRoot, MemoryPressureConfig, RootDir};
13use crate::fuchsia::{FxRemoteVolume, RemoteCrypt};
14use anyhow::{Context, Error, anyhow, ensure};
15use fidl::endpoints::{DiscoverableProtocolMarker, ServerEnd};
16use fidl_fuchsia_fs::{AdminMarker, AdminRequest, AdminRequestStream};
17use fidl_fuchsia_fs_startup::{
18    CheckOptions, CreateOptions, MountOptions, VolumeRequest, VolumeRequestStream,
19};
20use fidl_fuchsia_fxfs::{
21    self as ffxfs, DebugMarker, FileBackedVolumeProviderMarker, ProjectIdMarker,
22};
23use fidl_fuchsia_io as fio;
24use fs_inspect::{FsInspectTree, FsInspectVolume};
25use fuchsia_async as fasync;
26use futures::stream::FuturesUnordered;
27use futures::{StreamExt, TryStreamExt};
28use fxfs::errors::FxfsError;
29use fxfs::filesystem::{FlushReason, ForceMajor, FxFilesystem};
30use fxfs::fsck;
31use fxfs::log::*;
32use fxfs::object_store::transaction::{LockKey, Options, ReservationOptions, lock_keys};
33use fxfs::object_store::volume::RootVolume;
34use fxfs::object_store::{
35    Directory, NewChildStoreOptions, ObjectDescriptor, ObjectStore, StoreOptions,
36};
37use fxfs_crypto::Crypt;
38use fxfs_trace::{TraceFutureExt, trace_future_args};
39use refaults_vmo::PageFaultCounter;
40use rustc_hash::FxHashMap as HashMap;
41use std::sync::atomic::{AtomicU64, Ordering};
42use std::sync::{Arc, OnceLock, Weak};
43use vfs::directory::entry_container::MutableDirectory;
44use vfs::directory::helper::DirectlyMutable;
45const MEBIBYTE: u64 = 1024 * 1024;
46
47struct ProfileState {
48    task: fasync::Task<()>,
49    profile_name: String,
50    all_volumes: bool,
51}
52
53/// VolumesDirectory is a special pseudo-directory used to enumerate and operate on volumes.
54/// Volume creation happens via fuchsia.fs.startup.Volumes.Create, rather than open.
55///
56/// Note that VolumesDirectory assumes exclusive access to |root_volume| and if volumes are
57/// manipulated from elsewhere, strange things will happen.
58pub struct VolumesDirectory {
59    root_volume: RootVolume,
60    directory_node: Arc<vfs::directory::immutable::Simple>,
61    mounted_volumes: futures::lock::Mutex<HashMap<u64, MountedVolume>>,
62    inspect_tree: Weak<FsInspectTree>,
63    mem_monitor: Option<MemoryPressureMonitor>,
64    page_fault_counter: Arc<PageFaultCounter>,
65    // The state of profile recordings. Should be locked *after* mounted_volumes.
66    profiling_state: futures::lock::Mutex<Option<ProfileState>>,
67
68    /// A running estimate of the number of dirty bytes outstanding in all pager-backed VMOs across
69    /// all volumes.
70    pager_dirty_bytes_count: PagerDirtyByteCount,
71
72    /// Max outstanding dirty bytes under critical memory pressure. This could be hardcoded, but is
73    /// broken out for testing.
74    max_dirty_bytes_when_critical: AtomicU64,
75
76    // A callback to invoke when a volume is added.  When the volume is removed, this is called
77    // again with `None` as the second parameter.
78    on_volume_added:
79        OnceLock<Box<dyn Fn(&str, Option<(Arc<FxVolume>, Arc<ObjectStore>)>) + Send + Sync>>,
80
81    /// The cache configuration to use under different memory pressure levels.
82    memory_pressure_config: MemoryPressureConfig,
83}
84
85/// Operations on VolumesDirectory that cannot be performed concurrently (i.e. most
86/// volume creation/removal ops) should exist on this guard instead of VolumesDirectory.
87pub struct MountedVolumesGuard<'a> {
88    volumes_directory: Arc<VolumesDirectory>,
89    mounted_volumes: futures::lock::MutexGuard<'a, HashMap<u64, MountedVolume>>,
90}
91
92struct MountedVolume {
93    sequence: u64,
94    volume: FxVolumeAndRoot,
95    remote_volume: Option<Arc<FxRemoteVolume>>,
96
97    // True if the volume was forcibly locked.
98    locked: bool,
99}
100
101pub(crate) enum Mode {
102    Mount,
103    Create { guid: Option<[u8; 16]>, low_32_bit_object_ids: bool },
104}
105
106impl MountedVolumesGuard<'_> {
107    /// Creates or mounts a volume. If |crypt| is set, the volume will be created or mounted as
108    /// encrypted. The volume is mounted according to |as_blob|.
109    async fn create_or_mount_volume(
110        &mut self,
111        name: &str,
112        crypt: Option<Arc<dyn Crypt>>,
113        mode: Mode,
114        as_blob: bool,
115        use_driver_blob_paging: bool,
116    ) -> Result<FxVolumeAndRoot, Error> {
117        let store = match mode {
118            Mode::Create { guid, low_32_bit_object_ids } => self
119                .volumes_directory
120                .root_volume
121                .new_volume(
122                    name,
123                    NewChildStoreOptions {
124                        options: StoreOptions { crypt },
125                        guid,
126                        low_32_bit_object_ids,
127                        ..Default::default()
128                    },
129                )
130                .await
131                .context("failed to create new volume")?,
132            Mode::Mount => {
133                self.volumes_directory.root_volume.volume(name, StoreOptions { crypt }).await?
134            }
135        };
136        ensure!(
137            !self.mounted_volumes.contains_key(&store.store_object_id()),
138            FxfsError::AlreadyBound
139        );
140
141        let volume = if as_blob {
142            self.mount_store::<BlobDirectory>(
143                name,
144                store,
145                self.volumes_directory.memory_pressure_config,
146                use_driver_blob_paging,
147            )
148            .await?
149        } else {
150            self.mount_store::<FxDirectory>(
151                name,
152                store,
153                self.volumes_directory.memory_pressure_config,
154                false,
155            )
156            .await?
157        };
158        // If there is an ongoing startup profile activity across all volumes, apply it to the
159        // mounted volume unless this is a blob volume using driver blob paging (where pkg-cache
160        // drives blob profiling).
161        if !(as_blob && use_driver_blob_paging) {
162            if let Some(ProfileState { profile_name, all_volumes: true, .. }) =
163                &(*self.volumes_directory.profiling_state.lock().await)
164            {
165                if let Err(e) = volume
166                    .volume()
167                    .record_and_replay_profile(new_profile_state(as_blob), profile_name)
168                    .await
169                {
170                    error!(
171                        "Failed to record or replay profile '{}' for volume {}: {:?}",
172                        profile_name, name, e
173                    );
174                }
175            }
176        }
177
178        if let Mode::Create { .. } = mode {
179            let store_object_id = volume.volume().store().store_object_id();
180            self.volumes_directory.add_directory_entry(name, store_object_id);
181        }
182        Ok(volume)
183    }
184
185    pub(crate) async fn mount_remote_volume(
186        &mut self,
187        name: &str,
188        crypt: Option<Arc<dyn Crypt>>,
189        server_end: ServerEnd<ffxfs::RemoteVolumeMarker>,
190    ) -> Result<(ffxfs::VolumeInfo, ffxfs::LayerSet, [u8; 16]), Error> {
191        let store = self.volumes_directory.root_volume.volume(name, StoreOptions { crypt }).await?;
192
193        let store_object_id = store.store_object_id();
194        ensure!(!self.mounted_volumes.contains_key(&store_object_id), FxfsError::AlreadyBound);
195
196        // Wait for any initial graveyard reaping queued on volume unlock or filesystem open to
197        // finish before flushing the store, so the background reaper task cannot mutate the
198        // mutable layer concurrently with or after the flush.
199        self.volumes_directory.root_volume.filesystem().graveyard().flush().await;
200
201        // The remote volume client only receives the immutable persistent layer files via
202        // `get_layer_set()`, not the in-memory mutable layer. Flush the store first so that any
203        // mutations in the mutable layer (e.g. from journal replay on unlock or graveyard reaping)
204        // are written to a persistent layer.
205        store
206            .flush_with_reason(FlushReason::Journal(ForceMajor::False))
207            .await
208            .context("failed to flush volume")?;
209        assert_eq!(store.tree().mutable_layer().len(), 0, "Mutable layer should be empty");
210
211        let guid = store.guid();
212        let root_dir_id = store.root_directory_object_id();
213
214        let fx_volume_and_root = self
215            .mount_store::<FxDirectory>(
216                name,
217                store.clone(),
218                self.volumes_directory.memory_pressure_config,
219                false,
220            )
221            .await?;
222        let fx_volume = fx_volume_and_root.volume().clone();
223        let sequence = self.mounted_volumes.get(&store_object_id).unwrap().sequence;
224
225        let volumes_dir_weak = Arc::downgrade(&self.volumes_directory);
226        let unmount_fn: UnmountFn = Box::new(move || {
227            Box::pin(async move {
228                if let Some(volumes_dir) = volumes_dir_weak.upgrade() {
229                    let mut mounted_volumes = volumes_dir.lock().await;
230                    match mounted_volumes.mounted_volumes.get(&store_object_id) {
231                        Some(m) if m.sequence == sequence => {}
232                        _ => return Ok(()),
233                    }
234                    let root_store = volumes_dir.root_volume.volume_directory().store();
235                    let fs = root_store.filesystem();
236                    let _guard = fs
237                        .lock_manager()
238                        .txn_lock(lock_keys![LockKey::object(
239                            root_store.store_object_id(),
240                            volumes_dir.root_volume.volume_directory().object_id(),
241                        )])
242                        .await;
243                    if let Ok(volume) = mounted_volumes.unmount(store_object_id).await {
244                        volume.admin_scope().shutdown();
245                    }
246                }
247                Ok(())
248            })
249        });
250
251        let remote_vol = FxRemoteVolume::new(store.clone(), Some(fx_volume), Some(unmount_fn));
252        let initial_layers = match remote_vol.get_layer_set().await {
253            Ok(layers) => layers,
254            Err(e) => {
255                let _ = self.unmount(store_object_id).await;
256                return Err(e);
257            }
258        };
259
260        if let Some(mounted_volume) = self.mounted_volumes.get_mut(&store_object_id) {
261            mounted_volume.remote_volume = Some(remote_vol.clone());
262        }
263
264        remote_vol.serve(server_end.into_stream());
265
266        let info = ffxfs::VolumeInfo {
267            store_object_id,
268            root_directory_object_id: root_dir_id,
269            block_size: store.filesystem().block_size().get(),
270        };
271
272        Ok((info, initial_layers, guid))
273    }
274
275    /// Returns the volume if it is found and unlocked, along with a bool to indicate that it is or
276    /// isn't a blob volume.
277    async fn get_unlocked_volume_by_name(
278        &self,
279        volume_name: &str,
280    ) -> Result<(FxVolumeAndRoot, bool), zx::Status> {
281        let (store_object_id, _, _) = self
282            .volumes_directory
283            .root_volume
284            .volume_directory()
285            .lookup(volume_name)
286            .await
287            .map_err(map_to_status)?
288            .ok_or(zx::Status::NOT_FOUND)?;
289        if let Some(MountedVolume { volume, .. }) = self.mounted_volumes.get(&store_object_id) {
290            let is_blob = volume.root().clone().into_any().downcast::<BlobDirectory>().is_ok();
291            Ok((volume.clone(), is_blob))
292        } else {
293            Err(zx::Status::UNAVAILABLE)
294        }
295    }
296
297    // Verifies the integrity of `name` if it exists.  Returns Ok otherwise.
298    async fn check_volume(
299        &mut self,
300        filesystem: &FxFilesystem,
301        name: &str,
302        crypt: Option<Arc<dyn Crypt>>,
303    ) -> Result<Option<Arc<ObjectStore>>, Error> {
304        if let Ok(store) = self
305            .volumes_directory
306            .root_volume
307            .volume(name, StoreOptions { crypt: crypt.clone() })
308            .await
309        {
310            fsck::fsck_volume(filesystem, store.store_object_id(), crypt).await?;
311            Ok(Some(store))
312        } else {
313            Ok(None)
314        }
315    }
316
317    // Mounts the given store.  A lock *must* be held on the volume directory.
318    async fn mount_store<T: From<Directory<FxVolume>> + RootDir>(
319        &mut self,
320        name: &str,
321        store: Arc<ObjectStore>,
322        flush_task_config: MemoryPressureConfig,
323        use_driver_blob_paging: bool,
324    ) -> Result<FxVolumeAndRoot, Error> {
325        let unique_id = zx::Event::create();
326        let volume = FxVolumeAndRoot::new::<T>(
327            Arc::downgrade(&self.volumes_directory),
328            store,
329            unique_id.koid().unwrap().raw_koid(),
330            name.to_owned(),
331            self.volumes_directory.page_fault_counter.clone(),
332            self.volumes_directory.memory_pressure_config,
333        )
334        .await?;
335        if use_driver_blob_paging {
336            volume.volume().set_use_driver_blob_paging(true);
337        }
338        volume
339            .volume()
340            .start_background_task(flush_task_config, self.volumes_directory.mem_monitor.as_ref());
341        self.add_mount(name, &volume);
342        Ok(volume)
343    }
344
345    /// Adds a volume (`FxVolumeAndRoot`) into the mount list.
346    pub fn add_mount(&mut self, name: &str, volume: &FxVolumeAndRoot) {
347        static SEQUENCE: AtomicU64 = AtomicU64::new(0);
348        let sequence = SEQUENCE.fetch_add(1, Ordering::Relaxed);
349        self.mounted_volumes.insert(
350            volume.volume().store().store_object_id(),
351            MountedVolume { sequence, volume: volume.clone(), remote_volume: None, locked: false },
352        );
353        if let Some(inspect) = self.volumes_directory.inspect_tree.upgrade() {
354            inspect.register_volume(
355                name.to_string(),
356                Arc::downgrade(volume.volume()) as Weak<dyn FsInspectVolume + Send + Sync>,
357            )
358        }
359        if let Some(callback) = self.volumes_directory.on_volume_added.get() {
360            callback(
361                name,
362                Some((
363                    volume.volume().clone(),
364                    self.volumes_directory.root_volume.filesystem().root_store(),
365                )),
366            );
367        }
368    }
369
370    async fn lock_mount(&self, mounted_volume: &mut MountedVolume) {
371        let MountedVolume { volume, locked, .. } = mounted_volume;
372
373        if let Some(callback) = self.volumes_directory.on_volume_added.get() {
374            callback(&volume.volume().name(), None);
375        }
376        if !*locked {
377            if let Some(inspect) = self.volumes_directory.inspect_tree.upgrade() {
378                inspect.unregister_volume(volume.volume().name());
379            }
380            // We must make sure to remove the root entry which holds strong references to the
381            // volume since otherwise `Volume::try_unwrap` might fail.
382            let _ = volume.outgoing_dir().remove_entry("root", true);
383            volume.volume().terminate().await;
384            *locked = true;
385        }
386    }
387
388    async fn remove_volume(&mut self, name: &str) -> Result<(), Error> {
389        let (object_id, transaction) = self
390            .volumes_directory
391            .root_volume
392            .acquire_transaction_for_remove_volume(
393                name,
394                [],
395                false,
396                Options { reservation: ReservationOptions::Borrowed, ..Default::default() },
397            )
398            .await?;
399
400        // Cowardly refuse to delete a mounted volume.
401        ensure!(!self.mounted_volumes.contains_key(&object_id), FxfsError::AlreadyBound);
402        let directory_node = self.volumes_directory.directory_node.clone();
403        self.volumes_directory
404            .root_volume
405            .delete_volume(name, transaction, || {
406                // This shouldn't fail because the entry should exist.
407                directory_node.remove_entry(name, /* must_be_directory: */ false).unwrap();
408            })
409            .await?;
410        Ok(())
411    }
412
413    async fn terminate(&mut self) {
414        let mut volumes = std::mem::take(&mut *self.mounted_volumes);
415        for mounted_volume in volumes.values_mut() {
416            if let Some(remote_volume) = &mounted_volume.remote_volume {
417                remote_volume.shutdown();
418                remote_volume.wait().await;
419            }
420            let admin_scope = mounted_volume.volume.admin_scope();
421            admin_scope.shutdown();
422            admin_scope.wait().await;
423
424            self.lock_mount(mounted_volume).await;
425        }
426    }
427
428    // Unmounts the volume identified by `store_id`.  The caller should take locks to avoid races if
429    // necessary.
430    //
431    // NOTE: This will not terminate any connections on the admin scope.
432    pub async fn unmount(&mut self, store_id: u64) -> Result<FxVolumeAndRoot, Error> {
433        let mut mounted_volume =
434            self.mounted_volumes.remove(&store_id).ok_or(FxfsError::NotFound)?;
435        self.lock_mount(&mut mounted_volume).await;
436        Ok(mounted_volume.volume)
437    }
438
439    // Auto-unmount the volume when the last connection to the volume is closed.
440    fn auto_unmount(&self, store_id: u64) {
441        let volumes_directory = self.volumes_directory.clone();
442        let mounted_volume = self.mounted_volumes.get(&store_id).unwrap();
443        let sequence = mounted_volume.sequence;
444        let admin_scope = mounted_volume.volume.admin_scope().clone();
445        let scope = mounted_volume.volume.volume().scope().clone();
446        fasync::Task::spawn(
447            async move {
448                // Check the admin_scope first because once that has finished, there can never be
449                // any more connections to it.
450                admin_scope.wait().await;
451                scope.wait().await;
452
453                // Check that the same volume is still mounted i.e. there wasn't an explicit
454                // unmount.
455                let mut mounted_volumes = volumes_directory.lock().await;
456                match mounted_volumes.mounted_volumes.get(&store_id) {
457                    Some(m) if m.sequence == sequence => {}
458                    _ => return,
459                }
460
461                warn!(store_id; "Last connection to volume closed without unmount, shutting down");
462                let root_store = volumes_directory.root_volume.volume_directory().store();
463                let fs = root_store.filesystem();
464                let _guard = fs
465                    .lock_manager()
466                    .txn_lock(lock_keys![LockKey::object(
467                        root_store.store_object_id(),
468                        volumes_directory.root_volume.volume_directory().object_id(),
469                    )])
470                    .await;
471
472                if let Err(e) = mounted_volumes.unmount(store_id).await {
473                    warn!(e:?, store_id; "Failed to unmount volume");
474                }
475            }
476            .trace(trace_future_args!("Volume::auto_unmount")),
477        )
478        .detach();
479    }
480}
481
482impl VolumesDirectory {
483    /// Fills the VolumesDirectory with all volumes in |root_volume|.  No volume is opened during
484    /// this.
485    pub async fn new(
486        root_volume: RootVolume,
487        inspect_tree: Weak<FsInspectTree>,
488        mem_monitor: Option<MemoryPressureMonitor>,
489        page_fault_counter: Arc<PageFaultCounter>,
490        memory_pressure_config: MemoryPressureConfig,
491    ) -> Result<Arc<Self>, Error> {
492        let layer_set = root_volume.volume_directory().store().tree().layer_set();
493        let mut merger = layer_set.merger();
494        let me = Arc::new(Self {
495            root_volume,
496            directory_node: vfs::directory::immutable::simple(),
497            mounted_volumes: futures::lock::Mutex::new(HashMap::default()),
498            inspect_tree,
499            mem_monitor,
500            page_fault_counter,
501            profiling_state: futures::lock::Mutex::new(None),
502            pager_dirty_bytes_count: PagerDirtyByteCount::new(),
503            max_dirty_bytes_when_critical: AtomicU64::new(zx::system_get_physmem() / 100),
504            on_volume_added: OnceLock::new(),
505            memory_pressure_config,
506        });
507        let mut iter = me.root_volume.volume_directory().iter(&mut merger).await?;
508        while let Some((name, store_id, object_descriptor)) = iter.get() {
509            ensure!(*object_descriptor == ObjectDescriptor::Volume, FxfsError::Inconsistent);
510
511            me.add_directory_entry(&name, store_id);
512
513            iter.advance().await?;
514        }
515        Ok(me)
516    }
517
518    /// Clears the directory entry cache (dirent cache) and internal object store caches for all
519    /// mounted volumes and filesystem metadata stores.
520    pub async fn clear_caches(&self) {
521        let volumes: Vec<_> =
522            self.mounted_volumes.lock().await.values().map(|v| v.volume.volume().clone()).collect();
523        for volume in volumes {
524            volume.clear_caches();
525        }
526        let fs = self.root_volume.filesystem();
527        fs.root_store().clear_caches();
528        fs.root_parent_store().clear_caches();
529        fs.allocator().tree().clear_cache();
530    }
531
532    /// Delete a profile for a given volume. Fails if that volume isn't mounted or if there is
533    /// active profile recording or replay.
534    pub async fn delete_profile(
535        self: &Arc<Self>,
536        volume_name: &str,
537        profile_name: &str,
538    ) -> Result<(), zx::Status> {
539        // Volumes lock is taken first to provide consistent lock ordering with mounting a volume.
540        let volumes = self.mounted_volumes.lock().await;
541        let state = self.profiling_state.lock().await;
542
543        // Only allow deletion when no operations are in flight. This removes confusion around
544        // deleting a profile while one is recording with the same name, as the profile will not be
545        // available for deletion until the recording completes. This would also mean that deleting
546        // during a recording may succeed for deleting an older version but will be confusingly
547        // replaced moments later.
548        if state.is_some() {
549            warn!("Failing profile deletion while profile operations are in flight.");
550            return Err(zx::Status::SHOULD_WAIT);
551        }
552        for MountedVolume { volume, .. } in volumes.values() {
553            if volume.volume().name() == volume_name {
554                let dir = Arc::new(FxDirectory::new(
555                    None,
556                    volume.volume().get_profile_directory().await.map_err(map_to_status)?,
557                ));
558                return dir.unlink(profile_name, false).await;
559            }
560        }
561        warn!(volume_name, profile_name; "Volume not found while deleting profile");
562        Err(zx::Status::NOT_FOUND)
563    }
564
565    pub fn memory_pressure_monitor(&self) -> Option<&MemoryPressureMonitor> {
566        self.mem_monitor.as_ref()
567    }
568
569    /// Stop all ongoing replays, and complete and persist ongoing recordings.
570    pub async fn stop_profile_tasks(self: &Arc<Self>) {
571        let mut state;
572        let volumes;
573        // Take the mounted_volumes lock first to keep consistent lock ordering with other
574        // operations, but don't need to hold it for the entire operation. We need to take the
575        // profiling_state lock before the mounted_volumes lock is dropped to ensure that another
576        // thread doesn't mount a volume and start a profile task on it in between.
577        {
578            volumes = self
579                .mounted_volumes
580                .lock()
581                .await
582                .values()
583                .map(|v| v.volume.volume().clone()) // Clones of each FxVolume.
584                .collect::<Vec<Arc<FxVolume>>>();
585            state = self.profiling_state.lock().await;
586        }
587        for volume in volumes {
588            volume.stop_profile_tasks().await;
589        }
590        *state = None;
591    }
592
593    /// Record a named profile for a number of seconds, fails if there is an in flight recording or
594    /// replay. The given volume must be unlocked, if no volume is given then all volumes will be
595    /// affected and all volumes mounted during the process will also be affected.
596    pub async fn record_and_replay_profile(
597        self: &Arc<Self>,
598        volume_name: Option<String>,
599        profile_name: String,
600        duration_secs: u32,
601    ) -> Result<(), zx::Status> {
602        // Volumes lock is taken first to provide consistent lock ordering with mounting a volume.
603        let volumes = self.lock().await;
604        let mut state = self.profiling_state.lock().await;
605        if state.is_some() {
606            // Consistency in the recording and replaying cannot be ensured at the volume level
607            // if more than one operation can be in flight at a time.
608            return Err(zx::Status::SHOULD_WAIT);
609        }
610        match volume_name.as_ref() {
611            Some(volume_name) => {
612                let (volume, is_blob) = volumes.get_unlocked_volume_by_name(&volume_name).await?;
613                if is_blob && volume.volume().use_driver_blob_paging() {
614                    return Err(zx::Status::NOT_SUPPORTED);
615                }
616                if let Err(error) = volume
617                    .volume()
618                    .record_and_replay_profile(new_profile_state(is_blob), &profile_name)
619                    .await
620                {
621                    error!(
622                        error:?,
623                        profile_name = profile_name.as_str(),
624                        volume_name = volume_name.as_str();
625                        "Failed to record or replay profile",
626                    );
627                    return Err(map_to_status(error));
628                }
629            }
630            None => {
631                for MountedVolume { volume, .. } in volumes.mounted_volumes.values() {
632                    let is_blob =
633                        volume.root().clone().into_any().downcast::<BlobDirectory>().is_ok();
634                    if is_blob && volume.volume().use_driver_blob_paging() {
635                        continue;
636                    }
637                    // Just log the errors, don't stop half-way.
638                    if let Err(error) = volume
639                        .volume()
640                        .record_and_replay_profile(new_profile_state(is_blob), &profile_name)
641                        .await
642                    {
643                        error!(
644                            error:?,
645                            profile_name = profile_name.as_str(),
646                            volume_name = volume.volume().name();
647                            "Failed to record or replay profile",
648                        );
649                    }
650                }
651            }
652        }
653
654        let this = self.clone();
655        let task = fasync::Task::spawn(async move {
656            fasync::Timer::new(fasync::MonotonicDuration::from_seconds(duration_secs.into())).await;
657            this.stop_profile_tasks().await;
658        });
659        *state = Some(ProfileState { task, profile_name, all_volumes: volume_name.is_none() });
660        Ok(())
661    }
662
663    /// Replays a profile if one exists, and only records if one does not exist.
664    /// The given volume must be unlocked.
665    pub async fn replay_xor_record_profile(
666        self: &Arc<Self>,
667        volume_name: String,
668        identifier: fidl_fuchsia_fxfs::ProfileIdentifier,
669        duration_secs: u32,
670    ) -> Result<(), zx::Status> {
671        let volumes = self.lock().await;
672        let mut state = self.profiling_state.lock().await;
673        if state.is_some() {
674            return Err(zx::Status::SHOULD_WAIT);
675        }
676        let (volume, is_blob) = volumes.get_unlocked_volume_by_name(&volume_name).await?;
677        if is_blob && volume.volume().use_driver_blob_paging() {
678            return Err(zx::Status::NOT_SUPPORTED);
679        }
680
681        let (opened_node, profile_name) = match identifier {
682            fidl_fuchsia_fxfs::ProfileIdentifier::BlobHash(hash) => {
683                if !is_blob {
684                    warn!("Attempted to use a blob hash identifier on a non-blob volume");
685                    return Err(zx::Status::INVALID_ARGS);
686                }
687                let id = Identifier::from(fuchsia_hash::Hash::from(hash));
688                let blob_dir = volume
689                    .root()
690                    .clone()
691                    .into_any()
692                    .downcast::<BlobDirectory>()
693                    .map_err(|_| zx::Status::IO_DATA_INTEGRITY)?;
694                let opened = blob_dir.open_blob(&id).await.map_err(|_| zx::Status::INTERNAL)?;
695                let Some(node) = opened else {
696                    return Err(zx::Status::NOT_FOUND);
697                };
698                (node.into_dyn(), fuchsia_hash::Hash::from(hash).to_string())
699            }
700            fidl_fuchsia_fxfs::ProfileIdentifier::ObjectId(oid) => {
701                if is_blob {
702                    warn!("Attempted to use an object ID identifier on a blob volume");
703                    return Err(zx::Status::INVALID_ARGS);
704                }
705
706                let opened_node =
707                    volume.volume().open_file_by_id(oid).await.map_err(map_to_status)?;
708
709                (opened_node.into_dyn(), oid.to_string())
710            }
711            _ => return Err(zx::Status::INVALID_ARGS),
712        };
713
714        if let Err(error) =
715            volume.volume().replay_xor_record_profile(new_profile_state(is_blob), opened_node).await
716        {
717            error!(
718                error:?,
719                profile_name = profile_name.as_str(),
720                volume_name = volume_name.as_str();
721                "Failed to replay or record profile",
722            );
723            return Err(map_to_status(error));
724        }
725
726        let this = self.clone();
727        let task = fasync::Task::spawn(async move {
728            fasync::Timer::new(fasync::MonotonicDuration::from_seconds(duration_secs.into())).await;
729            this.stop_profile_tasks().await;
730        });
731        *state = Some(ProfileState { task, profile_name, all_volumes: false });
732        Ok(())
733    }
734
735    /// Returns the directory node which can be used to provide connections for e.g. enumerating
736    /// entries in the VolumesDirectory.
737    /// Directly manipulating the entries in this node will result in strange behaviour.
738    pub fn directory_node(&self) -> &Arc<vfs::directory::immutable::Simple> {
739        &self.directory_node
740    }
741
742    // This serves as an exclusive lock for operations that manipulate the set of mounted volumes.
743    pub async fn lock<'a>(self: &'a Arc<Self>) -> MountedVolumesGuard<'a> {
744        MountedVolumesGuard {
745            volumes_directory: self.clone(),
746            mounted_volumes: self.mounted_volumes.lock().await,
747        }
748    }
749
750    fn add_directory_entry(self: &Arc<Self>, name: &str, store_id: u64) {
751        let weak = Arc::downgrade(self);
752        let name_owned = Arc::new(name.to_string());
753        self.directory_node
754            .add_entry(
755                name,
756                vfs::service::host(move |requests| {
757                    let weak = weak.clone();
758                    let name = name_owned.clone();
759                    async move {
760                        if let Some(me) = weak.upgrade() {
761                            let _ =
762                                me.handle_volume_requests(name.as_ref(), requests, store_id).await;
763                        }
764                    }
765                }),
766            )
767            .unwrap();
768    }
769
770    /// Creates and mounts a new volume. If |crypt| is set, the volume will be encrypted. The
771    /// volume is mounted according to |as_blob|.
772    pub async fn create_and_mount_volume(
773        self: &Arc<Self>,
774        name: &str,
775        crypt: Option<Arc<dyn Crypt>>,
776        as_blob: bool,
777        options: CreateOptions,
778    ) -> Result<FxVolumeAndRoot, Error> {
779        self.lock()
780            .await
781            .create_or_mount_volume(
782                name,
783                crypt,
784                Mode::Create {
785                    guid: options.guid,
786                    low_32_bit_object_ids: options.restrict_inode_ids_to_32_bit.unwrap_or(false),
787                },
788                as_blob,
789                false,
790            )
791            .await
792    }
793
794    /// Mounts an existing volume. `crypt` will be used to unlock the volume if provided.
795    /// If `as_blob` is `true`, the volume will be mounted as a blob filesystem, otherwise
796    /// it will be treated as a regular fxfs volume.
797    pub async fn mount_volume(
798        self: &Arc<Self>,
799        name: &str,
800        crypt: Option<Arc<dyn Crypt>>,
801        as_blob: bool,
802    ) -> Result<FxVolumeAndRoot, Error> {
803        self.lock().await.create_or_mount_volume(name, crypt, Mode::Mount, as_blob, false).await
804    }
805
806    /// Checks the integrity of volume `name`, or succeeds silently if the volume doesn't exist.
807    pub async fn check_volume(
808        self: &Arc<Self>,
809        name: &str,
810        crypt: Option<Arc<dyn Crypt>>,
811    ) -> Result<(), Error> {
812        let fs = self.root_volume.filesystem();
813        let store = self.lock().await.check_volume(fs.as_ref(), name, crypt).await?;
814        if let Some(store) = store {
815            if store.is_unlocked() {
816                let _ = store.lock().await;
817            }
818        }
819        Ok(())
820    }
821
822    /// Removes a volume. The volume must exist but encrypted volume keys are not required.
823    pub async fn remove_volume(self: &Arc<Self>, name: &str) -> Result<(), Error> {
824        self.lock().await.remove_volume(name).await
825    }
826
827    /// Terminates all opened volumes.  This will not cancel any profiling that might be taking
828    /// place.
829    pub async fn terminate(self: &Arc<Self>) {
830        // Abort the profiling timer task.
831        let profiling_state = self.profiling_state.lock().await.take();
832        if let Some(state) = profiling_state {
833            state.task.abort().await;
834        }
835        self.lock().await.terminate().await;
836        // TODO(https://fxbug.dev/452935329): Turn this into a real assert.
837        debug_assert!(
838            self.pager_dirty_bytes_count.load() == 0,
839            "Leaked {} dirty bytes.",
840            self.pager_dirty_bytes_count.load()
841        );
842    }
843
844    /// Serves the given volume on `outgoing_dir_server_end`.
845    pub fn serve_volume(
846        self: &Arc<Self>,
847        volume: &FxVolumeAndRoot,
848        outgoing_dir_server_end: ServerEnd<fio::DirectoryMarker>,
849        as_blob: bool,
850    ) -> Result<(), Error> {
851        // A note regarding strong references to `FxVolume`: connections to services here are all on
852        // the admin scope.  When we force lock a volume, we want to keep the admin scope running
853        // but terminate the volume.  When a volume is terminated in this way, we want to ensure
854        // that there are no outstanding strong references to the volume.  With that in mind, the
855        // services here should not hold strong references.  They can hold a strong reference to
856        // VolumesDirectory and find the volume via the mount list, or they can hold a weak
857        // reference to the FxVolume.  Before upgrading the weak reference, an active guard must be
858        // acquired on the volume's scope first.  This ensures that no new strong references are
859        // taken once the volume has commenced termination.  The "root" entry just below is an
860        // exception that does hold a strong reference.  We handle that by making sure we remove
861        // that entry before we call `FxVolume::terminate`.
862
863        let outgoing_dir = volume.outgoing_dir();
864        outgoing_dir.add_entry("root", volume.root().clone().as_directory_entry())?;
865        let svc_dir = vfs::directory::immutable::simple();
866        outgoing_dir.add_entry("svc", svc_dir.clone())?;
867
868        let store_id = volume.volume().store().store_object_id();
869        let me = self.clone();
870        svc_dir.add_entry(
871            AdminMarker::PROTOCOL_NAME,
872            vfs::service::host(move |requests| {
873                let me = me.clone();
874                async move {
875                    let _ = me.handle_admin_requests(requests, store_id).await;
876                }
877            }),
878        )?;
879        let vol_scope = volume.volume().scope().clone();
880        let weak_vol = Arc::downgrade(volume.volume());
881        {
882            let vol_scope = vol_scope.clone();
883            let weak_vol = weak_vol.clone();
884            svc_dir.add_entry(
885                ProjectIdMarker::PROTOCOL_NAME,
886                vfs::service::host(move |requests| {
887                    let weak_vol = weak_vol.clone();
888                    let scope = vol_scope.clone();
889                    async move {
890                        let _ =
891                            FxVolume::handle_project_id_requests(weak_vol, scope, requests).await;
892                    }
893                }),
894            )?;
895        }
896        svc_dir.add_entry(
897            FileBackedVolumeProviderMarker::PROTOCOL_NAME,
898            vfs::service::host(move |requests| {
899                let weak_vol = weak_vol.clone();
900                let scope = vol_scope.clone();
901                async move {
902                    let _ = FxVolume::handle_file_backed_volume_provider_requests(
903                        weak_vol, scope, requests,
904                    )
905                    .await;
906                }
907            }),
908        )?;
909        {
910            let vol_scope = volume.volume().scope().clone();
911            let weak_vol = Arc::downgrade(volume.volume());
912            svc_dir.add_entry(
913                DebugMarker::PROTOCOL_NAME,
914                vfs::service::host(move |requests| {
915                    let weak_vol = weak_vol.clone();
916                    let scope = vol_scope.clone();
917                    async move {
918                        let _ = FxVolume::handle_debug_requests(weak_vol, scope, requests).await;
919                    }
920                }),
921            )?;
922        }
923        volume.root().clone().register_additional_volume_services(&svc_dir)?;
924
925        let scope = volume.admin_scope().clone();
926        let mut flags = fio::PERM_READABLE | fio::PERM_WRITABLE;
927        if as_blob {
928            flags |= fio::PERM_EXECUTABLE;
929        }
930        vfs::directory::serve_on(Arc::clone(outgoing_dir), flags, scope, outgoing_dir_server_end);
931
932        info!(
933            store_id;
934            "Serving volume, pager port koid={}",
935            fasync::EHandle::local().port().koid().unwrap().raw_koid()
936        );
937        Ok(())
938    }
939
940    /// Creates and serves the volume with the given name.
941    pub async fn create_and_serve_volume(
942        self: &Arc<Self>,
943        name: &str,
944        outgoing_directory_server_end: ServerEnd<fio::DirectoryMarker>,
945        mount_options: MountOptions,
946        create_options: CreateOptions,
947    ) -> Result<(), Error> {
948        let mut guard = self.lock().await;
949        let device = self.root_volume.filesystem().device();
950        let crypt = mount_options
951            .crypt
952            .map(|crypt| Arc::new(RemoteCrypt::new_with_device(crypt, device)) as Arc<dyn Crypt>);
953        let as_blob = mount_options.as_blob.unwrap_or(false);
954        let use_driver_blob_paging = mount_options.use_driver_blob_paging.unwrap_or(false);
955        let guid = create_options.guid;
956        let low_32_bit_object_ids = create_options.restrict_inode_ids_to_32_bit.unwrap_or(false);
957        let volume = guard
958            .create_or_mount_volume(
959                name,
960                crypt,
961                Mode::Create { guid, low_32_bit_object_ids },
962                as_blob,
963                use_driver_blob_paging,
964            )
965            .await?;
966        self.serve_volume(&volume, outgoing_directory_server_end, as_blob)
967            .context("failed to serve volume")?;
968        guard.auto_unmount(volume.volume().store().store_object_id());
969        Ok(())
970    }
971
972    pub async fn mount_remote_volume(
973        self: &Arc<Self>,
974        name: &str,
975        crypt: Option<Arc<dyn Crypt>>,
976        server_end: ServerEnd<ffxfs::RemoteVolumeMarker>,
977    ) -> Result<(ffxfs::VolumeInfo, ffxfs::LayerSet, [u8; 16]), Error> {
978        self.lock().await.mount_remote_volume(name, crypt, server_end).await
979    }
980
981    async fn handle_volume_requests(
982        self: &Arc<Self>,
983        name: &str,
984        mut requests: VolumeRequestStream,
985        store_id: u64,
986    ) -> Result<(), Error> {
987        while let Some(request) = requests.try_next().await? {
988            match request {
989                VolumeRequest::Check { responder, options } => {
990                    async move {
991                        responder.send(self.handle_check(store_id, options).await.map_err(
992                            |error| {
993                                error!(error:?, store_id; "Failed to check volume");
994                                map_to_raw_status(error)
995                            },
996                        ))
997                    }
998                    .trace(trace_future_args!("Volume::Check"))
999                    .await?;
1000                }
1001                VolumeRequest::Mount { responder, outgoing_directory, options } => {
1002                    async move {
1003                        responder.send(
1004                            self.handle_mount(name, store_id, outgoing_directory, options)
1005                                .await
1006                                .map_err(|error| {
1007                                    error!(error:?, name, store_id; "Failed to mount volume");
1008                                    map_to_raw_status(error)
1009                                }),
1010                        )
1011                    }
1012                    .trace(trace_future_args!("Volume::Mount"))
1013                    .await?;
1014                }
1015                VolumeRequest::SetLimit { responder, bytes } => {
1016                    async move {
1017                        responder.send(self.handle_set_limit(store_id, bytes).await.map_err(
1018                            |error| {
1019                                error!(error:?, store_id; "Failed to set volume limit");
1020                                map_to_raw_status(error)
1021                            },
1022                        ))
1023                    }
1024                    .trace(trace_future_args!("Volume::SetLimit"))
1025                    .await?;
1026                }
1027                VolumeRequest::GetLimit { responder } => {
1028                    fxfs_trace::duration!("Volume::GetLimit");
1029                    responder.send(Ok(self.handle_get_limit(store_id)))?
1030                }
1031                VolumeRequest::GetInfo { responder } => {
1032                    async move {
1033                        let result = self.handle_get_info(store_id).await.map(|guid| {
1034                            fidl_fuchsia_fs_startup::VolumeInfo {
1035                                guid: Some(guid),
1036                                ..Default::default()
1037                            }
1038                        });
1039                        match result {
1040                            Ok(response) => responder.send(Ok(&response)),
1041                            Err(error) => {
1042                                error!(error:?, store_id; "Failed to get volume info");
1043                                responder.send(Err(map_to_raw_status(error)))
1044                            }
1045                        }
1046                    }
1047                    .trace(trace_future_args!("Volume::GetInfo"))
1048                    .await?;
1049                }
1050                VolumeRequest::MountRemote { responder, options, volume } => {
1051                    async move {
1052                        let result =
1053                            self.handle_mount_remote(name, store_id, options, volume).await;
1054                        match result {
1055                            Ok((info, initial_layers, guid)) => {
1056                                responder.send(Ok((info, initial_layers, &guid)))
1057                            }
1058                            Err(error) => {
1059                                error!(error:?, name, store_id; "Failed to mount remote volume");
1060                                responder.send(Err(map_to_raw_status(error)))
1061                            }
1062                        }
1063                    }
1064                    .trace(trace_future_args!("Volume::MountRemote"))
1065                    .await?;
1066                }
1067            }
1068        }
1069        Ok(())
1070    }
1071
1072    pub fn memory_pressure_config(&self) -> &MemoryPressureConfig {
1073        &self.memory_pressure_config
1074    }
1075
1076    fn is_flush_required_to_dirty(&self, byte_count: u64) -> bool {
1077        let mem_pressure = self
1078            .mem_monitor
1079            .as_ref()
1080            .map(|mem_monitor| mem_monitor.level())
1081            .unwrap_or(MemoryPressureLevel::Normal);
1082        if !matches!(mem_pressure, MemoryPressureLevel::Critical) {
1083            return false;
1084        }
1085
1086        let total_dirty = self.pager_dirty_bytes_count.load();
1087        total_dirty + byte_count >= self.max_dirty_bytes_when_critical.load(Ordering::Relaxed)
1088    }
1089
1090    /// Reports that a certain number of bytes will be dirtied in a pager-backed VMO. If the memory
1091    /// pressure level is critical and fxfs has lots of dirty pages then a new task will be spawned
1092    /// in `volume` to flush the dirty pages before `mark_dirty` is called. If the memory pressure
1093    /// level is not critical then `mark_dirty` will be synchronously called.
1094    pub fn report_pager_dirty(
1095        self: Arc<Self>,
1096        byte_count: u64,
1097        volume: Arc<FxVolume>,
1098        mark_dirty: impl FnOnce() + Send + 'static,
1099    ) {
1100        if !self.is_flush_required_to_dirty(byte_count) {
1101            self.pager_dirty_bytes_count.fetch_add(byte_count);
1102            mark_dirty();
1103        } else {
1104            volume.spawn(
1105                async move {
1106                    let volumes = self.mounted_volumes.lock().await;
1107
1108                    // Re-check the number of outstanding pager dirty bytes because another thread
1109                    // could have raced and flushed the volumes first.
1110                    if self.is_flush_required_to_dirty(byte_count) {
1111                        debug!(
1112                            "Flushing all volumes. Memory pressure is critical & dirty pager bytes \
1113                            ({} MiB) >= limit ({} MiB)",
1114                            self.pager_dirty_bytes_count.load() / MEBIBYTE,
1115                            self.max_dirty_bytes_when_critical.load(Ordering::Relaxed) / MEBIBYTE
1116                        );
1117
1118                        let flushes = FuturesUnordered::new();
1119                        for MountedVolume { volume, .. } in volumes.values() {
1120                            let vol = volume.volume().clone();
1121                            flushes.push(async move {
1122                                vol.minimize_memory().await;
1123                            });
1124                        }
1125
1126                        flushes.collect::<()>().await;
1127                    }
1128                    self.pager_dirty_bytes_count.fetch_add(byte_count);
1129                    mark_dirty();
1130                }
1131                .trace(trace_future_args!("flush-before-mark-dirty")),
1132            )
1133        }
1134    }
1135
1136    /// Reports that a certain number of bytes were cleaned in a pager-backed VMO.
1137    pub fn report_pager_clean(&self, byte_count: u64) {
1138        let prev_dirty = self.pager_dirty_bytes_count.fetch_sub(byte_count);
1139        // TODO(https://fxbug.dev/452935329): Turn this into a real assert.
1140        debug_assert!(prev_dirty >= byte_count, "Underflowed dirty bytes.");
1141
1142        if prev_dirty < byte_count {
1143            // An unlikely scenario, but if there was an underflow, reset the pager dirty bytes to
1144            // zero.
1145            self.pager_dirty_bytes_count.store(0);
1146        }
1147    }
1148
1149    async fn handle_check(
1150        self: &Arc<Self>,
1151        store_id: u64,
1152        options: CheckOptions,
1153    ) -> Result<(), Error> {
1154        let fs = self.root_volume.filesystem();
1155        let crypt = if let Some(crypt) = options.crypt {
1156            Some(Arc::new(RemoteCrypt::new_with_device(crypt, fs.device())) as Arc<dyn Crypt>)
1157        } else {
1158            None
1159        };
1160        let result = fsck::fsck_volume(fs.as_ref(), store_id, crypt).await?;
1161        // TODO(b/311550633): Stash result in inspect.
1162        info!(store_id:%; "{result:?}");
1163        Ok(())
1164    }
1165
1166    async fn handle_set_limit(self: &Arc<Self>, store_id: u64, bytes: u64) -> Result<(), Error> {
1167        let fs = self.root_volume.filesystem();
1168        if fs.allocator().get_owner_bytes_limit(store_id) == Some(bytes) {
1169            return Ok(());
1170        }
1171        let mut transaction = self
1172            .root_volume
1173            .volume_directory()
1174            .store()
1175            .new_transaction(lock_keys![], Options::default())
1176            .await?;
1177        fs.allocator().set_bytes_limit(&mut transaction, store_id, bytes)?;
1178        transaction.commit().await?;
1179        Ok(())
1180    }
1181
1182    fn handle_get_limit(self: &Arc<Self>, store_id: u64) -> u64 {
1183        let fs = self.root_volume.filesystem();
1184        fs.allocator().get_owner_bytes_limit(store_id).unwrap_or_default()
1185    }
1186
1187    async fn handle_get_info(self: &Arc<Self>, store_id: u64) -> Result<[u8; 16], Error> {
1188        let fs = self.root_volume.filesystem();
1189        let store =
1190            fs.object_manager().store(store_id).ok_or_else(|| anyhow!("Store not found"))?;
1191        Ok(store.guid())
1192    }
1193
1194    async fn handle_mount(
1195        self: &Arc<Self>,
1196        name: &str,
1197        store_id: u64,
1198        outgoing_directory_server_end: ServerEnd<fio::DirectoryMarker>,
1199        options: MountOptions,
1200    ) -> Result<(), Error> {
1201        info!(name:%, store_id:%, options:?; "Received mount request");
1202        let device = self.root_volume.filesystem().device();
1203        let crypt = options
1204            .crypt
1205            .map(|crypt| Arc::new(RemoteCrypt::new_with_device(crypt, device)) as Arc<dyn Crypt>);
1206        let as_blob = options.as_blob.unwrap_or(false);
1207        let use_driver_blob_paging = options.use_driver_blob_paging.unwrap_or(false);
1208        let mut guard = self.lock().await;
1209        let volume = guard
1210            .create_or_mount_volume(name, crypt, Mode::Mount, as_blob, use_driver_blob_paging)
1211            .await
1212            .context("failed to mount volume")?;
1213        self.serve_volume(&volume, outgoing_directory_server_end, as_blob)
1214            .context("failed to serve volume")?;
1215        guard.auto_unmount(volume.volume().store().store_object_id());
1216        Ok(())
1217    }
1218
1219    async fn handle_mount_remote(
1220        self: &Arc<Self>,
1221        name: &str,
1222        store_id: u64,
1223        options: MountOptions,
1224        volume: ServerEnd<ffxfs::RemoteVolumeMarker>,
1225    ) -> Result<(ffxfs::VolumeInfo, ffxfs::LayerSet, [u8; 16]), Error> {
1226        info!(name:%, store_id:%, options:?; "Received mount remote request");
1227        let device = self.root_volume.filesystem().device();
1228        let crypt = options
1229            .crypt
1230            .map(|crypt| Arc::new(RemoteCrypt::new_with_device(crypt, device)) as Arc<dyn Crypt>);
1231        self.mount_remote_volume(name, crypt, volume).await
1232    }
1233
1234    async fn handle_admin_requests(
1235        self: &Arc<Self>,
1236        mut stream: AdminRequestStream,
1237        store_id: u64,
1238    ) -> Result<(), Error> {
1239        // If the Admin protocol ever supports more methods, this should change to a while.
1240        if let Some(request) = stream.try_next().await.context("Reading request")? {
1241            match request {
1242                AdminRequest::Shutdown { responder } => {
1243                    info!(store_id; "Received shutdown request for volume");
1244
1245                    let root_store = self.root_volume.volume_directory().store();
1246                    let fs = root_store.filesystem();
1247                    let _guard = fs
1248                        .lock_manager()
1249                        .txn_lock(lock_keys![LockKey::object(
1250                            root_store.store_object_id(),
1251                            self.root_volume.volume_directory().object_id(),
1252                        )])
1253                        .await;
1254
1255                    let maybe_volume = self.lock().await.unmount(store_id).await;
1256                    responder
1257                        .send()
1258                        .unwrap_or_else(|e| warn!("Failed to send shutdown response: {}", e));
1259
1260                    if let Ok(volume) = maybe_volume {
1261                        // NOTE: After calling this, this task might be dropped at the next await
1262                        // point.
1263                        volume.admin_scope().shutdown();
1264                    }
1265
1266                    return Ok(());
1267                }
1268            }
1269        }
1270        Ok(())
1271    }
1272
1273    /// Sets a callback which is invoked when a volume is added.  When the volume is removed, this
1274    /// is called again with `None` as the second parameter. The root store is included along with
1275    /// volume so the volume's layers can be accessed. Note that this can only be set once per
1276    /// VolumesDirectory; repeated calls will panic.
1277    pub fn set_on_mount_callback<
1278        F: Fn(&str, Option<(Arc<FxVolume>, Arc<ObjectStore>)>) + Send + Sync + 'static,
1279    >(
1280        &self,
1281        callback: F,
1282    ) {
1283        self.on_volume_added.set(Box::new(callback)).ok().unwrap();
1284    }
1285
1286    pub async fn install_volume(
1287        self: &Arc<Self>,
1288        src: &str,
1289        image_file: &str,
1290        dst: &str,
1291    ) -> Result<(), Error> {
1292        let guard = self.lock().await;
1293        info!("installing {src}/{image_file} -> {dst}");
1294        for MountedVolume { volume, .. } in guard.mounted_volumes.values() {
1295            if volume.volume().name() == src {
1296                return Err(zx::Status::ALREADY_BOUND)
1297                    .with_context(|| format!("volume {src} is already mounted"));
1298            }
1299            if volume.volume().name() == dst {
1300                return Err(zx::Status::ALREADY_BOUND)
1301                    .with_context(|| format!("volume {dst} is already mounted"));
1302            }
1303        }
1304        guard.volumes_directory.root_volume.install_volume(&src, &image_file, &dst).await?;
1305
1306        // The above function ensures that we've deleted `src` and `dst` now exists. Before we
1307        // release `guard`, we need to update the entries in the volumes directory accordingly.
1308        guard
1309            .volumes_directory
1310            .directory_node()
1311            .remove_entry(src, /* must_be_directory: */ false)
1312            .unwrap();
1313        guard
1314            .volumes_directory
1315            .directory_node()
1316            .remove_entry(dst, /* must_be_directory: */ false)
1317            .unwrap();
1318        let new_dst_object_id =
1319            match guard.volumes_directory.root_volume.volume_directory().lookup(dst).await? {
1320                Some((object_id, ObjectDescriptor::Volume, _)) => Ok(object_id),
1321                Some(_) => Err(FxfsError::Inconsistent),
1322                None => Err(FxfsError::NotFound),
1323            }?;
1324        self.add_directory_entry(dst, new_dst_object_id);
1325
1326        info!("install complete");
1327        Ok(())
1328    }
1329}
1330
1331#[cfg(test)]
1332pub(crate) fn serve_startup_volume_proxy(
1333    volumes_directory: &Arc<VolumesDirectory>,
1334    volume_name: &str,
1335) -> (fidl_fuchsia_fs_startup::VolumeProxy, vfs::ExecutionScope) {
1336    use vfs::ToObjectRequest;
1337    use vfs::service::ServiceLike;
1338    let scope = vfs::ExecutionScope::new();
1339    let entry = volumes_directory.directory_node().get_entry(volume_name).unwrap();
1340    let service = entry.into_any().downcast::<vfs::service::Service>().unwrap();
1341    let (proxy, server) = fidl::endpoints::create_proxy::<fidl_fuchsia_fs_startup::VolumeMarker>();
1342    service
1343        .connect(
1344            scope.clone(),
1345            Default::default(),
1346            &mut fio::Flags::PROTOCOL_SERVICE.to_object_request(server),
1347        )
1348        .unwrap();
1349    (proxy, scope)
1350}
1351
1352struct PagerDirtyByteCount(AtomicU64);
1353
1354impl PagerDirtyByteCount {
1355    pub fn new() -> Self {
1356        Self(AtomicU64::new(0))
1357    }
1358
1359    pub fn fetch_add(&self, value: u64) -> u64 {
1360        let prev = self.0.fetch_add(value, Ordering::Relaxed);
1361        fxfs_trace::counter!("dirty-bytes", 0, "total" => prev.saturating_add(value));
1362        prev
1363    }
1364
1365    pub fn fetch_sub(&self, value: u64) -> u64 {
1366        let prev = self.0.fetch_sub(value, Ordering::Relaxed);
1367        fxfs_trace::counter!("dirty-bytes", 0, "total" => prev.saturating_sub(value));
1368        prev
1369    }
1370
1371    pub fn load(&self) -> u64 {
1372        self.0.load(Ordering::Relaxed)
1373    }
1374
1375    pub fn store(&self, value: u64) {
1376        self.0.store(value, Ordering::Relaxed);
1377        fxfs_trace::counter!("dirty-bytes", 0, "total" => value);
1378    }
1379}
1380
1381#[cfg(test)]
1382mod tests {
1383    use super::{Mode, serve_startup_volume_proxy};
1384    use crate::fuchsia::RemoteCrypt;
1385    use crate::fuchsia::memory_pressure::MemoryPressureLevel;
1386    use crate::fuchsia::testing::{
1387        self, TestFixture, close_file_checked, open_dir_checked, open_file_checked,
1388    };
1389    use crate::fuchsia::volume::MemoryPressureConfig;
1390    use crate::fuchsia::volumes_directory::VolumesDirectory;
1391    use crate::testing::TestFixtureOptions;
1392    use fidl::endpoints::{DiscoverableProtocolMarker, create_proxy, create_request_stream};
1393    use fidl_fuchsia_fs::AdminMarker;
1394    use fidl_fuchsia_fs_startup::{CreateOptions, MountOptions, VolumeProxy};
1395    use fidl_fuchsia_fxfs as ffxfs;
1396    use fidl_fuchsia_fxfs::{
1397        CryptRequest, DebugMarker, FxfsKey, KeyPurpose, ProfileIdentifier, WrappedKey,
1398    };
1399    use fidl_fuchsia_io as fio;
1400    use fuchsia_async as fasync;
1401    use fuchsia_async::TimeoutExt;
1402    use fuchsia_component_client::connect_to_protocol_at_dir_svc;
1403    use fuchsia_fs::file;
1404    use futures::{TryStreamExt, join};
1405    use fxfs::errors::FxfsError;
1406    use fxfs::filesystem::{
1407        FlushReason, ForceMajor, FxFilesystem, FxFilesystemBuilder, OpenFxFilesystem,
1408    };
1409    use fxfs::fsck::{FsckOptions, fsck, fsck_volume_with_options, fsck_with_options};
1410    use fxfs::lock_keys;
1411    use fxfs::object_handle::ObjectHandle;
1412    use fxfs::object_store::allocator::Allocator;
1413    use fxfs::object_store::transaction::{LockKey, Options};
1414    use fxfs::object_store::volume::root_volume;
1415    use fxfs::object_store::{
1416        AttributeId, AttributeKey, NewChildStoreOptions, ObjectDescriptor, ObjectKey, ObjectStore,
1417        ObjectValue,
1418    };
1419    use fxfs_crypto::Crypt;
1420    use fxfs_insecure_crypto::new_insecure_crypt;
1421    use refaults_vmo::PageFaultCounter;
1422    use std::sync::atomic::Ordering;
1423    use std::sync::{Arc, Weak};
1424    use std::time::Duration;
1425    use storage_device::DeviceHolder;
1426    use storage_device::fake_device::FakeDevice;
1427    use storage_units::{BlockSize, page_size};
1428    use vfs::execution_scope::ExecutionScope;
1429    use vfs::temp_clone::{TempClonable, unblock};
1430    use zx::Status;
1431    async fn write_image_to_file(image: DeviceHolder, file: fio::FileProxy) {
1432        file.resize(image.size()).await.unwrap().expect("resize failed");
1433        let vmo = TempClonable::new(
1434            file.get_backing_memory(fio::VmoFlags::SHARED_BUFFER | fio::VmoFlags::WRITE)
1435                .await
1436                .unwrap()
1437                .expect("get backing memory failed"),
1438        );
1439
1440        const CHUNK_READ_SIZE: usize = 131_072; /* 128 KiB */
1441        let mut buff = image.allocate_buffer(CHUNK_READ_SIZE).await;
1442        let total = image.size();
1443        let mut offset = 0;
1444        while offset < total {
1445            let amount = std::cmp::min(total - offset, CHUNK_READ_SIZE as u64);
1446            image.read(offset, buff.as_mut()).await.expect("image read failed");
1447            {
1448                // *NOTE*: We have to unblock our write to the VMO since it's pager backed and could
1449                // be running on the same thread as the filesystem is.
1450                let vmo = vmo.temp_clone();
1451                let data = buff.subslice(0..amount as usize).to_vec();
1452                let offset = offset;
1453                unblock(move || vmo.write(&data, offset)).await.expect("vmo write failed");
1454            }
1455            offset += amount;
1456        }
1457        assert_eq!(offset, total);
1458        file.sync().await.unwrap().expect("sync failed");
1459        file.close().await.unwrap().expect("close failed");
1460    }
1461
1462    #[fuchsia::test]
1463    async fn test_volume_creation() {
1464        let device = DeviceHolder::new(FakeDevice::new(8192, 512));
1465        let filesystem = FxFilesystem::new_empty(device).await.unwrap();
1466        let page_fault_counter =
1467            Arc::new(PageFaultCounter::new().expect("Failed to create PageFaultCounter"));
1468        let volumes_directory = VolumesDirectory::new(
1469            root_volume(filesystem.clone()).await.unwrap(),
1470            Weak::new(),
1471            None,
1472            page_fault_counter,
1473            MemoryPressureConfig::default(),
1474        )
1475        .await
1476        .unwrap();
1477
1478        let crypt = Arc::new(new_insecure_crypt()) as Arc<dyn Crypt>;
1479        {
1480            let vol = volumes_directory
1481                .create_and_mount_volume(
1482                    "encrypted",
1483                    Some(crypt.clone()),
1484                    false,
1485                    CreateOptions::default(),
1486                )
1487                .await
1488                .expect("create encrypted volume failed");
1489            vol.volume().store().store_object_id()
1490        };
1491
1492        volumes_directory.terminate().await;
1493        std::mem::drop(volumes_directory);
1494        filesystem.close().await.expect("close filesystem failed");
1495        let device = filesystem.take_device().await;
1496        device.reopen(false);
1497        let filesystem = FxFilesystem::open(device).await.unwrap();
1498        let page_fault_counter =
1499            Arc::new(PageFaultCounter::new().expect("Failed to create PageFaultCounter"));
1500        let volumes_directory = VolumesDirectory::new(
1501            root_volume(filesystem.clone()).await.unwrap(),
1502            Weak::new(),
1503            None,
1504            page_fault_counter,
1505            MemoryPressureConfig::default(),
1506        )
1507        .await
1508        .unwrap();
1509
1510        let error = volumes_directory
1511            .create_and_mount_volume(
1512                "encrypted",
1513                Some(crypt.clone()),
1514                false,
1515                CreateOptions::default(),
1516            )
1517            .await
1518            .err()
1519            .expect("Creating existing encrypted volume should fail");
1520        assert!(FxfsError::AlreadyExists.matches(&error));
1521    }
1522
1523    #[fuchsia::test]
1524    async fn test_dirty_pages_accumulate_in_parent() {
1525        let device = DeviceHolder::new(FakeDevice::new(8192, 512));
1526        let filesystem = FxFilesystem::new_empty(device).await.unwrap();
1527        let page_fault_counter =
1528            Arc::new(PageFaultCounter::new().expect("Failed to create PageFaultCounter"));
1529        let volumes_directory = VolumesDirectory::new(
1530            root_volume(filesystem.clone()).await.unwrap(),
1531            Weak::new(),
1532            None,
1533            page_fault_counter,
1534            MemoryPressureConfig::default(),
1535        )
1536        .await
1537        .unwrap();
1538
1539        let crypt = Arc::new(new_insecure_crypt()) as Arc<dyn Crypt>;
1540        let vol = volumes_directory
1541            .create_and_mount_volume(
1542                "encrypted",
1543                Some(crypt.clone()),
1544                false,
1545                CreateOptions::default(),
1546            )
1547            .await
1548            .expect("create encrypted volume failed");
1549        let old_dirty = volumes_directory.pager_dirty_bytes_count.load();
1550
1551        let new_dirty = {
1552            let (root, server_end) = create_proxy::<fio::DirectoryMarker>();
1553            vol.root().clone().serve(fio::PERM_READABLE | fio::PERM_WRITABLE, server_end);
1554            let f = open_file_checked(
1555                &root,
1556                "foo",
1557                fio::Flags::FLAG_MAYBE_CREATE
1558                    | fio::PERM_READABLE
1559                    | fio::PERM_WRITABLE
1560                    | fio::Flags::PROTOCOL_FILE,
1561                &Default::default(),
1562            )
1563            .await;
1564            let buf = vec![0xaa as u8; 8192];
1565            file::write(&f, buf.as_slice()).await.expect("Write");
1566            // It's important to check the dirty bytes before closing the file, as closing can
1567            // trigger a flush.
1568            volumes_directory.pager_dirty_bytes_count.load()
1569        };
1570        assert_ne!(old_dirty, new_dirty);
1571
1572        volumes_directory.terminate().await;
1573        std::mem::drop(volumes_directory);
1574        filesystem.close().await.expect("close filesystem failed");
1575    }
1576
1577    #[fuchsia::test]
1578    async fn test_volume_reopen() {
1579        let device = DeviceHolder::new(FakeDevice::new(8192, 512));
1580        let filesystem = FxFilesystem::new_empty(device).await.unwrap();
1581        let page_fault_counter =
1582            Arc::new(PageFaultCounter::new().expect("Failed to create PageFaultCounter"));
1583        let volumes_directory = VolumesDirectory::new(
1584            root_volume(filesystem.clone()).await.unwrap(),
1585            Weak::new(),
1586            None,
1587            page_fault_counter,
1588            MemoryPressureConfig::default(),
1589        )
1590        .await
1591        .unwrap();
1592
1593        let crypt = Arc::new(new_insecure_crypt()) as Arc<dyn Crypt>;
1594        let volume_id = {
1595            let vol = volumes_directory
1596                .create_and_mount_volume(
1597                    "encrypted",
1598                    Some(crypt.clone()),
1599                    false,
1600                    CreateOptions::default(),
1601                )
1602                .await
1603                .expect("create encrypted volume failed");
1604            vol.volume().store().store_object_id()
1605        };
1606
1607        volumes_directory.terminate().await;
1608        std::mem::drop(volumes_directory);
1609        filesystem.close().await.expect("close filesystem failed");
1610        let device = filesystem.take_device().await;
1611        device.reopen(false);
1612        let filesystem = FxFilesystem::open(device).await.unwrap();
1613        let page_fault_counter =
1614            Arc::new(PageFaultCounter::new().expect("Failed to create PageFaultCounter"));
1615        let volumes_directory = VolumesDirectory::new(
1616            root_volume(filesystem.clone()).await.unwrap(),
1617            Weak::new(),
1618            None,
1619            page_fault_counter,
1620            MemoryPressureConfig::default(),
1621        )
1622        .await
1623        .unwrap();
1624
1625        {
1626            let vol = volumes_directory
1627                .mount_volume("encrypted", Some(crypt.clone()), false)
1628                .await
1629                .expect("open existing encrypted volume failed");
1630            assert_eq!(vol.volume().store().store_object_id(), volume_id);
1631        }
1632
1633        volumes_directory.terminate().await;
1634        std::mem::drop(volumes_directory);
1635        filesystem.close().await.expect("close filesystem failed");
1636    }
1637
1638    #[fuchsia::test]
1639    async fn test_volume_creation_unencrypted() {
1640        let device = DeviceHolder::new(FakeDevice::new(8192, 512));
1641        let filesystem = FxFilesystem::new_empty(device).await.unwrap();
1642        let page_fault_counter =
1643            Arc::new(PageFaultCounter::new().expect("Failed to create PageFaultCounter"));
1644        let volumes_directory = VolumesDirectory::new(
1645            root_volume(filesystem.clone()).await.unwrap(),
1646            Weak::new(),
1647            None,
1648            page_fault_counter,
1649            MemoryPressureConfig::default(),
1650        )
1651        .await
1652        .unwrap();
1653
1654        {
1655            let vol = volumes_directory
1656                .create_and_mount_volume("unencrypted", None, false, CreateOptions::default())
1657                .await
1658                .expect("create unencrypted volume failed");
1659            vol.volume().store().store_object_id()
1660        };
1661
1662        volumes_directory.terminate().await;
1663        std::mem::drop(volumes_directory);
1664        filesystem.close().await.expect("close filesystem failed");
1665        let device = filesystem.take_device().await;
1666        device.reopen(false);
1667        let filesystem = FxFilesystem::open(device).await.unwrap();
1668        let page_fault_counter =
1669            Arc::new(PageFaultCounter::new().expect("Failed to create PageFaultCounter"));
1670        let volumes_directory = VolumesDirectory::new(
1671            root_volume(filesystem.clone()).await.unwrap(),
1672            Weak::new(),
1673            None,
1674            page_fault_counter,
1675            MemoryPressureConfig::default(),
1676        )
1677        .await
1678        .unwrap();
1679
1680        let error = volumes_directory
1681            .create_and_mount_volume("unencrypted", None, false, CreateOptions::default())
1682            .await
1683            .err()
1684            .expect("Creating existing unencrypted volume should fail");
1685        assert!(FxfsError::AlreadyExists.matches(&error));
1686
1687        volumes_directory.terminate().await;
1688        std::mem::drop(volumes_directory);
1689        filesystem.close().await.expect("close filesystem failed");
1690    }
1691
1692    #[fuchsia::test]
1693    async fn test_volume_reopen_unencrypted() {
1694        let device = DeviceHolder::new(FakeDevice::new(8192, 512));
1695        let filesystem = FxFilesystem::new_empty(device).await.unwrap();
1696        let page_fault_counter =
1697            Arc::new(PageFaultCounter::new().expect("Failed to create PageFaultCounter"));
1698        let volumes_directory = VolumesDirectory::new(
1699            root_volume(filesystem.clone()).await.unwrap(),
1700            Weak::new(),
1701            None,
1702            page_fault_counter,
1703            MemoryPressureConfig::default(),
1704        )
1705        .await
1706        .unwrap();
1707
1708        let volume_id = {
1709            let vol = volumes_directory
1710                .create_and_mount_volume("unencrypted", None, false, CreateOptions::default())
1711                .await
1712                .expect("create unencrypted volume failed");
1713            vol.volume().store().store_object_id()
1714        };
1715
1716        volumes_directory.terminate().await;
1717        std::mem::drop(volumes_directory);
1718        filesystem.close().await.expect("close filesystem failed");
1719        let device = filesystem.take_device().await;
1720        device.reopen(false);
1721        let filesystem = FxFilesystem::open(device).await.unwrap();
1722        let page_fault_counter =
1723            Arc::new(PageFaultCounter::new().expect("Failed to create PageFaultCounter"));
1724        let volumes_directory = VolumesDirectory::new(
1725            root_volume(filesystem.clone()).await.unwrap(),
1726            Weak::new(),
1727            None,
1728            page_fault_counter,
1729            MemoryPressureConfig::default(),
1730        )
1731        .await
1732        .unwrap();
1733
1734        {
1735            let vol = volumes_directory
1736                .mount_volume("unencrypted", None, false)
1737                .await
1738                .expect("open existing unencrypted volume failed");
1739            assert_eq!(vol.volume().store().store_object_id(), volume_id);
1740        }
1741
1742        volumes_directory.terminate().await;
1743        std::mem::drop(volumes_directory);
1744        filesystem.close().await.expect("close filesystem failed");
1745    }
1746
1747    #[fuchsia::test]
1748    async fn test_volume_enumeration() {
1749        let device = DeviceHolder::new(FakeDevice::new(8192, 512));
1750        let filesystem = FxFilesystem::new_empty(device).await.unwrap();
1751        let page_fault_counter =
1752            Arc::new(PageFaultCounter::new().expect("Failed to create PageFaultCounter"));
1753        let volumes_directory = VolumesDirectory::new(
1754            root_volume(filesystem.clone()).await.unwrap(),
1755            Weak::new(),
1756            None,
1757            page_fault_counter,
1758            MemoryPressureConfig::default(),
1759        )
1760        .await
1761        .unwrap();
1762
1763        // Add an encrypted volume...
1764        let crypt = Arc::new(new_insecure_crypt()) as Arc<dyn Crypt>;
1765        {
1766            volumes_directory
1767                .create_and_mount_volume(
1768                    "encrypted",
1769                    Some(crypt.clone()),
1770                    false,
1771                    CreateOptions::default(),
1772                )
1773                .await
1774                .expect("create encrypted volume failed");
1775        };
1776        // And an unencrypted volume.
1777        {
1778            volumes_directory
1779                .create_and_mount_volume("unencrypted", None, false, CreateOptions::default())
1780                .await
1781                .expect("create unencrypted volume failed");
1782        };
1783
1784        // Restart, so that we can test enumeration of unopened volumes.
1785        volumes_directory.terminate().await;
1786        std::mem::drop(volumes_directory);
1787        filesystem.close().await.expect("close filesystem failed");
1788        let device = filesystem.take_device().await;
1789        device.reopen(false);
1790        let filesystem = FxFilesystem::open(device).await.unwrap();
1791        let page_fault_counter =
1792            Arc::new(PageFaultCounter::new().expect("Failed to create PageFaultCounter"));
1793        let volumes_directory = VolumesDirectory::new(
1794            root_volume(filesystem.clone()).await.unwrap(),
1795            Weak::new(),
1796            None,
1797            page_fault_counter,
1798            MemoryPressureConfig::default(),
1799        )
1800        .await
1801        .unwrap();
1802
1803        let readdir = |dir: Arc<fio::DirectoryProxy>| async move {
1804            let status = dir.rewind().await.expect("FIDL call failed");
1805            Status::ok(status).expect("rewind failed");
1806            let (status, buf) = dir.read_dirents(fio::MAX_BUF).await.expect("FIDL call failed");
1807            Status::ok(status).expect("read_dirents failed");
1808            let mut entries = vec![];
1809            for res in fuchsia_fs::directory::parse_dir_entries(&buf) {
1810                entries.push(res.expect("Failed to parse entry").name);
1811            }
1812            entries
1813        };
1814
1815        let dir_proxy = Arc::new(vfs::directory::serve_read_only(
1816            volumes_directory.directory_node().clone(),
1817            ExecutionScope::new(),
1818        ));
1819        let entries = readdir(dir_proxy.clone()).await;
1820        assert_eq!(entries, [".", "encrypted", "unencrypted"]);
1821
1822        let _vol = volumes_directory
1823            .mount_volume("encrypted", Some(crypt.clone()), false)
1824            .await
1825            .expect("Open encrypted volume failed");
1826
1827        // Ensure that the behaviour is the same after we've opened a volume.
1828        let entries = readdir(dir_proxy).await;
1829        assert_eq!(entries, [".", "encrypted", "unencrypted"]);
1830
1831        volumes_directory.terminate().await;
1832        std::mem::drop(volumes_directory);
1833        filesystem.close().await.expect("close filesystem failed");
1834    }
1835
1836    #[fuchsia::test]
1837    async fn test_get_info() {
1838        let device = DeviceHolder::new(FakeDevice::new(8192, 512));
1839        let filesystem = FxFilesystem::new_empty(device).await.unwrap();
1840        let root_volume = root_volume(filesystem.clone()).await.unwrap();
1841        let page_fault_counter =
1842            Arc::new(PageFaultCounter::new().expect("Failed to create PageFaultCounter"));
1843        let volumes_directory = VolumesDirectory::new(
1844            root_volume,
1845            Weak::new(),
1846            None,
1847            page_fault_counter,
1848            MemoryPressureConfig::default(),
1849        )
1850        .await
1851        .unwrap();
1852
1853        let vol = volumes_directory
1854            .create_and_mount_volume("vol", None, false, CreateOptions::default())
1855            .await
1856            .expect("create_and_mount_volume failed");
1857        let guid = vol.volume().store().guid();
1858
1859        let (volume_proxy, _scope) = serve_startup_volume_proxy(&volumes_directory, "vol");
1860
1861        let info: fidl_fuchsia_fs_startup::VolumeInfo = volume_proxy
1862            .get_info()
1863            .await
1864            .expect("get_info failed")
1865            .expect("get_info returned error");
1866        assert_eq!(info.guid, Some(guid));
1867
1868        volumes_directory.terminate().await;
1869    }
1870
1871    #[fuchsia::test]
1872    async fn test_deleted_encrypted_volume_while_mounted() {
1873        const VOLUME_NAME: &str = "encrypted";
1874
1875        let device = DeviceHolder::new(FakeDevice::new(8192, 512));
1876        let filesystem = FxFilesystem::new_empty(device).await.unwrap();
1877        let crypt = Arc::new(new_insecure_crypt()) as Arc<dyn Crypt>;
1878        let page_fault_counter =
1879            Arc::new(PageFaultCounter::new().expect("Failed to create PageFaultCounter"));
1880        let volumes_directory = VolumesDirectory::new(
1881            root_volume(filesystem.clone()).await.unwrap(),
1882            Weak::new(),
1883            None,
1884            page_fault_counter,
1885            MemoryPressureConfig::default(),
1886        )
1887        .await
1888        .unwrap();
1889        volumes_directory
1890            .create_and_mount_volume(
1891                VOLUME_NAME,
1892                Some(crypt.clone()),
1893                false,
1894                CreateOptions::default(),
1895            )
1896            .await
1897            .expect("create encrypted volume failed");
1898        // We have the volume mounted so delete attempts should fail.
1899        assert!(
1900            FxfsError::AlreadyBound.matches(
1901                &volumes_directory
1902                    .remove_volume(VOLUME_NAME)
1903                    .await
1904                    .err()
1905                    .expect("Deleting volume should fail")
1906            )
1907        );
1908        volumes_directory.terminate().await;
1909        std::mem::drop(volumes_directory);
1910        filesystem.close().await.expect("close filesystem failed");
1911    }
1912
1913    #[fuchsia::test]
1914    async fn test_mount_volume_using_volume_protocol() {
1915        let device = DeviceHolder::new(FakeDevice::new(8192, 512));
1916        let filesystem = FxFilesystem::new_empty(device).await.unwrap();
1917        let page_fault_counter =
1918            Arc::new(PageFaultCounter::new().expect("Failed to create PageFaultCounter"));
1919        let volumes_directory = VolumesDirectory::new(
1920            root_volume(filesystem.clone()).await.unwrap(),
1921            Weak::new(),
1922            None,
1923            page_fault_counter,
1924            MemoryPressureConfig::default(),
1925        )
1926        .await
1927        .unwrap();
1928
1929        let crypt = Arc::new(new_insecure_crypt()) as Arc<dyn Crypt>;
1930        let store_id = {
1931            let vol = volumes_directory
1932                .create_and_mount_volume(
1933                    "encrypted",
1934                    Some(crypt.clone()),
1935                    false,
1936                    CreateOptions::default(),
1937                )
1938                .await
1939                .expect("create encrypted volume failed");
1940            vol.volume().store().store_object_id()
1941        };
1942        volumes_directory.lock().await.unmount(store_id).await.expect("unmount failed");
1943
1944        let (volume_proxy, _scope) = serve_startup_volume_proxy(&volumes_directory, "encrypted");
1945
1946        let (dir_proxy, dir_server_end) = fidl::endpoints::create_proxy::<fio::DirectoryMarker>();
1947
1948        let crypt_service = fxfs_crypt::CryptService::new();
1949        crypt_service
1950            .add_wrapping_key(0, fxfs_insecure_crypto::DATA_KEY.to_vec())
1951            .expect("add_wrapping_key failed");
1952        crypt_service
1953            .add_wrapping_key(1, fxfs_insecure_crypto::METADATA_KEY.to_vec())
1954            .expect("add_wrapping_key failed");
1955        crypt_service.set_active_key(KeyPurpose::Data, 0).expect("set_active_key failed");
1956        crypt_service.set_active_key(KeyPurpose::Metadata, 1).expect("set_active_key failed");
1957        let (client1, stream1) = create_request_stream();
1958        let (client2, stream2) = create_request_stream();
1959
1960        join!(
1961            async {
1962                volume_proxy
1963                    .mount(
1964                        dir_server_end,
1965                        MountOptions { crypt: Some(client1), ..MountOptions::default() },
1966                    )
1967                    .await
1968                    .expect("mount (fidl) failed")
1969                    .expect("mount failed");
1970
1971                open_file_checked(
1972                    &dir_proxy,
1973                    "root/test",
1974                    fio::PERM_READABLE | fio::PERM_WRITABLE | fio::Flags::FLAG_MAYBE_CREATE,
1975                    &Default::default(),
1976                )
1977                .await;
1978
1979                // Attempting to mount again should fail with ALREADY_BOUND.
1980                let (_dir_proxy, dir_server_end) =
1981                    fidl::endpoints::create_proxy::<fio::DirectoryMarker>();
1982
1983                assert_eq!(
1984                    Status::ok(
1985                        volume_proxy
1986                            .mount(
1987                                dir_server_end,
1988                                MountOptions { crypt: Some(client2), ..MountOptions::default() },
1989                            )
1990                            .await
1991                            .expect("mount (fidl) failed")
1992                            .expect_err("mount succeeded")
1993                    ),
1994                    Err(Status::ALREADY_BOUND)
1995                );
1996
1997                std::mem::drop(dir_proxy);
1998
1999                // The volume should get unmounted a short time later.
2000                let mut count = 0;
2001                loop {
2002                    if volumes_directory.mounted_volumes.lock().await.is_empty() {
2003                        break;
2004                    }
2005                    count += 1;
2006                    assert!(count <= 100);
2007                    fasync::Timer::new(Duration::from_millis(100)).await;
2008                }
2009            },
2010            async {
2011                crypt_service
2012                    .handle_request(fxfs_crypt::Services::Crypt(stream1))
2013                    .await
2014                    .expect("handle_request failed");
2015                crypt_service
2016                    .handle_request(fxfs_crypt::Services::Crypt(stream2))
2017                    .await
2018                    .expect("handle_request failed");
2019            }
2020        );
2021        // Make sure the background thread that actually calls terminate() on the volume finishes
2022        // before exiting the test. terminate() should be a no-op since we already verified
2023        // mounted_directories is empty, but the volume's terminate() future in the background task
2024        // may still be outstanding. As both the background task and VolumesDirectory::terminate()
2025        // hold the write lock, we use that to block until the background task has completed.
2026        volumes_directory.terminate().await;
2027    }
2028
2029    #[fuchsia::test]
2030    #[ignore] // TODO(b/293917849) re-enable this test when de-flaked
2031
2032    async fn test_volume_dir_races() {
2033        let device = DeviceHolder::new(FakeDevice::new(8192, 512));
2034        let filesystem = FxFilesystem::new_empty(device).await.unwrap();
2035        let page_fault_counter =
2036            Arc::new(PageFaultCounter::new().expect("Failed to create PageFaultCounter"));
2037        let volumes_directory = VolumesDirectory::new(
2038            root_volume(filesystem.clone()).await.unwrap(),
2039            Weak::new(),
2040            None,
2041            page_fault_counter,
2042            MemoryPressureConfig::default(),
2043        )
2044        .await
2045        .unwrap();
2046
2047        let crypt = Arc::new(new_insecure_crypt()) as Arc<dyn Crypt>;
2048        let store_id = {
2049            let vol = volumes_directory
2050                .create_and_mount_volume(
2051                    "encrypted",
2052                    Some(crypt.clone()),
2053                    false,
2054                    CreateOptions::default(),
2055                )
2056                .await
2057                .expect("create encrypted volume failed");
2058            vol.volume().store().store_object_id()
2059        };
2060        volumes_directory.lock().await.unmount(store_id).await.expect("unmount failed");
2061
2062        let (volume_proxy, _scope) = serve_startup_volume_proxy(&volumes_directory, "encrypted");
2063
2064        let crypt_service = Arc::new(fxfs_crypt::CryptService::new());
2065        crypt_service
2066            .add_wrapping_key(0, fxfs_insecure_crypto::DATA_KEY.to_vec())
2067            .expect("add_wrapping_key failed");
2068        crypt_service
2069            .add_wrapping_key(1, fxfs_insecure_crypto::METADATA_KEY.to_vec())
2070            .expect("add_wrapping_key failed");
2071        crypt_service.set_active_key(KeyPurpose::Data, 0).expect("set_active_key failed");
2072        crypt_service.set_active_key(KeyPurpose::Metadata, 1).expect("set_active_key failed");
2073        let (client1, stream1) = create_request_stream();
2074        let (client2, stream2) = create_request_stream();
2075        let crypt_service_clone = crypt_service.clone();
2076        let crypt_task1 = fasync::Task::spawn(async move {
2077            crypt_service_clone
2078                .handle_request(fxfs_crypt::Services::Crypt(stream1))
2079                .await
2080                .expect("handle_request failed");
2081        });
2082        let crypt_task2 = fasync::Task::spawn(async move {
2083            crypt_service
2084                .handle_request(fxfs_crypt::Services::Crypt(stream2))
2085                .await
2086                .expect("handle_request failed");
2087        });
2088
2089        // Create two tasks each of mount and remove, and one to recreate the volume, so that we get
2090        // to exercise a wide variety of concurrent actions.
2091        // Delay remove and create a bit, since mount is slower due to FIDL.
2092        join!(
2093            async {
2094                let (_dir_proxy, dir_server_end) =
2095                    fidl::endpoints::create_proxy::<fio::DirectoryMarker>();
2096                if let Err(status) = volume_proxy
2097                    .mount(
2098                        dir_server_end,
2099                        MountOptions { crypt: Some(client1), ..MountOptions::default() },
2100                    )
2101                    .await
2102                    .expect("mount (fidl) failed")
2103                {
2104                    let status = Status::err_from_raw(status);
2105                    if status != Status::NOT_FOUND && status != Status::ALREADY_BOUND {
2106                        assert!(false, "Unexpected status {:}", status);
2107                    }
2108                }
2109            },
2110            async {
2111                let (_dir_proxy, dir_server_end) =
2112                    fidl::endpoints::create_proxy::<fio::DirectoryMarker>();
2113                if let Err(status) = volume_proxy
2114                    .mount(
2115                        dir_server_end,
2116                        MountOptions { crypt: Some(client2), ..MountOptions::default() },
2117                    )
2118                    .await
2119                    .expect("mount (fidl) failed")
2120                {
2121                    let status = Status::err_from_raw(status);
2122                    if status != Status::NOT_FOUND && status != Status::ALREADY_BOUND {
2123                        assert!(false, "Unexpected status {:}", status);
2124                    }
2125                }
2126            },
2127            async {
2128                let volumes_directory = volumes_directory.clone();
2129                let wait_time = rand::random_range(0..5);
2130                fasync::Timer::new(Duration::from_millis(wait_time)).await;
2131                if let Err(err) = volumes_directory.remove_volume("encrypted").await {
2132                    assert!(
2133                        FxfsError::NotFound.matches(&err) || FxfsError::AlreadyBound.matches(&err),
2134                        "Unexpected error {:?}",
2135                        err
2136                    );
2137                }
2138            },
2139            async {
2140                let volumes_directory = volumes_directory.clone();
2141                let wait_time = rand::random_range(0..5);
2142                fasync::Timer::new(Duration::from_millis(wait_time)).await;
2143                if let Err(err) = volumes_directory.remove_volume("encrypted").await {
2144                    assert!(
2145                        FxfsError::NotFound.matches(&err) || FxfsError::AlreadyBound.matches(&err),
2146                        "Unexpected error {:?}",
2147                        err
2148                    );
2149                }
2150            },
2151            async {
2152                let volumes_directory = volumes_directory.clone();
2153                let wait_time = rand::random_range(0..5);
2154                fasync::Timer::new(Duration::from_millis(wait_time)).await;
2155                let mut guard = volumes_directory.lock().await;
2156                match guard
2157                    .create_or_mount_volume(
2158                        "encrypted",
2159                        Some(crypt.clone()),
2160                        Mode::Create { guid: None, low_32_bit_object_ids: false },
2161                        false,
2162                        false,
2163                    )
2164                    .await
2165                {
2166                    Ok(vol) => {
2167                        let store_id = vol.volume().store().store_object_id();
2168                        std::mem::drop(vol);
2169                        guard.unmount(store_id).await.expect("unmount failed");
2170                    }
2171                    Err(err) => {
2172                        assert!(
2173                            FxfsError::AlreadyExists.matches(&err)
2174                                || FxfsError::AlreadyBound.matches(&err),
2175                            "Unexpected error {:?}",
2176                            err
2177                        );
2178                    }
2179                }
2180            }
2181        );
2182        std::mem::drop(crypt_task1);
2183        std::mem::drop(crypt_task2);
2184        // Make sure the background thread that actually calls terminate() on the volume finishes
2185        // before exiting the test. terminate() should be a no-op since we already verified
2186        // mounted_directories is empty, but the volume's terminate() future in the background task
2187        // may still be outstanding. As both the background task and VolumesDirectory::terminate()
2188        // hold the write lock, we use that to block until the background task has completed.
2189        volumes_directory.terminate().await;
2190        filesystem.close().await.expect("close filesystem failed");
2191    }
2192
2193    #[fuchsia::test]
2194    async fn test_shutdown_volume() {
2195        let device = DeviceHolder::new(FakeDevice::new(8192, 512));
2196        let filesystem = FxFilesystem::new_empty(device).await.unwrap();
2197        let page_fault_counter =
2198            Arc::new(PageFaultCounter::new().expect("Failed to create PageFaultCounter"));
2199        let volumes_directory = VolumesDirectory::new(
2200            root_volume(filesystem.clone()).await.unwrap(),
2201            Weak::new(),
2202            None,
2203            page_fault_counter,
2204            MemoryPressureConfig::default(),
2205        )
2206        .await
2207        .unwrap();
2208
2209        let crypt = Arc::new(new_insecure_crypt()) as Arc<dyn Crypt>;
2210        let vol = volumes_directory
2211            .create_and_mount_volume(
2212                "encrypted",
2213                Some(crypt.clone()),
2214                false,
2215                CreateOptions::default(),
2216            )
2217            .await
2218            .expect("create encrypted volume failed");
2219
2220        let (dir_proxy, dir_server_end) = fidl::endpoints::create_proxy::<fio::DirectoryMarker>();
2221
2222        volumes_directory.serve_volume(&vol, dir_server_end, false).expect("serve_volume failed");
2223
2224        let admin_proxy = connect_to_protocol_at_dir_svc::<AdminMarker>(&dir_proxy)
2225            .expect("Unable to connect to admin service");
2226
2227        admin_proxy.shutdown().await.expect("shutdown failed");
2228
2229        assert!(volumes_directory.mounted_volumes.lock().await.is_empty());
2230    }
2231
2232    #[fuchsia::test]
2233    async fn test_volume_debug_clear_caches() {
2234        let device = DeviceHolder::new(FakeDevice::new(8192, 512));
2235        let filesystem = FxFilesystem::new_empty(device).await.unwrap();
2236        let page_fault_counter =
2237            Arc::new(PageFaultCounter::new().expect("Failed to create PageFaultCounter"));
2238        let volumes_directory = VolumesDirectory::new(
2239            root_volume(filesystem.clone()).await.unwrap(),
2240            Weak::new(),
2241            None,
2242            page_fault_counter,
2243            MemoryPressureConfig::default(),
2244        )
2245        .await
2246        .unwrap();
2247
2248        let crypt = Arc::new(new_insecure_crypt()) as Arc<dyn Crypt>;
2249        let vol = volumes_directory
2250            .create_and_mount_volume("test_vol", Some(crypt), false, CreateOptions::default())
2251            .await
2252            .expect("create encrypted volume failed");
2253
2254        let (dir_proxy, dir_server_end) = fidl::endpoints::create_proxy::<fio::DirectoryMarker>();
2255        volumes_directory.serve_volume(&vol, dir_server_end, false).expect("serve_volume failed");
2256
2257        let (root, root_server_end) = create_proxy::<fio::DirectoryMarker>();
2258        vol.root().clone().serve(fio::PERM_READABLE | fio::PERM_WRITABLE, root_server_end);
2259        let file = open_file_checked(
2260            &root,
2261            "foo",
2262            fio::Flags::FLAG_MAYBE_CREATE
2263                | fio::PERM_READABLE
2264                | fio::PERM_WRITABLE
2265                | fio::Flags::PROTOCOL_FILE,
2266            &Default::default(),
2267        )
2268        .await;
2269
2270        file.write(b"Hello, world!").await.expect("write fidl failed").expect("write failed");
2271        file.sync()
2272            .await
2273            .expect("sync fidl failed")
2274            .map_err(Status::err_from_raw)
2275            .expect("sync failed");
2276
2277        let (_, attrs) = file
2278            .get_attributes(fio::NodeAttributesQuery::ID)
2279            .await
2280            .expect("get_attributes fidl failed")
2281            .expect("get_attributes failed");
2282        let file_id = attrs.id.expect("missing file id");
2283
2284        let store = vol.volume().store();
2285        // Flush the store so that records are compacted into a PersistentLayer.
2286        store.flush().await.expect("flush failed");
2287
2288        // Clear the tree cache so the lookup below misses TreeCache and reads from the
2289        // PersistentLayer on disk, populating both the layer chunk cache and TreeCache.
2290        store.tree().clear_cache();
2291        let _ = store
2292            .tree()
2293            .find(&fxfs::object_store::ObjectKey::object(file_id))
2294            .await
2295            .expect("tree find failed");
2296
2297        let layer_object_id =
2298            store.tree().immutable_layer_set().layers[0].handle().unwrap().object_id();
2299
2300        // Verify all caches are populated prior to ClearCaches.
2301        assert!(vol.volume().dirent_cache().len() > 0);
2302        assert!(store.tree().cache_len() > 0);
2303        assert!(store.key_manager().get(file_id).await.unwrap().is_some());
2304        assert!(
2305            filesystem.root_store().key_manager().get(layer_object_id).await.unwrap().is_some()
2306        );
2307
2308        let debug_proxy = connect_to_protocol_at_dir_svc::<DebugMarker>(&dir_proxy)
2309            .expect("Unable to connect to debug service");
2310
2311        debug_proxy
2312            .clear_caches()
2313            .await
2314            .expect("clear_caches fidl failed")
2315            .expect("clear_caches failed");
2316
2317        // Verify dirent cache and TreeCache are cleared.
2318        assert_eq!(vol.volume().dirent_cache().len(), 0);
2319        assert_eq!(store.tree().cache_len(), 0);
2320        // Verify non-permanent file key is evicted from the volume store.
2321        assert!(store.key_manager().get(file_id).await.unwrap().is_none());
2322
2323        // Also clear caches on the top-level VolumesDirectory and verify permanent layer keys in
2324        // root_store are preserved so reading from the encrypted volume continues to work.
2325        volumes_directory.clear_caches().await;
2326        assert!(
2327            filesystem.root_store().key_manager().get(layer_object_id).await.unwrap().is_some()
2328        );
2329        let _ = store
2330            .tree()
2331            .find(&fxfs::object_store::ObjectKey::object(file_id))
2332            .await
2333            .expect("tree find after clear_caches failed");
2334
2335        close_file_checked(file).await;
2336        std::mem::drop(root);
2337        std::mem::drop(dir_proxy);
2338        std::mem::drop(vol);
2339        volumes_directory.terminate().await;
2340        std::mem::drop(volumes_directory);
2341        filesystem.close().await.expect("close filesystem failed");
2342    }
2343
2344    #[fuchsia::test]
2345    async fn test_byte_limit_persistence() {
2346        const BYTES_LIMIT_1: u64 = 123456;
2347        const BYTES_LIMIT_2: u64 = 456789;
2348        const VOLUME_NAME: &str = "A";
2349        let mut device = DeviceHolder::new(FakeDevice::new(8192, 512));
2350        {
2351            let filesystem = FxFilesystem::new_empty(device).await.unwrap();
2352            let page_fault_counter =
2353                Arc::new(PageFaultCounter::new().expect("Failed to create PageFaultCounter"));
2354            let volumes_directory = VolumesDirectory::new(
2355                root_volume(filesystem.clone()).await.unwrap(),
2356                Weak::new(),
2357                None,
2358                page_fault_counter,
2359                MemoryPressureConfig::default(),
2360            )
2361            .await
2362            .unwrap();
2363
2364            volumes_directory
2365                .create_and_mount_volume(VOLUME_NAME, None, false, CreateOptions::default())
2366                .await
2367                .expect("create unencrypted volume failed");
2368
2369            let (volume_proxy, _scope) =
2370                serve_startup_volume_proxy(&volumes_directory, VOLUME_NAME);
2371
2372            volume_proxy.set_limit(BYTES_LIMIT_1).await.unwrap().expect("To set limits");
2373            {
2374                let limits = (filesystem.allocator() as Arc<Allocator>).owner_byte_limits();
2375                assert_eq!(limits.len(), 1);
2376                assert_eq!(limits[0].1, BYTES_LIMIT_1);
2377            }
2378
2379            volume_proxy.set_limit(BYTES_LIMIT_2).await.unwrap().expect("To set limits");
2380            {
2381                let limits = (filesystem.allocator() as Arc<Allocator>).owner_byte_limits();
2382                assert_eq!(limits.len(), 1);
2383                assert_eq!(limits[0].1, BYTES_LIMIT_2);
2384            }
2385            std::mem::drop(volume_proxy);
2386            volumes_directory.terminate().await;
2387            std::mem::drop(volumes_directory);
2388            filesystem.close().await.expect("close filesystem failed");
2389            device = filesystem.take_device().await;
2390        }
2391        device.ensure_unique();
2392        device.reopen(false);
2393        {
2394            let filesystem = FxFilesystem::open(device as DeviceHolder).await.unwrap();
2395            fsck(filesystem.clone()).await.expect("Fsck");
2396            let page_fault_counter =
2397                Arc::new(PageFaultCounter::new().expect("Failed to create PageFaultCounter"));
2398            let volumes_directory = VolumesDirectory::new(
2399                root_volume(filesystem.clone()).await.unwrap(),
2400                Weak::new(),
2401                None,
2402                page_fault_counter,
2403                MemoryPressureConfig::default(),
2404            )
2405            .await
2406            .unwrap();
2407            {
2408                let limits = (filesystem.allocator() as Arc<Allocator>).owner_byte_limits();
2409                assert_eq!(limits.len(), 1);
2410                assert_eq!(limits[0].1, BYTES_LIMIT_2);
2411            }
2412            volumes_directory.remove_volume(VOLUME_NAME).await.expect("Volume deletion failed");
2413            {
2414                let limits = (filesystem.allocator() as Arc<Allocator>).owner_byte_limits();
2415                assert_eq!(limits.len(), 0);
2416            }
2417            volumes_directory.terminate().await;
2418            std::mem::drop(volumes_directory);
2419            filesystem.close().await.expect("close filesystem failed");
2420            device = filesystem.take_device().await;
2421        }
2422        device.ensure_unique();
2423        device.reopen(false);
2424        let filesystem = FxFilesystem::open(device as DeviceHolder).await.unwrap();
2425        fsck(filesystem.clone()).await.expect("Fsck");
2426        let limits = (filesystem.allocator() as Arc<Allocator>).owner_byte_limits();
2427        assert_eq!(limits.len(), 0);
2428    }
2429
2430    struct VolumeInfo {
2431        _scope: vfs::ExecutionScope,
2432        volume_proxy: VolumeProxy,
2433        file_proxy: fio::FileProxy,
2434    }
2435
2436    impl VolumeInfo {
2437        async fn new(volumes_directory: &Arc<VolumesDirectory>, name: &'static str) -> Self {
2438            let volume = volumes_directory
2439                .create_and_mount_volume(name, None, false, CreateOptions::default())
2440                .await
2441                .expect("create unencrypted volume failed");
2442
2443            let (volume_dir_proxy, dir_server_end) =
2444                fidl::endpoints::create_proxy::<fio::DirectoryMarker>();
2445            volumes_directory
2446                .serve_volume(&volume, dir_server_end, false)
2447                .expect("serve_volume failed");
2448
2449            let (volume_proxy, _scope) = serve_startup_volume_proxy(&volumes_directory, name);
2450
2451            let (root_proxy, root_server_end) =
2452                fidl::endpoints::create_proxy::<fio::DirectoryMarker>();
2453            volume_dir_proxy
2454                .open(
2455                    "root",
2456                    fio::PERM_READABLE | fio::PERM_WRITABLE | fio::Flags::PROTOCOL_DIRECTORY,
2457                    &Default::default(),
2458                    root_server_end.into_channel(),
2459                )
2460                .expect("Failed to open volume root");
2461
2462            let file_proxy = open_file_checked(
2463                &root_proxy,
2464                "foo",
2465                fio::Flags::FLAG_MAYBE_CREATE
2466                    | fio::PERM_READABLE
2467                    | fio::PERM_WRITABLE
2468                    | fio::Flags::PROTOCOL_FILE,
2469                &Default::default(),
2470            )
2471            .await;
2472            VolumeInfo { _scope, volume_proxy, file_proxy }
2473        }
2474    }
2475
2476    #[fuchsia::test]
2477    async fn test_limit_bytes() {
2478        const BYTES_LIMIT: u64 = 262_144; // 256KiB
2479        const BLOCK_SIZE: BlockSize = BlockSize::SIZE_512B;
2480        let device = DeviceHolder::new(FakeDevice::new(8192, BLOCK_SIZE.get() as u32));
2481        let filesystem = FxFilesystem::new_empty(device).await.unwrap();
2482        let page_fault_counter =
2483            Arc::new(PageFaultCounter::new().expect("Failed to create PageFaultCounter"));
2484        let volumes_directory = VolumesDirectory::new(
2485            root_volume(filesystem.clone()).await.unwrap(),
2486            Weak::new(),
2487            None,
2488            page_fault_counter,
2489            MemoryPressureConfig::default(),
2490        )
2491        .await
2492        .unwrap();
2493
2494        let vol = VolumeInfo::new(&volumes_directory, "foo").await;
2495        let old_info = {
2496            let (status, info) = vol.file_proxy.query_filesystem().await.expect("Getting fs info");
2497            assert_eq!(status, zx::sys::ZX_OK);
2498            let info = info.unwrap();
2499            // With no limit set, the total filesystem size should be returned.
2500            assert!(info.total_bytes > BYTES_LIMIT);
2501            info
2502        };
2503
2504        vol.volume_proxy.set_limit(BYTES_LIMIT).await.unwrap().expect("To set limits");
2505        {
2506            let (status, info) = vol.file_proxy.query_filesystem().await.expect("Getting fs info");
2507            assert_eq!(status, zx::sys::ZX_OK);
2508            let new_info = info.unwrap();
2509            assert_eq!(new_info.total_bytes, BYTES_LIMIT);
2510            // Now since the limit is the volume limit, the space used should be the volume usage,
2511            // which should be strictly less than the filesystem.
2512            assert!(new_info.used_bytes < old_info.used_bytes);
2513        }
2514
2515        let zeros = vec![0u8; BLOCK_SIZE.get() as usize];
2516        // First write should succeed.
2517        assert_eq!(
2518            vol.file_proxy
2519                .write(&zeros)
2520                .await
2521                .expect("Failed Write message")
2522                .expect("Failed write"),
2523            BLOCK_SIZE
2524        );
2525        // Likely to run out of space before writing the full limit due to overheads.
2526        for _ in (BLOCK_SIZE.get()..BYTES_LIMIT).step_by(BLOCK_SIZE.get() as usize) {
2527            match vol.file_proxy.write(&zeros).await.expect("Failed Write message") {
2528                Err(_) => break,
2529                Ok(b) if b < BLOCK_SIZE => break,
2530                _ => (),
2531            };
2532        }
2533
2534        // Any further writes should fail with out of space.
2535        assert_eq!(
2536            vol.file_proxy
2537                .write(&zeros)
2538                .await
2539                .expect("Failed write message")
2540                .expect_err("Write should have been limited"),
2541            Status::NO_SPACE.into_raw()
2542        );
2543
2544        // Double the limit and try again. We should have write space again.
2545        vol.volume_proxy.set_limit(BYTES_LIMIT * 2).await.unwrap().expect("To set limits");
2546        assert_eq!(
2547            vol.file_proxy
2548                .write(&zeros)
2549                .await
2550                .expect("Failed Write message")
2551                .expect("Failed write"),
2552            BLOCK_SIZE
2553        );
2554
2555        vol.file_proxy.close().await.unwrap().expect("Failed to close file");
2556        volumes_directory.terminate().await;
2557        std::mem::drop(volumes_directory);
2558        filesystem.close().await.expect("close filesystem failed");
2559    }
2560
2561    #[fuchsia::test]
2562    async fn test_limit_bytes_two_hit_device_limit() {
2563        const BYTES_LIMIT: u64 = 3_145_728; // 3MiB
2564        const BLOCK_SIZE: BlockSize = BlockSize::SIZE_512B;
2565        const BLOCK_COUNT: u64 = 8192;
2566        let device = DeviceHolder::new(FakeDevice::new(BLOCK_COUNT, BLOCK_SIZE.get() as u32));
2567        let filesystem = FxFilesystem::new_empty(device).await.unwrap();
2568        let page_fault_counter =
2569            Arc::new(PageFaultCounter::new().expect("Failed to create PageFaultCounter"));
2570        let volumes_directory = VolumesDirectory::new(
2571            root_volume(filesystem.clone()).await.unwrap(),
2572            Weak::new(),
2573            None,
2574            page_fault_counter,
2575            MemoryPressureConfig::default(),
2576        )
2577        .await
2578        .unwrap();
2579
2580        let a = VolumeInfo::new(&volumes_directory, "foo").await;
2581        let b = VolumeInfo::new(&volumes_directory, "bar").await;
2582        a.volume_proxy.set_limit(BYTES_LIMIT).await.unwrap().expect("To set limits");
2583        b.volume_proxy.set_limit(BYTES_LIMIT).await.unwrap().expect("To set limits");
2584        let mut a_written: u64 = 0;
2585        let mut b_written: u64 = 0;
2586
2587        // Write chunks of BLOCK_SIZE.
2588        let zeros = vec![0u8; BLOCK_SIZE.get() as usize];
2589
2590        // First write should succeed for both.
2591        assert_eq!(
2592            a.file_proxy.write(&zeros).await.expect("Failed Write message").expect("Failed write"),
2593            BLOCK_SIZE
2594        );
2595        a_written += BLOCK_SIZE;
2596        assert_eq!(
2597            b.file_proxy.write(&zeros).await.expect("Failed Write message").expect("Failed write"),
2598            BLOCK_SIZE
2599        );
2600        b_written += BLOCK_SIZE;
2601
2602        // Likely to run out of space before writing the full limit due to overheads.
2603        for _ in (BLOCK_SIZE.get()..BYTES_LIMIT).step_by(BLOCK_SIZE.get() as usize) {
2604            match a.file_proxy.write(&zeros).await.expect("Failed Write message") {
2605                Err(_) => break,
2606                Ok(bytes) => {
2607                    a_written += bytes;
2608                    if bytes < BLOCK_SIZE {
2609                        break;
2610                    }
2611                }
2612            };
2613        }
2614        // Any further writes should fail with out of space.
2615        assert_eq!(
2616            a.file_proxy
2617                .write(&zeros)
2618                .await
2619                .expect("Failed write message")
2620                .expect_err("Write should have been limited"),
2621            Status::NO_SPACE.into_raw()
2622        );
2623
2624        // Now write to the second volume. Likely to run out of space before writing the full limit
2625        // due to overheads.
2626        for _ in (BLOCK_SIZE.get()..BYTES_LIMIT).step_by(BLOCK_SIZE.get() as usize) {
2627            match b.file_proxy.write(&zeros).await.expect("Failed Write message") {
2628                Err(_) => break,
2629                Ok(bytes) => {
2630                    b_written += bytes;
2631                    if bytes < BLOCK_SIZE {
2632                        break;
2633                    }
2634                }
2635            };
2636        }
2637        // Any further writes should fail with out of space.
2638        assert_eq!(
2639            b.file_proxy
2640                .write(&zeros)
2641                .await
2642                .expect("Failed write message")
2643                .expect_err("Write should have been limited"),
2644            Status::NO_SPACE.into_raw()
2645        );
2646
2647        // Second volume should have failed very early.
2648        assert!(BLOCK_SIZE * BLOCK_COUNT - BYTES_LIMIT >= b_written);
2649        // First volume should have gotten further.
2650        assert!(BLOCK_SIZE * BLOCK_COUNT - BYTES_LIMIT <= a_written);
2651
2652        a.file_proxy.close().await.unwrap().expect("Failed to close file");
2653        b.file_proxy.close().await.unwrap().expect("Failed to close file");
2654        volumes_directory.terminate().await;
2655        std::mem::drop(volumes_directory);
2656        filesystem.close().await.expect("close filesystem failed");
2657    }
2658
2659    #[fuchsia::test(threads = 10)]
2660    async fn test_profile_start() {
2661        const PREMOUNT_BLOB: &str = "premount_blob";
2662        const PREMOUNT_DRIVER_BLOB: &str = "premount_driver_blob";
2663        const PREMOUNT_NOBLOB: &str = "premount_noblob";
2664        const LIVE_BLOB: &str = "live_blob";
2665        const LIVE_DRIVER_BLOB: &str = "live_driver_blob";
2666        const LIVE_NOBLOB: &str = "live_noblob";
2667
2668        const RECORDING_NAME: &str = "foo";
2669
2670        let device = {
2671            let device = DeviceHolder::new(FakeDevice::new(8192, 512));
2672            let filesystem = FxFilesystem::new_empty(device).await.unwrap();
2673            let page_fault_counter =
2674                Arc::new(PageFaultCounter::new().expect("Failed to create PageFaultCounter"));
2675            let volumes_directory = VolumesDirectory::new(
2676                root_volume(filesystem.clone()).await.unwrap(),
2677                Weak::new(),
2678                None,
2679                page_fault_counter,
2680                MemoryPressureConfig::default(),
2681            )
2682            .await
2683            .unwrap();
2684            volumes_directory
2685                .create_and_mount_volume(PREMOUNT_BLOB, None, true, CreateOptions::default())
2686                .await
2687                .unwrap();
2688            volumes_directory
2689                .create_and_mount_volume(PREMOUNT_DRIVER_BLOB, None, true, CreateOptions::default())
2690                .await
2691                .expect("create_and_mount_volume failed");
2692            volumes_directory
2693                .create_and_mount_volume(PREMOUNT_NOBLOB, None, false, CreateOptions::default())
2694                .await
2695                .unwrap();
2696            volumes_directory
2697                .create_and_mount_volume(LIVE_BLOB, None, true, CreateOptions::default())
2698                .await
2699                .unwrap();
2700            volumes_directory
2701                .create_and_mount_volume(LIVE_DRIVER_BLOB, None, true, CreateOptions::default())
2702                .await
2703                .expect("create_and_mount_volume failed");
2704            volumes_directory
2705                .create_and_mount_volume(LIVE_NOBLOB, None, false, CreateOptions::default())
2706                .await
2707                .unwrap();
2708
2709            volumes_directory.terminate().await;
2710            std::mem::drop(volumes_directory);
2711            filesystem.close().await.expect("Filesystem close");
2712            filesystem.take_device().await
2713        };
2714
2715        device.ensure_unique();
2716        device.reopen(false);
2717        let device = {
2718            let filesystem = FxFilesystem::open(device as DeviceHolder).await.unwrap();
2719            let page_fault_counter =
2720                Arc::new(PageFaultCounter::new().expect("Failed to create PageFaultCounter"));
2721            let volumes_directory = VolumesDirectory::new(
2722                root_volume(filesystem.clone()).await.unwrap(),
2723                Weak::new(),
2724                None,
2725                page_fault_counter,
2726                MemoryPressureConfig::default(),
2727            )
2728            .await
2729            .unwrap();
2730
2731            // Premount volumes.
2732            let _premount_blob = volumes_directory
2733                .mount_volume(PREMOUNT_BLOB, None, true)
2734                .await
2735                .expect("Reopen volume");
2736            let _premount_driver_blob = volumes_directory
2737                .lock()
2738                .await
2739                .create_or_mount_volume(PREMOUNT_DRIVER_BLOB, None, Mode::Mount, true, true)
2740                .await
2741                .expect("Reopen volume");
2742            let _premount_noblob = volumes_directory
2743                .mount_volume(PREMOUNT_NOBLOB, None, false)
2744                .await
2745                .expect("Reopen volume");
2746
2747            // Start the recording, let it run a really long time, it doesn't need to end for this
2748            // test. If it does wait this long then it should trigger test timeouts.
2749            volumes_directory
2750                .clone()
2751                .record_and_replay_profile(None, RECORDING_NAME.to_owned(), 600)
2752                .await
2753                .expect("Recording");
2754
2755            // Live mount volumes.
2756            let _live_blob =
2757                volumes_directory.mount_volume(LIVE_BLOB, None, true).await.expect("Reopen volume");
2758            let _live_driver_blob = volumes_directory
2759                .lock()
2760                .await
2761                .create_or_mount_volume(LIVE_DRIVER_BLOB, None, Mode::Mount, true, true)
2762                .await
2763                .expect("Reopen volume");
2764            let _live_noblob = volumes_directory
2765                .mount_volume(LIVE_NOBLOB, None, false)
2766                .await
2767                .expect("Reopen volume");
2768
2769            // Wait for the recordings to finish.
2770            volumes_directory.stop_profile_tasks().await;
2771
2772            volumes_directory.terminate().await;
2773            std::mem::drop(volumes_directory);
2774            filesystem.close().await.expect("Filesystem close");
2775            filesystem.take_device().await
2776        };
2777
2778        device.ensure_unique();
2779        device.reopen(false);
2780        let filesystem = FxFilesystem::open(device as DeviceHolder).await.unwrap();
2781        {
2782            let page_fault_counter =
2783                Arc::new(PageFaultCounter::new().expect("Failed to create PageFaultCounter"));
2784            let volumes_directory = VolumesDirectory::new(
2785                root_volume(filesystem.clone()).await.unwrap(),
2786                Weak::new(),
2787                None,
2788                page_fault_counter,
2789                MemoryPressureConfig::default(),
2790            )
2791            .await
2792            .unwrap();
2793
2794            let _premount_blob = volumes_directory
2795                .mount_volume(PREMOUNT_BLOB, None, true)
2796                .await
2797                .expect("Reopen volume");
2798            let _premount_driver_blob = volumes_directory
2799                .mount_volume(PREMOUNT_DRIVER_BLOB, None, true)
2800                .await
2801                .expect("Reopen volume");
2802            let _premount_noblob = volumes_directory
2803                .mount_volume(PREMOUNT_NOBLOB, None, false)
2804                .await
2805                .expect("Reopen volume");
2806            let _live_blob =
2807                volumes_directory.mount_volume(LIVE_BLOB, None, true).await.expect("Reopen volume");
2808            let _live_driver_blob = volumes_directory
2809                .mount_volume(LIVE_DRIVER_BLOB, None, true)
2810                .await
2811                .expect("Reopen volume");
2812            let _live_noblob = volumes_directory
2813                .mount_volume(LIVE_NOBLOB, None, false)
2814                .await
2815                .expect("Reopen volume");
2816
2817            // Verify which recordings ran based on the saved recordings.
2818            volumes_directory
2819                .delete_profile(PREMOUNT_BLOB, RECORDING_NAME)
2820                .await
2821                .expect("Finding profile to delete.");
2822            assert_eq!(
2823                volumes_directory
2824                    .delete_profile(PREMOUNT_DRIVER_BLOB, RECORDING_NAME)
2825                    .await
2826                    .expect_err("Driver blob volume should not have recorded a profile in Fxfs"),
2827                zx::Status::NOT_FOUND
2828            );
2829            volumes_directory
2830                .delete_profile(PREMOUNT_NOBLOB, RECORDING_NAME)
2831                .await
2832                .expect("Finding profile to delete.");
2833            volumes_directory
2834                .delete_profile(LIVE_BLOB, RECORDING_NAME)
2835                .await
2836                .expect("Finding profile to delete.");
2837            assert_eq!(
2838                volumes_directory
2839                    .delete_profile(LIVE_DRIVER_BLOB, RECORDING_NAME)
2840                    .await
2841                    .expect_err("Driver blob volume should not have recorded a profile in Fxfs"),
2842                zx::Status::NOT_FOUND
2843            );
2844            volumes_directory
2845                .delete_profile(LIVE_NOBLOB, RECORDING_NAME)
2846                .await
2847                .expect("Finding profile to delete.");
2848
2849            volumes_directory.terminate().await;
2850        }
2851
2852        filesystem.close().await.expect("Filesystem close");
2853    }
2854
2855    #[fuchsia::test(threads = 10)]
2856    async fn test_profile_stop() {
2857        let device = DeviceHolder::new(FakeDevice::new(8192, 512));
2858        let filesystem = FxFilesystem::new_empty(device).await.unwrap();
2859        let page_fault_counter =
2860            Arc::new(PageFaultCounter::new().expect("Failed to create PageFaultCounter"));
2861        let volumes_directory = VolumesDirectory::new(
2862            root_volume(filesystem.clone()).await.unwrap(),
2863            Weak::new(),
2864            None,
2865            page_fault_counter,
2866            MemoryPressureConfig::default(),
2867        )
2868        .await
2869        .unwrap();
2870        let volume = volumes_directory
2871            .create_and_mount_volume("foo", None, true, CreateOptions::default())
2872            .await
2873            .unwrap();
2874
2875        // Run the recording with no time at all and ensure that it still shuts down properly.
2876        volumes_directory
2877            .clone()
2878            .record_and_replay_profile(None, "foo".to_owned(), 0)
2879            .await
2880            .expect("Recording");
2881
2882        // Delete will succeed once the profile is completed.
2883        while volumes_directory.delete_profile("foo", "foo").await.is_err() {
2884            fasync::Timer::new(Duration::from_millis(10)).await;
2885        }
2886
2887        std::mem::drop(volume);
2888        volumes_directory.terminate().await;
2889        std::mem::drop(volumes_directory);
2890        filesystem.close().await.expect("Filesystem close");
2891    }
2892
2893    #[fuchsia::test(threads = 10)]
2894    async fn test_delete_profile() {
2895        let device = DeviceHolder::new(FakeDevice::new(8192, 512));
2896        let filesystem = FxFilesystem::new_empty(device).await.unwrap();
2897        let page_fault_counter =
2898            Arc::new(PageFaultCounter::new().expect("Failed to create PageFaultCounter"));
2899        let volumes_directory = VolumesDirectory::new(
2900            root_volume(filesystem.clone()).await.unwrap(),
2901            Weak::new(),
2902            None,
2903            page_fault_counter,
2904            MemoryPressureConfig::default(),
2905        )
2906        .await
2907        .unwrap();
2908        let volume = volumes_directory
2909            .create_and_mount_volume("foo", None, true, CreateOptions::default())
2910            .await
2911            .unwrap();
2912
2913        volumes_directory
2914            .clone()
2915            .record_and_replay_profile(None, "foo".to_owned(), 600)
2916            .await
2917            .expect("Recording");
2918
2919        // Deletion fails during in-flight recording.
2920        assert_eq!(
2921            volumes_directory.delete_profile("foo", "foo").await.expect_err("File shouldn't exist"),
2922            Status::SHOULD_WAIT
2923        );
2924
2925        volumes_directory.stop_profile_tasks().await;
2926
2927        // Missing volume name.
2928        assert_eq!(
2929            volumes_directory.delete_profile("bar", "foo").await.expect_err("File shouldn't exist"),
2930            Status::NOT_FOUND
2931        );
2932
2933        // Missing Profile name.
2934        assert_eq!(
2935            volumes_directory.delete_profile("foo", "bar").await.expect_err("File shouldn't exist"),
2936            Status::NOT_FOUND
2937        );
2938
2939        // Deletion should now succeed as the profile will be placed as part of `finish_profiling()`
2940        volumes_directory.delete_profile("foo", "foo").await.expect("Deleting");
2941
2942        // Deletion fails as the file shouldn't exist anymore.
2943        assert_eq!(
2944            volumes_directory.delete_profile("foo", "foo").await.expect_err("File shouldn't exist"),
2945            Status::NOT_FOUND
2946        );
2947
2948        std::mem::drop(volume);
2949        volumes_directory.terminate().await;
2950        std::mem::drop(volumes_directory);
2951        filesystem.close().await.expect("Filesystem close");
2952    }
2953
2954    #[fuchsia::test(threads = 10)]
2955    async fn test_profile_start_single_volume() {
2956        const TEST_VOLUME: &str = "test_1234";
2957        const TEST_RECORDING: &str = "test_5678";
2958        let crypt = Arc::new(new_insecure_crypt()) as Arc<dyn Crypt>;
2959
2960        let fixture = TestFixture::new().await;
2961        {
2962            let volumes_directory = fixture.volumes_directory();
2963            // Start recording for volume that doesn't exist.
2964            assert_eq!(
2965                volumes_directory
2966                    .record_and_replay_profile(
2967                        Some(TEST_VOLUME.to_owned()),
2968                        TEST_RECORDING.to_owned(),
2969                        1
2970                    )
2971                    .await
2972                    .expect_err("Volumes doesn't exist yet"),
2973                Status::NOT_FOUND
2974            );
2975
2976            // Create the volume unmounted.
2977            {
2978                let volume = volumes_directory
2979                    .create_and_mount_volume(
2980                        TEST_VOLUME,
2981                        Some(crypt.clone()),
2982                        false,
2983                        CreateOptions::default(),
2984                    )
2985                    .await
2986                    .unwrap();
2987                volumes_directory
2988                    .lock()
2989                    .await
2990                    .unmount(volume.volume().store().store_object_id())
2991                    .await
2992                    .expect("unmount failed");
2993            }
2994
2995            // Start recording for volume that is not mounted.
2996            assert_eq!(
2997                volumes_directory
2998                    .record_and_replay_profile(
2999                        Some(TEST_VOLUME.to_owned()),
3000                        TEST_RECORDING.to_owned(),
3001                        1
3002                    )
3003                    .await
3004                    .expect_err("Volumes doesn't exist yet"),
3005                Status::UNAVAILABLE
3006            );
3007
3008            // Remount the volume and try again.
3009            let volume = volumes_directory
3010                .mount_volume(TEST_VOLUME, Some(crypt.clone()), false)
3011                .await
3012                .expect("Remount volume");
3013            volumes_directory
3014                .record_and_replay_profile(
3015                    Some(TEST_VOLUME.to_owned()),
3016                    TEST_RECORDING.to_owned(),
3017                    1,
3018                )
3019                .await
3020                .expect("Starting recording");
3021
3022            // Stop the recording and check that it was created on the new volume.
3023            volumes_directory.stop_profile_tasks().await;
3024            {
3025                let profile_dir = volume.volume().get_profile_directory().await.unwrap();
3026                assert!(profile_dir.lookup(TEST_RECORDING).await.unwrap().is_some());
3027            }
3028
3029            // Should be no recording for the other volume.
3030            {
3031                let profile_dir = fixture.volume().volume().get_profile_directory().await.unwrap();
3032                assert!(profile_dir.lookup(TEST_RECORDING).await.unwrap().is_none());
3033            }
3034        }
3035        fixture.close().await;
3036    }
3037
3038    #[fuchsia::test(threads = 10)]
3039    async fn test_replay_xor_record_profile_blob() {
3040        use crate::fuchsia::fxblob::testing::{BlobFixture, new_blob_fixture, open_blob_fixture};
3041        use crate::fuchsia::pager::PagerBacked;
3042        use delivery_blob::CompressionMode;
3043
3044        let fixture = new_blob_fixture().await;
3045        let hash = {
3046            let data = vec![88u8; 1024];
3047            fixture.write_blob(&data, CompressionMode::Never).await
3048        };
3049
3050        // Close and reopen to clear all caches so that subsequent reads trigger page faults.
3051        let device = fixture.close().await;
3052        device.ensure_unique();
3053
3054        device.reopen(false);
3055        let fixture = open_blob_fixture(device).await;
3056        let hash = {
3057            let volumes_directory = fixture.volumes_directory().clone();
3058            let identifier = ProfileIdentifier::BlobHash(*hash);
3059
3060            volumes_directory
3061                .clone()
3062                .replay_xor_record_profile("blob".to_owned(), identifier, 600)
3063                .await
3064                .expect("Starting replay_xor_record_profile recording");
3065
3066            // Trigger page faults by reading the VMO.
3067            let vmo = fixture.get_blob_vmo(hash).await;
3068            let mut read_buf = vec![0u8; 1024];
3069            vmo.read(&mut read_buf, 0).expect("VMO read failed");
3070
3071            volumes_directory.stop_profile_tasks().await;
3072            hash
3073        };
3074
3075        // Close and reopen again to clear caches and persist the profile.
3076        let device = fixture.close().await;
3077        device.ensure_unique();
3078
3079        device.reopen(false);
3080        let fixture = open_blob_fixture(device).await;
3081        {
3082            let volumes_directory = fixture.volumes_directory().clone();
3083            let identifier = ProfileIdentifier::BlobHash(*hash);
3084
3085            // Verify that initially nothing is paged in.
3086            let blob = fixture.get_blob(hash).await.expect("Opening blob");
3087            assert_eq!(blob.vmo().info().unwrap().populated_bytes, 0);
3088
3089            // Since the profile exists, it will replay it.
3090            volumes_directory
3091                .clone()
3092                .replay_xor_record_profile("blob".to_owned(), identifier, 600)
3093                .await
3094                .expect("Starting replay_xor_record_profile replay");
3095
3096            // Await all data being played back by checking that things have paged in.
3097            async {
3098                while blob.vmo().info().unwrap().populated_bytes == 0 {
3099                    fasync::Timer::new(Duration::from_millis(25)).await;
3100                }
3101            }
3102            .on_timeout(Duration::from_secs(60), || panic!("Replay did not page in for all VMOs"))
3103            .await;
3104
3105            volumes_directory.stop_profile_tasks().await;
3106        }
3107        fixture.close().await;
3108    }
3109
3110    #[fuchsia::test(threads = 10)]
3111    async fn test_replay_xor_record_profile_file() {
3112        use crate::fuchsia::file::FxFile;
3113        use crate::fuchsia::pager::PagerBacked;
3114
3115        let fixture = TestFixture::new_unencrypted().await;
3116        let object_id = {
3117            // 1. Create a file.
3118            let file_proxy = open_file_checked(
3119                fixture.root(),
3120                "foo",
3121                fio::Flags::FLAG_MAYBE_CREATE
3122                    | fio::PERM_READABLE
3123                    | fio::PERM_WRITABLE
3124                    | fio::Flags::PROTOCOL_FILE,
3125                &Default::default(),
3126            )
3127            .await;
3128
3129            let data = vec![88u8; 1024];
3130            file::write(&file_proxy, &data).await.expect("Write failed");
3131            file_proxy
3132                .get_attributes(fio::NodeAttributesQuery::ID)
3133                .await
3134                .unwrap()
3135                .expect("get_id")
3136                .1
3137                .id
3138                .expect("Missing id")
3139        };
3140
3141        let device = fixture.close().await;
3142        device.ensure_unique();
3143
3144        device.reopen(false);
3145        let fixture = TestFixture::open(
3146            device,
3147            TestFixtureOptions { encrypted: false, format: false, ..Default::default() },
3148        )
3149        .await;
3150        {
3151            let volumes_directory = fixture.volumes_directory().clone();
3152            let identifier = ProfileIdentifier::ObjectId(object_id);
3153
3154            // New profile, should record.
3155            volumes_directory
3156                .clone()
3157                .replay_xor_record_profile("vol".to_owned(), identifier, 600)
3158                .await
3159                .expect("Starting replay_xor_record_profile recording");
3160
3161            // Trigger page faults by reading the VMO.
3162            let file_proxy = open_file_checked(
3163                fixture.root(),
3164                "foo",
3165                fio::PERM_READABLE | fio::Flags::PROTOCOL_FILE,
3166                &Default::default(),
3167            )
3168            .await;
3169            let vmo = file_proxy
3170                .get_backing_memory(fio::VmoFlags::READ)
3171                .await
3172                .unwrap()
3173                .expect("Getting vmo");
3174            let mut buf = vec![0u8; 1024];
3175            vmo.read(&mut buf, 0).unwrap();
3176
3177            volumes_directory.stop_profile_tasks().await;
3178        }
3179
3180        let device = fixture.close().await;
3181        device.ensure_unique();
3182
3183        device.reopen(false);
3184        let fixture = TestFixture::open(
3185            device,
3186            TestFixtureOptions { encrypted: false, format: false, ..Default::default() },
3187        )
3188        .await;
3189        {
3190            let volumes_directory = fixture.volumes_directory().clone();
3191            let identifier = ProfileIdentifier::ObjectId(object_id);
3192
3193            // Verify initially nothing is paged in.
3194            let file_node = fixture
3195                .volume()
3196                .volume()
3197                .get_or_load_node(
3198                    object_id,
3199                    ObjectDescriptor::File,
3200                    Some(fixture.volume().root_dir()),
3201                )
3202                .await
3203                .expect("get_or_load_node failed")
3204                .into_any()
3205                .downcast::<FxFile>()
3206                .expect("Expected FxFile");
3207            assert_eq!(file_node.vmo().info().unwrap().populated_bytes, 0);
3208
3209            volumes_directory
3210                .clone()
3211                .replay_xor_record_profile("vol".to_owned(), identifier, 600)
3212                .await
3213                .expect("Starting replay_xor_record_profile replay");
3214
3215            // Await all data being played back.
3216            async {
3217                while file_node.vmo().info().unwrap().populated_bytes == 0 {
3218                    fasync::Timer::new(Duration::from_millis(25)).await;
3219                }
3220            }
3221            .on_timeout(Duration::from_secs(60), || panic!("Replay did not page in for all VMOs"))
3222            .await;
3223
3224            volumes_directory.stop_profile_tasks().await;
3225        }
3226        fixture.close().await;
3227    }
3228
3229    #[fuchsia::test(threads = 10)]
3230    async fn test_replay_xor_record_profile_unsupported_for_directory() {
3231        use crate::fuchsia::node::FxNode;
3232
3233        let fixture = TestFixture::new_unencrypted().await;
3234        {
3235            let dir_object_id = fixture.volume().root_dir().object_id();
3236            let volumes_directory = fixture.volumes_directory().clone();
3237            let identifier = ProfileIdentifier::ObjectId(dir_object_id);
3238
3239            let err = volumes_directory
3240                .clone()
3241                .replay_xor_record_profile("vol".to_owned(), identifier, 600)
3242                .await
3243                .expect_err("Expected NOT_SUPPORTED for directory");
3244            assert_eq!(err, zx::Status::NOT_SUPPORTED);
3245        }
3246
3247        fixture.close().await;
3248    }
3249
3250    #[fuchsia::test(threads = 10)]
3251    async fn test_replay_xor_record_profile_fails_if_unlinked() {
3252        let fixture = TestFixture::new_unencrypted().await;
3253        let (file_proxy, object_id) = {
3254            let file_proxy = open_file_checked(
3255                fixture.root(),
3256                "foo",
3257                fio::Flags::FLAG_MAYBE_CREATE
3258                    | fio::PERM_READABLE
3259                    | fio::PERM_WRITABLE
3260                    | fio::Flags::PROTOCOL_FILE,
3261                &Default::default(),
3262            )
3263            .await;
3264            let object_id = file_proxy
3265                .get_attributes(fio::NodeAttributesQuery::ID)
3266                .await
3267                .unwrap()
3268                .expect("get_id")
3269                .1
3270                .id
3271                .expect("Missing id");
3272            (file_proxy, object_id)
3273        };
3274
3275        // Unlink and close the file so it is purged.
3276        fixture
3277            .root()
3278            .unlink("foo", &fio::UnlinkOptions::default())
3279            .await
3280            .unwrap()
3281            .expect("unlink failed");
3282        file_proxy.close().await.expect("FIDL call failed").expect("close failed");
3283
3284        {
3285            let volumes_directory = fixture.volumes_directory().clone();
3286            let identifier = ProfileIdentifier::ObjectId(object_id);
3287
3288            let err = volumes_directory
3289                .clone()
3290                .replay_xor_record_profile("vol".to_owned(), identifier, 600)
3291                .await
3292                .expect_err("Expected NOT_FOUND for unlinked file");
3293            assert_eq!(err, zx::Status::NOT_FOUND);
3294        }
3295
3296        fixture.close().await;
3297    }
3298
3299    #[fuchsia::test(threads = 10)]
3300    async fn test_replay_xor_record_profile_fails_if_unlinked_while_open() {
3301        let fixture = TestFixture::new_unencrypted().await;
3302        let (file_proxy, object_id) = {
3303            let file_proxy = open_file_checked(
3304                fixture.root(),
3305                "foo",
3306                fio::Flags::FLAG_MAYBE_CREATE
3307                    | fio::PERM_READABLE
3308                    | fio::PERM_WRITABLE
3309                    | fio::Flags::PROTOCOL_FILE,
3310                &Default::default(),
3311            )
3312            .await;
3313            let object_id = file_proxy
3314                .get_attributes(fio::NodeAttributesQuery::ID)
3315                .await
3316                .unwrap()
3317                .expect("get_id")
3318                .1
3319                .id
3320                .expect("Missing id");
3321            (file_proxy, object_id)
3322        };
3323
3324        // Unlink the file while it is still open by file_proxy.
3325        fixture
3326            .root()
3327            .unlink("foo", &fio::UnlinkOptions::default())
3328            .await
3329            .unwrap()
3330            .expect("unlink failed");
3331
3332        {
3333            let volumes_directory = fixture.volumes_directory().clone();
3334            let identifier = ProfileIdentifier::ObjectId(object_id);
3335
3336            // The file is still open, but it is in the graveyard, so any profile we recorded would
3337            // be purged along with the file once the last handle closes. Reject it.
3338            let err = volumes_directory
3339                .clone()
3340                .replay_xor_record_profile("vol".to_owned(), identifier, 600)
3341                .await
3342                .expect_err("Expected NOT_FOUND for unlinked file that is still open");
3343            assert_eq!(err, zx::Status::NOT_FOUND);
3344        }
3345
3346        drop(file_proxy);
3347        fixture.close().await;
3348    }
3349
3350    // A file that has been truncated may have a `Trim` graveyard entry while remaining perfectly
3351    // live. That must not be confused with the `Some` entry that marks an object for purging.
3352    #[fuchsia::test(threads = 10)]
3353    async fn test_replay_xor_record_profile_succeeds_after_truncate() {
3354        let fixture = TestFixture::new_unencrypted().await;
3355        let file_proxy = open_file_checked(
3356            fixture.root(),
3357            "foo",
3358            fio::Flags::FLAG_MAYBE_CREATE
3359                | fio::PERM_READABLE
3360                | fio::PERM_WRITABLE
3361                | fio::Flags::PROTOCOL_FILE,
3362            &Default::default(),
3363        )
3364        .await;
3365        let object_id = file_proxy
3366            .get_attributes(fio::NodeAttributesQuery::ID)
3367            .await
3368            .unwrap()
3369            .expect("get_id")
3370            .1
3371            .id
3372            .expect("Missing id");
3373
3374        // Grow the file and then truncate it back down, which may leave a `Trim` graveyard entry.
3375        file_proxy.resize(1_048_576).await.expect("FIDL call failed").expect("resize failed");
3376        file_proxy.resize(0).await.expect("FIDL call failed").expect("resize failed");
3377
3378        {
3379            let volumes_directory = fixture.volumes_directory().clone();
3380            let identifier = ProfileIdentifier::ObjectId(object_id);
3381
3382            volumes_directory
3383                .clone()
3384                .replay_xor_record_profile("vol".to_owned(), identifier, 600)
3385                .await
3386                .expect("Profiling a live, recently truncated file should succeed");
3387
3388            volumes_directory.stop_profile_tasks().await;
3389        }
3390
3391        file_proxy.close().await.expect("FIDL call failed").expect("close failed");
3392        fixture.close().await;
3393    }
3394
3395    // Unlinking while a recording is in progress must not purge the file, because the recording
3396    // handle holds an open count. The purge should happen once the recording finishes.
3397    #[fuchsia::test(threads = 10)]
3398    async fn test_replay_xor_record_profile_unlink_during_recording() {
3399        let fixture = TestFixture::new_unencrypted().await;
3400        let file_proxy = open_file_checked(
3401            fixture.root(),
3402            "foo",
3403            fio::Flags::FLAG_MAYBE_CREATE
3404                | fio::PERM_READABLE
3405                | fio::PERM_WRITABLE
3406                | fio::Flags::PROTOCOL_FILE,
3407            &Default::default(),
3408        )
3409        .await;
3410        let object_id = file_proxy
3411            .get_attributes(fio::NodeAttributesQuery::ID)
3412            .await
3413            .unwrap()
3414            .expect("get_id")
3415            .1
3416            .id
3417            .expect("Missing id");
3418
3419        // Borrow rather than clone: an extra `Arc<ObjectStore>` alive at `fixture.close()` would
3420        // trip the fixture's check for dangling device references.
3421        let store = fixture.volume().volume().store();
3422        let graveyard_id = store.graveyard_directory_object_id();
3423
3424        {
3425            let volumes_directory = fixture.volumes_directory().clone();
3426            let identifier = ProfileIdentifier::ObjectId(object_id);
3427
3428            volumes_directory
3429                .clone()
3430                .replay_xor_record_profile("vol".to_owned(), identifier, 600)
3431                .await
3432                .expect("Starting replay_xor_record_profile recording");
3433
3434            // Unlink and close while the recording is active. The recording handle holds an open
3435            // count, so the tombstone must be deferred rather than run now.
3436            fixture
3437                .root()
3438                .unlink("foo", &fio::UnlinkOptions::default())
3439                .await
3440                .unwrap()
3441                .expect("unlink failed");
3442            file_proxy.close().await.expect("FIDL call failed").expect("close failed");
3443
3444            // Drain the graveyard queue. Anything that was going to purge the object has now had
3445            // its chance, so the assertions below distinguish "deferred" from "merely slow".
3446            fixture.fs().graveyard().flush().await;
3447
3448            assert!(
3449                store.tree().find(&ObjectKey::object(object_id)).await.unwrap().is_some(),
3450                "Object must not be purged while a recording holds it open",
3451            );
3452            assert!(
3453                matches!(
3454                    store
3455                        .tree()
3456                        .find_value(&ObjectKey::graveyard_entry(graveyard_id, object_id))
3457                        .await
3458                        .unwrap(),
3459                    Some(ObjectValue::Some)
3460                ),
3461                "Object should be in the graveyard awaiting purge",
3462            );
3463
3464            // Completes the recording and drops the handle, releasing the open count.
3465            volumes_directory.stop_profile_tasks().await;
3466        }
3467
3468        // The deferred purge must now actually run, rather than leaking the object.
3469        fixture.fs().graveyard().flush().await;
3470
3471        assert!(
3472            store.tree().find(&ObjectKey::object(object_id)).await.unwrap().is_none(),
3473            "Object should be purged once the recording handle is dropped",
3474        );
3475        assert!(
3476            store
3477                .tree()
3478                .find_value(&ObjectKey::graveyard_entry(graveyard_id, object_id))
3479                .await
3480                .unwrap()
3481                .is_none(),
3482            "Graveyard entry should be removed once the object is purged",
3483        );
3484        assert!(
3485            store
3486                .tree()
3487                .find(&ObjectKey::attribute(
3488                    object_id,
3489                    AttributeId::PROFILE_RECORDING,
3490                    AttributeKey::Attribute,
3491                ))
3492                .await
3493                .unwrap()
3494                .is_none(),
3495            "Profile recording attribute should not outlive the object",
3496        );
3497
3498        fixture.close().await;
3499    }
3500
3501    #[fuchsia::test(threads = 10)]
3502    async fn test_delete_volume_while_flushing() {
3503        let device = DeviceHolder::new(FakeDevice::new(8192, 512));
3504        let filesystem = FxFilesystem::new_empty(device).await.unwrap();
3505        let page_fault_counter =
3506            Arc::new(PageFaultCounter::new().expect("Failed to create PageFaultCounter"));
3507        let volumes_directory = VolumesDirectory::new(
3508            root_volume(filesystem.clone()).await.unwrap(),
3509            Weak::new(),
3510            None,
3511            page_fault_counter,
3512            MemoryPressureConfig::default(),
3513        )
3514        .await
3515        .unwrap();
3516        let name = "vol";
3517        let volume = volumes_directory
3518            .create_and_mount_volume(name, None, false, CreateOptions::default())
3519            .await
3520            .unwrap();
3521        let mut transaction = filesystem
3522            .root_store()
3523            .new_transaction(
3524                lock_keys![LockKey::object(
3525                    volume.volume().store().store_object_id(),
3526                    volume.root_dir().directory().object_id()
3527                )],
3528                Options::default(),
3529            )
3530            .await
3531            .unwrap();
3532        volume
3533            .root_dir()
3534            .directory()
3535            .create_child_file(&mut transaction, "foo")
3536            .await
3537            .expect("create_child_file failed");
3538        transaction.commit().await.expect("commit failed");
3539        volumes_directory
3540            .lock()
3541            .await
3542            .unmount(volume.volume().store().store_object_id())
3543            .await
3544            .expect("unmount failed");
3545
3546        let filesystem_clone = filesystem.clone();
3547        let filesystem_clone2 = filesystem.clone();
3548        let volumes_directory_clone1 = volumes_directory.clone();
3549        let volumes_directory_clone2 = volumes_directory.clone();
3550        let root_store_object_id = filesystem.root_store().store_object_id();
3551        let store_info_object_id = volume.volume().store().store_info_handle_object_id().unwrap();
3552        join!(
3553            async move {
3554                // Take a lock that the EndFlush transaction requires, so we interleave removing
3555                // the volume between StartFlush and EndFlush.  Release it on a timer since once the
3556                // volume is deleted, `remove_volume` needs to take this lock as well to tombstone
3557                // the store info.
3558                let _guard = filesystem_clone2
3559                    .lock_manager()
3560                    .read_lock(lock_keys![LockKey::object(
3561                        root_store_object_id,
3562                        store_info_object_id,
3563                    )])
3564                    .await;
3565                fasync::Timer::new(Duration::from_millis(200)).await;
3566            },
3567            async move {
3568                filesystem_clone.journal().force_compact().await.expect("Compact failed");
3569            },
3570            async move {
3571                if let Err(e) = volumes_directory_clone1.remove_volume(name).await {
3572                    if !FxfsError::NotFound.matches(&e) {
3573                        panic!("remove_volume failed: {e:?}");
3574                    }
3575                }
3576            },
3577            async move {
3578                if let Err(e) = volumes_directory_clone2.remove_volume(name).await {
3579                    if !FxfsError::NotFound.matches(&e) {
3580                        panic!("remove_volume failed: {e:?}");
3581                    }
3582                }
3583            },
3584        );
3585        volumes_directory.terminate().await;
3586        std::mem::drop(volumes_directory);
3587        filesystem.close().await.expect("Filesystem close");
3588    }
3589
3590    // This mostly just ensures that we exercise the code path. It was added because the path at
3591    // one point contained a deadlock.
3592    #[fuchsia::test(threads = 10)]
3593    async fn test_flush_before_mark_dirty_under_critical_memory_pressure() {
3594        let fixture = TestFixture::new().await;
3595        // Memory is critical, and it's always our fault.
3596        let _ = fixture
3597            .memory_pressure_proxy()
3598            .on_level_changed(MemoryPressureLevel::Critical)
3599            .await
3600            .expect("memory pressure FIDL");
3601        fixture.volumes_directory().max_dirty_bytes_when_critical.store(1, Ordering::Relaxed);
3602
3603        let root = fixture.root();
3604        let file = open_file_checked(
3605            &root,
3606            "foo",
3607            fio::Flags::FLAG_MAYBE_CREATE
3608                | fio::PERM_READABLE
3609                | fio::PERM_WRITABLE
3610                | fio::Flags::PROTOCOL_FILE,
3611            &Default::default(),
3612        )
3613        .await;
3614
3615        file.resize((page_size() * 2).into()).await.expect("resize (FIDL)").expect("resize failed");
3616        // The above resize creates zero pages which aren't dirty pages and don't contribute to the
3617        // dirty bytes count but still need to be flushed. The first write below will cross the
3618        // `max_dirty_bytes_when_critical` threshold but `minimize_memory` won't flush the file
3619        // because the zero pages aren't dirty pages. The second write below will also cross the
3620        // `max_dirty_bytes_when_critical` threshold and since the first write dirtied a page, a
3621        // flush will occur. The flush cleans the 2nd page which is a zero page and the kernel is
3622        // actively trying to dirty. The kernel doesn't end up dirtying the 2nd page because it's
3623        // concerned that the clean and dirty raced so it issues another dirty request for the same
3624        // page. The duplicate dirty request again crosses the `max_dirty_bytes_when_critical`
3625        // threshold. The file thinks that it has a dirty page so `minimize_memory` flushes the
3626        // file. `zx_pager_query_dirty_ranges` doesn't return any pages because the kernel didn't
3627        // actually dirty the page that fxfs thought it did. This causes only the file metadata to
3628        // be flushed and the dirty page count to not be reduced. The 2nd page finally gets dirtied
3629        // and now fxfs thinks it has 2 dirty pages instead of 1. `PagedObjectHandle` knows that
3630        // this can happen and will fix up the counts on the next flush. This test doesn't want to
3631        // deal with all of that so it syncs here to clean the zero pages that would cause that
3632        // mess.
3633        file.sync().await.expect("Failed to make sync call").expect("sync failed");
3634
3635        let vmo = file
3636            .get_backing_memory(fio::VmoFlags::READ | fio::VmoFlags::WRITE)
3637            .await
3638            .expect("get_backing_memory (FIDL)")
3639            .expect("get_backing_memory");
3640
3641        let buf = [0xAAu8];
3642        // One call to get dirty bytes over 0, the second to force a flush during mark_dirty.
3643        vmo.write(&buf, 0).expect("Writing to create dirty bytes");
3644        let before = fixture.volumes_directory().pager_dirty_bytes_count.load();
3645        vmo.write(&buf, page_size().get()).expect("Writing to force a flush during mark_dirty");
3646        // This is still the page size because we forced a flush of the first write during the
3647        // second write.
3648        assert_eq!(fixture.volumes_directory().pager_dirty_bytes_count.load(), before,);
3649
3650        fixture.close().await;
3651    }
3652
3653    #[fuchsia::test(threads = 10)]
3654    async fn test_delete_crypt_for_volume() {
3655        let device = DeviceHolder::new(FakeDevice::new(8192, 512));
3656        let filesystem = FxFilesystem::new_empty(device).await.unwrap();
3657        let store_id;
3658        {
3659            let page_fault_counter =
3660                Arc::new(PageFaultCounter::new().expect("Failed to create PageFaultCounter"));
3661            let volumes_directory = VolumesDirectory::new(
3662                root_volume(filesystem.clone()).await.unwrap(),
3663                Weak::new(),
3664                None,
3665                page_fault_counter,
3666                MemoryPressureConfig::default(),
3667            )
3668            .await
3669            .unwrap();
3670            let name = "vol";
3671            let crypt = Arc::new(new_insecure_crypt());
3672            let volume = volumes_directory
3673                .create_and_mount_volume(name, Some(crypt.clone()), false, CreateOptions::default())
3674                .await
3675                .unwrap();
3676            store_id = volume.volume().store().store_object_id();
3677            // Make sure the volume has some journaled mutations.
3678            let mut transaction = filesystem
3679                .root_store()
3680                .new_transaction(
3681                    lock_keys![LockKey::object(
3682                        volume.volume().store().store_object_id(),
3683                        volume.root_dir().directory().object_id()
3684                    )],
3685                    Options::default(),
3686                )
3687                .await
3688                .unwrap();
3689            volume
3690                .root_dir()
3691                .directory()
3692                .create_child_file(&mut transaction, "foo")
3693                .await
3694                .expect("create_child_file failed");
3695            transaction.commit().await.expect("commit failed");
3696
3697            let (volume_dir_proxy, dir_server_end) =
3698                fidl::endpoints::create_proxy::<fio::DirectoryMarker>();
3699            volumes_directory
3700                .serve_volume(&volume, dir_server_end, false)
3701                .expect("serve_volume failed");
3702            let (root_dir, root_server_end) =
3703                fidl::endpoints::create_proxy::<fio::DirectoryMarker>();
3704            volume_dir_proxy
3705                .open(
3706                    "root",
3707                    fio::PERM_READABLE | fio::PERM_WRITABLE | fio::Flags::PROTOCOL_DIRECTORY,
3708                    &Default::default(),
3709                    root_server_end.into_channel(),
3710                )
3711                .expect("Failed to open volume root");
3712
3713            let filesystem_clone = filesystem.clone();
3714            join!(
3715                async move {
3716                    filesystem_clone.journal().force_compact().await.expect("Compact failed");
3717                },
3718                async move {
3719                    let mut i = 0;
3720                    while let Ok(_) = fuchsia_fs::directory::open_file(
3721                        &root_dir,
3722                        &format!("foo{i}"),
3723                        fio::Flags::FLAG_MAYBE_CREATE | fio::PERM_READABLE,
3724                    )
3725                    .await
3726                    {
3727                        i += 1;
3728                    }
3729                },
3730                async move {
3731                    crypt.shutdown();
3732                },
3733            );
3734
3735            // Make sure we can still ask the volume to shutdown.
3736            let (admin_proxy, server_end) =
3737                fidl::endpoints::create_proxy::<fidl_fuchsia_fs::AdminMarker>();
3738            volume_dir_proxy
3739                .open(
3740                    &format!("svc/{}", fidl_fuchsia_fs::AdminMarker::PROTOCOL_NAME),
3741                    fio::Flags::PROTOCOL_SERVICE,
3742                    &Default::default(),
3743                    server_end.into(),
3744                )
3745                .expect("Failed to open Admin connection");
3746            admin_proxy.shutdown().await.expect("shutdown failed");
3747
3748            volumes_directory.terminate().await;
3749        }
3750        filesystem.close().await.expect("Filesystem close");
3751        let device = filesystem.take_device().await;
3752        device.reopen(false);
3753        let filesystem = FxFilesystem::open(device).await.expect("open failed");
3754        let options = FsckOptions { fail_on_warning: true, ..Default::default() };
3755        fsck_with_options(filesystem.clone(), &options).await.expect("fsck failed");
3756        fsck_volume_with_options(
3757            filesystem.as_ref(),
3758            &options,
3759            store_id,
3760            Some(Arc::new(new_insecure_crypt())),
3761        )
3762        .await
3763        .expect("fsck_volume failed");
3764        filesystem.close().await.expect("Filesystem close");
3765    }
3766
3767    /// Tests writing a partition image and installing a volume contained within.
3768    #[fuchsia::test(threads = 10)]
3769    async fn test_volume_installation() {
3770        let fixture = TestFixture::open(
3771            DeviceHolder::new(FakeDevice::new(1024, 4096)),
3772            TestFixtureOptions { format: true, encrypted: false, ..Default::default() },
3773        )
3774        .await;
3775
3776        // Create a file "foo" in the existing volume "vol". This should be gone after installation.
3777        {
3778            let file = open_file_checked(
3779                fixture.root(),
3780                "foo",
3781                fio::Flags::PROTOCOL_FILE | fio::Flags::FLAG_MUST_CREATE | fio::PERM_WRITABLE,
3782                &Default::default(),
3783            )
3784            .await;
3785            file.write("Hello, world!".as_bytes()).await.unwrap().expect("write failed");
3786        };
3787
3788        // Create another in-memory partition image with a different set of files.
3789        let image = {
3790            let inner_fixture = TestFixture::open(
3791                DeviceHolder::new(FakeDevice::new(512, 4096)),
3792                TestFixtureOptions { format: true, encrypted: false, ..Default::default() },
3793            )
3794            .await;
3795            let file = open_file_checked(
3796                inner_fixture.root(),
3797                "bar",
3798                fio::Flags::PROTOCOL_FILE | fio::Flags::FLAG_MUST_CREATE | fio::PERM_WRITABLE,
3799                &Default::default(),
3800            )
3801            .await;
3802            file.write("Well, this is new...".as_bytes()).await.unwrap().expect("write failed");
3803            file.close().await.unwrap().expect("close error");
3804            inner_fixture.close().await
3805        };
3806
3807        // Write the partition image to a file "install" in a new volume called "src".
3808        {
3809            let (src_out_dir, server_end) = fidl::endpoints::create_proxy::<fio::DirectoryMarker>();
3810            fixture
3811                .volumes_directory()
3812                .create_and_serve_volume("src", server_end, Default::default(), Default::default())
3813                .await
3814                .unwrap();
3815            let src_root = open_dir_checked(
3816                &src_out_dir,
3817                "root",
3818                fio::PERM_READABLE | fio::PERM_WRITABLE,
3819                Default::default(),
3820            )
3821            .await;
3822            let file = open_file_checked(
3823                &src_root,
3824                "image",
3825                fio::Flags::PROTOCOL_FILE | fio::Flags::FLAG_MUST_CREATE | fio::PERM_WRITABLE,
3826                &Default::default(),
3827            )
3828            .await;
3829            write_image_to_file(image, file).await;
3830        };
3831
3832        // Installation should not be possible yet since both volumes are still mounted.
3833        assert!(
3834            fixture.volumes_directory().install_volume("src", "image", "vol").await.is_err(),
3835            "volume installation should fail while either src/dst is still mounted"
3836        );
3837
3838        // Now let's re-mount the filesystem manually without a fixture, install the volumes, and
3839        // spin up a new fixture to verify the result.
3840        let device = fixture.close().await;
3841        let fs = FxFilesystem::open(device).await.unwrap();
3842        {
3843            let root = root_volume(fs.clone()).await.unwrap();
3844            root.install_volume("src", "image", "vol").await.unwrap();
3845        }
3846        fs.close().await.unwrap();
3847        let device = fs.take_device().await;
3848        device.reopen(false);
3849        let fixture = TestFixture::open(
3850            device,
3851            TestFixtureOptions { encrypted: false, format: false, ..Default::default() },
3852        )
3853        .await;
3854
3855        // Ensure that the "src" volume is now gone, and the old file "foo" is gone from "vol".
3856        assert!(
3857            fixture.volumes_directory().mount_volume("src", None, false).await.is_err(),
3858            "src volume should be deleted after installation"
3859        );
3860        assert!(
3861            testing::open_file(
3862                fixture.volume_out_dir(),
3863                "foo",
3864                fio::PERM_READABLE,
3865                &Default::default()
3866            )
3867            .await
3868            .is_err(),
3869            "foo should be deleted after installation"
3870        );
3871
3872        // Check that we can find the contents of "vol" that we installed from the image.
3873        let file =
3874            open_file_checked(fixture.root(), "bar", fio::PERM_READABLE, &Default::default()).await;
3875        let data = file.read(fio::MAX_TRANSFER_SIZE).await.unwrap().expect("read failed");
3876        assert_eq!(String::from_utf8(data).unwrap(), "Well, this is new...");
3877        file.close().await.unwrap().unwrap();
3878
3879        fixture.close().await;
3880    }
3881
3882    #[fuchsia::test]
3883    async fn test_create_with_low_32_bit_ids() {
3884        let device = DeviceHolder::new(FakeDevice::new(8192, 512));
3885        let filesystem = FxFilesystem::new_empty(device).await.unwrap();
3886        let page_fault_counter =
3887            Arc::new(PageFaultCounter::new().expect("Failed to create PageFaultCounter"));
3888
3889        {
3890            let volumes_directory = VolumesDirectory::new(
3891                root_volume(filesystem.clone()).await.unwrap(),
3892                Weak::new(),
3893                None,
3894                page_fault_counter,
3895                MemoryPressureConfig::default(),
3896            )
3897            .await
3898            .unwrap();
3899
3900            let mut guard = volumes_directory.lock().await;
3901
3902            let vol = guard
3903                .create_or_mount_volume(
3904                    "low_32",
3905                    None,
3906                    Mode::Create { guid: None, low_32_bit_object_ids: true },
3907                    false,
3908                    false,
3909                )
3910                .await
3911                .expect("create volume failed");
3912
3913            let root_dir = vol.volume().store().root_directory_object_id();
3914            let root_dir = fxfs::object_store::Directory::open(vol.volume().store(), root_dir)
3915                .await
3916                .expect("open failed");
3917
3918            let mut transaction = filesystem
3919                .root_store()
3920                .new_transaction(
3921                    lock_keys![LockKey::object(
3922                        vol.volume().store().store_object_id(),
3923                        root_dir.object_id()
3924                    )],
3925                    Options::default(),
3926                )
3927                .await
3928                .expect("new_transaction failed");
3929
3930            let object = root_dir
3931                .create_child_file(&mut transaction, "test")
3932                .await
3933                .expect("create_child_file failed");
3934
3935            // We can't check LastObjectIdInfo as it is private, but we can verify behavior.
3936            assert!(object.object_id() < 1 << 32);
3937            transaction.commit().await.expect("commit failed");
3938        };
3939
3940        filesystem.close().await.expect("close filesystem failed");
3941
3942        // Reopen and verify persistence
3943        let device = filesystem.take_device().await;
3944        device.reopen(false);
3945        let filesystem = FxFilesystem::open(device).await.unwrap();
3946        let page_fault_counter =
3947            Arc::new(PageFaultCounter::new().expect("Failed to create PageFaultCounter"));
3948        let volumes_directory = VolumesDirectory::new(
3949            root_volume(filesystem.clone()).await.unwrap(),
3950            Weak::new(),
3951            None,
3952            page_fault_counter,
3953            MemoryPressureConfig::default(),
3954        )
3955        .await
3956        .unwrap();
3957
3958        // Mount the volume again, and check that new files are still created with expected IDs.
3959        {
3960            let mut guard = volumes_directory.lock().await;
3961
3962            let vol = guard
3963                .create_or_mount_volume("low_32", None, Mode::Mount, false, false)
3964                .await
3965                .expect("mount volume failed");
3966
3967            let root_dir = vol.volume().store().root_directory_object_id();
3968            let root_dir = fxfs::object_store::Directory::open(vol.volume().store(), root_dir)
3969                .await
3970                .expect("open failed");
3971
3972            let mut transaction = filesystem
3973                .root_store()
3974                .new_transaction(
3975                    lock_keys![LockKey::object(
3976                        vol.volume().store().store_object_id(),
3977                        root_dir.object_id()
3978                    )],
3979                    Options::default(),
3980                )
3981                .await
3982                .expect("new_transaction failed");
3983
3984            let object = root_dir
3985                .create_child_file(&mut transaction, "test2")
3986                .await
3987                .expect("create_child_file failed");
3988
3989            assert!(object.object_id() < 1 << 32);
3990            transaction.commit().await.expect("commit failed");
3991        }
3992
3993        filesystem.close().await.expect("close filesystem failed");
3994    }
3995
3996    #[fuchsia::test(threads = 10)]
3997    async fn test_race_unmount_and_flush_with_crypt_error() {
3998        let device = DeviceHolder::new(FakeDevice::new(8192, 512));
3999        let filesystem = FxFilesystem::new_empty(device).await.unwrap();
4000        let page_fault_counter = Arc::new(PageFaultCounter::new().unwrap());
4001        let volumes_directory = VolumesDirectory::new(
4002            root_volume(filesystem.clone()).await.unwrap(),
4003            Weak::new(),
4004            None,
4005            page_fault_counter,
4006            MemoryPressureConfig::default(),
4007        )
4008        .await
4009        .unwrap();
4010
4011        let crypt_service = Arc::new(fxfs_crypt::CryptService::new());
4012        crypt_service
4013            .add_wrapping_key(0, fxfs_insecure_crypto::DATA_KEY.to_vec())
4014            .expect("add_wrapping_key failed");
4015        crypt_service
4016            .add_wrapping_key(1, fxfs_insecure_crypto::METADATA_KEY.to_vec())
4017            .expect("add_wrapping_key failed");
4018        crypt_service.set_active_key(KeyPurpose::Data, 0).expect("set_active_key failed");
4019        crypt_service.set_active_key(KeyPurpose::Metadata, 1).expect("set_active_key failed");
4020
4021        for _ in 0..20 {
4022            let (client, mut stream) = create_request_stream::<fidl_fuchsia_fxfs::CryptMarker>();
4023            let (close_tx, mut close_rx) = futures::channel::oneshot::channel::<()>();
4024
4025            let crypt_task = fasync::Task::spawn(async move {
4026                loop {
4027                    futures::select! {
4028                        _ = close_rx => return, // Close signal
4029                        request = stream.try_next() => {
4030                            match request {
4031                                Ok(Some(CryptRequest::CreateKey { responder, .. })) => {
4032                                    responder.send(Ok((&[0; 16], &[0; 48], &[0; 32]))).unwrap();
4033                                }
4034                                Ok(Some(CryptRequest::CreateKeyWithId {
4035                                        wrapping_key_id, responder, .. })) => {
4036                                    let key = WrappedKey::Fxfs(FxfsKey {
4037                                         wrapping_key_id,
4038                                         wrapped_key: [0u8; 48],
4039                                     });
4040                                     responder.send(Ok((&key, &[0; 32], None))).unwrap();
4041                                 }
4042                                 Ok(Some(CryptRequest::UnwrapKey { responder, .. })) => {
4043                                     responder.send(Ok((&vec![0; 32], None))).unwrap();
4044                                 }
4045                                _ => return,
4046                            }
4047                        }
4048                    }
4049                }
4050            });
4051
4052            let volume = volumes_directory
4053                .create_and_mount_volume(
4054                    "encrypted",
4055                    Some(Arc::new(RemoteCrypt::new(client))),
4056                    false,
4057                    CreateOptions::default(),
4058                )
4059                .await
4060                .unwrap();
4061
4062            // Write some data to dirty the journal.
4063            {
4064                let mut transaction = filesystem
4065                    .root_store()
4066                    .new_transaction(
4067                        lock_keys![LockKey::object(
4068                            volume.volume().store().store_object_id(),
4069                            volume.root_dir().directory().object_id()
4070                        )],
4071                        Options::default(),
4072                    )
4073                    .await
4074                    .unwrap();
4075                volume
4076                    .root_dir()
4077                    .directory()
4078                    .create_child_file(&mut transaction, "foo")
4079                    .await
4080                    .expect("create_child_file failed");
4081                transaction.commit().await.expect("commit failed");
4082            }
4083
4084            let (dir_proxy, dir_server_end) =
4085                fidl::endpoints::create_proxy::<fio::DirectoryMarker>();
4086            volumes_directory.serve_volume(&volume, dir_server_end, false).unwrap();
4087            volumes_directory.lock().await.auto_unmount(volume.volume().store().store_object_id());
4088
4089            // Kill crypt.  The next usage should be in flush.
4090            let _ = close_tx.send(());
4091
4092            let filesystem_clone = filesystem.clone();
4093            let compact_task = fasync::Task::spawn(async move {
4094                // Flush should not fail, because that would close the journal for the rest of the
4095                // filesystem.  Instead, the volume should be force-locked and flushed (which
4096                // doesn't depend on crypt).
4097                filesystem_clone
4098                    .object_manager()
4099                    .flush(FlushReason::Journal(ForceMajor::False))
4100                    .await
4101                    .expect("flush failed");
4102            });
4103
4104            // Trigger unmount.
4105            std::mem::drop(dir_proxy);
4106
4107            // Wait for volume to be unmounted, so we can clean up for the next iteration.
4108            let store_id = volume.volume().store().store_object_id();
4109            loop {
4110                {
4111                    let guard = volumes_directory.lock().await;
4112                    if !guard.mounted_volumes.contains_key(&store_id) {
4113                        break;
4114                    }
4115                }
4116                fasync::Timer::new(Duration::from_millis(10)).await;
4117            }
4118
4119            join!(compact_task, crypt_task);
4120            volumes_directory.remove_volume("encrypted").await.expect("remove_volume failed");
4121        }
4122        volumes_directory.terminate().await;
4123        filesystem.close().await.expect("close filesystem failed");
4124    }
4125
4126    async fn test_setup() -> (OpenFxFilesystem, Arc<VolumesDirectory>) {
4127        let device = DeviceHolder::new(FakeDevice::new(8192, 512));
4128        let filesystem = FxFilesystemBuilder::new().format(true).open(device).await.unwrap();
4129        let blob_resupplied_count =
4130            Arc::new(PageFaultCounter::new().expect("Failed to create PageFaultCounter"));
4131        let volumes_directory = VolumesDirectory::new(
4132            root_volume(filesystem.clone()).await.unwrap(),
4133            Weak::new(),
4134            None,
4135            blob_resupplied_count,
4136            MemoryPressureConfig::default(),
4137        )
4138        .await
4139        .unwrap();
4140        (filesystem, volumes_directory)
4141    }
4142
4143    #[fuchsia::test]
4144    async fn test_mount_remote_volume_mounts_and_serves_remote_volume() {
4145        let (filesystem, volumes_directory) = test_setup().await;
4146
4147        volumes_directory
4148            .root_volume
4149            .new_volume("remote_vol_test", NewChildStoreOptions::default())
4150            .await
4151            .expect("new_volume failed");
4152
4153        let (remote_proxy, remote_server_end) =
4154            fidl::endpoints::create_proxy::<ffxfs::RemoteVolumeMarker>();
4155
4156        let (info, initial_layers, _guid) = volumes_directory
4157            .mount_remote_volume("remote_vol_test", None, remote_server_end)
4158            .await
4159            .expect("mount_remote_volume failed");
4160
4161        assert_ne!(info.root_directory_object_id, 0);
4162        assert_eq!(info.block_size, filesystem.block_size().get());
4163
4164        // Even for a newly created volume, flushing the initial root and graveyard directory
4165        // mutations produces a persistent layer.
4166        assert!(!initial_layers.layers.is_empty());
4167
4168        // Close remote volume.
4169        let close_res = remote_proxy.close().await.expect("close FIDL failed");
4170        assert!(close_res.is_ok());
4171
4172        volumes_directory.terminate().await;
4173        filesystem.close().await.expect("close failed");
4174    }
4175
4176    #[fuchsia::test]
4177    async fn test_mount_remote_volume_prevents_duplicate_mounts() {
4178        let (filesystem, volumes_directory) = test_setup().await;
4179
4180        volumes_directory
4181            .root_volume
4182            .new_volume("dup_vol_test", NewChildStoreOptions::default())
4183            .await
4184            .expect("new_volume failed");
4185
4186        let (_remote_proxy1, remote_server_end1) =
4187            fidl::endpoints::create_proxy::<ffxfs::RemoteVolumeMarker>();
4188        let (_remote_proxy2, remote_server_end2) =
4189            fidl::endpoints::create_proxy::<ffxfs::RemoteVolumeMarker>();
4190
4191        // First mount succeeds.
4192        volumes_directory
4193            .mount_remote_volume("dup_vol_test", None, remote_server_end1)
4194            .await
4195            .expect("first mount should succeed");
4196
4197        // Second mount for the same volume while mounted must fail with AlreadyBound.
4198        let err = volumes_directory
4199            .mount_remote_volume("dup_vol_test", None, remote_server_end2)
4200            .await
4201            .expect_err("second mount must fail");
4202        assert!(FxfsError::AlreadyBound.matches(&err));
4203
4204        volumes_directory.terminate().await;
4205        filesystem.close().await.expect("close failed");
4206    }
4207
4208    #[fuchsia::test]
4209    async fn test_mount_remote_volume_via_volume_request_mount_remote() {
4210        let (filesystem, volumes_directory) = test_setup().await;
4211
4212        // Create volume through volumes_directory so it has an entry.
4213        {
4214            let (dir_proxy, dir_server_end) =
4215                fidl::endpoints::create_proxy::<fio::DirectoryMarker>();
4216            volumes_directory
4217                .create_and_serve_volume(
4218                    "vol_fidl_test",
4219                    dir_server_end,
4220                    MountOptions::default(),
4221                    CreateOptions::default(),
4222                )
4223                .await
4224                .expect("create_and_serve_volume failed");
4225            drop(dir_proxy);
4226        }
4227
4228        // Wait for it to unmount.
4229        loop {
4230            {
4231                let guard = volumes_directory.lock().await;
4232                if guard.mounted_volumes.is_empty() {
4233                    break;
4234                }
4235            }
4236            fasync::Timer::new(Duration::from_millis(10)).await;
4237        }
4238
4239        // Open volume directory node to send MountRemote.
4240        let (vol_proxy, vol_server_end) =
4241            fidl::endpoints::create_proxy::<fidl_fuchsia_fs_startup::VolumeMarker>();
4242        let (store_id, _, _) = volumes_directory
4243            .root_volume
4244            .volume_directory()
4245            .lookup("vol_fidl_test")
4246            .await
4247            .unwrap()
4248            .unwrap();
4249        let volumes_dir_clone = volumes_directory.clone();
4250        let _task = fasync::Task::spawn(async move {
4251            let _ = volumes_dir_clone
4252                .handle_volume_requests("vol_fidl_test", vol_server_end.into_stream(), store_id)
4253                .await;
4254        });
4255
4256        let (remote_proxy, remote_server_end) =
4257            fidl::endpoints::create_proxy::<ffxfs::RemoteVolumeMarker>();
4258        let res = vol_proxy
4259            .mount_remote(MountOptions::default(), remote_server_end)
4260            .await
4261            .expect("mount_remote FIDL failed");
4262        assert!(res.is_ok());
4263
4264        let close_res = remote_proxy.close().await.expect("close FIDL failed");
4265        assert!(close_res.is_ok());
4266
4267        drop(vol_proxy);
4268
4269        volumes_directory.terminate().await;
4270        filesystem.close().await.expect("close failed");
4271    }
4272
4273    #[fuchsia::test]
4274    async fn test_mount_remote_volume_unmount_on_close() {
4275        let (filesystem, volumes_directory) = test_setup().await;
4276
4277        volumes_directory
4278            .root_volume
4279            .new_volume("unmount_test", NewChildStoreOptions::default())
4280            .await
4281            .expect("new_volume failed");
4282
4283        let (remote_proxy, remote_server_end) =
4284            fidl::endpoints::create_proxy::<ffxfs::RemoteVolumeMarker>();
4285
4286        let _ = volumes_directory
4287            .mount_remote_volume("unmount_test", None, remote_server_end)
4288            .await
4289            .expect("mount_remote_volume failed");
4290
4291        let (store_id, _, _) = volumes_directory
4292            .root_volume
4293            .volume_directory()
4294            .lookup("unmount_test")
4295            .await
4296            .unwrap()
4297            .unwrap();
4298
4299        // Volume is currently mounted.
4300        assert!(volumes_directory.lock().await.mounted_volumes.contains_key(&store_id));
4301
4302        // Call close on RemoteVolume proxy.
4303        let close_res = remote_proxy.close().await.expect("close FIDL failed");
4304        assert!(close_res.is_ok());
4305
4306        // Wait for unmount to complete in VolumesDirectory.
4307        loop {
4308            {
4309                let guard = volumes_directory.lock().await;
4310                if !guard.mounted_volumes.contains_key(&store_id) {
4311                    break;
4312                }
4313            }
4314            fasync::Timer::new(Duration::from_millis(10)).await;
4315        }
4316
4317        volumes_directory.terminate().await;
4318        filesystem.close().await.expect("close failed");
4319    }
4320
4321    #[fuchsia::test]
4322    async fn test_mount_remote_volume_unmount_on_client_channel_drop() {
4323        let (filesystem, volumes_directory) = test_setup().await;
4324
4325        volumes_directory
4326            .root_volume
4327            .new_volume("drop_test", NewChildStoreOptions::default())
4328            .await
4329            .expect("new_volume failed");
4330
4331        let (remote_proxy, remote_server_end) =
4332            fidl::endpoints::create_proxy::<ffxfs::RemoteVolumeMarker>();
4333
4334        let _ = volumes_directory
4335            .mount_remote_volume("drop_test", None, remote_server_end)
4336            .await
4337            .expect("mount_remote_volume failed");
4338
4339        let (store_id, _, _) = volumes_directory
4340            .root_volume
4341            .volume_directory()
4342            .lookup("drop_test")
4343            .await
4344            .unwrap()
4345            .unwrap();
4346
4347        // Volume is currently mounted.
4348        assert!(volumes_directory.lock().await.mounted_volumes.contains_key(&store_id));
4349
4350        // Drop the client proxy (simulates client disconnect / crash).
4351        drop(remote_proxy);
4352
4353        // Wait for unmount to complete in VolumesDirectory.
4354        loop {
4355            {
4356                let guard = volumes_directory.lock().await;
4357                if !guard.mounted_volumes.contains_key(&store_id) {
4358                    break;
4359                }
4360            }
4361            fasync::Timer::new(Duration::from_millis(10)).await;
4362        }
4363
4364        volumes_directory.terminate().await;
4365        filesystem.close().await.expect("close failed");
4366    }
4367
4368    #[fuchsia::test]
4369    async fn test_mount_remote_volume_encrypted_lifecycle() {
4370        use fxfs_insecure_crypto::new_insecure_crypt;
4371        let (filesystem, volumes_directory) = test_setup().await;
4372        let crypt = Arc::new(new_insecure_crypt());
4373
4374        let store_id = {
4375            let volume = volumes_directory
4376                .create_and_mount_volume(
4377                    "enc_remote_vol",
4378                    Some(crypt.clone()),
4379                    false,
4380                    CreateOptions::default(),
4381                )
4382                .await
4383                .expect("create_and_mount_volume failed");
4384            let store_id = volume.volume().store().store_object_id();
4385            volumes_directory.lock().await.unmount(store_id).await.expect("unmount failed");
4386            store_id
4387        };
4388
4389        let store = filesystem.object_manager().store(store_id).unwrap();
4390        assert!(!store.is_unlocked());
4391
4392        let (remote_proxy, remote_server_end) =
4393            fidl::endpoints::create_proxy::<ffxfs::RemoteVolumeMarker>();
4394
4395        let (info, _initial_layers, _guid) = volumes_directory
4396            .mount_remote_volume("enc_remote_vol", Some(crypt.clone()), remote_server_end)
4397            .await
4398            .expect("mount_remote_volume failed");
4399
4400        assert_ne!(info.root_directory_object_id, 0);
4401        assert!(store.is_unlocked());
4402
4403        // Close remote volume.
4404        let close_res = remote_proxy.close().await.expect("close FIDL failed");
4405        assert!(close_res.is_ok());
4406
4407        // Wait for unmount.
4408        loop {
4409            {
4410                let guard = volumes_directory.lock().await;
4411                if !guard.mounted_volumes.contains_key(&store_id) {
4412                    break;
4413                }
4414            }
4415            fasync::Timer::new(Duration::from_millis(10)).await;
4416        }
4417
4418        // Store should be locked after close.
4419        assert!(!store.is_unlocked());
4420
4421        volumes_directory.terminate().await;
4422        filesystem.close().await.expect("close failed");
4423    }
4424
4425    #[fuchsia::test]
4426    async fn test_mount_remote_volume_flushes_journaled_mutations() {
4427        use crate::fuchsia::layer_pager::VmoLayerObject;
4428        use fxfs::lsm_tree::persistent_layer::SyncPersistentLayer;
4429        use fxfs::lsm_tree::types::Layer;
4430        use fxfs::object_store::{DirType, ObjectKey, ObjectValue};
4431        use fxfs_insecure_crypto::new_insecure_crypt;
4432        use std::ops::Bound;
4433
4434        let crypt = Arc::new(new_insecure_crypt());
4435        let device = {
4436            let (filesystem, volumes_directory) = test_setup().await;
4437            {
4438                let volume = volumes_directory
4439                    .create_and_mount_volume(
4440                        "dirty_vol",
4441                        Some(crypt.clone()),
4442                        false,
4443                        CreateOptions::default(),
4444                    )
4445                    .await
4446                    .expect("create_and_mount_volume failed");
4447
4448                let store_id = volume.volume().store().store_object_id();
4449                let root_dir_node = volume.root_dir();
4450                let root_dir = root_dir_node.directory();
4451                let mut transaction = filesystem
4452                    .root_store()
4453                    .new_transaction(
4454                        lock_keys![LockKey::object(store_id, root_dir.object_id())],
4455                        Options::default(),
4456                    )
4457                    .await
4458                    .expect("new_transaction failed");
4459                root_dir
4460                    .create_child_file(&mut transaction, "dirty_file")
4461                    .await
4462                    .expect("create_child_file failed");
4463                transaction.commit().await.expect("commit failed");
4464            }
4465
4466            volumes_directory.terminate().await;
4467            std::mem::drop(volumes_directory);
4468            filesystem.close().await.expect("close failed");
4469            filesystem.take_device().await
4470        };
4471
4472        // Reopen the filesystem; "dirty_file" is in the journal and not yet in a persistent layer.
4473        device.reopen(false);
4474        let filesystem = FxFilesystemBuilder::new().open(device).await.expect("open failed");
4475        let blob_resupplied_count =
4476            Arc::new(PageFaultCounter::new().expect("Failed to create PageFaultCounter"));
4477        let volumes_directory = VolumesDirectory::new(
4478            root_volume(filesystem.clone()).await.unwrap(),
4479            Weak::new(),
4480            None,
4481            blob_resupplied_count,
4482            MemoryPressureConfig::default(),
4483        )
4484        .await
4485        .unwrap();
4486
4487        let (store_id, _, _) = volumes_directory
4488            .root_volume
4489            .volume_directory()
4490            .lookup("dirty_vol")
4491            .await
4492            .unwrap()
4493            .unwrap();
4494        assert!(filesystem.object_manager().needs_flush(store_id));
4495
4496        let (remote_proxy, remote_server_end) =
4497            fidl::endpoints::create_proxy::<ffxfs::RemoteVolumeMarker>();
4498        let (info, initial_layers, _guid) = volumes_directory
4499            .mount_remote_volume("dirty_vol", Some(crypt), remote_server_end)
4500            .await
4501            .expect("mount_remote_volume failed");
4502
4503        assert!(!filesystem.object_manager().needs_flush(store_id));
4504        assert!(!initial_layers.layers.is_empty());
4505
4506        // Verify that "dirty_file" is present in the returned persistent layers.
4507        let key = ObjectKey::child(info.root_directory_object_id, "dirty_file", DirType::Normal);
4508        let mut found = false;
4509        for layer_file in initial_layers.layers {
4510            let vmo_obj = Arc::new(
4511                VmoLayerObject::new(layer_file.vmo, layer_file.object_id, filesystem.block_size())
4512                    .expect("VmoLayerObject::new failed"),
4513            );
4514            let layer: Arc<SyncPersistentLayer<ObjectKey, ObjectValue>> =
4515                SyncPersistentLayer::open(vmo_obj).expect("SyncPersistentLayer::open failed");
4516            let iter = layer.seek(Bound::Included(&key)).await.expect("seek failed");
4517            if let Some(item) = iter.get() {
4518                if item.key == &key && matches!(item.value, ObjectValue::Child(_)) {
4519                    found = true;
4520                    break;
4521                }
4522            }
4523        }
4524        assert!(found, "dirty_file not found in initial_layers");
4525
4526        let close_res = remote_proxy.close().await.expect("close FIDL failed");
4527        assert!(close_res.is_ok());
4528
4529        volumes_directory.terminate().await;
4530        filesystem.close().await.expect("close failed");
4531    }
4532
4533    #[fuchsia::test(threads = 2)]
4534    async fn test_mount_remote_volume_flushes_graveyard_reap() {
4535        use crate::fuchsia::layer_pager::VmoLayerObject;
4536        use fxfs::lsm_tree::persistent_layer::SyncPersistentLayer;
4537        use fxfs::lsm_tree::types::Layer;
4538        use fxfs::object_store::{HandleOptions, ObjectKey, ObjectValue};
4539        use fxfs_insecure_crypto::new_insecure_crypt;
4540        use std::ops::Bound;
4541
4542        let (filesystem, volumes_directory) = test_setup().await;
4543        let crypt = Arc::new(new_insecure_crypt());
4544
4545        let (store_id, graveyard_obj_id) = {
4546            let volume = volumes_directory
4547                .create_and_mount_volume(
4548                    "graveyard_vol",
4549                    Some(crypt.clone()),
4550                    false,
4551                    CreateOptions::default(),
4552                )
4553                .await
4554                .expect("create_and_mount_volume failed");
4555
4556            let store = volume.volume().store();
4557            let store_id = store.store_object_id();
4558            let mut transaction = store
4559                .new_transaction(lock_keys![], Options::default())
4560                .await
4561                .expect("new_transaction failed");
4562            let handle = ObjectStore::create_object(
4563                volume.volume(),
4564                &mut transaction,
4565                HandleOptions::default(),
4566                None,
4567            )
4568            .await
4569            .expect("create_object failed");
4570            let object_id = handle.object_id();
4571            store.add_to_graveyard(&mut transaction, object_id);
4572            transaction.commit().await.expect("commit failed");
4573            std::mem::drop(handle);
4574
4575            // Flush the store before unmounting so the object and its graveyard entry are in a
4576            // persistent layer and `needs_flush` is false prior to `mount_remote_volume`.
4577            store
4578                .flush_with_reason(FlushReason::Journal(ForceMajor::False))
4579                .await
4580                .expect("flush failed");
4581            assert!(
4582                store
4583                    .tree()
4584                    .find(&ObjectKey::object(object_id))
4585                    .await
4586                    .expect("find failed")
4587                    .is_some(),
4588                "graveyard object should exist in persistent layer before unmount"
4589            );
4590            volumes_directory.lock().await.unmount(store_id).await.expect("unmount failed");
4591            (store_id, object_id)
4592        };
4593
4594        let store = filesystem.object_manager().store(store_id).unwrap();
4595        assert!(!store.is_unlocked());
4596        assert!(!filesystem.object_manager().needs_flush(store_id));
4597
4598        // Mount remotely: unlocking the encrypted store queues `graveyard_obj_id` onto the
4599        // background graveyard reaper task. `mount_remote_volume` must wait for the reaper to
4600        // finish before flushing the mutable layer to persistent layers.
4601        let (remote_proxy, remote_server_end) =
4602            fidl::endpoints::create_proxy::<ffxfs::RemoteVolumeMarker>();
4603        let (_info, initial_layers, _guid) = volumes_directory
4604            .mount_remote_volume("graveyard_vol", Some(crypt), remote_server_end)
4605            .await
4606            .expect("mount_remote_volume failed");
4607
4608        filesystem.graveyard().flush().await;
4609        assert_eq!(store.tree().mutable_layer().len(), 0);
4610        assert!(!filesystem.object_manager().needs_flush(store_id));
4611
4612        // Verify that the graveyard object was reaped and compacted out of `initial_layers`.
4613        let key = ObjectKey::object(graveyard_obj_id);
4614        for layer_file in initial_layers.layers {
4615            let vmo_obj = Arc::new(
4616                VmoLayerObject::new(layer_file.vmo, layer_file.object_id, filesystem.block_size())
4617                    .expect("VmoLayerObject::new failed"),
4618            );
4619            let layer: Arc<SyncPersistentLayer<ObjectKey, ObjectValue>> =
4620                SyncPersistentLayer::open(vmo_obj).expect("SyncPersistentLayer::open failed");
4621            let iter = layer.seek(Bound::Included(&key)).await.expect("seek failed");
4622            if let Some(item) = iter.get() {
4623                assert!(
4624                    item.key != &key || matches!(item.value, ObjectValue::None),
4625                    "graveyard object was not reaped before flushing initial_layers: {:?}",
4626                    item.value
4627                );
4628            }
4629        }
4630
4631        let close_res = remote_proxy.close().await.expect("close FIDL failed");
4632        assert!(close_res.is_ok());
4633
4634        volumes_directory.terminate().await;
4635        filesystem.close().await.expect("close failed");
4636    }
4637}