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