1use crate::errors::FxfsError;
6use crate::filesystem::FxFilesystem;
7use crate::object_store::directory::Directory;
8use crate::object_store::transaction::{LockKeys, Mutation, Options, Transaction, lock_keys};
9use crate::object_store::tree_cache::TreeCache;
10use crate::object_store::{
11 ChildValue, DirType, INVALID_OBJECT_ID, LockKey, NewChildStoreOptions, ObjectDescriptor,
12 ObjectKey, ObjectStore, ObjectValue, StoreOptions, load_store_info,
13};
14use anyhow::{Context, Error, anyhow, bail, ensure};
15use std::sync::Arc;
16
17pub const VOLUMES_DIRECTORY: &str = "volumes";
25
26pub struct RootVolume {
28 _root_directory: Directory<ObjectStore>,
29 filesystem: Arc<FxFilesystem>,
30}
31
32impl RootVolume {
33 pub fn volume_directory(&self) -> &Directory<ObjectStore> {
34 self.filesystem.object_manager().volume_directory()
35 }
36
37 pub async fn new_volume(
39 &self,
40 volume_name: &str,
41 options: NewChildStoreOptions,
42 ) -> Result<Arc<ObjectStore>, Error> {
43 let root_store = self.filesystem.root_store();
44 let store;
45 let mut transaction = root_store
46 .new_transaction(
47 lock_keys![LockKey::object(
48 root_store.store_object_id(),
49 self.volume_directory().object_id(),
50 )],
51 Options::default(),
52 )
53 .await?;
54
55 ensure!(
56 matches!(self.volume_directory().lookup(volume_name).await?, None),
57 FxfsError::AlreadyExists
58 );
59 store = root_store
60 .new_child_store(&mut transaction, options, Box::new(TreeCache::new()))
61 .await?;
62 store.set_trace(self.filesystem.trace());
63
64 self.filesystem.object_manager().add_store(store.clone());
66
67 struct CleanUp<'a>(&'a ObjectStore);
69 impl Drop for CleanUp<'_> {
70 fn drop(&mut self) {
71 self.0.filesystem().object_manager().forget_store(self.0.store_object_id());
72 }
73 }
74 let clean_up = CleanUp(&store);
75
76 store.create(&mut transaction).await?;
78
79 self.volume_directory()
80 .add_child_volume(&mut transaction, volume_name, store.store_object_id())
81 .await?;
82 transaction.commit().await?;
83
84 std::mem::forget(clean_up);
85
86 Ok(store)
87 }
88
89 pub async fn volume(
91 &self,
92 volume_name: &str,
93 options: StoreOptions,
94 ) -> Result<Arc<ObjectStore>, Error> {
95 let (store_object_id, descriptor, _) = self
97 .volume_directory()
98 .lookup(volume_name)
99 .await
100 .context("Volume lookup failed")?
101 .ok_or(FxfsError::NotFound)
102 .context("Volume missing in volume directory")?;
103 match descriptor {
104 ObjectDescriptor::Volume => (),
105 _ => bail!(anyhow!(FxfsError::Inconsistent).context("Expected volume")),
106 }
107 let store = self
109 .filesystem
110 .object_manager()
111 .store(store_object_id)
112 .ok_or(FxfsError::NotFound)
113 .context("Missing volume store")?;
114 store.set_trace(self.filesystem.trace());
115 if let Some(crypt) = options.crypt {
117 let read_only = self.filesystem.options().read_only;
118 store.unlock_inner(crypt, read_only).await.context("Failed to unlock volume")?;
119 } else if store.is_locked() {
120 bail!(FxfsError::AccessDenied);
121 }
122 Ok(store)
123 }
124
125 pub async fn delete_volume(
128 &self,
129 volume_name: &str,
130 mut transaction: Transaction<'_>,
131 callback: impl FnOnce() + Send,
132 ) -> Result<(), Error> {
133 let objects_to_delete = self.delete_volume_impl(volume_name, &mut transaction).await?;
134 transaction.commit_with_callback(|_| callback()).await.context("commit")?;
135 let root_store = self.filesystem.root_store();
137 for object_id in &objects_to_delete {
138 root_store.tombstone_object(*object_id, Options::default()).await?;
139 }
140 Ok(())
141 }
142
143 async fn delete_volume_impl(
144 &self,
145 volume_name: &str,
146 transaction: &mut Transaction<'_>,
147 ) -> Result<Vec<u64>, Error> {
148 let object_id =
149 match self.volume_directory().lookup(volume_name).await?.ok_or(FxfsError::NotFound)? {
150 (object_id, ObjectDescriptor::Volume, _) => object_id,
151 _ => bail!(anyhow!(FxfsError::Inconsistent).context("Expected volume")),
152 };
153 let root_store = self.filesystem.root_store();
154
155 let mut objects_to_delete = load_store_info(&root_store, object_id).await?.parent_objects();
158 objects_to_delete.push(object_id);
159
160 for object_id in &objects_to_delete {
161 root_store.adjust_refs(transaction, *object_id, -1).await?;
162 }
163 self.filesystem.allocator().mark_for_deletion(transaction, object_id);
165 self.volume_directory().delete_child_volume(transaction, volume_name, object_id)?;
167 Ok(objects_to_delete)
168 }
169
170 pub(crate) async fn replace_volume(
174 &self,
175 transaction: &mut Transaction<'_>,
176 src: &str,
177 dst: &str,
178 ) -> Result<Option<Vec<u64>>, Error> {
179 let src_object_id = match self.volume_directory().lookup(src).await? {
180 Some((object_id, ObjectDescriptor::Volume, _)) => Ok(object_id),
181 Some(_) => Err(FxfsError::Inconsistent),
182 None => Err(FxfsError::NotFound),
183 }?;
184
185 let replaced_objects = if let Some((_, ObjectDescriptor::Volume, _)) =
186 self.volume_directory().lookup(dst).await?
187 {
188 Some(self.delete_volume_impl(dst, transaction).await?)
189 } else {
190 None
191 };
192
193 transaction.add(
194 self.volume_directory().store().store_object_id(),
195 Mutation::replace_or_insert_object(
196 ObjectKey::child(self.volume_directory().object_id(), src, DirType::Normal),
197 ObjectValue::None,
198 ),
199 );
200
201 transaction.add(
202 self.volume_directory().store().store_object_id(),
203 Mutation::replace_or_insert_object(
204 ObjectKey::child(self.volume_directory().object_id(), dst, DirType::Normal),
205 ObjectValue::Child(ChildValue {
206 object_id: src_object_id,
207 object_descriptor: ObjectDescriptor::Volume,
208 }),
209 ),
210 );
211
212 Ok(replaced_objects)
213 }
214
215 pub async fn install_volume(
223 &self,
224 src: &str,
225 image_file: &str,
226 dst: &str,
227 ) -> Result<(), Error> {
228 ObjectStore::install_volume(self, src, image_file, dst).await
229 }
230
231 pub async fn acquire_transaction_for_remove_volume(
234 &self,
235 name: &str,
236 extra_keys: impl IntoIterator<Item = LockKey>,
237 allow_not_found: bool,
238 ) -> Result<(u64, Transaction<'_>), Error> {
239 let volume_dir = self.volume_directory();
243 let store = volume_dir.store();
244 let extra_keys = extra_keys.into_iter();
245 let mut lock_keys = Vec::with_capacity(extra_keys.size_hint().1.unwrap_or(2) + 2);
246 lock_keys.extend(extra_keys);
247 lock_keys.push(LockKey::object(store.store_object_id(), volume_dir.object_id()));
248 let orig_len = lock_keys.len();
249 let mut transaction = None;
250 loop {
251 lock_keys.truncate(orig_len);
252 let object_id = match volume_dir.lookup(name).await? {
253 Some((object_id, ObjectDescriptor::Volume, _)) => {
254 lock_keys.push(LockKey::flush(object_id));
258 object_id
259 }
260 None => {
261 if allow_not_found {
262 INVALID_OBJECT_ID
263 } else {
264 bail!(FxfsError::NotFound);
265 }
266 }
267 _ => bail!(anyhow!(FxfsError::Inconsistent).context("Expected volume")),
268 };
269
270 match transaction {
272 Some(result @ (id, _)) if id == object_id => return Ok(result),
273 _ => {}
274 }
275
276 transaction = Some((
277 object_id,
278 store
279 .new_transaction(
280 LockKeys::Vec(lock_keys.clone()),
281 Options { borrow_metadata_space: true, ..Default::default() },
282 )
283 .await?,
284 ));
285 }
286 }
287}
288
289pub async fn root_volume(filesystem: Arc<FxFilesystem>) -> Result<RootVolume, Error> {
291 let root_store = filesystem.root_store();
292 let root_directory = Directory::open(&root_store, root_store.root_directory_object_id())
293 .await
294 .context("Unable to open root volume directory")?;
295 Ok(RootVolume { _root_directory: root_directory, filesystem })
296}
297
298pub async fn list_volumes(volume_directory: &Directory<ObjectStore>) -> Result<Vec<u64>, Error> {
300 let layer_set = volume_directory.store().tree().layer_set();
301 let mut merger = layer_set.merger();
302 let mut iter = volume_directory.iter(&mut merger).await?;
303 let mut object_ids = vec![];
304 while let Some((_, id, _)) = iter.get() {
305 object_ids.push(id);
306 iter.advance().await?;
307 }
308 Ok(object_ids)
309}
310
311#[cfg(test)]
312mod tests {
313 use super::root_volume;
314 use crate::filesystem::{FxFilesystem, JournalingObject, SyncOptions};
315 use crate::fsck::{FsckOptions, fsck_volume_with_options, fsck_with_options};
316 use crate::object_handle::{ObjectHandle, WriteObjectHandle};
317 use crate::object_store::directory::Directory;
318 use crate::object_store::transaction::{Options, lock_keys};
319 use crate::object_store::{LockKey, NewChildStoreOptions, StoreOptions};
320 use fxfs_crypto::Crypt;
321 use fxfs_insecure_crypto::new_insecure_crypt;
322 use std::sync::Arc;
323 use storage_device::DeviceHolder;
324 use storage_device::fake_device::FakeDevice;
325
326 async fn do_fsck(
327 fs: &Arc<FxFilesystem>,
328 volume_name: Option<&str>,
329 crypt: Option<Arc<dyn Crypt>>,
330 ) {
331 let fsck_options = FsckOptions {
332 fail_on_warning: true,
333 on_error: Box::new(|err| eprintln!("fsck error: {:?}", err)),
334 ..Default::default()
335 };
336 fsck_with_options(fs.clone(), &fsck_options).await.expect("fsck filesystem");
337 if let Some(volume_name) = volume_name {
338 let root = root_volume(fs.clone()).await.unwrap();
339 let vol = root
340 .volume(
341 volume_name,
342 StoreOptions { crypt: crypt.clone(), ..StoreOptions::default() },
343 )
344 .await
345 .expect("could not open volume");
346 fsck_volume_with_options(&fs, &fsck_options, vol.store_object_id(), crypt)
347 .await
348 .expect("fsck volume");
349 }
350 }
351
352 #[fuchsia::test]
353 async fn test_lookup_nonexistent_volume() {
354 let device = DeviceHolder::new(FakeDevice::new(8192, 512));
355 let filesystem = FxFilesystem::new_empty(device).await.expect("new_empty failed");
356 let root_volume = root_volume(filesystem.clone()).await.expect("root_volume failed");
357 root_volume
358 .volume(
359 "vol",
360 StoreOptions {
361 crypt: Some(Arc::new(new_insecure_crypt())),
362 ..StoreOptions::default()
363 },
364 )
365 .await
366 .err()
367 .expect("Volume shouldn't exist");
368 filesystem.close().await.expect("Close failed");
369 }
370
371 #[fuchsia::test]
372 async fn test_add_volume() {
373 let device = DeviceHolder::new(FakeDevice::new(16384, 512));
374 let filesystem = FxFilesystem::new_empty(device).await.expect("new_empty failed");
375 let crypt = Arc::new(new_insecure_crypt());
376 {
377 let root_volume = root_volume(filesystem.clone()).await.expect("root_volume failed");
378 let store = root_volume
379 .new_volume(
380 "vol",
381 NewChildStoreOptions {
382 options: StoreOptions {
383 crypt: Some(crypt.clone()),
384 ..StoreOptions::default()
385 },
386 ..Default::default()
387 },
388 )
389 .await
390 .expect("new_volume failed");
391 let mut transaction = filesystem
392 .root_store()
393 .new_transaction(
394 lock_keys![LockKey::object(
395 store.store_object_id(),
396 store.root_directory_object_id()
397 )],
398 Options::default(),
399 )
400 .await
401 .expect("new transaction failed");
402 let root_directory = Directory::open(&store, store.root_directory_object_id())
403 .await
404 .expect("open failed");
405 root_directory
406 .create_child_file(&mut transaction, "foo")
407 .await
408 .expect("create_child_file failed");
409 transaction.commit().await.expect("commit failed");
410 filesystem.sync(SyncOptions::default()).await.expect("sync failed");
411 };
412 {
413 filesystem.close().await.expect("Close failed");
414 let device = filesystem.take_device().await;
415 device.reopen(false);
416 let filesystem = FxFilesystem::open(device).await.expect("open failed");
417 do_fsck(&filesystem, Some("vol"), Some(crypt)).await;
418 let root_volume = root_volume(filesystem.clone()).await.expect("root_volume failed");
419 let volume = root_volume
421 .volume("vol", StoreOptions { crypt: None, ..StoreOptions::default() })
422 .await
423 .expect("volume failed");
424 let root_directory = Directory::open(&volume, volume.root_directory_object_id())
425 .await
426 .expect("open failed");
427 root_directory.lookup("foo").await.expect("lookup failed").expect("not found");
428 filesystem.close().await.expect("Close failed");
429 };
430 }
431
432 #[fuchsia::test]
433 async fn test_delete_volume() {
434 let device = DeviceHolder::new(FakeDevice::new(16384, 512));
435 let filesystem = FxFilesystem::new_empty(device).await.expect("new_empty failed");
436 let crypt = Arc::new(new_insecure_crypt());
437 let store_object_id;
438 let parent_objects;
439 let store_id = {
441 let root_volume = root_volume(filesystem.clone()).await.expect("root_volume failed");
442 let store = root_volume
443 .new_volume(
444 "vol",
445 NewChildStoreOptions {
446 options: StoreOptions {
447 crypt: Some(crypt.clone()),
448 ..StoreOptions::default()
449 },
450 ..Default::default()
451 },
452 )
453 .await
454 .expect("new_volume failed");
455 store_object_id = store.store_object_id();
456 let mut transaction = filesystem
457 .root_store()
458 .new_transaction(
459 lock_keys![LockKey::object(store_object_id, store.root_directory_object_id())],
460 Options::default(),
461 )
462 .await
463 .expect("new transaction failed");
464 let root_directory = Directory::open(&store, store.root_directory_object_id())
465 .await
466 .expect("open failed");
467 let handle = root_directory
468 .create_child_file(&mut transaction, "foo")
469 .await
470 .expect("create_child_file failed");
471 transaction.commit().await.expect("commit failed");
472
473 let mut buf = handle.allocate_buffer(8192).await;
474 buf.as_mut_slice().fill(0xaa);
475 handle.write_or_append(Some(0), buf.as_ref()).await.expect("write failed");
476 store.flush().await.expect("flush failed");
477 filesystem.sync(SyncOptions::default()).await.expect("sync failed");
478 parent_objects = store.parent_objects();
479 for object_id in &parent_objects {
481 let _ = filesystem
482 .root_store()
483 .get_file_size(*object_id)
484 .await
485 .expect("Layer file missing? Bug in test.");
486 }
487 store.store_object_id()
488 };
489 filesystem.close().await.expect("Close failed");
490 let device = filesystem.take_device().await;
491 device.reopen(false);
492 let filesystem = FxFilesystem::open(device).await.expect("open failed");
493 do_fsck(&filesystem, Some("vol"), Some(crypt.clone())).await;
494 {
495 assert_eq!(
497 filesystem.allocator().get_owner_allocated_bytes().get(&store_object_id),
498 Some(&8192)
499 );
500 let root = root_volume(filesystem.clone()).await.expect("root_volume failed");
501 let transaction = filesystem
502 .root_store()
503 .new_transaction(
504 lock_keys![
505 LockKey::object(
506 root.volume_directory().store().store_object_id(),
507 root.volume_directory().object_id(),
508 ),
509 LockKey::flush(store_id)
510 ],
511 Options { borrow_metadata_space: true, ..Default::default() },
512 )
513 .await
514 .expect("new_transaction failed");
515 root.delete_volume("vol", transaction, || {}).await.expect("delete_volume");
516 assert_eq!(
518 filesystem
519 .allocator()
520 .get_owner_allocated_bytes()
521 .get(&store_object_id)
522 .unwrap_or(&0),
523 &0,
524 );
525 root.volume(
527 "vol",
528 StoreOptions { crypt: Some(crypt.clone()), ..StoreOptions::default() },
529 )
530 .await
531 .err()
532 .expect("volume shouldn't exist anymore.");
533 }
534 filesystem.close().await.expect("Close failed");
535 let device = filesystem.take_device().await;
536 device.reopen(false);
537 let filesystem = FxFilesystem::open(device).await.expect("open failed");
539 do_fsck(&filesystem, None, None).await;
540 for object_id in &parent_objects {
541 let _ = filesystem
542 .root_store()
543 .get_file_size(*object_id)
544 .await
545 .err()
546 .expect("File wasn't deleted.");
547 }
548 filesystem.close().await.expect("Close failed");
549 }
550
551 #[fuchsia::test]
552 async fn test_replace_volume() {
553 let device = DeviceHolder::new(FakeDevice::new(16384, 512));
554 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
555 {
557 let root = root_volume(fs.clone()).await.expect("root_volume failed");
558 let store = root.new_volume("vol", NewChildStoreOptions::default()).await.unwrap();
559 let mut transaction = fs
560 .root_store()
561 .new_transaction(
562 lock_keys![LockKey::object(
563 store.store_object_id(),
564 store.root_directory_object_id()
565 )],
566 Options::default(),
567 )
568 .await
569 .unwrap();
570 let root_directory =
571 Directory::open(&store, store.root_directory_object_id()).await.unwrap();
572 let _ = root_directory.create_child_file(&mut transaction, "foo").await.unwrap();
573 transaction.commit().await.expect("commit failed");
574 }
575 {
577 let root = root_volume(fs.clone()).await.expect("root_volume failed");
578 let store = root
579 .new_volume("vol2", NewChildStoreOptions::default())
580 .await
581 .expect("new_volume failed");
582 let mut transaction = fs
583 .root_store()
584 .new_transaction(
585 lock_keys![LockKey::object(
586 store.store_object_id(),
587 store.root_directory_object_id()
588 )],
589 Options::default(),
590 )
591 .await
592 .expect("new transaction failed");
593 let root_directory = Directory::open(&store, store.root_directory_object_id())
594 .await
595 .expect("open failed");
596 let _ = root_directory
597 .create_child_file(&mut transaction, "foo2")
598 .await
599 .expect("create_child_file failed");
600 transaction.commit().await.expect("commit failed");
601 }
602 {
604 let root = root_volume(fs.clone()).await.expect("root_volume failed");
605 let mut transaction =
606 root.acquire_transaction_for_remove_volume("vol", [], false).await.unwrap().1;
607 root.replace_volume(&mut transaction, "vol2", "vol").await.unwrap();
608 transaction.commit().await.unwrap();
609 do_fsck(&fs, Some("vol"), None).await;
610 }
611 fs.close().await.expect("Close failed");
612 let device = fs.take_device().await;
613 device.reopen(false);
614 let fs = FxFilesystem::open(device).await.unwrap();
615 do_fsck(&fs, Some("vol"), None).await;
616 {
617 let root = root_volume(fs.clone()).await.unwrap();
618 root.volume("vol2", StoreOptions::default())
620 .await
621 .err()
622 .expect("vol2 shouldn't exist anymore.");
623 let vol = root.volume("vol", StoreOptions::default()).await.unwrap();
624 let dir = Directory::open(&vol, vol.root_directory_object_id()).await.unwrap();
625 assert!(dir.lookup("foo").await.unwrap().is_none(), "foo should not be present");
627 assert!(dir.lookup("foo2").await.unwrap().is_some(), "foo2 should be present");
628 }
629 fs.close().await.unwrap();
630 }
631
632 #[fuchsia::test]
633 async fn test_create_volume_with_guid() {
634 let device = DeviceHolder::new(FakeDevice::new(16384, 512));
635 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
636 let guid = [1u8; 16];
637 {
638 let root = root_volume(fs.clone()).await.expect("root_volume failed");
639 let store = root
640 .new_volume("vol", NewChildStoreOptions { guid: Some(guid), ..Default::default() })
641 .await
642 .unwrap();
643 assert_eq!(store.store_info().unwrap().guid, guid);
644 }
645 fs.close().await.expect("Close failed");
646 let device = fs.take_device().await;
647 device.reopen(false);
648 let fs = FxFilesystem::open(device).await.unwrap();
649 {
650 let root = root_volume(fs.clone()).await.unwrap();
651 let vol = root.volume("vol", StoreOptions::default()).await.unwrap();
652 assert_eq!(vol.guid(), guid);
653 }
654 fs.close().await.unwrap();
655 }
656}