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::RemoteCrypt;
6use crate::fuchsia::component::map_to_raw_status;
7use crate::fuchsia::directory::FxDirectory;
8use crate::fuchsia::errors::map_to_status;
9use crate::fuchsia::fxblob::BlobDirectory;
10use crate::fuchsia::memory_pressure::{MemoryPressureLevel, MemoryPressureMonitor};
11use crate::fuchsia::profile::new_profile_state;
12use crate::fuchsia::volume::{FxVolume, FxVolumeAndRoot, MemoryPressureConfig, RootDir};
13use anyhow::{Context, Error, anyhow, ensure};
14use fidl::endpoints::{DiscoverableProtocolMarker, ServerEnd};
15use fidl_fuchsia_fs::{AdminMarker, AdminRequest, AdminRequestStream};
16use fidl_fuchsia_fs_startup::{
17    CheckOptions, CreateOptions, MountOptions, VolumeRequest, VolumeRequestStream,
18};
19use fidl_fuchsia_fxfs::{FileBackedVolumeProviderMarker, ProjectIdMarker};
20use fidl_fuchsia_io as fio;
21use fs_inspect::{FsInspectTree, FsInspectVolume};
22use fuchsia_async as fasync;
23use futures::stream::FuturesUnordered;
24use futures::{StreamExt, TryStreamExt};
25use fxfs::errors::FxfsError;
26use fxfs::filesystem::FxFilesystem;
27use fxfs::fsck;
28use fxfs::log::*;
29use fxfs::object_store::transaction::{LockKey, Options, lock_keys};
30use fxfs::object_store::volume::RootVolume;
31use fxfs::object_store::{
32    Directory, NewChildStoreOptions, ObjectDescriptor, ObjectStore, StoreOptions,
33};
34use fxfs_crypto::Crypt;
35use fxfs_trace::{TraceFutureExt, trace_future_args};
36use refaults_vmo::PageRefaultCounter;
37use rustc_hash::FxHashMap as HashMap;
38use std::sync::atomic::{AtomicU64, Ordering};
39use std::sync::{Arc, OnceLock, Weak};
40use vfs::directory::entry_container::MutableDirectory;
41use vfs::directory::helper::DirectlyMutable;
42const MEBIBYTE: u64 = 1024 * 1024;
43
44struct ProfileState {
45    task: fasync::Task<()>,
46    profile_name: String,
47    all_volumes: bool,
48}
49
50/// VolumesDirectory is a special pseudo-directory used to enumerate and operate on volumes.
51/// Volume creation happens via fuchsia.fs.startup.Volumes.Create, rather than open.
52///
53/// Note that VolumesDirectory assumes exclusive access to |root_volume| and if volumes are
54/// manipulated from elsewhere, strange things will happen.
55pub struct VolumesDirectory {
56    root_volume: RootVolume,
57    directory_node: Arc<vfs::directory::immutable::Simple>,
58    mounted_volumes: futures::lock::Mutex<HashMap<u64, MountedVolume>>,
59    inspect_tree: Weak<FsInspectTree>,
60    mem_monitor: Option<MemoryPressureMonitor>,
61    blob_resupplied_count: Arc<PageRefaultCounter>,
62    // The state of profile recordings. Should be locked *after* mounted_volumes.
63    profiling_state: futures::lock::Mutex<Option<ProfileState>>,
64
65    /// A running estimate of the number of dirty bytes outstanding in all pager-backed VMOs across
66    /// all volumes.
67    pager_dirty_bytes_count: PagerDirtyByteCount,
68
69    /// Max outstanding dirty bytes under critical memory pressure. This could be hardcoded, but is
70    /// broken out for testing.
71    max_dirty_bytes_when_critical: AtomicU64,
72
73    // A callback to invoke when a volume is added.  When the volume is removed, this is called
74    // again with `None` as the second parameter.
75    on_volume_added:
76        OnceLock<Box<dyn Fn(&str, Option<(Arc<FxVolume>, Arc<ObjectStore>)>) + Send + Sync>>,
77
78    /// The cache configuration to use under different memory pressure levels.
79    memory_pressure_config: MemoryPressureConfig,
80}
81
82/// Operations on VolumesDirectory that cannot be performed concurrently (i.e. most
83/// volume creation/removal ops) should exist on this guard instead of VolumesDirectory.
84pub struct MountedVolumesGuard<'a> {
85    volumes_directory: Arc<VolumesDirectory>,
86    mounted_volumes: futures::lock::MutexGuard<'a, HashMap<u64, MountedVolume>>,
87}
88
89struct MountedVolume {
90    sequence: u64,
91    volume: FxVolumeAndRoot,
92
93    // True if the volume was forcibly locked.
94    locked: bool,
95}
96
97pub(crate) enum Mode {
98    Mount,
99    Create { guid: Option<[u8; 16]>, low_32_bit_object_ids: bool },
100}
101
102impl MountedVolumesGuard<'_> {
103    /// Creates or mounts a volume. If |crypt| is set, the volume will be created or mounted as
104    /// encrypted. The volume is mounted according to |as_blob|.
105    async fn create_or_mount_volume(
106        &mut self,
107        name: &str,
108        crypt: Option<Arc<dyn Crypt>>,
109        mode: Mode,
110        as_blob: bool,
111    ) -> Result<FxVolumeAndRoot, Error> {
112        let store = match mode {
113            Mode::Create { guid, low_32_bit_object_ids } => self
114                .volumes_directory
115                .root_volume
116                .new_volume(
117                    name,
118                    NewChildStoreOptions {
119                        options: StoreOptions { crypt },
120                        guid,
121                        low_32_bit_object_ids,
122                        ..Default::default()
123                    },
124                )
125                .await
126                .context("failed to create new volume")?,
127            Mode::Mount => {
128                self.volumes_directory.root_volume.volume(name, StoreOptions { crypt }).await?
129            }
130        };
131        ensure!(
132            !self.mounted_volumes.contains_key(&store.store_object_id()),
133            FxfsError::AlreadyBound
134        );
135
136        let volume = if as_blob {
137            self.mount_store::<BlobDirectory>(
138                name,
139                store,
140                self.volumes_directory.memory_pressure_config,
141            )
142            .await?
143        } else {
144            self.mount_store::<FxDirectory>(
145                name,
146                store,
147                self.volumes_directory.memory_pressure_config,
148            )
149            .await?
150        };
151        // If there is an ongoing profile activity, we should apply it to the mounted volume.
152        if let Some(ProfileState { profile_name, all_volumes: true, .. }) =
153            &(*self.volumes_directory.profiling_state.lock().await)
154        {
155            if let Err(e) = volume
156                .volume()
157                .record_and_replay_profile(new_profile_state(as_blob), profile_name)
158                .await
159            {
160                error!(
161                    "Failed to record or replay profile '{}' for volume {}: {:?}",
162                    profile_name, name, e
163                );
164            }
165        }
166
167        if let Mode::Create { .. } = mode {
168            let store_object_id = volume.volume().store().store_object_id();
169            self.volumes_directory.add_directory_entry(name, store_object_id);
170        }
171        Ok(volume)
172    }
173
174    /// Returns the volume if it is found and unlocked, along with a bool to indicate that it is or
175    /// isn't a blob volume.
176    async fn get_unlocked_volume_by_name(
177        &self,
178        volume_name: &str,
179    ) -> Result<(FxVolumeAndRoot, bool), zx::Status> {
180        let (store_object_id, _, _) = self
181            .volumes_directory
182            .root_volume
183            .volume_directory()
184            .lookup(volume_name)
185            .await
186            .map_err(map_to_status)?
187            .ok_or(zx::Status::NOT_FOUND)?;
188        if let Some(MountedVolume { volume, .. }) = self.mounted_volumes.get(&store_object_id) {
189            let is_blob = volume.root().clone().into_any().downcast::<BlobDirectory>().is_ok();
190            Ok((volume.clone(), is_blob))
191        } else {
192            Err(zx::Status::UNAVAILABLE)
193        }
194    }
195
196    // Verifies the integrity of `name` if it exists.  Returns Ok otherwise.
197    async fn check_volume(
198        &mut self,
199        filesystem: &FxFilesystem,
200        name: &str,
201        crypt: Option<Arc<dyn Crypt>>,
202    ) -> Result<Option<Arc<ObjectStore>>, Error> {
203        if let Ok(store) = self
204            .volumes_directory
205            .root_volume
206            .volume(name, StoreOptions { crypt: crypt.clone() })
207            .await
208        {
209            fsck::fsck_volume(filesystem, store.store_object_id(), crypt).await?;
210            Ok(Some(store))
211        } else {
212            Ok(None)
213        }
214    }
215
216    // Mounts the given store.  A lock *must* be held on the volume directory.
217    async fn mount_store<T: From<Directory<FxVolume>> + RootDir>(
218        &mut self,
219        name: &str,
220        store: Arc<ObjectStore>,
221        flush_task_config: MemoryPressureConfig,
222    ) -> Result<FxVolumeAndRoot, Error> {
223        let unique_id = zx::Event::create();
224        let volume = FxVolumeAndRoot::new::<T>(
225            Arc::downgrade(&self.volumes_directory),
226            store,
227            unique_id.koid().unwrap().raw_koid(),
228            name.to_owned(),
229            self.volumes_directory.blob_resupplied_count.clone(),
230            self.volumes_directory.memory_pressure_config,
231        )
232        .await?;
233        volume
234            .volume()
235            .start_background_task(flush_task_config, self.volumes_directory.mem_monitor.as_ref());
236        self.add_mount(name, &volume);
237        Ok(volume)
238    }
239
240    /// Adds a volume (`FxVolumeAndRoot`) into the mount list.
241    pub fn add_mount(&mut self, name: &str, volume: &FxVolumeAndRoot) {
242        static SEQUENCE: AtomicU64 = AtomicU64::new(0);
243        let sequence = SEQUENCE.fetch_add(1, Ordering::Relaxed);
244        self.mounted_volumes.insert(
245            volume.volume().store().store_object_id(),
246            MountedVolume { sequence, volume: volume.clone(), locked: false },
247        );
248        if let Some(inspect) = self.volumes_directory.inspect_tree.upgrade() {
249            inspect.register_volume(
250                name.to_string(),
251                Arc::downgrade(volume.volume()) as Weak<dyn FsInspectVolume + Send + Sync>,
252            )
253        }
254        if let Some(callback) = self.volumes_directory.on_volume_added.get() {
255            callback(
256                name,
257                Some((
258                    volume.volume().clone(),
259                    self.volumes_directory
260                        .root_volume
261                        .volume_directory()
262                        .store()
263                        .filesystem()
264                        .root_store(),
265                )),
266            );
267        }
268    }
269
270    async fn lock_mount(&self, mounted_volume: &mut MountedVolume) {
271        let MountedVolume { volume, locked, .. } = mounted_volume;
272
273        if let Some(callback) = self.volumes_directory.on_volume_added.get() {
274            callback(&volume.volume().name(), None);
275        }
276        if !*locked {
277            if let Some(inspect) = self.volumes_directory.inspect_tree.upgrade() {
278                inspect.unregister_volume(volume.volume().name());
279            }
280            // We must make sure to remove the root entry which holds strong references to the
281            // volume since otherwise `Volume::try_unwrap` might fail.
282            let _ = volume.outgoing_dir().remove_entry("root", true);
283            volume.volume().terminate().await;
284            *locked = true;
285        }
286    }
287
288    async fn remove_volume(&mut self, name: &str) -> Result<(), Error> {
289        let (object_id, transaction) = self
290            .volumes_directory
291            .root_volume
292            .acquire_transaction_for_remove_volume(name, [], false)
293            .await?;
294
295        // Cowardly refuse to delete a mounted volume.
296        ensure!(!self.mounted_volumes.contains_key(&object_id), FxfsError::AlreadyBound);
297        let directory_node = self.volumes_directory.directory_node.clone();
298        self.volumes_directory
299            .root_volume
300            .delete_volume(name, transaction, || {
301                // This shouldn't fail because the entry should exist.
302                directory_node.remove_entry(name, /* must_be_directory: */ false).unwrap();
303            })
304            .await?;
305        Ok(())
306    }
307
308    async fn terminate(&mut self) {
309        let mut volumes = std::mem::take(&mut *self.mounted_volumes);
310        for mounted_volume in volumes.values_mut() {
311            let admin_scope = mounted_volume.volume.admin_scope();
312            admin_scope.shutdown();
313            admin_scope.wait().await;
314
315            self.lock_mount(mounted_volume).await;
316        }
317    }
318
319    // Unmounts the volume identified by `store_id`.  The caller should take locks to avoid races if
320    // necessary.
321    //
322    // NOTE: This will not terminate any connections on the admin scope.
323    pub async fn unmount(&mut self, store_id: u64) -> Result<FxVolumeAndRoot, Error> {
324        let mut mounted_volume =
325            self.mounted_volumes.remove(&store_id).ok_or(FxfsError::NotFound)?;
326        self.lock_mount(&mut mounted_volume).await;
327        Ok(mounted_volume.volume)
328    }
329
330    // Auto-unmount the volume when the last connection to the volume is closed.
331    fn auto_unmount(&self, store_id: u64) {
332        let volumes_directory = self.volumes_directory.clone();
333        let mounted_volume = self.mounted_volumes.get(&store_id).unwrap();
334        let sequence = mounted_volume.sequence;
335        let admin_scope = mounted_volume.volume.admin_scope().clone();
336        let scope = mounted_volume.volume.volume().scope().clone();
337        fasync::Task::spawn(
338            async move {
339                // Check the admin_scope first because once that has finished, there can never be
340                // any more connections to it.
341                admin_scope.wait().await;
342                scope.wait().await;
343
344                // Check that the same volume is still mounted i.e. there wasn't an explicit
345                // unmount.
346                let mut mounted_volumes = volumes_directory.lock().await;
347                match mounted_volumes.mounted_volumes.get(&store_id) {
348                    Some(m) if m.sequence == sequence => {}
349                    _ => return,
350                }
351
352                warn!(store_id; "Last connection to volume closed without unmount, shutting down");
353                let root_store = volumes_directory.root_volume.volume_directory().store();
354                let fs = root_store.filesystem();
355                let _guard = fs
356                    .lock_manager()
357                    .txn_lock(lock_keys![LockKey::object(
358                        root_store.store_object_id(),
359                        volumes_directory.root_volume.volume_directory().object_id(),
360                    )])
361                    .await;
362
363                if let Err(e) = mounted_volumes.unmount(store_id).await {
364                    warn!(e:?, store_id; "Failed to unmount volume");
365                }
366            }
367            .trace(trace_future_args!("Volume::auto_unmount")),
368        )
369        .detach();
370    }
371}
372
373impl VolumesDirectory {
374    /// Fills the VolumesDirectory with all volumes in |root_volume|.  No volume is opened during
375    /// this.
376    pub async fn new(
377        root_volume: RootVolume,
378        inspect_tree: Weak<FsInspectTree>,
379        mem_monitor: Option<MemoryPressureMonitor>,
380        blob_resupplied_count: Arc<PageRefaultCounter>,
381        memory_pressure_config: MemoryPressureConfig,
382    ) -> Result<Arc<Self>, Error> {
383        let layer_set = root_volume.volume_directory().store().tree().layer_set();
384        let mut merger = layer_set.merger();
385        let me = Arc::new(Self {
386            root_volume,
387            directory_node: vfs::directory::immutable::simple(),
388            mounted_volumes: futures::lock::Mutex::new(HashMap::default()),
389            inspect_tree,
390            mem_monitor,
391            blob_resupplied_count,
392            profiling_state: futures::lock::Mutex::new(None),
393            pager_dirty_bytes_count: PagerDirtyByteCount::new(),
394            max_dirty_bytes_when_critical: AtomicU64::new(zx::system_get_physmem() / 100),
395            on_volume_added: OnceLock::new(),
396            memory_pressure_config,
397        });
398        let mut iter = me.root_volume.volume_directory().iter(&mut merger).await?;
399        while let Some((name, store_id, object_descriptor)) = iter.get() {
400            ensure!(*object_descriptor == ObjectDescriptor::Volume, FxfsError::Inconsistent);
401
402            me.add_directory_entry(&name, store_id);
403
404            iter.advance().await?;
405        }
406        Ok(me)
407    }
408
409    /// Delete a profile for a given volume. Fails if that volume isn't mounted or if there is
410    /// active profile recording or replay.
411    pub async fn delete_profile(
412        self: &Arc<Self>,
413        volume_name: &str,
414        profile_name: &str,
415    ) -> Result<(), zx::Status> {
416        // Volumes lock is taken first to provide consistent lock ordering with mounting a volume.
417        let volumes = self.mounted_volumes.lock().await;
418        let state = self.profiling_state.lock().await;
419
420        // Only allow deletion when no operations are in flight. This removes confusion around
421        // deleting a profile while one is recording with the same name, as the profile will not be
422        // available for deletion until the recording completes. This would also mean that deleting
423        // during a recording may succeed for deleting an older version but will be confusingly
424        // replaced moments later.
425        if state.is_some() {
426            warn!("Failing profile deletion while profile operations are in flight.");
427            return Err(zx::Status::SHOULD_WAIT);
428        }
429        for MountedVolume { volume, .. } in volumes.values() {
430            if volume.volume().name() == volume_name {
431                let dir = Arc::new(FxDirectory::new(
432                    None,
433                    volume.volume().get_profile_directory().await.map_err(map_to_status)?,
434                ));
435                return dir.unlink(profile_name, false).await;
436            }
437        }
438        warn!(volume_name, profile_name; "Volume not found while deleting profile");
439        Err(zx::Status::NOT_FOUND)
440    }
441
442    pub fn memory_pressure_monitor(&self) -> Option<&MemoryPressureMonitor> {
443        self.mem_monitor.as_ref()
444    }
445
446    /// Stop all ongoing replays, and complete and persist ongoing recordings.
447    pub async fn stop_profile_tasks(self: &Arc<Self>) {
448        let mut state;
449        let volumes;
450        // Take the mounted_volumes lock first to keep consistent lock ordering with other
451        // operations, but don't need to hold it for the entire operation. We need to take the
452        // profiling_state lock before the mounted_volumes lock is dropped to ensure that another
453        // thread doesn't mount a volume and start a profile task on it in between.
454        {
455            volumes = self
456                .mounted_volumes
457                .lock()
458                .await
459                .values()
460                .map(|v| v.volume.volume().clone()) // Clones of each FxVolume.
461                .collect::<Vec<Arc<FxVolume>>>();
462            state = self.profiling_state.lock().await;
463        }
464        for volume in volumes {
465            volume.stop_profile_tasks().await;
466        }
467        *state = None;
468    }
469
470    /// Record a named profile for a number of seconds, fails if there is an in flight recording or
471    /// replay. The given volume must be unlocked, if no volume is given then all volumes will be
472    /// affected and all volumes mounted during the process will also be affected.
473    pub async fn record_and_replay_profile(
474        self: &Arc<Self>,
475        volume_name: Option<String>,
476        profile_name: String,
477        duration_secs: u32,
478    ) -> Result<(), zx::Status> {
479        // Volumes lock is taken first to provide consistent lock ordering with mounting a volume.
480        let volumes = self.lock().await;
481        let mut state = self.profiling_state.lock().await;
482        if state.is_some() {
483            // Consistency in the recording and replaying cannot be ensured at the volume level
484            // if more than one operation can be in flight at a time.
485            return Err(zx::Status::SHOULD_WAIT);
486        }
487        match volume_name.as_ref() {
488            Some(volume_name) => {
489                let (volume, is_blob) = volumes.get_unlocked_volume_by_name(&volume_name).await?;
490                if let Err(error) = volume
491                    .volume()
492                    .record_and_replay_profile(new_profile_state(is_blob), &profile_name)
493                    .await
494                {
495                    error!(
496                        error:?,
497                        profile_name = profile_name.as_str(),
498                        volume_name = volume_name.as_str();
499                        "Failed to record or replay profile",
500                    );
501                    return Err(map_to_status(error));
502                }
503            }
504            None => {
505                for MountedVolume { volume, .. } in volumes.mounted_volumes.values() {
506                    let is_blob =
507                        volume.root().clone().into_any().downcast::<BlobDirectory>().is_ok();
508                    // Just log the errors, don't stop half-way.
509                    if let Err(error) = volume
510                        .volume()
511                        .record_and_replay_profile(new_profile_state(is_blob), &profile_name)
512                        .await
513                    {
514                        error!(
515                            error:?,
516                            profile_name = profile_name.as_str(),
517                            volume_name = volume.volume().name();
518                            "Failed to record or replay profile",
519                        );
520                    }
521                }
522            }
523        }
524
525        let this = self.clone();
526        let task = fasync::Task::spawn(async move {
527            fasync::Timer::new(fasync::MonotonicDuration::from_seconds(duration_secs.into())).await;
528            this.stop_profile_tasks().await;
529        });
530        *state = Some(ProfileState { task, profile_name, all_volumes: volume_name.is_none() });
531        Ok(())
532    }
533
534    /// Replays a profile if one exists, and only records if one does not exist.
535    /// The given volume must be unlocked.
536    pub async fn replay_xor_record_profile(
537        self: &Arc<Self>,
538        volume_name: String,
539        profile_name: String,
540        duration_secs: u32,
541    ) -> Result<(), zx::Status> {
542        // Volumes lock is taken first to provide consistent lock ordering with mounting a volume.
543        let volumes = self.lock().await;
544        let mut state = self.profiling_state.lock().await;
545        if state.is_some() {
546            return Err(zx::Status::SHOULD_WAIT);
547        }
548        let (volume, is_blob) = volumes.get_unlocked_volume_by_name(&volume_name).await?;
549        if let Err(error) = volume
550            .volume()
551            .replay_xor_record_profile(new_profile_state(is_blob), &profile_name)
552            .await
553        {
554            error!(
555                error:?,
556                profile_name = profile_name.as_str(),
557                volume_name = volume_name.as_str();
558                "Failed to replay or record profile",
559            );
560            return Err(map_to_status(error));
561        }
562
563        let this = self.clone();
564        let task = fasync::Task::spawn(async move {
565            fasync::Timer::new(fasync::MonotonicDuration::from_seconds(duration_secs.into())).await;
566            this.stop_profile_tasks().await;
567        });
568        *state = Some(ProfileState { task, profile_name, all_volumes: false });
569        Ok(())
570    }
571
572    /// Returns the directory node which can be used to provide connections for e.g. enumerating
573    /// entries in the VolumesDirectory.
574    /// Directly manipulating the entries in this node will result in strange behaviour.
575    pub fn directory_node(&self) -> &Arc<vfs::directory::immutable::Simple> {
576        &self.directory_node
577    }
578
579    // This serves as an exclusive lock for operations that manipulate the set of mounted volumes.
580    pub async fn lock<'a>(self: &'a Arc<Self>) -> MountedVolumesGuard<'a> {
581        MountedVolumesGuard {
582            volumes_directory: self.clone(),
583            mounted_volumes: self.mounted_volumes.lock().await,
584        }
585    }
586
587    fn add_directory_entry(self: &Arc<Self>, name: &str, store_id: u64) {
588        let weak = Arc::downgrade(self);
589        let name_owned = Arc::new(name.to_string());
590        self.directory_node
591            .add_entry(
592                name,
593                vfs::service::host(move |requests| {
594                    let weak = weak.clone();
595                    let name = name_owned.clone();
596                    async move {
597                        if let Some(me) = weak.upgrade() {
598                            let _ =
599                                me.handle_volume_requests(name.as_ref(), requests, store_id).await;
600                        }
601                    }
602                }),
603            )
604            .unwrap();
605    }
606
607    /// Creates and mounts a new volume. If |crypt| is set, the volume will be encrypted. The
608    /// volume is mounted according to |as_blob|.
609    pub async fn create_and_mount_volume(
610        self: &Arc<Self>,
611        name: &str,
612        crypt: Option<Arc<dyn Crypt>>,
613        as_blob: bool,
614        guid: Option<[u8; 16]>,
615    ) -> Result<FxVolumeAndRoot, Error> {
616        self.lock()
617            .await
618            .create_or_mount_volume(
619                name,
620                crypt,
621                Mode::Create { guid, low_32_bit_object_ids: false },
622                as_blob,
623            )
624            .await
625    }
626
627    /// Mounts an existing volume. `crypt` will be used to unlock the volume if provided.
628    /// If `as_blob` is `true`, the volume will be mounted as a blob filesystem, otherwise
629    /// it will be treated as a regular fxfs volume.
630    pub async fn mount_volume(
631        self: &Arc<Self>,
632        name: &str,
633        crypt: Option<Arc<dyn Crypt>>,
634        as_blob: bool,
635    ) -> Result<FxVolumeAndRoot, Error> {
636        self.lock().await.create_or_mount_volume(name, crypt, Mode::Mount, as_blob).await
637    }
638
639    /// Checks the integrity of volume `name`, or succeeds silently if the volume doesn't exist.
640    pub async fn check_volume(
641        self: &Arc<Self>,
642        name: &str,
643        crypt: Option<Arc<dyn Crypt>>,
644    ) -> Result<(), Error> {
645        let fs = self.root_volume.volume_directory().store().filesystem();
646        let store = self.lock().await.check_volume(fs.as_ref(), name, crypt).await?;
647        if let Some(store) = store {
648            if store.is_unlocked() {
649                let _ = store.lock().await;
650            }
651        }
652        Ok(())
653    }
654
655    /// Removes a volume. The volume must exist but encrypted volume keys are not required.
656    pub async fn remove_volume(self: &Arc<Self>, name: &str) -> Result<(), Error> {
657        self.lock().await.remove_volume(name).await
658    }
659
660    /// Terminates all opened volumes.  This will not cancel any profiling that might be taking
661    /// place.
662    pub async fn terminate(self: &Arc<Self>) {
663        // Abort the profiling timer task.
664        let profiling_state = self.profiling_state.lock().await.take();
665        if let Some(state) = profiling_state {
666            state.task.abort().await;
667        }
668        self.lock().await.terminate().await;
669        // TODO(https://fxbug.dev/452935329): Turn this into a real assert.
670        debug_assert!(
671            self.pager_dirty_bytes_count.load() == 0,
672            "Leaked {} dirty bytes.",
673            self.pager_dirty_bytes_count.load()
674        );
675    }
676
677    /// Serves the given volume on `outgoing_dir_server_end`.
678    pub fn serve_volume(
679        self: &Arc<Self>,
680        volume: &FxVolumeAndRoot,
681        outgoing_dir_server_end: ServerEnd<fio::DirectoryMarker>,
682        as_blob: bool,
683    ) -> Result<(), Error> {
684        // A note regarding strong references to `FxVolume`: connections to services here are all on
685        // the admin scope.  When we force lock a volume, we want to keep the admin scope running
686        // but terminate the volume.  When a volume is terminated in this way, we want to ensure
687        // that there are no outstanding strong references to the volume.  With that in mind, the
688        // services here should not hold strong references.  They can hold a strong reference to
689        // VolumesDirectory and find the volume via the mount list, or they can hold a weak
690        // reference to the FxVolume.  Before upgrading the weak reference, an active guard must be
691        // acquired on the volume's scope first.  This ensures that no new strong references are
692        // taken once the volume has commenced termination.  The "root" entry just below is an
693        // exception that does hold a strong reference.  We handle that by making sure we remove
694        // that entry before we call `FxVolume::terminate`.
695
696        let outgoing_dir = volume.outgoing_dir();
697        outgoing_dir.add_entry("root", volume.root().clone().as_directory_entry())?;
698        let svc_dir = vfs::directory::immutable::simple();
699        outgoing_dir.add_entry("svc", svc_dir.clone())?;
700
701        let store_id = volume.volume().store().store_object_id();
702        let me = self.clone();
703        svc_dir.add_entry(
704            AdminMarker::PROTOCOL_NAME,
705            vfs::service::host(move |requests| {
706                let me = me.clone();
707                async move {
708                    let _ = me.handle_admin_requests(requests, store_id).await;
709                }
710            }),
711        )?;
712        let vol_scope = volume.volume().scope().clone();
713        let weak_vol = Arc::downgrade(volume.volume());
714        {
715            let vol_scope = vol_scope.clone();
716            let weak_vol = weak_vol.clone();
717            svc_dir.add_entry(
718                ProjectIdMarker::PROTOCOL_NAME,
719                vfs::service::host(move |requests| {
720                    let weak_vol = weak_vol.clone();
721                    let scope = vol_scope.clone();
722                    async move {
723                        let _ =
724                            FxVolume::handle_project_id_requests(weak_vol, scope, requests).await;
725                    }
726                }),
727            )?;
728        }
729        svc_dir.add_entry(
730            FileBackedVolumeProviderMarker::PROTOCOL_NAME,
731            vfs::service::host(move |requests| {
732                let weak_vol = weak_vol.clone();
733                let scope = vol_scope.clone();
734                async move {
735                    let _ = FxVolume::handle_file_backed_volume_provider_requests(
736                        weak_vol, scope, requests,
737                    )
738                    .await;
739                }
740            }),
741        )?;
742        volume.root().clone().register_additional_volume_services(&svc_dir)?;
743
744        let scope = volume.admin_scope().clone();
745        let mut flags = fio::PERM_READABLE | fio::PERM_WRITABLE;
746        if as_blob {
747            flags |= fio::PERM_EXECUTABLE;
748        }
749        vfs::directory::serve_on(Arc::clone(outgoing_dir), flags, scope, outgoing_dir_server_end);
750
751        info!(
752            store_id;
753            "Serving volume, pager port koid={}",
754            fasync::EHandle::local().port().koid().unwrap().raw_koid()
755        );
756        Ok(())
757    }
758
759    /// Creates and serves the volume with the given name.
760    pub async fn create_and_serve_volume(
761        self: &Arc<Self>,
762        name: &str,
763        outgoing_directory_server_end: ServerEnd<fio::DirectoryMarker>,
764        mount_options: MountOptions,
765        create_options: CreateOptions,
766    ) -> Result<(), Error> {
767        let mut guard = self.lock().await;
768        let crypt =
769            mount_options.crypt.map(|crypt| Arc::new(RemoteCrypt::new(crypt)) as Arc<dyn Crypt>);
770        let as_blob = mount_options.as_blob.unwrap_or(false);
771        let guid = create_options.guid;
772        let low_32_bit_object_ids = create_options.restrict_inode_ids_to_32_bit.unwrap_or(false);
773        let volume = guard
774            .create_or_mount_volume(
775                name,
776                crypt,
777                Mode::Create { guid, low_32_bit_object_ids },
778                as_blob,
779            )
780            .await?;
781        self.serve_volume(&volume, outgoing_directory_server_end, as_blob)
782            .context("failed to serve volume")?;
783        guard.auto_unmount(volume.volume().store().store_object_id());
784        Ok(())
785    }
786
787    async fn handle_volume_requests(
788        self: &Arc<Self>,
789        name: &str,
790        mut requests: VolumeRequestStream,
791        store_id: u64,
792    ) -> Result<(), Error> {
793        while let Some(request) = requests.try_next().await? {
794            match request {
795                VolumeRequest::Check { responder, options } => {
796                    async move {
797                        responder.send(self.handle_check(store_id, options).await.map_err(
798                            |error| {
799                                error!(error:?, store_id; "Failed to check volume");
800                                map_to_raw_status(error)
801                            },
802                        ))
803                    }
804                    .trace(trace_future_args!("Volume::Check"))
805                    .await?;
806                }
807                VolumeRequest::Mount { responder, outgoing_directory, options } => {
808                    async move {
809                        responder.send(
810                            self.handle_mount(name, store_id, outgoing_directory, options)
811                                .await
812                                .map_err(|error| {
813                                    error!(error:?, name, store_id; "Failed to mount volume");
814                                    map_to_raw_status(error)
815                                }),
816                        )
817                    }
818                    .trace(trace_future_args!("Volume::Mount"))
819                    .await?;
820                }
821                VolumeRequest::SetLimit { responder, bytes } => {
822                    async move {
823                        responder.send(self.handle_set_limit(store_id, bytes).await.map_err(
824                            |error| {
825                                error!(error:?, store_id; "Failed to set volume limit");
826                                map_to_raw_status(error)
827                            },
828                        ))
829                    }
830                    .trace(trace_future_args!("Volume::SetLimit"))
831                    .await?;
832                }
833                VolumeRequest::GetLimit { responder } => {
834                    fxfs_trace::duration!("Volume::GetLimit");
835                    responder.send(Ok(self.handle_get_limit(store_id)))?
836                }
837                VolumeRequest::GetInfo { responder } => {
838                    async move {
839                        let result = self.handle_get_info(store_id).await.map(|guid| {
840                            fidl_fuchsia_fs_startup::VolumeInfo {
841                                guid: Some(guid),
842                                ..Default::default()
843                            }
844                        });
845                        match result {
846                            Ok(response) => responder.send(Ok(&response)),
847                            Err(error) => {
848                                error!(error:?, store_id; "Failed to get volume info");
849                                responder.send(Err(map_to_raw_status(error)))
850                            }
851                        }
852                    }
853                    .trace(trace_future_args!("Volume::GetInfo"))
854                    .await?;
855                }
856            }
857        }
858        Ok(())
859    }
860
861    pub fn memory_pressure_config(&self) -> &MemoryPressureConfig {
862        &self.memory_pressure_config
863    }
864
865    fn is_flush_required_to_dirty(&self, byte_count: u64) -> bool {
866        let mem_pressure = self
867            .mem_monitor
868            .as_ref()
869            .map(|mem_monitor| mem_monitor.level())
870            .unwrap_or(MemoryPressureLevel::Normal);
871        if !matches!(mem_pressure, MemoryPressureLevel::Critical) {
872            return false;
873        }
874
875        let total_dirty = self.pager_dirty_bytes_count.load();
876        total_dirty + byte_count >= self.max_dirty_bytes_when_critical.load(Ordering::Relaxed)
877    }
878
879    /// Reports that a certain number of bytes will be dirtied in a pager-backed VMO. If the memory
880    /// pressure level is critical and fxfs has lots of dirty pages then a new task will be spawned
881    /// in `volume` to flush the dirty pages before `mark_dirty` is called. If the memory pressure
882    /// level is not critical then `mark_dirty` will be synchronously called.
883    pub fn report_pager_dirty(
884        self: Arc<Self>,
885        byte_count: u64,
886        volume: Arc<FxVolume>,
887        mark_dirty: impl FnOnce() + Send + 'static,
888    ) {
889        if !self.is_flush_required_to_dirty(byte_count) {
890            self.pager_dirty_bytes_count.fetch_add(byte_count);
891            mark_dirty();
892        } else {
893            volume.spawn(
894                async move {
895                    let volumes = self.mounted_volumes.lock().await;
896
897                    // Re-check the number of outstanding pager dirty bytes because another thread
898                    // could have raced and flushed the volumes first.
899                    if self.is_flush_required_to_dirty(byte_count) {
900                        debug!(
901                            "Flushing all volumes. Memory pressure is critical & dirty pager bytes \
902                            ({} MiB) >= limit ({} MiB)",
903                            self.pager_dirty_bytes_count.load() / MEBIBYTE,
904                            self.max_dirty_bytes_when_critical.load(Ordering::Relaxed) / MEBIBYTE
905                        );
906
907                        let flushes = FuturesUnordered::new();
908                        for MountedVolume { volume, .. } in volumes.values() {
909                            let vol = volume.volume().clone();
910                            flushes.push(async move {
911                                vol.minimize_memory().await;
912                            });
913                        }
914
915                        flushes.collect::<()>().await;
916                    }
917                    self.pager_dirty_bytes_count.fetch_add(byte_count);
918                    mark_dirty();
919                }
920                .trace(trace_future_args!("flush-before-mark-dirty")),
921            )
922        }
923    }
924
925    /// Reports that a certain number of bytes were cleaned in a pager-backed VMO.
926    pub fn report_pager_clean(&self, byte_count: u64) {
927        let prev_dirty = self.pager_dirty_bytes_count.fetch_sub(byte_count);
928        // TODO(https://fxbug.dev/452935329): Turn this into a real assert.
929        debug_assert!(prev_dirty >= byte_count, "Underflowed dirty bytes.");
930
931        if prev_dirty < byte_count {
932            // An unlikely scenario, but if there was an underflow, reset the pager dirty bytes to
933            // zero.
934            self.pager_dirty_bytes_count.store(0);
935        }
936    }
937
938    async fn handle_check(
939        self: &Arc<Self>,
940        store_id: u64,
941        options: CheckOptions,
942    ) -> Result<(), Error> {
943        let fs = self.root_volume.volume_directory().store().filesystem();
944        let crypt = if let Some(crypt) = options.crypt {
945            Some(Arc::new(RemoteCrypt::new(crypt)) as Arc<dyn Crypt>)
946        } else {
947            None
948        };
949        let result = fsck::fsck_volume(fs.as_ref(), store_id, crypt).await?;
950        // TODO(b/311550633): Stash result in inspect.
951        info!(store_id:%; "{result:?}");
952        Ok(())
953    }
954
955    async fn handle_set_limit(self: &Arc<Self>, store_id: u64, bytes: u64) -> Result<(), Error> {
956        let store = self.root_volume.volume_directory().store();
957        let mut transaction = store.new_transaction(lock_keys![], Options::default()).await?;
958        store.filesystem().allocator().set_bytes_limit(&mut transaction, store_id, bytes)?;
959        transaction.commit().await?;
960        Ok(())
961    }
962
963    fn handle_get_limit(self: &Arc<Self>, store_id: u64) -> u64 {
964        let fs = self.root_volume.volume_directory().store().filesystem();
965        fs.allocator().get_owner_bytes_limit(store_id).unwrap_or_default()
966    }
967
968    async fn handle_get_info(self: &Arc<Self>, store_id: u64) -> Result<[u8; 16], Error> {
969        let fs = self.root_volume.volume_directory().store().filesystem();
970        let store =
971            fs.object_manager().store(store_id).ok_or_else(|| anyhow!("Store not found"))?;
972        Ok(store.guid())
973    }
974
975    async fn handle_mount(
976        self: &Arc<Self>,
977        name: &str,
978        store_id: u64,
979        outgoing_directory_server_end: ServerEnd<fio::DirectoryMarker>,
980        options: MountOptions,
981    ) -> Result<(), Error> {
982        info!(name:%, store_id:%, options:?; "Received mount request");
983        let crypt = options.crypt.map(|crypt| Arc::new(RemoteCrypt::new(crypt)) as Arc<dyn Crypt>);
984        let as_blob = options.as_blob.unwrap_or(false);
985        let mut guard = self.lock().await;
986        let volume = guard
987            .create_or_mount_volume(name, crypt, Mode::Mount, as_blob)
988            .await
989            .context("failed to mount volume")?;
990        self.serve_volume(&volume, outgoing_directory_server_end, as_blob)
991            .context("failed to serve volume")?;
992        guard.auto_unmount(volume.volume().store().store_object_id());
993        Ok(())
994    }
995
996    async fn handle_admin_requests(
997        self: &Arc<Self>,
998        mut stream: AdminRequestStream,
999        store_id: u64,
1000    ) -> Result<(), Error> {
1001        // If the Admin protocol ever supports more methods, this should change to a while.
1002        if let Some(request) = stream.try_next().await.context("Reading request")? {
1003            match request {
1004                AdminRequest::Shutdown { responder } => {
1005                    info!(store_id; "Received shutdown request for volume");
1006
1007                    let root_store = self.root_volume.volume_directory().store();
1008                    let fs = root_store.filesystem();
1009                    let _guard = fs
1010                        .lock_manager()
1011                        .txn_lock(lock_keys![LockKey::object(
1012                            root_store.store_object_id(),
1013                            self.root_volume.volume_directory().object_id(),
1014                        )])
1015                        .await;
1016
1017                    let maybe_volume = self.lock().await.unmount(store_id).await;
1018                    responder
1019                        .send()
1020                        .unwrap_or_else(|e| warn!("Failed to send shutdown response: {}", e));
1021
1022                    if let Ok(volume) = maybe_volume {
1023                        // NOTE: After calling this, this task might be dropped at the next await
1024                        // point.
1025                        volume.admin_scope().shutdown();
1026                    }
1027
1028                    return Ok(());
1029                }
1030            }
1031        }
1032        Ok(())
1033    }
1034
1035    /// Sets a callback which is invoked when a volume is added.  When the volume is removed, this
1036    /// is called again with `None` as the second parameter. The root store is included along with
1037    /// volume so the volume's layers can be accessed. Note that this can only be set once per
1038    /// VolumesDirectory; repeated calls will panic.
1039    pub fn set_on_mount_callback<
1040        F: Fn(&str, Option<(Arc<FxVolume>, Arc<ObjectStore>)>) + Send + Sync + 'static,
1041    >(
1042        &self,
1043        callback: F,
1044    ) {
1045        self.on_volume_added.set(Box::new(callback)).ok().unwrap();
1046    }
1047
1048    pub async fn install_volume(
1049        self: &Arc<Self>,
1050        src: &str,
1051        image_file: &str,
1052        dst: &str,
1053    ) -> Result<(), Error> {
1054        let guard = self.lock().await;
1055        info!("installing {src}/{image_file} -> {dst}");
1056        for MountedVolume { volume, .. } in guard.mounted_volumes.values() {
1057            if volume.volume().name() == src {
1058                return Err(zx::Status::ALREADY_BOUND)
1059                    .with_context(|| format!("volume {src} is already mounted"));
1060            }
1061            if volume.volume().name() == dst {
1062                return Err(zx::Status::ALREADY_BOUND)
1063                    .with_context(|| format!("volume {dst} is already mounted"));
1064            }
1065        }
1066        guard.volumes_directory.root_volume.install_volume(&src, &image_file, &dst).await?;
1067
1068        // The above function ensures that we've deleted `src` and `dst` now exists. Before we
1069        // release `guard`, we need to update the entries in the volumes directory accordingly.
1070        guard
1071            .volumes_directory
1072            .directory_node()
1073            .remove_entry(src, /* must_be_directory: */ false)
1074            .unwrap();
1075        guard
1076            .volumes_directory
1077            .directory_node()
1078            .remove_entry(dst, /* must_be_directory: */ false)
1079            .unwrap();
1080        let new_dst_object_id =
1081            match guard.volumes_directory.root_volume.volume_directory().lookup(dst).await? {
1082                Some((object_id, ObjectDescriptor::Volume, _)) => Ok(object_id),
1083                Some(_) => Err(FxfsError::Inconsistent),
1084                None => Err(FxfsError::NotFound),
1085            }?;
1086        self.add_directory_entry(dst, new_dst_object_id);
1087
1088        info!("install complete");
1089        Ok(())
1090    }
1091}
1092
1093#[cfg(test)]
1094pub(crate) fn serve_startup_volume_proxy(
1095    volumes_directory: &Arc<VolumesDirectory>,
1096    volume_name: &str,
1097) -> (fidl_fuchsia_fs_startup::VolumeProxy, vfs::ExecutionScope) {
1098    use vfs::ToObjectRequest;
1099    use vfs::service::ServiceLike;
1100    let scope = vfs::ExecutionScope::new();
1101    let entry = volumes_directory.directory_node().get_entry(volume_name).unwrap();
1102    let service = entry.into_any().downcast::<vfs::service::Service>().unwrap();
1103    let (proxy, server) = fidl::endpoints::create_proxy::<fidl_fuchsia_fs_startup::VolumeMarker>();
1104    service
1105        .connect(
1106            scope.clone(),
1107            Default::default(),
1108            &mut fio::Flags::PROTOCOL_SERVICE.to_object_request(server),
1109        )
1110        .unwrap();
1111    (proxy, scope)
1112}
1113
1114struct PagerDirtyByteCount(AtomicU64);
1115
1116impl PagerDirtyByteCount {
1117    pub fn new() -> Self {
1118        Self(AtomicU64::new(0))
1119    }
1120
1121    pub fn fetch_add(&self, value: u64) -> u64 {
1122        let prev = self.0.fetch_add(value, Ordering::Relaxed);
1123        fxfs_trace::counter!("dirty-bytes", 0, "total" => prev.saturating_add(value));
1124        prev
1125    }
1126
1127    pub fn fetch_sub(&self, value: u64) -> u64 {
1128        let prev = self.0.fetch_sub(value, Ordering::Relaxed);
1129        fxfs_trace::counter!("dirty-bytes", 0, "total" => prev.saturating_sub(value));
1130        prev
1131    }
1132
1133    pub fn load(&self) -> u64 {
1134        self.0.load(Ordering::Relaxed)
1135    }
1136
1137    pub fn store(&self, value: u64) {
1138        self.0.store(value, Ordering::Relaxed);
1139        fxfs_trace::counter!("dirty-bytes", 0, "total" => value);
1140    }
1141}
1142
1143#[cfg(test)]
1144mod tests {
1145    use super::{Mode, serve_startup_volume_proxy};
1146    use crate::fuchsia::RemoteCrypt;
1147    use crate::fuchsia::memory_pressure::MemoryPressureLevel;
1148    use crate::fuchsia::testing::{self, TestFixture, open_dir_checked, open_file_checked};
1149    use crate::fuchsia::volume::MemoryPressureConfig;
1150    use crate::fuchsia::volumes_directory::VolumesDirectory;
1151    use crate::testing::TestFixtureOptions;
1152    use fidl::endpoints::{DiscoverableProtocolMarker, create_proxy, create_request_stream};
1153    use fidl_fuchsia_fs::AdminMarker;
1154    use fidl_fuchsia_fs_startup::{MountOptions, VolumeProxy};
1155    use fidl_fuchsia_fxfs::{CryptRequest, FxfsKey, KeyPurpose, WrappedKey};
1156    use fidl_fuchsia_io as fio;
1157    use fuchsia_async as fasync;
1158    use fuchsia_component_client::connect_to_protocol_at_dir_svc;
1159    use fuchsia_fs::file;
1160    use futures::{TryStreamExt, join};
1161    use fxfs::errors::FxfsError;
1162    use fxfs::filesystem::FxFilesystem;
1163    use fxfs::fsck::{FsckOptions, fsck, fsck_volume_with_options, fsck_with_options};
1164    use fxfs::lock_keys;
1165    use fxfs::object_handle::ObjectHandle;
1166    use fxfs::object_store::allocator::Allocator;
1167    use fxfs::object_store::transaction::{LockKey, Options};
1168    use fxfs::object_store::volume::root_volume;
1169    use fxfs_crypto::Crypt;
1170    use fxfs_insecure_crypto::new_insecure_crypt;
1171    use refaults_vmo::PageRefaultCounter;
1172    use std::sync::atomic::Ordering;
1173    use std::sync::{Arc, Weak};
1174    use std::time::Duration;
1175    use storage_device::DeviceHolder;
1176    use storage_device::fake_device::FakeDevice;
1177    use vfs::execution_scope::ExecutionScope;
1178    use vfs::temp_clone::{TempClonable, unblock};
1179    use zx::Status;
1180    async fn write_image_to_file(image: DeviceHolder, file: fio::FileProxy) {
1181        file.resize(image.size()).await.unwrap().expect("resize failed");
1182        let vmo = TempClonable::new(
1183            file.get_backing_memory(fio::VmoFlags::SHARED_BUFFER | fio::VmoFlags::WRITE)
1184                .await
1185                .unwrap()
1186                .expect("get backing memory failed"),
1187        );
1188
1189        const CHUNK_READ_SIZE: usize = 131_072; /* 128 KiB */
1190        let mut buff = image.allocate_buffer(CHUNK_READ_SIZE).await;
1191        let total = image.size();
1192        let mut offset = 0;
1193        while offset < total {
1194            let amount = std::cmp::min(total - offset, CHUNK_READ_SIZE as u64);
1195            image.read(offset, buff.as_mut()).await.expect("image read failed");
1196            {
1197                // *NOTE*: We have to unblock our write to the VMO since it's pager backed and could
1198                // be running on the same thread as the filesystem is.
1199                let vmo = vmo.temp_clone();
1200                let data = buff.as_slice()[0..amount as usize].to_vec();
1201                let offset = offset;
1202                unblock(move || vmo.write(&data, offset)).await.expect("vmo write failed");
1203            }
1204            offset += amount;
1205        }
1206        assert_eq!(offset, total);
1207        file.sync().await.unwrap().expect("sync failed");
1208        file.close().await.unwrap().expect("close failed");
1209    }
1210
1211    #[fuchsia::test]
1212    async fn test_volume_creation() {
1213        let device = DeviceHolder::new(FakeDevice::new(8192, 512));
1214        let filesystem = FxFilesystem::new_empty(device).await.unwrap();
1215        let blob_resupplied_count =
1216            Arc::new(PageRefaultCounter::new().expect("Failed to create PageRefaultCounter"));
1217        let volumes_directory = VolumesDirectory::new(
1218            root_volume(filesystem.clone()).await.unwrap(),
1219            Weak::new(),
1220            None,
1221            blob_resupplied_count,
1222            MemoryPressureConfig::default(),
1223        )
1224        .await
1225        .unwrap();
1226
1227        let crypt = Arc::new(new_insecure_crypt()) as Arc<dyn Crypt>;
1228        {
1229            let vol = volumes_directory
1230                .create_and_mount_volume("encrypted", Some(crypt.clone()), false, None)
1231                .await
1232                .expect("create encrypted volume failed");
1233            vol.volume().store().store_object_id()
1234        };
1235
1236        volumes_directory.terminate().await;
1237        std::mem::drop(volumes_directory);
1238        filesystem.close().await.expect("close filesystem failed");
1239        let device = filesystem.take_device().await;
1240        device.reopen(false);
1241        let filesystem = FxFilesystem::open(device).await.unwrap();
1242        let blob_resupplied_count =
1243            Arc::new(PageRefaultCounter::new().expect("Failed to create PageRefaultCounter"));
1244        let volumes_directory = VolumesDirectory::new(
1245            root_volume(filesystem.clone()).await.unwrap(),
1246            Weak::new(),
1247            None,
1248            blob_resupplied_count,
1249            MemoryPressureConfig::default(),
1250        )
1251        .await
1252        .unwrap();
1253
1254        let error = volumes_directory
1255            .create_and_mount_volume("encrypted", Some(crypt.clone()), false, None)
1256            .await
1257            .err()
1258            .expect("Creating existing encrypted volume should fail");
1259        assert!(FxfsError::AlreadyExists.matches(&error));
1260    }
1261
1262    #[fuchsia::test]
1263    async fn test_dirty_pages_accumulate_in_parent() {
1264        let device = DeviceHolder::new(FakeDevice::new(8192, 512));
1265        let filesystem = FxFilesystem::new_empty(device).await.unwrap();
1266        let blob_resupplied_count =
1267            Arc::new(PageRefaultCounter::new().expect("Failed to create PageRefaultCounter"));
1268        let volumes_directory = VolumesDirectory::new(
1269            root_volume(filesystem.clone()).await.unwrap(),
1270            Weak::new(),
1271            None,
1272            blob_resupplied_count,
1273            MemoryPressureConfig::default(),
1274        )
1275        .await
1276        .unwrap();
1277
1278        let crypt = Arc::new(new_insecure_crypt()) as Arc<dyn Crypt>;
1279        let vol = volumes_directory
1280            .create_and_mount_volume("encrypted", Some(crypt.clone()), false, None)
1281            .await
1282            .expect("create encrypted volume failed");
1283        let old_dirty = volumes_directory.pager_dirty_bytes_count.load();
1284
1285        let new_dirty = {
1286            let (root, server_end) = create_proxy::<fio::DirectoryMarker>();
1287            vol.root().clone().serve(fio::PERM_READABLE | fio::PERM_WRITABLE, server_end);
1288            let f = open_file_checked(
1289                &root,
1290                "foo",
1291                fio::Flags::FLAG_MAYBE_CREATE
1292                    | fio::PERM_READABLE
1293                    | fio::PERM_WRITABLE
1294                    | fio::Flags::PROTOCOL_FILE,
1295                &Default::default(),
1296            )
1297            .await;
1298            let buf = vec![0xaa as u8; 8192];
1299            file::write(&f, buf.as_slice()).await.expect("Write");
1300            // It's important to check the dirty bytes before closing the file, as closing can
1301            // trigger a flush.
1302            volumes_directory.pager_dirty_bytes_count.load()
1303        };
1304        assert_ne!(old_dirty, new_dirty);
1305
1306        volumes_directory.terminate().await;
1307        std::mem::drop(volumes_directory);
1308        filesystem.close().await.expect("close filesystem failed");
1309    }
1310
1311    #[fuchsia::test]
1312    async fn test_volume_reopen() {
1313        let device = DeviceHolder::new(FakeDevice::new(8192, 512));
1314        let filesystem = FxFilesystem::new_empty(device).await.unwrap();
1315        let blob_resupplied_count =
1316            Arc::new(PageRefaultCounter::new().expect("Failed to create PageRefaultCounter"));
1317        let volumes_directory = VolumesDirectory::new(
1318            root_volume(filesystem.clone()).await.unwrap(),
1319            Weak::new(),
1320            None,
1321            blob_resupplied_count,
1322            MemoryPressureConfig::default(),
1323        )
1324        .await
1325        .unwrap();
1326
1327        let crypt = Arc::new(new_insecure_crypt()) as Arc<dyn Crypt>;
1328        let volume_id = {
1329            let vol = volumes_directory
1330                .create_and_mount_volume("encrypted", Some(crypt.clone()), false, None)
1331                .await
1332                .expect("create encrypted volume failed");
1333            vol.volume().store().store_object_id()
1334        };
1335
1336        volumes_directory.terminate().await;
1337        std::mem::drop(volumes_directory);
1338        filesystem.close().await.expect("close filesystem failed");
1339        let device = filesystem.take_device().await;
1340        device.reopen(false);
1341        let filesystem = FxFilesystem::open(device).await.unwrap();
1342        let blob_resupplied_count =
1343            Arc::new(PageRefaultCounter::new().expect("Failed to create PageRefaultCounter"));
1344        let volumes_directory = VolumesDirectory::new(
1345            root_volume(filesystem.clone()).await.unwrap(),
1346            Weak::new(),
1347            None,
1348            blob_resupplied_count,
1349            MemoryPressureConfig::default(),
1350        )
1351        .await
1352        .unwrap();
1353
1354        {
1355            let vol = volumes_directory
1356                .mount_volume("encrypted", Some(crypt.clone()), false)
1357                .await
1358                .expect("open existing encrypted volume failed");
1359            assert_eq!(vol.volume().store().store_object_id(), volume_id);
1360        }
1361
1362        volumes_directory.terminate().await;
1363        std::mem::drop(volumes_directory);
1364        filesystem.close().await.expect("close filesystem failed");
1365    }
1366
1367    #[fuchsia::test]
1368    async fn test_volume_creation_unencrypted() {
1369        let device = DeviceHolder::new(FakeDevice::new(8192, 512));
1370        let filesystem = FxFilesystem::new_empty(device).await.unwrap();
1371        let blob_resupplied_count =
1372            Arc::new(PageRefaultCounter::new().expect("Failed to create PageRefaultCounter"));
1373        let volumes_directory = VolumesDirectory::new(
1374            root_volume(filesystem.clone()).await.unwrap(),
1375            Weak::new(),
1376            None,
1377            blob_resupplied_count,
1378            MemoryPressureConfig::default(),
1379        )
1380        .await
1381        .unwrap();
1382
1383        {
1384            let vol = volumes_directory
1385                .create_and_mount_volume("unencrypted", None, false, None)
1386                .await
1387                .expect("create unencrypted volume failed");
1388            vol.volume().store().store_object_id()
1389        };
1390
1391        volumes_directory.terminate().await;
1392        std::mem::drop(volumes_directory);
1393        filesystem.close().await.expect("close filesystem failed");
1394        let device = filesystem.take_device().await;
1395        device.reopen(false);
1396        let filesystem = FxFilesystem::open(device).await.unwrap();
1397        let blob_resupplied_count =
1398            Arc::new(PageRefaultCounter::new().expect("Failed to create PageRefaultCounter"));
1399        let volumes_directory = VolumesDirectory::new(
1400            root_volume(filesystem.clone()).await.unwrap(),
1401            Weak::new(),
1402            None,
1403            blob_resupplied_count,
1404            MemoryPressureConfig::default(),
1405        )
1406        .await
1407        .unwrap();
1408
1409        let error = volumes_directory
1410            .create_and_mount_volume("unencrypted", None, false, None)
1411            .await
1412            .err()
1413            .expect("Creating existing unencrypted volume should fail");
1414        assert!(FxfsError::AlreadyExists.matches(&error));
1415
1416        volumes_directory.terminate().await;
1417        std::mem::drop(volumes_directory);
1418        filesystem.close().await.expect("close filesystem failed");
1419    }
1420
1421    #[fuchsia::test]
1422    async fn test_volume_reopen_unencrypted() {
1423        let device = DeviceHolder::new(FakeDevice::new(8192, 512));
1424        let filesystem = FxFilesystem::new_empty(device).await.unwrap();
1425        let blob_resupplied_count =
1426            Arc::new(PageRefaultCounter::new().expect("Failed to create PageRefaultCounter"));
1427        let volumes_directory = VolumesDirectory::new(
1428            root_volume(filesystem.clone()).await.unwrap(),
1429            Weak::new(),
1430            None,
1431            blob_resupplied_count,
1432            MemoryPressureConfig::default(),
1433        )
1434        .await
1435        .unwrap();
1436
1437        let volume_id = {
1438            let vol = volumes_directory
1439                .create_and_mount_volume("unencrypted", None, false, None)
1440                .await
1441                .expect("create unencrypted volume failed");
1442            vol.volume().store().store_object_id()
1443        };
1444
1445        volumes_directory.terminate().await;
1446        std::mem::drop(volumes_directory);
1447        filesystem.close().await.expect("close filesystem failed");
1448        let device = filesystem.take_device().await;
1449        device.reopen(false);
1450        let filesystem = FxFilesystem::open(device).await.unwrap();
1451        let blob_resupplied_count =
1452            Arc::new(PageRefaultCounter::new().expect("Failed to create PageRefaultCounter"));
1453        let volumes_directory = VolumesDirectory::new(
1454            root_volume(filesystem.clone()).await.unwrap(),
1455            Weak::new(),
1456            None,
1457            blob_resupplied_count,
1458            MemoryPressureConfig::default(),
1459        )
1460        .await
1461        .unwrap();
1462
1463        {
1464            let vol = volumes_directory
1465                .mount_volume("unencrypted", None, false)
1466                .await
1467                .expect("open existing unencrypted volume failed");
1468            assert_eq!(vol.volume().store().store_object_id(), volume_id);
1469        }
1470
1471        volumes_directory.terminate().await;
1472        std::mem::drop(volumes_directory);
1473        filesystem.close().await.expect("close filesystem failed");
1474    }
1475
1476    #[fuchsia::test]
1477    async fn test_volume_enumeration() {
1478        let device = DeviceHolder::new(FakeDevice::new(8192, 512));
1479        let filesystem = FxFilesystem::new_empty(device).await.unwrap();
1480        let blob_resupplied_count =
1481            Arc::new(PageRefaultCounter::new().expect("Failed to create PageRefaultCounter"));
1482        let volumes_directory = VolumesDirectory::new(
1483            root_volume(filesystem.clone()).await.unwrap(),
1484            Weak::new(),
1485            None,
1486            blob_resupplied_count,
1487            MemoryPressureConfig::default(),
1488        )
1489        .await
1490        .unwrap();
1491
1492        // Add an encrypted volume...
1493        let crypt = Arc::new(new_insecure_crypt()) as Arc<dyn Crypt>;
1494        {
1495            volumes_directory
1496                .create_and_mount_volume("encrypted", Some(crypt.clone()), false, None)
1497                .await
1498                .expect("create encrypted volume failed");
1499        };
1500        // And an unencrypted volume.
1501        {
1502            volumes_directory
1503                .create_and_mount_volume("unencrypted", None, false, None)
1504                .await
1505                .expect("create unencrypted volume failed");
1506        };
1507
1508        // Restart, so that we can test enumeration of unopened volumes.
1509        volumes_directory.terminate().await;
1510        std::mem::drop(volumes_directory);
1511        filesystem.close().await.expect("close filesystem failed");
1512        let device = filesystem.take_device().await;
1513        device.reopen(false);
1514        let filesystem = FxFilesystem::open(device).await.unwrap();
1515        let blob_resupplied_count =
1516            Arc::new(PageRefaultCounter::new().expect("Failed to create PageRefaultCounter"));
1517        let volumes_directory = VolumesDirectory::new(
1518            root_volume(filesystem.clone()).await.unwrap(),
1519            Weak::new(),
1520            None,
1521            blob_resupplied_count,
1522            MemoryPressureConfig::default(),
1523        )
1524        .await
1525        .unwrap();
1526
1527        let readdir = |dir: Arc<fio::DirectoryProxy>| async move {
1528            let status = dir.rewind().await.expect("FIDL call failed");
1529            Status::ok(status).expect("rewind failed");
1530            let (status, buf) = dir.read_dirents(fio::MAX_BUF).await.expect("FIDL call failed");
1531            Status::ok(status).expect("read_dirents failed");
1532            let mut entries = vec![];
1533            for res in fuchsia_fs::directory::parse_dir_entries(&buf) {
1534                entries.push(res.expect("Failed to parse entry").name);
1535            }
1536            entries
1537        };
1538
1539        let dir_proxy = Arc::new(vfs::directory::serve_read_only(
1540            volumes_directory.directory_node().clone(),
1541            ExecutionScope::new(),
1542        ));
1543        let entries = readdir(dir_proxy.clone()).await;
1544        assert_eq!(entries, [".", "encrypted", "unencrypted"]);
1545
1546        let _vol = volumes_directory
1547            .mount_volume("encrypted", Some(crypt.clone()), false)
1548            .await
1549            .expect("Open encrypted volume failed");
1550
1551        // Ensure that the behaviour is the same after we've opened a volume.
1552        let entries = readdir(dir_proxy).await;
1553        assert_eq!(entries, [".", "encrypted", "unencrypted"]);
1554
1555        volumes_directory.terminate().await;
1556        std::mem::drop(volumes_directory);
1557        filesystem.close().await.expect("close filesystem failed");
1558    }
1559
1560    #[fuchsia::test]
1561    async fn test_get_info() {
1562        let device = DeviceHolder::new(FakeDevice::new(8192, 512));
1563        let filesystem = FxFilesystem::new_empty(device).await.unwrap();
1564        let root_volume = root_volume(filesystem.clone()).await.unwrap();
1565        let blob_resupplied_count =
1566            Arc::new(PageRefaultCounter::new().expect("Failed to create PageRefaultCounter"));
1567        let volumes_directory = VolumesDirectory::new(
1568            root_volume,
1569            Weak::new(),
1570            None,
1571            blob_resupplied_count,
1572            MemoryPressureConfig::default(),
1573        )
1574        .await
1575        .unwrap();
1576
1577        let vol = volumes_directory
1578            .create_and_mount_volume("vol", None, false, None)
1579            .await
1580            .expect("create_and_mount_volume failed");
1581        let guid = vol.volume().store().guid();
1582
1583        let (volume_proxy, _scope) = serve_startup_volume_proxy(&volumes_directory, "vol");
1584
1585        let info: fidl_fuchsia_fs_startup::VolumeInfo = volume_proxy
1586            .get_info()
1587            .await
1588            .expect("get_info failed")
1589            .expect("get_info returned error");
1590        assert_eq!(info.guid, Some(guid));
1591
1592        volumes_directory.terminate().await;
1593    }
1594
1595    #[fuchsia::test]
1596    async fn test_deleted_encrypted_volume_while_mounted() {
1597        const VOLUME_NAME: &str = "encrypted";
1598
1599        let device = DeviceHolder::new(FakeDevice::new(8192, 512));
1600        let filesystem = FxFilesystem::new_empty(device).await.unwrap();
1601        let crypt = Arc::new(new_insecure_crypt()) as Arc<dyn Crypt>;
1602        let blob_resupplied_count =
1603            Arc::new(PageRefaultCounter::new().expect("Failed to create PageRefaultCounter"));
1604        let volumes_directory = VolumesDirectory::new(
1605            root_volume(filesystem.clone()).await.unwrap(),
1606            Weak::new(),
1607            None,
1608            blob_resupplied_count,
1609            MemoryPressureConfig::default(),
1610        )
1611        .await
1612        .unwrap();
1613        volumes_directory
1614            .create_and_mount_volume(VOLUME_NAME, Some(crypt.clone()), false, None)
1615            .await
1616            .expect("create encrypted volume failed");
1617        // We have the volume mounted so delete attempts should fail.
1618        assert!(
1619            FxfsError::AlreadyBound.matches(
1620                &volumes_directory
1621                    .remove_volume(VOLUME_NAME)
1622                    .await
1623                    .err()
1624                    .expect("Deleting volume should fail")
1625            )
1626        );
1627        volumes_directory.terminate().await;
1628        std::mem::drop(volumes_directory);
1629        filesystem.close().await.expect("close filesystem failed");
1630    }
1631
1632    #[fuchsia::test]
1633    async fn test_mount_volume_using_volume_protocol() {
1634        let device = DeviceHolder::new(FakeDevice::new(8192, 512));
1635        let filesystem = FxFilesystem::new_empty(device).await.unwrap();
1636        let blob_resupplied_count =
1637            Arc::new(PageRefaultCounter::new().expect("Failed to create PageRefaultCounter"));
1638        let volumes_directory = VolumesDirectory::new(
1639            root_volume(filesystem.clone()).await.unwrap(),
1640            Weak::new(),
1641            None,
1642            blob_resupplied_count,
1643            MemoryPressureConfig::default(),
1644        )
1645        .await
1646        .unwrap();
1647
1648        let crypt = Arc::new(new_insecure_crypt()) as Arc<dyn Crypt>;
1649        let store_id = {
1650            let vol = volumes_directory
1651                .create_and_mount_volume("encrypted", Some(crypt.clone()), false, None)
1652                .await
1653                .expect("create encrypted volume failed");
1654            vol.volume().store().store_object_id()
1655        };
1656        volumes_directory.lock().await.unmount(store_id).await.expect("unmount failed");
1657
1658        let (volume_proxy, _scope) = serve_startup_volume_proxy(&volumes_directory, "encrypted");
1659
1660        let (dir_proxy, dir_server_end) = fidl::endpoints::create_proxy::<fio::DirectoryMarker>();
1661
1662        let crypt_service = fxfs_crypt::CryptService::new();
1663        crypt_service
1664            .add_wrapping_key(0, fxfs_insecure_crypto::DATA_KEY.to_vec())
1665            .expect("add_wrapping_key failed");
1666        crypt_service
1667            .add_wrapping_key(1, fxfs_insecure_crypto::METADATA_KEY.to_vec())
1668            .expect("add_wrapping_key failed");
1669        crypt_service.set_active_key(KeyPurpose::Data, 0).expect("set_active_key failed");
1670        crypt_service.set_active_key(KeyPurpose::Metadata, 1).expect("set_active_key failed");
1671        let (client1, stream1) = create_request_stream();
1672        let (client2, stream2) = create_request_stream();
1673
1674        join!(
1675            async {
1676                volume_proxy
1677                    .mount(
1678                        dir_server_end,
1679                        MountOptions { crypt: Some(client1), ..MountOptions::default() },
1680                    )
1681                    .await
1682                    .expect("mount (fidl) failed")
1683                    .expect("mount failed");
1684
1685                open_file_checked(
1686                    &dir_proxy,
1687                    "root/test",
1688                    fio::PERM_READABLE | fio::PERM_WRITABLE | fio::Flags::FLAG_MAYBE_CREATE,
1689                    &Default::default(),
1690                )
1691                .await;
1692
1693                // Attempting to mount again should fail with ALREADY_BOUND.
1694                let (_dir_proxy, dir_server_end) =
1695                    fidl::endpoints::create_proxy::<fio::DirectoryMarker>();
1696
1697                assert_eq!(
1698                    Status::from_raw(
1699                        volume_proxy
1700                            .mount(
1701                                dir_server_end,
1702                                MountOptions { crypt: Some(client2), ..MountOptions::default() },
1703                            )
1704                            .await
1705                            .expect("mount (fidl) failed")
1706                            .expect_err("mount succeeded")
1707                    ),
1708                    Status::ALREADY_BOUND
1709                );
1710
1711                std::mem::drop(dir_proxy);
1712
1713                // The volume should get unmounted a short time later.
1714                let mut count = 0;
1715                loop {
1716                    if volumes_directory.mounted_volumes.lock().await.is_empty() {
1717                        break;
1718                    }
1719                    count += 1;
1720                    assert!(count <= 100);
1721                    fasync::Timer::new(Duration::from_millis(100)).await;
1722                }
1723            },
1724            async {
1725                crypt_service
1726                    .handle_request(fxfs_crypt::Services::Crypt(stream1))
1727                    .await
1728                    .expect("handle_request failed");
1729                crypt_service
1730                    .handle_request(fxfs_crypt::Services::Crypt(stream2))
1731                    .await
1732                    .expect("handle_request failed");
1733            }
1734        );
1735        // Make sure the background thread that actually calls terminate() on the volume finishes
1736        // before exiting the test. terminate() should be a no-op since we already verified
1737        // mounted_directories is empty, but the volume's terminate() future in the background task
1738        // may still be outstanding. As both the background task and VolumesDirectory::terminate()
1739        // hold the write lock, we use that to block until the background task has completed.
1740        volumes_directory.terminate().await;
1741    }
1742
1743    #[fuchsia::test]
1744    #[ignore] // TODO(b/293917849) re-enable this test when de-flaked
1745
1746    async fn test_volume_dir_races() {
1747        let device = DeviceHolder::new(FakeDevice::new(8192, 512));
1748        let filesystem = FxFilesystem::new_empty(device).await.unwrap();
1749        let blob_resupplied_count =
1750            Arc::new(PageRefaultCounter::new().expect("Failed to create PageRefaultCounter"));
1751        let volumes_directory = VolumesDirectory::new(
1752            root_volume(filesystem.clone()).await.unwrap(),
1753            Weak::new(),
1754            None,
1755            blob_resupplied_count,
1756            MemoryPressureConfig::default(),
1757        )
1758        .await
1759        .unwrap();
1760
1761        let crypt = Arc::new(new_insecure_crypt()) as Arc<dyn Crypt>;
1762        let store_id = {
1763            let vol = volumes_directory
1764                .create_and_mount_volume("encrypted", Some(crypt.clone()), false, None)
1765                .await
1766                .expect("create encrypted volume failed");
1767            vol.volume().store().store_object_id()
1768        };
1769        volumes_directory.lock().await.unmount(store_id).await.expect("unmount failed");
1770
1771        let (volume_proxy, _scope) = serve_startup_volume_proxy(&volumes_directory, "encrypted");
1772
1773        let crypt_service = Arc::new(fxfs_crypt::CryptService::new());
1774        crypt_service
1775            .add_wrapping_key(0, fxfs_insecure_crypto::DATA_KEY.to_vec())
1776            .expect("add_wrapping_key failed");
1777        crypt_service
1778            .add_wrapping_key(1, fxfs_insecure_crypto::METADATA_KEY.to_vec())
1779            .expect("add_wrapping_key failed");
1780        crypt_service.set_active_key(KeyPurpose::Data, 0).expect("set_active_key failed");
1781        crypt_service.set_active_key(KeyPurpose::Metadata, 1).expect("set_active_key failed");
1782        let (client1, stream1) = create_request_stream();
1783        let (client2, stream2) = create_request_stream();
1784        let crypt_service_clone = crypt_service.clone();
1785        let crypt_task1 = fasync::Task::spawn(async move {
1786            crypt_service_clone
1787                .handle_request(fxfs_crypt::Services::Crypt(stream1))
1788                .await
1789                .expect("handle_request failed");
1790        });
1791        let crypt_task2 = fasync::Task::spawn(async move {
1792            crypt_service
1793                .handle_request(fxfs_crypt::Services::Crypt(stream2))
1794                .await
1795                .expect("handle_request failed");
1796        });
1797
1798        // Create two tasks each of mount and remove, and one to recreate the volume, so that we get
1799        // to exercise a wide variety of concurrent actions.
1800        // Delay remove and create a bit, since mount is slower due to FIDL.
1801        join!(
1802            async {
1803                let (_dir_proxy, dir_server_end) =
1804                    fidl::endpoints::create_proxy::<fio::DirectoryMarker>();
1805                if let Err(status) = volume_proxy
1806                    .mount(
1807                        dir_server_end,
1808                        MountOptions { crypt: Some(client1), ..MountOptions::default() },
1809                    )
1810                    .await
1811                    .expect("mount (fidl) failed")
1812                {
1813                    let status = Status::from_raw(status);
1814                    if status != Status::NOT_FOUND && status != Status::ALREADY_BOUND {
1815                        assert!(false, "Unexpected status {:}", status);
1816                    }
1817                }
1818            },
1819            async {
1820                let (_dir_proxy, dir_server_end) =
1821                    fidl::endpoints::create_proxy::<fio::DirectoryMarker>();
1822                if let Err(status) = volume_proxy
1823                    .mount(
1824                        dir_server_end,
1825                        MountOptions { crypt: Some(client2), ..MountOptions::default() },
1826                    )
1827                    .await
1828                    .expect("mount (fidl) failed")
1829                {
1830                    let status = Status::from_raw(status);
1831                    if status != Status::NOT_FOUND && status != Status::ALREADY_BOUND {
1832                        assert!(false, "Unexpected status {:}", status);
1833                    }
1834                }
1835            },
1836            async {
1837                let volumes_directory = volumes_directory.clone();
1838                let wait_time = rand::random_range(0..5);
1839                fasync::Timer::new(Duration::from_millis(wait_time)).await;
1840                if let Err(err) = volumes_directory.remove_volume("encrypted").await {
1841                    assert!(
1842                        FxfsError::NotFound.matches(&err) || FxfsError::AlreadyBound.matches(&err),
1843                        "Unexpected error {:?}",
1844                        err
1845                    );
1846                }
1847            },
1848            async {
1849                let volumes_directory = volumes_directory.clone();
1850                let wait_time = rand::random_range(0..5);
1851                fasync::Timer::new(Duration::from_millis(wait_time)).await;
1852                if let Err(err) = volumes_directory.remove_volume("encrypted").await {
1853                    assert!(
1854                        FxfsError::NotFound.matches(&err) || FxfsError::AlreadyBound.matches(&err),
1855                        "Unexpected error {:?}",
1856                        err
1857                    );
1858                }
1859            },
1860            async {
1861                let volumes_directory = volumes_directory.clone();
1862                let wait_time = rand::random_range(0..5);
1863                fasync::Timer::new(Duration::from_millis(wait_time)).await;
1864                let mut guard = volumes_directory.lock().await;
1865                match guard
1866                    .create_or_mount_volume(
1867                        "encrypted",
1868                        Some(crypt.clone()),
1869                        Mode::Create { guid: None, low_32_bit_object_ids: false },
1870                        false,
1871                    )
1872                    .await
1873                {
1874                    Ok(vol) => {
1875                        let store_id = vol.volume().store().store_object_id();
1876                        std::mem::drop(vol);
1877                        guard.unmount(store_id).await.expect("unmount failed");
1878                    }
1879                    Err(err) => {
1880                        assert!(
1881                            FxfsError::AlreadyExists.matches(&err)
1882                                || FxfsError::AlreadyBound.matches(&err),
1883                            "Unexpected error {:?}",
1884                            err
1885                        );
1886                    }
1887                }
1888            }
1889        );
1890        std::mem::drop(crypt_task1);
1891        std::mem::drop(crypt_task2);
1892        // Make sure the background thread that actually calls terminate() on the volume finishes
1893        // before exiting the test. terminate() should be a no-op since we already verified
1894        // mounted_directories is empty, but the volume's terminate() future in the background task
1895        // may still be outstanding. As both the background task and VolumesDirectory::terminate()
1896        // hold the write lock, we use that to block until the background task has completed.
1897        volumes_directory.terminate().await;
1898    }
1899
1900    #[fuchsia::test]
1901    async fn test_shutdown_volume() {
1902        let device = DeviceHolder::new(FakeDevice::new(8192, 512));
1903        let filesystem = FxFilesystem::new_empty(device).await.unwrap();
1904        let blob_resupplied_count =
1905            Arc::new(PageRefaultCounter::new().expect("Failed to create PageRefaultCounter"));
1906        let volumes_directory = VolumesDirectory::new(
1907            root_volume(filesystem.clone()).await.unwrap(),
1908            Weak::new(),
1909            None,
1910            blob_resupplied_count,
1911            MemoryPressureConfig::default(),
1912        )
1913        .await
1914        .unwrap();
1915
1916        let crypt = Arc::new(new_insecure_crypt()) as Arc<dyn Crypt>;
1917        let vol = volumes_directory
1918            .create_and_mount_volume("encrypted", Some(crypt.clone()), false, None)
1919            .await
1920            .expect("create encrypted volume failed");
1921
1922        let (dir_proxy, dir_server_end) = fidl::endpoints::create_proxy::<fio::DirectoryMarker>();
1923
1924        volumes_directory.serve_volume(&vol, dir_server_end, false).expect("serve_volume failed");
1925
1926        let admin_proxy = connect_to_protocol_at_dir_svc::<AdminMarker>(&dir_proxy)
1927            .expect("Unable to connect to admin service");
1928
1929        admin_proxy.shutdown().await.expect("shutdown failed");
1930
1931        assert!(volumes_directory.mounted_volumes.lock().await.is_empty());
1932    }
1933
1934    #[fuchsia::test]
1935    async fn test_byte_limit_persistence() {
1936        const BYTES_LIMIT_1: u64 = 123456;
1937        const BYTES_LIMIT_2: u64 = 456789;
1938        const VOLUME_NAME: &str = "A";
1939        let mut device = DeviceHolder::new(FakeDevice::new(8192, 512));
1940        {
1941            let filesystem = FxFilesystem::new_empty(device).await.unwrap();
1942            let blob_resupplied_count =
1943                Arc::new(PageRefaultCounter::new().expect("Failed to create PageRefaultCounter"));
1944            let volumes_directory = VolumesDirectory::new(
1945                root_volume(filesystem.clone()).await.unwrap(),
1946                Weak::new(),
1947                None,
1948                blob_resupplied_count,
1949                MemoryPressureConfig::default(),
1950            )
1951            .await
1952            .unwrap();
1953
1954            volumes_directory
1955                .create_and_mount_volume(VOLUME_NAME, None, false, None)
1956                .await
1957                .expect("create unencrypted volume failed");
1958
1959            let (volume_proxy, _scope) =
1960                serve_startup_volume_proxy(&volumes_directory, VOLUME_NAME);
1961
1962            volume_proxy.set_limit(BYTES_LIMIT_1).await.unwrap().expect("To set limits");
1963            {
1964                let limits = (filesystem.allocator() as Arc<Allocator>).owner_byte_limits();
1965                assert_eq!(limits.len(), 1);
1966                assert_eq!(limits[0].1, BYTES_LIMIT_1);
1967            }
1968
1969            volume_proxy.set_limit(BYTES_LIMIT_2).await.unwrap().expect("To set limits");
1970            {
1971                let limits = (filesystem.allocator() as Arc<Allocator>).owner_byte_limits();
1972                assert_eq!(limits.len(), 1);
1973                assert_eq!(limits[0].1, BYTES_LIMIT_2);
1974            }
1975            std::mem::drop(volume_proxy);
1976            volumes_directory.terminate().await;
1977            std::mem::drop(volumes_directory);
1978            filesystem.close().await.expect("close filesystem failed");
1979            device = filesystem.take_device().await;
1980        }
1981        device.ensure_unique();
1982        device.reopen(false);
1983        {
1984            let filesystem = FxFilesystem::open(device as DeviceHolder).await.unwrap();
1985            fsck(filesystem.clone()).await.expect("Fsck");
1986            let blob_resupplied_count =
1987                Arc::new(PageRefaultCounter::new().expect("Failed to create PageRefaultCounter"));
1988            let volumes_directory = VolumesDirectory::new(
1989                root_volume(filesystem.clone()).await.unwrap(),
1990                Weak::new(),
1991                None,
1992                blob_resupplied_count,
1993                MemoryPressureConfig::default(),
1994            )
1995            .await
1996            .unwrap();
1997            {
1998                let limits = (filesystem.allocator() as Arc<Allocator>).owner_byte_limits();
1999                assert_eq!(limits.len(), 1);
2000                assert_eq!(limits[0].1, BYTES_LIMIT_2);
2001            }
2002            volumes_directory.remove_volume(VOLUME_NAME).await.expect("Volume deletion failed");
2003            {
2004                let limits = (filesystem.allocator() as Arc<Allocator>).owner_byte_limits();
2005                assert_eq!(limits.len(), 0);
2006            }
2007            volumes_directory.terminate().await;
2008            std::mem::drop(volumes_directory);
2009            filesystem.close().await.expect("close filesystem failed");
2010            device = filesystem.take_device().await;
2011        }
2012        device.ensure_unique();
2013        device.reopen(false);
2014        let filesystem = FxFilesystem::open(device as DeviceHolder).await.unwrap();
2015        fsck(filesystem.clone()).await.expect("Fsck");
2016        let limits = (filesystem.allocator() as Arc<Allocator>).owner_byte_limits();
2017        assert_eq!(limits.len(), 0);
2018    }
2019
2020    struct VolumeInfo {
2021        _scope: vfs::ExecutionScope,
2022        volume_proxy: VolumeProxy,
2023        file_proxy: fio::FileProxy,
2024    }
2025
2026    impl VolumeInfo {
2027        async fn new(volumes_directory: &Arc<VolumesDirectory>, name: &'static str) -> Self {
2028            let volume = volumes_directory
2029                .create_and_mount_volume(name, None, false, None)
2030                .await
2031                .expect("create unencrypted volume failed");
2032
2033            let (volume_dir_proxy, dir_server_end) =
2034                fidl::endpoints::create_proxy::<fio::DirectoryMarker>();
2035            volumes_directory
2036                .serve_volume(&volume, dir_server_end, false)
2037                .expect("serve_volume failed");
2038
2039            let (volume_proxy, _scope) = serve_startup_volume_proxy(&volumes_directory, name);
2040
2041            let (root_proxy, root_server_end) =
2042                fidl::endpoints::create_proxy::<fio::DirectoryMarker>();
2043            volume_dir_proxy
2044                .open(
2045                    "root",
2046                    fio::PERM_READABLE | fio::PERM_WRITABLE | fio::Flags::PROTOCOL_DIRECTORY,
2047                    &Default::default(),
2048                    root_server_end.into_channel(),
2049                )
2050                .expect("Failed to open volume root");
2051
2052            let file_proxy = open_file_checked(
2053                &root_proxy,
2054                "foo",
2055                fio::Flags::FLAG_MAYBE_CREATE
2056                    | fio::PERM_READABLE
2057                    | fio::PERM_WRITABLE
2058                    | fio::Flags::PROTOCOL_FILE,
2059                &Default::default(),
2060            )
2061            .await;
2062            VolumeInfo { _scope, volume_proxy, file_proxy }
2063        }
2064    }
2065
2066    #[fuchsia::test]
2067    async fn test_limit_bytes() {
2068        const BYTES_LIMIT: u64 = 262_144; // 256KiB
2069        const BLOCK_SIZE: usize = 8192; // 8KiB
2070        let device = DeviceHolder::new(FakeDevice::new(BLOCK_SIZE.try_into().unwrap(), 512));
2071        let filesystem = FxFilesystem::new_empty(device).await.unwrap();
2072        let blob_resupplied_count =
2073            Arc::new(PageRefaultCounter::new().expect("Failed to create PageRefaultCounter"));
2074        let volumes_directory = VolumesDirectory::new(
2075            root_volume(filesystem.clone()).await.unwrap(),
2076            Weak::new(),
2077            None,
2078            blob_resupplied_count,
2079            MemoryPressureConfig::default(),
2080        )
2081        .await
2082        .unwrap();
2083
2084        let vol = VolumeInfo::new(&volumes_directory, "foo").await;
2085        let old_info = {
2086            let (status, info) = vol.file_proxy.query_filesystem().await.expect("Getting fs info");
2087            assert_eq!(status, zx::Status::OK.into_raw());
2088            let info = info.unwrap();
2089            // With no limit set, the total filesystem size should be returned.
2090            assert!(info.total_bytes > BYTES_LIMIT);
2091            info
2092        };
2093
2094        vol.volume_proxy.set_limit(BYTES_LIMIT).await.unwrap().expect("To set limits");
2095        {
2096            let (status, info) = vol.file_proxy.query_filesystem().await.expect("Getting fs info");
2097            assert!(status == zx::Status::OK.into_raw());
2098            let new_info = info.unwrap();
2099            assert_eq!(new_info.total_bytes, BYTES_LIMIT);
2100            // Now since the limit is the volume limit, the space used should be the volume usage,
2101            // which should be strictly less than the filesystem.
2102            assert!(new_info.used_bytes < old_info.used_bytes);
2103        }
2104
2105        let zeros = vec![0u8; BLOCK_SIZE];
2106        // First write should succeed.
2107        assert_eq!(
2108            <u64 as TryInto<usize>>::try_into(
2109                vol.file_proxy
2110                    .write(&zeros)
2111                    .await
2112                    .expect("Failed Write message")
2113                    .expect("Failed write")
2114            )
2115            .unwrap(),
2116            BLOCK_SIZE
2117        );
2118        // Likely to run out of space before writing the full limit due to overheads.
2119        for _ in (BLOCK_SIZE..BYTES_LIMIT as usize).step_by(BLOCK_SIZE) {
2120            match vol.file_proxy.write(&zeros).await.expect("Failed Write message") {
2121                Err(_) => break,
2122                Ok(b) if b < BLOCK_SIZE.try_into().unwrap() => break,
2123                _ => (),
2124            };
2125        }
2126
2127        // Any further writes should fail with out of space.
2128        assert_eq!(
2129            vol.file_proxy
2130                .write(&zeros)
2131                .await
2132                .expect("Failed write message")
2133                .expect_err("Write should have been limited"),
2134            Status::NO_SPACE.into_raw()
2135        );
2136
2137        // Double the limit and try again. We should have write space again.
2138        vol.volume_proxy.set_limit(BYTES_LIMIT * 2).await.unwrap().expect("To set limits");
2139        assert_eq!(
2140            <u64 as TryInto<usize>>::try_into(
2141                vol.file_proxy
2142                    .write(&zeros)
2143                    .await
2144                    .expect("Failed Write message")
2145                    .expect("Failed write")
2146            )
2147            .unwrap(),
2148            BLOCK_SIZE
2149        );
2150
2151        vol.file_proxy.close().await.unwrap().expect("Failed to close file");
2152        volumes_directory.terminate().await;
2153        std::mem::drop(volumes_directory);
2154        filesystem.close().await.expect("close filesystem failed");
2155    }
2156
2157    #[fuchsia::test]
2158    async fn test_limit_bytes_two_hit_device_limit() {
2159        const BYTES_LIMIT: u64 = 3_145_728; // 3MiB
2160        const BLOCK_SIZE: usize = 8192; // 8KiB
2161        const BLOCK_COUNT: u32 = 512;
2162        let device =
2163            DeviceHolder::new(FakeDevice::new(BLOCK_SIZE.try_into().unwrap(), BLOCK_COUNT));
2164        let filesystem = FxFilesystem::new_empty(device).await.unwrap();
2165        let blob_resupplied_count =
2166            Arc::new(PageRefaultCounter::new().expect("Failed to create PageRefaultCounter"));
2167        let volumes_directory = VolumesDirectory::new(
2168            root_volume(filesystem.clone()).await.unwrap(),
2169            Weak::new(),
2170            None,
2171            blob_resupplied_count,
2172            MemoryPressureConfig::default(),
2173        )
2174        .await
2175        .unwrap();
2176
2177        let a = VolumeInfo::new(&volumes_directory, "foo").await;
2178        let b = VolumeInfo::new(&volumes_directory, "bar").await;
2179        a.volume_proxy.set_limit(BYTES_LIMIT).await.unwrap().expect("To set limits");
2180        b.volume_proxy.set_limit(BYTES_LIMIT).await.unwrap().expect("To set limits");
2181        let mut a_written: u64 = 0;
2182        let mut b_written: u64 = 0;
2183
2184        // Write chunks of BLOCK_SIZE.
2185        let zeros = vec![0u8; BLOCK_SIZE];
2186
2187        // First write should succeed for both.
2188        assert_eq!(
2189            <u64 as TryInto<usize>>::try_into(
2190                a.file_proxy
2191                    .write(&zeros)
2192                    .await
2193                    .expect("Failed Write message")
2194                    .expect("Failed write")
2195            )
2196            .unwrap(),
2197            BLOCK_SIZE
2198        );
2199        a_written += BLOCK_SIZE as u64;
2200        assert_eq!(
2201            <u64 as TryInto<usize>>::try_into(
2202                b.file_proxy
2203                    .write(&zeros)
2204                    .await
2205                    .expect("Failed Write message")
2206                    .expect("Failed write")
2207            )
2208            .unwrap(),
2209            BLOCK_SIZE
2210        );
2211        b_written += BLOCK_SIZE as u64;
2212
2213        // Likely to run out of space before writing the full limit due to overheads.
2214        for _ in (BLOCK_SIZE..BYTES_LIMIT as usize).step_by(BLOCK_SIZE) {
2215            match a.file_proxy.write(&zeros).await.expect("Failed Write message") {
2216                Err(_) => break,
2217                Ok(bytes) => {
2218                    a_written += bytes;
2219                    if bytes < BLOCK_SIZE.try_into().unwrap() {
2220                        break;
2221                    }
2222                }
2223            };
2224        }
2225        // Any further writes should fail with out of space.
2226        assert_eq!(
2227            a.file_proxy
2228                .write(&zeros)
2229                .await
2230                .expect("Failed write message")
2231                .expect_err("Write should have been limited"),
2232            Status::NO_SPACE.into_raw()
2233        );
2234
2235        // Now write to the second volume. Likely to run out of space before writing the full limit
2236        // due to overheads.
2237        for _ in (BLOCK_SIZE..BYTES_LIMIT as usize).step_by(BLOCK_SIZE) {
2238            match b.file_proxy.write(&zeros).await.expect("Failed Write message") {
2239                Err(_) => break,
2240                Ok(bytes) => {
2241                    b_written += bytes;
2242                    if bytes < BLOCK_SIZE.try_into().unwrap() {
2243                        break;
2244                    }
2245                }
2246            };
2247        }
2248        // Any further writes should fail with out of space.
2249        assert_eq!(
2250            b.file_proxy
2251                .write(&zeros)
2252                .await
2253                .expect("Failed write message")
2254                .expect_err("Write should have been limited"),
2255            Status::NO_SPACE.into_raw()
2256        );
2257
2258        // Second volume should have failed very early.
2259        assert!(BLOCK_SIZE as u64 * BLOCK_COUNT as u64 - BYTES_LIMIT >= b_written);
2260        // First volume should have gotten further.
2261        assert!(BLOCK_SIZE as u64 * BLOCK_COUNT as u64 - BYTES_LIMIT <= a_written);
2262
2263        a.file_proxy.close().await.unwrap().expect("Failed to close file");
2264        b.file_proxy.close().await.unwrap().expect("Failed to close file");
2265        volumes_directory.terminate().await;
2266        std::mem::drop(volumes_directory);
2267        filesystem.close().await.expect("close filesystem failed");
2268    }
2269
2270    #[fuchsia::test(threads = 10)]
2271    async fn test_profile_start() {
2272        const PREMOUNT_BLOB: &str = "premount_blob";
2273        const PREMOUNT_NOBLOB: &str = "premount_noblob";
2274        const LIVE_BLOB: &str = "live_blob";
2275        const LIVE_NOBLOB: &str = "live_noblob";
2276
2277        const RECORDING_NAME: &str = "foo";
2278
2279        let device = {
2280            let device = DeviceHolder::new(FakeDevice::new(8192, 512));
2281            let filesystem = FxFilesystem::new_empty(device).await.unwrap();
2282            let blob_resupplied_count =
2283                Arc::new(PageRefaultCounter::new().expect("Failed to create PageRefaultCounter"));
2284            let volumes_directory = VolumesDirectory::new(
2285                root_volume(filesystem.clone()).await.unwrap(),
2286                Weak::new(),
2287                None,
2288                blob_resupplied_count,
2289                MemoryPressureConfig::default(),
2290            )
2291            .await
2292            .unwrap();
2293            volumes_directory
2294                .create_and_mount_volume(PREMOUNT_BLOB, None, true, None)
2295                .await
2296                .unwrap();
2297            volumes_directory
2298                .create_and_mount_volume(PREMOUNT_NOBLOB, None, false, None)
2299                .await
2300                .unwrap();
2301            volumes_directory.create_and_mount_volume(LIVE_BLOB, None, true, None).await.unwrap();
2302            volumes_directory
2303                .create_and_mount_volume(LIVE_NOBLOB, None, false, None)
2304                .await
2305                .unwrap();
2306
2307            volumes_directory.terminate().await;
2308            std::mem::drop(volumes_directory);
2309            filesystem.close().await.expect("Filesystem close");
2310            filesystem.take_device().await
2311        };
2312
2313        device.ensure_unique();
2314        device.reopen(false);
2315        let device = {
2316            let filesystem = FxFilesystem::open(device as DeviceHolder).await.unwrap();
2317            let blob_resupplied_count =
2318                Arc::new(PageRefaultCounter::new().expect("Failed to create PageRefaultCounter"));
2319            let volumes_directory = VolumesDirectory::new(
2320                root_volume(filesystem.clone()).await.unwrap(),
2321                Weak::new(),
2322                None,
2323                blob_resupplied_count,
2324                MemoryPressureConfig::default(),
2325            )
2326            .await
2327            .unwrap();
2328
2329            // Premount two volumes.
2330            let _premount_blob = volumes_directory
2331                .mount_volume(PREMOUNT_BLOB, None, true)
2332                .await
2333                .expect("Reopen volume");
2334            let _premount_noblob = volumes_directory
2335                .mount_volume(PREMOUNT_NOBLOB, None, false)
2336                .await
2337                .expect("Reopen volume");
2338
2339            // Start the recording, let it run a really long time, it doesn't need to end for this
2340            // test. If it does wait this long then it should trigger test timeouts.
2341            volumes_directory
2342                .clone()
2343                .record_and_replay_profile(None, RECORDING_NAME.to_owned(), 600)
2344                .await
2345                .expect("Recording");
2346
2347            // Live mount two volumes.
2348            let _live_blob =
2349                volumes_directory.mount_volume(LIVE_BLOB, None, true).await.expect("Reopen volume");
2350            let _live_noblob = volumes_directory
2351                .mount_volume(LIVE_NOBLOB, None, false)
2352                .await
2353                .expect("Reopen volume");
2354
2355            // Wait for the recordings to finish.
2356            volumes_directory.stop_profile_tasks().await;
2357
2358            volumes_directory.terminate().await;
2359            std::mem::drop(volumes_directory);
2360            filesystem.close().await.expect("Filesystem close");
2361            filesystem.take_device().await
2362        };
2363
2364        device.ensure_unique();
2365        device.reopen(false);
2366        let filesystem = FxFilesystem::open(device as DeviceHolder).await.unwrap();
2367        {
2368            let blob_resupplied_count =
2369                Arc::new(PageRefaultCounter::new().expect("Failed to create PageRefaultCounter"));
2370            let volumes_directory = VolumesDirectory::new(
2371                root_volume(filesystem.clone()).await.unwrap(),
2372                Weak::new(),
2373                None,
2374                blob_resupplied_count,
2375                MemoryPressureConfig::default(),
2376            )
2377            .await
2378            .unwrap();
2379
2380            let _premount_blob = volumes_directory
2381                .mount_volume(PREMOUNT_BLOB, None, true)
2382                .await
2383                .expect("Reopen volume");
2384            let _premount_noblob = volumes_directory
2385                .mount_volume(PREMOUNT_NOBLOB, None, false)
2386                .await
2387                .expect("Reopen volume");
2388            let _live_blob =
2389                volumes_directory.mount_volume(LIVE_BLOB, None, true).await.expect("Reopen volume");
2390            let _live_noblob = volumes_directory
2391                .mount_volume(LIVE_NOBLOB, None, false)
2392                .await
2393                .expect("Reopen volume");
2394
2395            // Verify which recordings ran based on the saved recordings.
2396            volumes_directory
2397                .delete_profile(PREMOUNT_BLOB, RECORDING_NAME)
2398                .await
2399                .expect("Finding profile to delete.");
2400            volumes_directory
2401                .delete_profile(PREMOUNT_NOBLOB, RECORDING_NAME)
2402                .await
2403                .expect("Finding profile to delete.");
2404            volumes_directory
2405                .delete_profile(LIVE_BLOB, RECORDING_NAME)
2406                .await
2407                .expect("Finding profile to delete.");
2408            volumes_directory
2409                .delete_profile(LIVE_NOBLOB, RECORDING_NAME)
2410                .await
2411                .expect("Finding profile to delete.");
2412
2413            volumes_directory.terminate().await;
2414        }
2415
2416        filesystem.close().await.expect("Filesystem close");
2417    }
2418
2419    #[fuchsia::test(threads = 10)]
2420    async fn test_profile_stop() {
2421        let device = DeviceHolder::new(FakeDevice::new(8192, 512));
2422        let filesystem = FxFilesystem::new_empty(device).await.unwrap();
2423        let blob_resupplied_count =
2424            Arc::new(PageRefaultCounter::new().expect("Failed to create PageRefaultCounter"));
2425        let volumes_directory = VolumesDirectory::new(
2426            root_volume(filesystem.clone()).await.unwrap(),
2427            Weak::new(),
2428            None,
2429            blob_resupplied_count,
2430            MemoryPressureConfig::default(),
2431        )
2432        .await
2433        .unwrap();
2434        let volume =
2435            volumes_directory.create_and_mount_volume("foo", None, true, None).await.unwrap();
2436
2437        // Run the recording with no time at all and ensure that it still shuts down properly.
2438        volumes_directory
2439            .clone()
2440            .record_and_replay_profile(None, "foo".to_owned(), 0)
2441            .await
2442            .expect("Recording");
2443
2444        // Delete will succeed once the profile is completed.
2445        while volumes_directory.delete_profile("foo", "foo").await.is_err() {
2446            fasync::Timer::new(Duration::from_millis(10)).await;
2447        }
2448
2449        std::mem::drop(volume);
2450        volumes_directory.terminate().await;
2451        std::mem::drop(volumes_directory);
2452        filesystem.close().await.expect("Filesystem close");
2453    }
2454
2455    #[fuchsia::test(threads = 10)]
2456    async fn test_delete_profile() {
2457        let device = DeviceHolder::new(FakeDevice::new(8192, 512));
2458        let filesystem = FxFilesystem::new_empty(device).await.unwrap();
2459        let blob_resupplied_count =
2460            Arc::new(PageRefaultCounter::new().expect("Failed to create PageRefaultCounter"));
2461        let volumes_directory = VolumesDirectory::new(
2462            root_volume(filesystem.clone()).await.unwrap(),
2463            Weak::new(),
2464            None,
2465            blob_resupplied_count,
2466            MemoryPressureConfig::default(),
2467        )
2468        .await
2469        .unwrap();
2470        let volume =
2471            volumes_directory.create_and_mount_volume("foo", None, true, None).await.unwrap();
2472
2473        volumes_directory
2474            .clone()
2475            .record_and_replay_profile(None, "foo".to_owned(), 600)
2476            .await
2477            .expect("Recording");
2478
2479        // Deletion fails during in-flight recording.
2480        assert_eq!(
2481            volumes_directory.delete_profile("foo", "foo").await.expect_err("File shouldn't exist"),
2482            Status::SHOULD_WAIT
2483        );
2484
2485        volumes_directory.stop_profile_tasks().await;
2486
2487        // Missing volume name.
2488        assert_eq!(
2489            volumes_directory.delete_profile("bar", "foo").await.expect_err("File shouldn't exist"),
2490            Status::NOT_FOUND
2491        );
2492
2493        // Missing Profile name.
2494        assert_eq!(
2495            volumes_directory.delete_profile("foo", "bar").await.expect_err("File shouldn't exist"),
2496            Status::NOT_FOUND
2497        );
2498
2499        // Deletion should now succeed as the profile will be placed as part of `finish_profiling()`
2500        volumes_directory.delete_profile("foo", "foo").await.expect("Deleting");
2501
2502        // Deletion fails as the file shouldn't exist anymore.
2503        assert_eq!(
2504            volumes_directory.delete_profile("foo", "foo").await.expect_err("File shouldn't exist"),
2505            Status::NOT_FOUND
2506        );
2507
2508        std::mem::drop(volume);
2509        volumes_directory.terminate().await;
2510        std::mem::drop(volumes_directory);
2511        filesystem.close().await.expect("Filesystem close");
2512    }
2513
2514    #[fuchsia::test(threads = 10)]
2515    async fn test_profile_start_single_volume() {
2516        const TEST_VOLUME: &str = "test_1234";
2517        const TEST_RECORDING: &str = "test_5678";
2518        let crypt = Arc::new(new_insecure_crypt()) as Arc<dyn Crypt>;
2519
2520        let fixture = TestFixture::new().await;
2521        {
2522            let volumes_directory = fixture.volumes_directory();
2523            // Start recording for volume that doesn't exist.
2524            assert_eq!(
2525                volumes_directory
2526                    .record_and_replay_profile(
2527                        Some(TEST_VOLUME.to_owned()),
2528                        TEST_RECORDING.to_owned(),
2529                        1
2530                    )
2531                    .await
2532                    .expect_err("Volumes doesn't exist yet"),
2533                Status::NOT_FOUND
2534            );
2535
2536            // Create the volume unmounted.
2537            {
2538                let volume = volumes_directory
2539                    .create_and_mount_volume(TEST_VOLUME, Some(crypt.clone()), false, None)
2540                    .await
2541                    .unwrap();
2542                volumes_directory
2543                    .lock()
2544                    .await
2545                    .unmount(volume.volume().store().store_object_id())
2546                    .await
2547                    .expect("unmount failed");
2548            }
2549
2550            // Start recording for volume that is not mounted.
2551            assert_eq!(
2552                volumes_directory
2553                    .record_and_replay_profile(
2554                        Some(TEST_VOLUME.to_owned()),
2555                        TEST_RECORDING.to_owned(),
2556                        1
2557                    )
2558                    .await
2559                    .expect_err("Volumes doesn't exist yet"),
2560                Status::UNAVAILABLE
2561            );
2562
2563            // Remount the volume and try again.
2564            let volume = volumes_directory
2565                .mount_volume(TEST_VOLUME, Some(crypt.clone()), false)
2566                .await
2567                .expect("Remount volume");
2568            volumes_directory
2569                .record_and_replay_profile(
2570                    Some(TEST_VOLUME.to_owned()),
2571                    TEST_RECORDING.to_owned(),
2572                    1,
2573                )
2574                .await
2575                .expect("Starting recording");
2576
2577            // Stop the recording and check that it was created on the new volume.
2578            volumes_directory.stop_profile_tasks().await;
2579            {
2580                let profile_dir = volume.volume().get_profile_directory().await.unwrap();
2581                assert!(profile_dir.lookup(TEST_RECORDING).await.unwrap().is_some());
2582            }
2583
2584            // Should be no recording for the other volume.
2585            {
2586                let profile_dir = fixture.volume().volume().get_profile_directory().await.unwrap();
2587                assert!(profile_dir.lookup(TEST_RECORDING).await.unwrap().is_none());
2588            }
2589        }
2590        fixture.close().await;
2591    }
2592
2593    #[fuchsia::test(threads = 10)]
2594    async fn test_delete_volume_while_flushing() {
2595        let device = DeviceHolder::new(FakeDevice::new(8192, 512));
2596        let filesystem = FxFilesystem::new_empty(device).await.unwrap();
2597        let blob_resupplied_count =
2598            Arc::new(PageRefaultCounter::new().expect("Failed to create PageRefaultCounter"));
2599        let volumes_directory = VolumesDirectory::new(
2600            root_volume(filesystem.clone()).await.unwrap(),
2601            Weak::new(),
2602            None,
2603            blob_resupplied_count,
2604            MemoryPressureConfig::default(),
2605        )
2606        .await
2607        .unwrap();
2608        let name = "vol";
2609        let volume =
2610            volumes_directory.create_and_mount_volume(name, None, false, None).await.unwrap();
2611        let mut transaction = filesystem
2612            .root_store()
2613            .new_transaction(
2614                lock_keys![LockKey::object(
2615                    volume.volume().store().store_object_id(),
2616                    volume.root_dir().directory().object_id()
2617                )],
2618                Options::default(),
2619            )
2620            .await
2621            .unwrap();
2622        volume
2623            .root_dir()
2624            .directory()
2625            .create_child_file(&mut transaction, "foo")
2626            .await
2627            .expect("create_child_file failed");
2628        transaction.commit().await.expect("commit failed");
2629        volumes_directory
2630            .lock()
2631            .await
2632            .unmount(volume.volume().store().store_object_id())
2633            .await
2634            .expect("unmount failed");
2635
2636        let filesystem_clone = filesystem.clone();
2637        let filesystem_clone2 = filesystem.clone();
2638        let volumes_directory_clone1 = volumes_directory.clone();
2639        let volumes_directory_clone2 = volumes_directory.clone();
2640        let root_store_object_id = filesystem.root_store().store_object_id();
2641        let store_info_object_id = volume.volume().store().store_info_handle_object_id().unwrap();
2642        join!(
2643            async move {
2644                // Take a lock that the EndFlush transaction requires, so we interleave removing
2645                // the volume between StartFlush and EndFlush.  Release it on a timer since once the
2646                // volume is deleted, `remove_volume` needs to take this lock as well to tombstone
2647                // the store info.
2648                let _guard = filesystem_clone2
2649                    .lock_manager()
2650                    .read_lock(lock_keys![LockKey::object(
2651                        root_store_object_id,
2652                        store_info_object_id,
2653                    )])
2654                    .await;
2655                fasync::Timer::new(Duration::from_millis(200)).await;
2656            },
2657            async move {
2658                filesystem_clone.journal().force_compact().await.expect("Compact failed");
2659            },
2660            async move {
2661                if let Err(e) = volumes_directory_clone1.remove_volume(name).await {
2662                    if !FxfsError::NotFound.matches(&e) {
2663                        panic!("remove_volume failed: {e:?}");
2664                    }
2665                }
2666            },
2667            async move {
2668                if let Err(e) = volumes_directory_clone2.remove_volume(name).await {
2669                    if !FxfsError::NotFound.matches(&e) {
2670                        panic!("remove_volume failed: {e:?}");
2671                    }
2672                }
2673            },
2674        );
2675        volumes_directory.terminate().await;
2676        std::mem::drop(volumes_directory);
2677        filesystem.close().await.expect("Filesystem close");
2678    }
2679
2680    // This mostly just ensures that we exercise the code path. It was added because the path at
2681    // one point contained a deadlock.
2682    #[fuchsia::test(threads = 10)]
2683    async fn test_flush_before_mark_dirty_under_critical_memory_pressure() {
2684        let fixture = TestFixture::new().await;
2685        // Memory is critical, and it's always our fault.
2686        let _ = fixture
2687            .memory_pressure_proxy()
2688            .on_level_changed(MemoryPressureLevel::Critical)
2689            .await
2690            .expect("memory pressure FIDL");
2691        fixture.volumes_directory().max_dirty_bytes_when_critical.store(1, Ordering::Relaxed);
2692
2693        let root = fixture.root();
2694        let file = open_file_checked(
2695            &root,
2696            "foo",
2697            fio::Flags::FLAG_MAYBE_CREATE
2698                | fio::PERM_READABLE
2699                | fio::PERM_WRITABLE
2700                | fio::Flags::PROTOCOL_FILE,
2701            &Default::default(),
2702        )
2703        .await;
2704
2705        file.resize((zx::system_get_page_size() * 2).into())
2706            .await
2707            .expect("resize (FIDL)")
2708            .expect("resize failed");
2709        // The above resize creates zero pages which aren't dirty pages and don't contribute to the
2710        // dirty bytes count but still need to be flushed. The first write below will cross the
2711        // `max_dirty_bytes_when_critical` threshold but `minimize_memory` won't flush the file
2712        // because the zero pages aren't dirty pages. The second write below will also cross the
2713        // `max_dirty_bytes_when_critical` threshold and since the first write dirtied a page, a
2714        // flush will occur. The flush cleans the 2nd page which is a zero page and the kernel is
2715        // actively trying to dirty. The kernel doesn't end up dirtying the 2nd page because it's
2716        // concerned that the clean and dirty raced so it issues another dirty request for the same
2717        // page. The duplicate dirty request again crosses the `max_dirty_bytes_when_critical`
2718        // threshold. The file thinks that it has a dirty page so `minimize_memory` flushes the
2719        // file. `zx_pager_query_dirty_ranges` doesn't return any pages because the kernel didn't
2720        // actually dirty the page that fxfs thought it did. This causes only the file metadata to
2721        // be flushed and the dirty page count to not be reduced. The 2nd page finally gets dirtied
2722        // and now fxfs thinks it has 2 dirty pages instead of 1. `PagedObjectHandle` knows that
2723        // this can happen and will fix up the counts on the next flush. This test doesn't want to
2724        // deal with all of that so it syncs here to clean the zero pages that would cause that
2725        // mess.
2726        file.sync().await.expect("Failed to make sync call").expect("sync failed");
2727
2728        let vmo = file
2729            .get_backing_memory(fio::VmoFlags::READ | fio::VmoFlags::WRITE)
2730            .await
2731            .expect("get_backing_memory (FIDL)")
2732            .expect("get_backing_memory");
2733
2734        let buf = [0xAAu8];
2735        // One call to get dirty bytes over 0, the second to force a flush during mark_dirty.
2736        vmo.write(&buf, 0).expect("Writing to create dirty bytes");
2737        let before = fixture.volumes_directory().pager_dirty_bytes_count.load();
2738        vmo.write(&buf, zx::system_get_page_size().into())
2739            .expect("Writing to force a flush during mark_dirty");
2740        // This is still the page size because we forced a flush of the first write during the
2741        // second write.
2742        assert_eq!(fixture.volumes_directory().pager_dirty_bytes_count.load(), before,);
2743
2744        fixture.close().await;
2745    }
2746
2747    #[fuchsia::test(threads = 10)]
2748    async fn test_delete_crypt_for_volume() {
2749        let device = DeviceHolder::new(FakeDevice::new(8192, 512));
2750        let filesystem = FxFilesystem::new_empty(device).await.unwrap();
2751        let store_id;
2752        {
2753            let blob_resupplied_count =
2754                Arc::new(PageRefaultCounter::new().expect("Failed to create PageRefaultCounter"));
2755            let volumes_directory = VolumesDirectory::new(
2756                root_volume(filesystem.clone()).await.unwrap(),
2757                Weak::new(),
2758                None,
2759                blob_resupplied_count,
2760                MemoryPressureConfig::default(),
2761            )
2762            .await
2763            .unwrap();
2764            let name = "vol";
2765            let crypt = Arc::new(new_insecure_crypt());
2766            let volume = volumes_directory
2767                .create_and_mount_volume(name, Some(crypt.clone()), false, None)
2768                .await
2769                .unwrap();
2770            store_id = volume.volume().store().store_object_id();
2771            // Make sure the volume has some journaled mutations.
2772            let mut transaction = filesystem
2773                .root_store()
2774                .new_transaction(
2775                    lock_keys![LockKey::object(
2776                        volume.volume().store().store_object_id(),
2777                        volume.root_dir().directory().object_id()
2778                    )],
2779                    Options::default(),
2780                )
2781                .await
2782                .unwrap();
2783            volume
2784                .root_dir()
2785                .directory()
2786                .create_child_file(&mut transaction, "foo")
2787                .await
2788                .expect("create_child_file failed");
2789            transaction.commit().await.expect("commit failed");
2790
2791            let (volume_dir_proxy, dir_server_end) =
2792                fidl::endpoints::create_proxy::<fio::DirectoryMarker>();
2793            volumes_directory
2794                .serve_volume(&volume, dir_server_end, false)
2795                .expect("serve_volume failed");
2796            let (root_dir, root_server_end) =
2797                fidl::endpoints::create_proxy::<fio::DirectoryMarker>();
2798            volume_dir_proxy
2799                .open(
2800                    "root",
2801                    fio::PERM_READABLE | fio::PERM_WRITABLE | fio::Flags::PROTOCOL_DIRECTORY,
2802                    &Default::default(),
2803                    root_server_end.into_channel(),
2804                )
2805                .expect("Failed to open volume root");
2806
2807            let filesystem_clone = filesystem.clone();
2808            join!(
2809                async move {
2810                    filesystem_clone.journal().force_compact().await.expect("Compact failed");
2811                },
2812                async move {
2813                    let mut i = 0;
2814                    while let Ok(_) = fuchsia_fs::directory::open_file(
2815                        &root_dir,
2816                        &format!("foo{i}"),
2817                        fio::Flags::FLAG_MAYBE_CREATE | fio::PERM_READABLE,
2818                    )
2819                    .await
2820                    {
2821                        i += 1;
2822                    }
2823                },
2824                async move {
2825                    crypt.shutdown();
2826                },
2827            );
2828
2829            // Make sure we can still ask the volume to shutdown.
2830            let (admin_proxy, server_end) =
2831                fidl::endpoints::create_proxy::<fidl_fuchsia_fs::AdminMarker>();
2832            volume_dir_proxy
2833                .open(
2834                    &format!("svc/{}", fidl_fuchsia_fs::AdminMarker::PROTOCOL_NAME),
2835                    fio::Flags::PROTOCOL_SERVICE,
2836                    &Default::default(),
2837                    server_end.into(),
2838                )
2839                .expect("Failed to open Admin connection");
2840            admin_proxy.shutdown().await.expect("shutdown failed");
2841
2842            volumes_directory.terminate().await;
2843        }
2844        filesystem.close().await.expect("Filesystem close");
2845        let device = filesystem.take_device().await;
2846        device.reopen(false);
2847        let filesystem = FxFilesystem::open(device).await.expect("open failed");
2848        let options = FsckOptions { fail_on_warning: true, ..Default::default() };
2849        fsck_with_options(filesystem.clone(), &options).await.expect("fsck failed");
2850        fsck_volume_with_options(
2851            filesystem.as_ref(),
2852            &options,
2853            store_id,
2854            Some(Arc::new(new_insecure_crypt())),
2855        )
2856        .await
2857        .expect("fsck_volume failed");
2858        filesystem.close().await.expect("Filesystem close");
2859    }
2860
2861    /// Tests writing a partition image and installing a volume contained within.
2862    #[fuchsia::test(threads = 10)]
2863    async fn test_volume_installation() {
2864        let fixture = TestFixture::open(
2865            DeviceHolder::new(FakeDevice::new(1024, 4096)),
2866            TestFixtureOptions { format: true, encrypted: false, ..Default::default() },
2867        )
2868        .await;
2869
2870        // Create a file "foo" in the existing volume "vol". This should be gone after installation.
2871        {
2872            let file = open_file_checked(
2873                fixture.root(),
2874                "foo",
2875                fio::Flags::PROTOCOL_FILE | fio::Flags::FLAG_MUST_CREATE | fio::PERM_WRITABLE,
2876                &Default::default(),
2877            )
2878            .await;
2879            file.write("Hello, world!".as_bytes()).await.unwrap().expect("write failed");
2880        };
2881
2882        // Create another in-memory partition image with a different set of files.
2883        let image = {
2884            let inner_fixture = TestFixture::open(
2885                DeviceHolder::new(FakeDevice::new(512, 4096)),
2886                TestFixtureOptions { format: true, encrypted: false, ..Default::default() },
2887            )
2888            .await;
2889            let file = open_file_checked(
2890                inner_fixture.root(),
2891                "bar",
2892                fio::Flags::PROTOCOL_FILE | fio::Flags::FLAG_MUST_CREATE | fio::PERM_WRITABLE,
2893                &Default::default(),
2894            )
2895            .await;
2896            file.write("Well, this is new...".as_bytes()).await.unwrap().expect("write failed");
2897            file.close().await.unwrap().expect("close error");
2898            inner_fixture.close().await
2899        };
2900
2901        // Write the partition image to a file "install" in a new volume called "src".
2902        {
2903            let (src_out_dir, server_end) = fidl::endpoints::create_proxy::<fio::DirectoryMarker>();
2904            fixture
2905                .volumes_directory()
2906                .create_and_serve_volume("src", server_end, Default::default(), Default::default())
2907                .await
2908                .unwrap();
2909            let src_root = open_dir_checked(
2910                &src_out_dir,
2911                "root",
2912                fio::PERM_READABLE | fio::PERM_WRITABLE,
2913                Default::default(),
2914            )
2915            .await;
2916            let file = open_file_checked(
2917                &src_root,
2918                "image",
2919                fio::Flags::PROTOCOL_FILE | fio::Flags::FLAG_MUST_CREATE | fio::PERM_WRITABLE,
2920                &Default::default(),
2921            )
2922            .await;
2923            write_image_to_file(image, file).await;
2924        };
2925
2926        // Installation should not be possible yet since both volumes are still mounted.
2927        assert!(
2928            fixture.volumes_directory().install_volume("src", "image", "vol").await.is_err(),
2929            "volume installation should fail while either src/dst is still mounted"
2930        );
2931
2932        // Now let's re-mount the filesystem manually without a fixture, install the volumes, and
2933        // spin up a new fixture to verify the result.
2934        let device = fixture.close().await;
2935        let fs = FxFilesystem::open(device).await.unwrap();
2936        {
2937            let root = root_volume(fs.clone()).await.unwrap();
2938            root.install_volume("src", "image", "vol").await.unwrap();
2939        }
2940        fs.close().await.unwrap();
2941        let device = fs.take_device().await;
2942        device.reopen(/*read_only*/ true);
2943        let fixture = TestFixture::open(
2944            device,
2945            TestFixtureOptions { encrypted: false, format: false, ..Default::default() },
2946        )
2947        .await;
2948
2949        // Ensure that the "src" volume is now gone, and the old file "foo" is gone from "vol".
2950        assert!(
2951            fixture.volumes_directory().mount_volume("src", None, false).await.is_err(),
2952            "src volume should be deleted after installation"
2953        );
2954        assert!(
2955            testing::open_file(
2956                fixture.volume_out_dir(),
2957                "foo",
2958                fio::PERM_READABLE,
2959                &Default::default()
2960            )
2961            .await
2962            .is_err(),
2963            "foo should be deleted after installation"
2964        );
2965
2966        // Check that we can find the contents of "vol" that we installed from the image.
2967        let file =
2968            open_file_checked(fixture.root(), "bar", fio::PERM_READABLE, &Default::default()).await;
2969        let data = file.read(fio::MAX_TRANSFER_SIZE).await.unwrap().expect("read failed");
2970        assert_eq!(String::from_utf8(data).unwrap(), "Well, this is new...");
2971        file.close().await.unwrap().unwrap();
2972
2973        fixture.close().await;
2974    }
2975
2976    #[fuchsia::test]
2977    async fn test_create_with_low_32_bit_ids() {
2978        let device = DeviceHolder::new(FakeDevice::new(8192, 512));
2979        let filesystem = FxFilesystem::new_empty(device).await.unwrap();
2980        let blob_resupplied_count =
2981            Arc::new(PageRefaultCounter::new().expect("Failed to create PageRefaultCounter"));
2982
2983        {
2984            let volumes_directory = VolumesDirectory::new(
2985                root_volume(filesystem.clone()).await.unwrap(),
2986                Weak::new(),
2987                None,
2988                blob_resupplied_count,
2989                MemoryPressureConfig::default(),
2990            )
2991            .await
2992            .unwrap();
2993
2994            let mut guard = volumes_directory.lock().await;
2995
2996            let vol = guard
2997                .create_or_mount_volume(
2998                    "low_32",
2999                    None,
3000                    Mode::Create { guid: None, low_32_bit_object_ids: true },
3001                    false,
3002                )
3003                .await
3004                .expect("create volume failed");
3005
3006            let root_dir = vol.volume().store().root_directory_object_id();
3007            let root_dir = fxfs::object_store::Directory::open(vol.volume().store(), root_dir)
3008                .await
3009                .expect("open failed");
3010
3011            let mut transaction = filesystem
3012                .root_store()
3013                .new_transaction(
3014                    lock_keys![LockKey::object(
3015                        vol.volume().store().store_object_id(),
3016                        root_dir.object_id()
3017                    )],
3018                    Options::default(),
3019                )
3020                .await
3021                .expect("new_transaction failed");
3022
3023            let object = root_dir
3024                .create_child_file(&mut transaction, "test")
3025                .await
3026                .expect("create_child_file failed");
3027
3028            // We can't check LastObjectIdInfo as it is private, but we can verify behavior.
3029            assert!(object.object_id() < 1 << 32);
3030            transaction.commit().await.expect("commit failed");
3031        };
3032
3033        filesystem.close().await.expect("close filesystem failed");
3034
3035        // Reopen and verify persistence
3036        let device = filesystem.take_device().await;
3037        device.reopen(false);
3038        let filesystem = FxFilesystem::open(device).await.unwrap();
3039        let blob_resupplied_count =
3040            Arc::new(PageRefaultCounter::new().expect("Failed to create PageRefaultCounter"));
3041        let volumes_directory = VolumesDirectory::new(
3042            root_volume(filesystem.clone()).await.unwrap(),
3043            Weak::new(),
3044            None,
3045            blob_resupplied_count,
3046            MemoryPressureConfig::default(),
3047        )
3048        .await
3049        .unwrap();
3050
3051        // Mount the volume again, and check that new files are still created with expected IDs.
3052        {
3053            let mut guard = volumes_directory.lock().await;
3054
3055            let vol = guard
3056                .create_or_mount_volume("low_32", None, Mode::Mount, false)
3057                .await
3058                .expect("mount volume failed");
3059
3060            let root_dir = vol.volume().store().root_directory_object_id();
3061            let root_dir = fxfs::object_store::Directory::open(vol.volume().store(), root_dir)
3062                .await
3063                .expect("open failed");
3064
3065            let mut transaction = filesystem
3066                .root_store()
3067                .new_transaction(
3068                    lock_keys![LockKey::object(
3069                        vol.volume().store().store_object_id(),
3070                        root_dir.object_id()
3071                    )],
3072                    Options::default(),
3073                )
3074                .await
3075                .expect("new_transaction failed");
3076
3077            let object = root_dir
3078                .create_child_file(&mut transaction, "test2")
3079                .await
3080                .expect("create_child_file failed");
3081
3082            assert!(object.object_id() < 1 << 32);
3083            transaction.commit().await.expect("commit failed");
3084        }
3085
3086        filesystem.close().await.expect("close filesystem failed");
3087    }
3088
3089    #[fuchsia::test(threads = 10)]
3090    async fn test_race_unmount_and_flush_with_crypt_error() {
3091        let device = DeviceHolder::new(FakeDevice::new(8192, 512));
3092        let filesystem = FxFilesystem::new_empty(device).await.unwrap();
3093        let blob_resupplied_count = Arc::new(PageRefaultCounter::new().unwrap());
3094        let volumes_directory = VolumesDirectory::new(
3095            root_volume(filesystem.clone()).await.unwrap(),
3096            Weak::new(),
3097            None,
3098            blob_resupplied_count,
3099            MemoryPressureConfig::default(),
3100        )
3101        .await
3102        .unwrap();
3103
3104        let crypt_service = Arc::new(fxfs_crypt::CryptService::new());
3105        crypt_service
3106            .add_wrapping_key(0, fxfs_insecure_crypto::DATA_KEY.to_vec())
3107            .expect("add_wrapping_key failed");
3108        crypt_service
3109            .add_wrapping_key(1, fxfs_insecure_crypto::METADATA_KEY.to_vec())
3110            .expect("add_wrapping_key failed");
3111        crypt_service.set_active_key(KeyPurpose::Data, 0).expect("set_active_key failed");
3112        crypt_service.set_active_key(KeyPurpose::Metadata, 1).expect("set_active_key failed");
3113
3114        for _ in 0..20 {
3115            let (client, mut stream) = create_request_stream::<fidl_fuchsia_fxfs::CryptMarker>();
3116            let (close_tx, mut close_rx) = futures::channel::oneshot::channel::<()>();
3117
3118            let crypt_task = fasync::Task::spawn(async move {
3119                loop {
3120                    futures::select! {
3121                        _ = close_rx => return, // Close signal
3122                        request = stream.try_next() => {
3123                            match request {
3124                                Ok(Some(CryptRequest::CreateKey { responder, .. })) => {
3125                                    responder.send(Ok((&[0; 16], &[0; 48], &[0; 32]))).unwrap();
3126                                }
3127                                Ok(Some(CryptRequest::CreateKeyWithId {
3128                                        wrapping_key_id, responder, .. })) => {
3129                                    let key = WrappedKey::Fxfs(FxfsKey {
3130                                        wrapping_key_id,
3131                                        wrapped_key: [0u8; 48],
3132                                    });
3133                                    responder.send(Ok((&key, &[0; 32]))).unwrap();
3134                                }
3135                                Ok(Some(CryptRequest::UnwrapKey { responder, .. })) => {
3136                                    responder.send(Ok(&vec![0; 32])).unwrap();
3137                                }
3138                                _ => return,
3139                            }
3140                        }
3141                    }
3142                }
3143            });
3144
3145            let volume = volumes_directory
3146                .create_and_mount_volume(
3147                    "encrypted",
3148                    Some(Arc::new(RemoteCrypt::new(client))),
3149                    false,
3150                    None,
3151                )
3152                .await
3153                .unwrap();
3154
3155            // Write some data to dirty the journal.
3156            {
3157                let mut transaction = filesystem
3158                    .root_store()
3159                    .new_transaction(
3160                        lock_keys![LockKey::object(
3161                            volume.volume().store().store_object_id(),
3162                            volume.root_dir().directory().object_id()
3163                        )],
3164                        Options::default(),
3165                    )
3166                    .await
3167                    .unwrap();
3168                volume
3169                    .root_dir()
3170                    .directory()
3171                    .create_child_file(&mut transaction, "foo")
3172                    .await
3173                    .expect("create_child_file failed");
3174                transaction.commit().await.expect("commit failed");
3175            }
3176
3177            let (dir_proxy, dir_server_end) =
3178                fidl::endpoints::create_proxy::<fio::DirectoryMarker>();
3179            volumes_directory.serve_volume(&volume, dir_server_end, false).unwrap();
3180            volumes_directory.lock().await.auto_unmount(volume.volume().store().store_object_id());
3181
3182            // Kill crypt.  The next usage should be in flush.
3183            let _ = close_tx.send(());
3184
3185            let filesystem_clone = filesystem.clone();
3186            let compact_task = fasync::Task::spawn(async move {
3187                // Flush should not fail, because that would close the journal for the rest of the
3188                // filesystem.  Instead, the volume should be force-locked and flushed (which
3189                // doesn't depend on crypt).
3190                filesystem_clone.object_manager().flush().await.expect("flush failed");
3191            });
3192
3193            // Trigger unmount.
3194            std::mem::drop(dir_proxy);
3195
3196            // Wait for volume to be unmounted, so we can clean up for the next iteration.
3197            let store_id = volume.volume().store().store_object_id();
3198            loop {
3199                {
3200                    let guard = volumes_directory.lock().await;
3201                    if !guard.mounted_volumes.contains_key(&store_id) {
3202                        break;
3203                    }
3204                }
3205                fasync::Timer::new(Duration::from_millis(10)).await;
3206            }
3207
3208            join!(compact_task, crypt_task);
3209            volumes_directory.remove_volume("encrypted").await.expect("remove_volume failed");
3210        }
3211        volumes_directory.terminate().await;
3212        filesystem.close().await.expect("close filesystem failed");
3213    }
3214}