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